feat: 实现域名绑定与授权 ip 功能 (#1089)

This commit is contained in:
ssongliu 2023-05-19 21:47:46 +08:00 committed by GitHub
parent c2f5908a9d
commit 8fd4060562
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 591 additions and 7 deletions

View file

@ -18,6 +18,8 @@ type SettingInfo struct {
ServerPort string `json:"serverPort"`
SSL string `json:"ssl"`
SSLType string `json:"sslType"`
BindDomain string `json:"bindDomain"`
AllowIPs string `json:"allowIPs"`
SecurityEntrance string `json:"securityEntrance"`
ExpirationDays string `json:"expirationDays"`
ExpirationTime string `json:"expirationTime"`

View file

@ -67,6 +67,12 @@ func (u *SettingService) Update(key, value string) error {
return err
}
}
if key == "BindDomain" {
global.CONF.System.BindDomain = value
}
if key == "AllowIPs" {
global.CONF.System.AllowIPs = value
}
if err := settingRepo.Update(key, value); err != nil {
return err
}

View file

@ -21,4 +21,6 @@ type System struct {
IsDemo bool `mapstructure:"is_demo"`
AppRepo string `mapstructure:"app_repo"`
ChangeUserInfo bool `mapstructure:"change_user_info"`
AllowIPs string `mapstructure:"allow_ips"`
BindDomain string `mapstructure:"bind_domain"`
}

View file

@ -14,6 +14,8 @@ const (
CodePasswordExpired = 405
CodeAuth = 406
CodeGlobalLoading = 407
CodeErrIP = 408
CodeErrDomain = 409
CodeErrInternalServer = 500
CodeErrHeader = 406
)

View file

@ -26,6 +26,18 @@ func Init() {
}
global.CONF.System.SSL = sslSetting.Value
ipsSetting, err := settingRepo.Get(settingRepo.WithByKey("AllowIPs"))
if err != nil {
global.LOG.Errorf("load allow ips from setting failed, err: %v", err)
}
global.CONF.System.AllowIPs = ipsSetting.Value
domainSetting, err := settingRepo.Get(settingRepo.WithByKey("BindDomain"))
if err != nil {
global.LOG.Errorf("load bind domain from setting failed, err: %v", err)
}
global.CONF.System.BindDomain = domainSetting.Value
if _, err := settingRepo.Get(settingRepo.WithByKey("SystemStatus")); err != nil {
_ = settingRepo.Create("SystemStatus", "Free")
}

View file

@ -28,6 +28,7 @@ func Init() {
migrations.AddEntranceAndSSL,
migrations.UpdateTableSetting,
migrations.UpdateTableAppDetail,
migrations.AddBindAndAllowIPs,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View file

@ -335,3 +335,16 @@ var UpdateTableAppDetail = &gormigrate.Migration{
return nil
},
}
var AddBindAndAllowIPs = &gormigrate.Migration{
ID: "20230414-add-bind-and-allow",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "BindDomain", Value: ""}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "AllowIPs", Value: ""}).Error; err != nil {
return err
}
return nil
},
}

View file

@ -63,6 +63,8 @@ func Routers() *gin.Engine {
})
}
PrivateGroup := Router.Group("/api/v1")
PrivateGroup.Use(middleware.WhiteAllow())
PrivateGroup.Use(middleware.BindDomain())
PrivateGroup.Use(middleware.GlobalLoading())
{
systemRouter.InitBaseRouter(PrivateGroup)

View file

@ -0,0 +1,31 @@
package middleware
import (
"errors"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/gin-gonic/gin"
)
func BindDomain() gin.HandlerFunc {
return func(c *gin.Context) {
if len(global.CONF.System.BindDomain) == 0 {
c.Next()
return
}
domains := c.Request.Host
parts := strings.Split(c.Request.Host, ":")
if len(parts) > 0 {
domains = parts[0]
}
if domains != global.CONF.System.BindDomain {
helper.ErrorWithDetail(c, constant.CodeErrDomain, constant.ErrTypeInternalServer, errors.New("domain not allowed"))
return
}
c.Next()
}
}

View file

@ -0,0 +1,28 @@
package middleware
import (
"errors"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/gin-gonic/gin"
)
func WhiteAllow() gin.HandlerFunc {
return func(c *gin.Context) {
if len(global.CONF.System.AllowIPs) == 0 {
c.Next()
return
}
clientIP := c.ClientIP()
for _, ip := range strings.Split(global.CONF.System.AllowIPs, ",") {
if len(ip) != 0 && ip == clientIP {
c.Next()
return
}
}
helper.ErrorWithDetail(c, constant.CodeErrIP, constant.ErrTypeInternalServer, errors.New("IP address not allowed"))
}
}

View file

@ -71,6 +71,8 @@ declare module 'vue' {
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElUpload: typeof import('element-plus/es')['ElUpload']
Err_domain: typeof import('./src/components/error-message/err_domain.vue')['default']
Err_ip: typeof import('./src/components/error-message/err_ip.vue')['default']
FileList: typeof import('./src/components/file-list/index.vue')['default']
FileRole: typeof import('./src/components/file-role/index.vue')['default']
Footer: typeof import('./src/components/app-layout/footer/index.vue')['default']

View file

@ -49,9 +49,21 @@ class RequestHttp {
});
return Promise.reject(data);
}
if (data.code == ResultEnum.EXPIRED) {
router.push({ name: 'Expired' });
return data;
if (data.code == ResultEnum.ERRIP) {
globalStore.setLogStatus(false);
router.push({
name: 'entrance',
params: { code: 'err-ip' },
});
return Promise.reject(data);
}
if (data.code == ResultEnum.ERRDOMAIN) {
globalStore.setLogStatus(false);
router.push({
name: 'entrance',
params: { code: 'err-domain' },
});
return Promise.reject(data);
}
if (data.code == ResultEnum.ERRGLOBALLOADDING) {
globalStore.setGlobalLoading(true);

View file

@ -17,6 +17,8 @@ export namespace Setting {
serverPort: number;
ssl: string;
sslType: string;
allowIPs: string;
bindDomain: string;
securityEntrance: string;
expirationDays: number;
expirationTime: string;

View file

@ -0,0 +1,66 @@
<template>
<div class="not-container">
<img src="@/assets/images/unsafe.svg" class="not-img" alt="404" />
<div class="not-detail">
<h2>{{ $t('commons.login.notSafe') }}</h2>
<h4>{{ $t('commons.login.errDomain1') }}</h4>
<div>
<h4>{{ $t('commons.login.errHelper') }} 1pctl reset-domain</h4>
<div style="cursor: pointer; float: left">
<el-icon color="#409EFC" style="margin-left: 5px; margin-top: 33px" :size="18" @click="onCopy()">
<DocumentCopy />
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="404">
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
const onCopy = () => {
let input = document.createElement('input');
input.value = '1pctl reset-domain';
document.body.appendChild(input);
input.select();
document.execCommand('Copy');
document.body.removeChild(input);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
};
</script>
<style scoped lang="scss">
.not-container {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
.not-img {
margin-top: 300px;
}
.not-detail {
margin-top: 300px;
display: flex;
flex-direction: column;
h2,
h4 {
padding: 0;
margin: 0;
}
h2 {
font-size: 60px;
color: #434e59;
}
h4 {
margin: 30px 0 20px;
float: left;
font-size: 19px;
font-weight: normal;
color: #848587;
}
}
}
</style>

View file

@ -0,0 +1,65 @@
<template>
<div class="not-container">
<img src="@/assets/images/unsafe.svg" class="not-img" alt="404" />
<div class="not-detail">
<h2>{{ $t('commons.login.notSafe') }}</h2>
<h4>{{ $t('commons.login.errIP1') }}</h4>
<div>
<h4>{{ $t('commons.login.errHelper') }} 1pctl reset-ips</h4>
<div style="cursor: pointer; float: left">
<el-icon color="#409EFC" style="margin-left: 5px; margin-top: 33px" :size="18" @click="onCopy()">
<DocumentCopy />
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="404">
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
const onCopy = () => {
let input = document.createElement('input');
input.value = '1pctl reset-ips';
document.body.appendChild(input);
input.select();
document.execCommand('Copy');
document.body.removeChild(input);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
};
</script>
<style scoped lang="scss">
.not-container {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
.not-img {
margin-top: 300px;
}
.not-detail {
margin-top: 300px;
display: flex;
flex-direction: column;
h2,
h4 {
padding: 0;
margin: 0;
}
h2 {
font-size: 60px;
color: #434e59;
}
h4 {
margin: 30px 0 20px;
float: left;
font-size: 19px;
font-weight: normal;
color: #848587;
}
}
}
</style>

View file

@ -7,6 +7,8 @@ export enum ResultEnum {
EXPIRED = 405,
ERRAUTH = 406,
ERRGLOBALLOADDING = 407,
ERRIP = 408,
ERRDOMAIN = 409,
TIMEOUT = 20000,
TYPE = 'success',
}

View file

@ -115,6 +115,9 @@ const message = {
notSafe: 'Access Denied',
safeEntrance1: 'The secure login has been enabled in the current environment',
safeEntrance2: 'Enter the following command on the SSH terminal to view the panel entry: 1pctl user-info',
errIP1: 'Authorized IP address access is enabled in the current environment',
errDomain1: 'Access domain name binding is enabled in the current environment',
errHelper: 'To reset the binding information, run the following command on the SSH terminal: ',
codeInput: 'Please enter the 6-digit verification code of the MFA validator',
mfaTitle: 'MFA Certification',
mfaCode: 'MFA verification code',
@ -933,6 +936,19 @@ const message = {
complexity: 'Complexity verification',
complexityHelper:
'The password must contain at least eight characters and contain at least three uppercase letters, lowercase letters, digits, and special characters',
bindDomain: 'Bind domain',
bindDomainHelper:
'After the domain binding, only the domain in the setting can be used to access 1Panel service',
bindDomainHelper1: 'If the binding domain is empty, the binding of the domain is cancelled',
bindDomainWarnning:
'If the binding domain is empty, the binding of the domain is cancelled. Do you want to continue?',
allowIPs: 'Authorized IP',
allowIPsHelper:
'After setting the authorized IP address, only the IP address in the setting can access the 1Panel service',
allowIPsWarnning:
'设After setting the authorized IP address, only the IP address in the setting can access the 1Panel service. Do you want to continue?',
allowIPsHelper1: 'If the authorized IP address is empty, the authorized IP address is canceled',
mfa: 'MFA',
mfaAlert:
'MFA password is generated based on the current time. Please ensure that the server time is synchronized.',

View file

@ -119,6 +119,9 @@ const message = {
notSafe: '暂无权限访问',
safeEntrance1: '当前环境已经开启了安全入口登录',
safeEntrance2: ' SSH 终端输入以下命令来查看面板入口: 1pctl user-info',
errIP1: '当前环境已经开启了授权 IP 访问',
errDomain1: '当前环境已经开启了访问域名绑定',
errHelper: '可在 SSH 终端输入以下命令来重置绑定信息: ',
codeInput: '请输入 MFA 验证器的 6 位验证码',
mfaTitle: 'MFA 认证',
mfaCode: 'MFA 验证码',
@ -965,6 +968,14 @@ const message = {
timeoutHelper: ' {0} 天后 面板密码即将过期过期后需要重新设置密码',
complexity: '密码复杂度验证',
complexityHelper: '开启后密码必须满足密码长度大于 8 位且包含字母数字及特殊字符',
bindDomain: '域名绑定',
bindDomainHelper: '设置域名绑定后仅能通过设置中域名访问 1Panel 服务',
bindDomainHelper1: '绑定域名为空时则取消域名绑定',
bindDomainWarnning: '设置域名绑定后仅能通过设置中域名访问 1Panel 服务是否继续',
allowIPs: '授权 IP',
allowIPsHelper: '设置授权 IP 仅有设置中的 IP 可以访问 1Panel 服务',
allowIPsWarnning: '设置授权 IP 仅有设置中的 IP 可以访问 1Panel 服务是否继续',
allowIPsHelper1: '授权 IP 为空时则取消授权 IP',
mfa: '两步验证',
mfaAlert: '两步验证密码是基于当前时间生成请确保服务器时间已同步',
mfaHelper: '开启后会验证手机应用验证码',

View file

@ -158,6 +158,9 @@ export function getIcon(extention: string): string {
}
export function checkIp(value: string): boolean {
if (value === '') {
return true;
}
const reg =
/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
if (!reg.test(value) && value !== '') {

View file

@ -1,6 +1,6 @@
<template>
<div>
<div class="login-backgroud" v-if="isSafety">
<div class="login-backgroud" v-if="isSafety && !isErr">
<div class="login-wrapper">
<div :class="screenWidth > 1110 ? 'left inline-block' : ''">
<div class="login-title">
@ -15,9 +15,15 @@
</div>
</div>
</div>
<div v-if="!isSafety">
<div v-if="!isSafety && !isErr">
<UnSafe />
</div>
<div v-if="isErr && mySafetyCode.code === 'err-ip'">
<ErrIP />
</div>
<div v-if="isErr && mySafetyCode.code === 'err-domain'">
<ErrDomain />
</div>
</div>
</template>
@ -25,12 +31,15 @@
import { checkIsSafety } from '@/api/modules/auth';
import LoginForm from '../components/login-form.vue';
import UnSafe from '@/components/error-message/unsafe.vue';
import ErrIP from '@/components/error-message/err_ip.vue';
import ErrDomain from '@/components/error-message/err_domain.vue';
import { ref, onMounted } from 'vue';
import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
const isSafety = ref(true);
const screenWidth = ref(null);
const isErr = ref();
const mySafetyCode = defineProps({
code: {
@ -41,7 +50,13 @@ const mySafetyCode = defineProps({
});
const getStatus = async () => {
if (mySafetyCode.code === 'err-ip' || mySafetyCode.code === 'err-domain') {
isErr.value = true;
}
const res = await checkIsSafety(mySafetyCode.code);
if (mySafetyCode.code === 'err-ip' || mySafetyCode.code === 'err-domain') {
isErr.value = false;
}
isSafety.value = res.data;
if (isSafety.value) {
globalStore.entrance = mySafetyCode.code;

View file

@ -0,0 +1,133 @@
<template>
<div>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('setting.allowIPs')" :back="handleClose" />
</template>
<el-form label-position="top" @submit.prevent v-loading="loading">
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item>
<table style="width: 100%" class="tab-table">
<tr v-if="allowIPs.length !== 0">
<th scope="col" width="90%" align="left">
<label>IP</label>
</th>
<th align="left"></th>
</tr>
<tr v-for="(row, index) in allowIPs" :key="index">
<td width="90%">
<el-input
:placeholder="$t('container.serverExample')"
style="width: 100%"
v-model="row.value"
/>
</td>
<td>
<el-button link style="font-size: 10px" @click="handlePortsDelete(index)">
{{ $t('commons.button.delete') }}
</el-button>
</td>
</tr>
<tr>
<td align="left">
<el-button @click="handlePortsAdd()">{{ $t('commons.button.add') }}</el-button>
</td>
</tr>
</table>
<span class="input-help">{{ $t('setting.allowIPsHelper1') }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :disabled="loading" type="primary" @click="onSavePort()">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import { updateSetting } from '@/api/modules/setting';
import { ElMessageBox } from 'element-plus';
import { checkIp } from '@/utils/util';
const emit = defineEmits<{ (e: 'search'): void }>();
const allowIPs = ref();
interface DialogProps {
allowIPs: string;
}
const drawerVisiable = ref();
const loading = ref();
const acceptParams = (params: DialogProps): void => {
allowIPs.value = [];
if (params.allowIPs) {
for (const ip of params.allowIPs.split(',')) {
if (ip) {
allowIPs.value.push({ value: ip });
}
}
}
drawerVisiable.value = true;
};
const handlePortsAdd = () => {
let item = {
value: '',
};
allowIPs.value.push(item);
};
const handlePortsDelete = (index: number) => {
allowIPs.value.splice(index, 1);
};
const onSavePort = async () => {
let allows = '';
if (allowIPs.value.length !== 0) {
for (const ip of allowIPs.value) {
if (checkIp(ip.value)) {
MsgError(i18n.global.t('firewall.addressFormatError'));
return false;
}
allows += ip.value + ',';
}
allows = allows.substring(0, allows.length - 1);
}
ElMessageBox.confirm(i18n.global.t('setting.allowIPsHelper'), i18n.global.t('setting.allowIPs'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
}).then(async () => {
loading.value = true;
await updateSetting({ key: 'AllowIPs', value: allows })
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
handleClose();
})
.catch(() => {
loading.value = false;
});
});
};
const handleClose = () => {
drawerVisiable.value = false;
};
defineExpose({
acceptParams,
});
</script>

View file

@ -0,0 +1,106 @@
<template>
<div>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('setting.bindDomain')" :back="handleClose" />
</template>
<el-form
ref="formRef"
label-position="top"
:rules="rules"
:model="form"
@submit.prevent
v-loading="loading"
>
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('setting.bindDomain')" prop="bindDomain">
<el-input clearable v-model="form.bindDomain" />
<span class="input-help">{{ $t('setting.bindDomainHelper1') }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :disabled="loading" type="primary" @click="onSavePort(formRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { updateSetting } from '@/api/modules/setting';
import { ElMessageBox, FormInstance } from 'element-plus';
const emit = defineEmits<{ (e: 'search'): void }>();
interface DialogProps {
bindDomain: string;
}
const drawerVisiable = ref();
const loading = ref();
const form = reactive({
bindDomain: '',
});
const rules = reactive({
bindDomain: [{ validator: checkSecurityEntrance, trigger: 'blur' }],
});
function checkSecurityEntrance(rule: any, value: any, callback: any) {
if (form.bindDomain !== '') {
const reg =
/^([\w\u4e00-\u9fa5\-\*]{1,100}\.){1,10}([\w\u4e00-\u9fa5\-]{1,24}|[\w\u4e00-\u9fa5\-]{1,24}\.[\w\u4e00-\u9fa5\-]{1,24})$/;
if (!reg.test(form.bindDomain)) {
return callback(new Error(i18n.global.t('commons.rule.domain')));
}
}
callback();
}
const formRef = ref<FormInstance>();
const acceptParams = (params: DialogProps): void => {
form.bindDomain = params.bindDomain;
drawerVisiable.value = true;
};
const onSavePort = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
ElMessageBox.confirm(i18n.global.t('setting.bindDomainWarnning'), i18n.global.t('setting.bindDomain'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
}).then(async () => {
loading.value = true;
await updateSetting({ key: 'BindDomain', value: form.bindDomain })
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
handleClose();
})
.catch(() => {
loading.value = false;
});
});
});
};
const handleClose = () => {
drawerVisiable.value = false;
};
defineExpose({
acceptParams,
});
</script>

View file

@ -39,6 +39,42 @@
<span class="input-help">{{ $t('setting.entranceHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.allowIPs')">
<el-input v-if="form.allowIPs" disabled v-model="form.allowIPs">
<template #append>
<el-button @click="onChangeAllowIPs" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<el-input disabled v-if="!form.allowIPs" v-model="unset">
<template #append>
<el-button @click="onChangeAllowIPs" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.allowIPsHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.bindDomain')">
<el-input disabled v-if="form.bindDomain" v-model="form.bindDomain">
<template #append>
<el-button @click="onChangeBindDomain" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<el-input disabled v-if="!form.bindDomain" v-model="unset">
<template #append>
<el-button @click="onChangeBindDomain" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.bindDomainHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.expirationTime')" prop="expirationTime">
<el-input disabled v-model="form.expirationTime">
<template #append>
@ -111,6 +147,8 @@
<SSLSetting ref="sslRef" @search="search" />
<EntranceSetting ref="entranceRef" @search="search" />
<TimeoutSetting ref="timeoutref" @search="search" />
<DomainSetting ref="domainRef" @search="search" />
<AllowIPsSetting ref="allowIPsRef" @search="search" />
</div>
</template>
@ -123,6 +161,8 @@ import SSLSetting from '@/views/setting/safe/ssl/index.vue';
import MfaSetting from '@/views/setting/safe/mfa/index.vue';
import TimeoutSetting from '@/views/setting/safe/timeout/index.vue';
import EntranceSetting from '@/views/setting/safe/entrance/index.vue';
import DomainSetting from '@/views/setting/safe/domain/index.vue';
import AllowIPsSetting from '@/views/setting/safe/allowips/index.vue';
import { updateSetting, getSettingInfo, getSystemAvailable, updateSSL, loadSSLInfo } from '@/api/modules/setting';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
@ -136,6 +176,8 @@ const mfaRef = ref();
const sslRef = ref();
const sslInfo = ref<Setting.SSLInfo>();
const domainRef = ref();
const allowIPsRef = ref();
const form = reactive({
serverPort: 9999,
@ -146,6 +188,8 @@ const form = reactive({
expirationTime: '',
complexityVerification: 'disable',
mfaStatus: 'disable',
allowIPs: '',
bindDomain: '',
});
const unset = ref(i18n.global.t('setting.unSetting'));
@ -163,6 +207,8 @@ const search = async () => {
form.expirationTime = res.data.expirationTime;
form.complexityVerification = res.data.complexityVerification;
form.mfaStatus = res.data.mfaStatus;
form.allowIPs = res.data.allowIPs || '';
form.bindDomain = res.data.bindDomain;
};
const onSaveComplexity = async () => {
@ -199,12 +245,18 @@ const handleMFA = async () => {
});
};
const onChangeEntrance = async () => {
const onChangeEntrance = () => {
entranceRef.value.acceptParams({ securityEntrance: form.securityEntrance });
};
const onChangePort = async () => {
const onChangePort = () => {
portRef.value.acceptParams({ serverPort: form.serverPort });
};
const onChangeBindDomain = () => {
domainRef.value.acceptParams({ bindDomain: form.bindDomain });
};
const onChangeAllowIPs = () => {
allowIPsRef.value.acceptParams({ allowIPs: form.allowIPs });
};
const handleSSL = async () => {
if (form.ssl === 'enable') {
let params = {