feat: add cors config for website (#10607)

This commit is contained in:
CityFun
2025-10-11 08:04:26 +00:00
committed by GitHub
parent 7cabb54c4e
commit 49ca336dd6
13 changed files with 535 additions and 88 deletions
+42
View File
@@ -1161,3 +1161,45 @@ func (b *BaseApi) BatchOpWebsites(c *gin.Context) {
}
helper.Success(c)
}
// @Tags Website
// @Summary Get CORS Config
// @Accept json
// @Param id path int true "id"
// @Success 200 {object} request.CorsConfig
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /websites/cors/{id} [get]
func (b *BaseApi) GetCORSConfig(c *gin.Context) {
id, err := helper.GetParamID(c)
if err != nil {
helper.BadRequest(c, err)
return
}
res, err := websiteService.GetCors(id)
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Update CORS Config
// @Accept json
// @Param request body request.CorsConfigReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /websites/cors/update [post]
func (b *BaseApi) UpdateCORSConfig(c *gin.Context) {
var req request.CorsConfigReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.UpdateCors(req); err != nil {
helper.InternalServer(c, err)
return
}
helper.Success(c)
}
+33 -24
View File
@@ -211,30 +211,39 @@ type WebsiteUpdateDirPermission struct {
}
type WebsiteProxyConfig struct {
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
Enable bool `json:"enable" `
Cache bool `json:"cache" `
CacheTime int `json:"cacheTime"`
CacheUnit string `json:"cacheUnit"`
ServerCacheTime int `json:"serverCacheTime"`
ServerCacheUnit string `json:"serverCacheUnit"`
Name string `json:"name" validate:"required"`
Modifier string `json:"modifier"`
Match string `json:"match" validate:"required"`
ProxyPass string `json:"proxyPass" validate:"required"`
ProxyHost string `json:"proxyHost" validate:"required"`
Content string `json:"content"`
FilePath string `json:"filePath"`
Replaces map[string]string `json:"replaces"`
SNI bool `json:"sni"`
ProxySSLName string `json:"proxySSLName"`
Cors bool `json:"cors"`
AllowOrigins string `json:"allowOrigins"`
AllowMethods string `json:"allowMethods"`
AllowHeaders string `json:"allowHeaders"`
AllowCredentials bool `json:"allowCredentials"`
Preflight bool `json:"preflight"`
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
Enable bool `json:"enable" `
Cache bool `json:"cache" `
CacheTime int `json:"cacheTime"`
CacheUnit string `json:"cacheUnit"`
ServerCacheTime int `json:"serverCacheTime"`
ServerCacheUnit string `json:"serverCacheUnit"`
Name string `json:"name" validate:"required"`
Modifier string `json:"modifier"`
Match string `json:"match" validate:"required"`
ProxyPass string `json:"proxyPass" validate:"required"`
ProxyHost string `json:"proxyHost" validate:"required"`
Content string `json:"content"`
FilePath string `json:"filePath"`
Replaces map[string]string `json:"replaces"`
SNI bool `json:"sni"`
ProxySSLName string `json:"proxySSLName"`
CorsConfig
}
type CorsConfig struct {
Cors bool `json:"cors"`
AllowOrigins string `json:"allowOrigins"`
AllowMethods string `json:"allowMethods"`
AllowHeaders string `json:"allowHeaders"`
AllowCredentials bool `json:"allowCredentials"`
Preflight bool `json:"preflight"`
}
type CorsConfigReq struct {
WebsiteID uint `json:"websiteID" validate:"required"`
CorsConfig
}
type WebsiteProxyReq struct {
+62
View File
@@ -96,6 +96,9 @@ type IWebsiteService interface {
ClearProxyCache(req request.NginxCommonReq) error
DeleteProxy(req request.WebsiteProxyDel) (err error)
UpdateCors(req request.CorsConfigReq) error
GetCors(websiteID uint) (*request.CorsConfig, error)
GetAntiLeech(id uint) (*response.NginxAntiLeechRes, error)
UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err error)
@@ -2018,6 +2021,65 @@ func (w WebsiteService) DeleteProxy(req request.WebsiteProxyDel) (err error) {
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
}
func (w WebsiteService) UpdateCors(req request.CorsConfigReq) error {
website, err := websiteRepo.GetFirst(repo.WithByID(req.WebsiteID))
if err != nil {
return err
}
params := []dto.NginxParam{
{Name: "add_header", Params: []string{"Access-Control-Allow-Origin"}},
{Name: "add_header", Params: []string{"Access-Control-Allow-Methods"}},
{Name: "add_header", Params: []string{"Access-Control-Allow-Headers"}},
{Name: "add_header", Params: []string{"Access-Control-Allow-Credentials"}},
{Name: "if", Params: []string{"(", "$request_method", "=", "'OPTIONS'", ")"}},
}
if err := deleteNginxConfig(constant.NginxScopeServer, params, &website); err != nil {
return err
}
if req.Cors {
return updateWebsiteConfig(website, func(server *components.Server) error {
server.UpdateDirective("add_header", []string{"Access-Control-Allow-Origin", req.AllowOrigins, "always"})
if req.AllowMethods != "" {
server.UpdateDirective("add_header", []string{"Access-Control-Allow-Methods", req.AllowMethods, "always"})
}
if req.AllowHeaders != "" {
server.UpdateDirective("add_header", []string{"Access-Control-Allow-Headers", req.AllowHeaders, "always"})
}
if req.AllowCredentials {
server.UpdateDirective("add_header", []string{"Access-Control-Allow-Credentials", "true", "always"})
}
if req.Preflight {
server.AddCorsOption()
}
return nil
})
}
return nil
}
func (w WebsiteService) GetCors(websiteID uint) (*request.CorsConfig, error) {
website, err := websiteRepo.GetFirst(repo.WithByID(websiteID))
if err != nil {
return nil, err
}
server, err := getServer(website)
if err != nil {
return nil, err
}
if server == nil {
return nil, nil
}
cors := &request.CorsConfig{
Cors: server.Cors,
AllowOrigins: server.AllowOrigins,
AllowMethods: server.AllowMethods,
AllowHeaders: server.AllowHeaders,
AllowCredentials: server.AllowCredentials,
Preflight: server.Preflight,
}
return cors, nil
}
func (w WebsiteService) GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error) {
var (
website model.Website
+53
View File
@@ -1303,6 +1303,7 @@ const (
SiteRootAuthBasicPath = "SiteRootAuthBasicPath"
SitePathAuthBasicDir = "SitePathAuthBasicDir"
SiteUpstreamDir = "SiteUpstreamDir"
SiteCorsPath = "SiteCorsPath"
)
func GetSitePath(website model.Website, confType string) string {
@@ -1333,6 +1334,8 @@ func GetSitePath(website model.Website, confType string) string {
return path.Join(GteSiteDir(website.Alias), "path_auth")
case SiteUpstreamDir:
return path.Join(GteSiteDir(website.Alias), "upstream")
case SiteCorsPath:
return path.Join(GteSiteDir(website.Alias), "cors", "cors.conf")
}
return ""
}
@@ -1481,3 +1484,53 @@ func ParseDomain(domain string) (*model.WebsiteDomain, error) {
Port: port,
}, nil
}
func updateWebsiteConfig(website model.Website, updateFunc func(server *components.Server) error) error {
configPath := GetSitePath(website, SiteConf)
nginxContent, err := files.NewFileOp().GetContent(configPath)
if err != nil {
return err
}
config, err := parser.NewStringParser(string(nginxContent)).Parse()
if err != nil {
return err
}
config.FilePath = configPath
servers := config.FindServers()
if len(servers) == 0 {
return errors.New("nginx config is not valid")
}
server := servers[0]
if err := updateFunc(server); err != nil {
return err
}
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return err
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
return nginxCheckAndReload(string(nginxContent), configPath, nginxInstall.ContainerName)
}
func getServer(website model.Website) (*components.Server, error) {
configPath := GetSitePath(website, SiteConf)
nginxContent, err := files.NewFileOp().GetContent(configPath)
if err != nil {
return nil, err
}
config, err := parser.NewStringParser(string(nginxContent)).Parse()
if err != nil {
return nil, err
}
servers := config.FindServers()
if len(servers) == 0 {
return nil, errors.New("nginx config is not valid")
}
server := servers[0]
return server, nil
}
+3
View File
@@ -61,6 +61,9 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
websiteRouter.POST("/auths/path", baseApi.GetPathAuthConfig)
websiteRouter.POST("/auths/path/update", baseApi.UpdatePathAuthConfig)
websiteRouter.GET("/cors/:id", baseApi.GetCORSConfig)
websiteRouter.POST("/cors/update", baseApi.UpdateCORSConfig)
websiteRouter.POST("/leech", baseApi.GetAntiLeech)
websiteRouter.POST("/leech/update", baseApi.UpdateAntiLeech)
+55 -4
View File
@@ -5,10 +5,16 @@ import (
)
type Server struct {
Comment string
Listens []*ServerListen
Directives []IDirective
Line int
Comment string
Listens []*ServerListen
Directives []IDirective
Line int
Cors bool
AllowMethods string
AllowHeaders string
AllowOrigins string
AllowCredentials bool
Preflight bool
}
func (s *Server) GetCodeBlock() string {
@@ -25,6 +31,28 @@ func NewServer(directive IDirective) (*Server, error) {
switch dir.GetName() {
case "listen":
server.Listens = append(server.Listens, NewServerListen(dir.GetParameters(), dir.GetLine()))
case "add_header":
params := dir.GetParameters()
if params[0] == "Access-Control-Allow-Origin" {
server.Cors = true
server.AllowOrigins = params[1]
}
if params[0] == "Access-Control-Allow-Methods" {
server.AllowMethods = params[1]
}
if params[0] == "Access-Control-Allow-Headers" {
server.AllowHeaders = params[1]
}
if params[0] == "Access-Control-Allow-Credentials" && params[1] == "true" {
server.AllowCredentials = true
}
server.Directives = append(server.Directives, dir)
case "if":
params := dir.GetParameters()
if params[0] == "(" && params[1] == "$request_method" && params[2] == `=` && params[3] == `'OPTIONS'` && params[4] == ")" {
server.Preflight = true
}
server.Directives = append(server.Directives, dir)
default:
server.Directives = append(server.Directives, dir)
}
@@ -479,3 +507,26 @@ func (s *Server) UpdateAllowIPs(ips []string) {
s.Directives = append(s.Directives, ipDirectives...)
}
}
func (s *Server) AddCorsOption() {
newDir := &Directive{
Name: "if",
Parameters: []string{"(", "$request_method", "=", "'OPTIONS'", ")"},
Block: &Block{},
}
block := &Block{}
block.AppendDirectives(&Directive{
Name: "return",
Parameters: []string{"204"},
})
newDir.Block = block
directives := s.GetDirectives()
newDirectives := make([]IDirective, 0)
for _, dir := range directives {
if dir.GetName() != "listen" {
newDirectives = append(newDirectives, dir)
}
}
newDirectives = append(newDirectives, newDir)
s.Directives = newDirectives
}
+13
View File
@@ -681,4 +681,17 @@ export namespace Website {
operate: string;
taskID: string;
}
export interface CorsConfig {
cors: boolean;
allowOrigins: string;
allowMethods: string;
allowHeaders: string;
allowCredentials: boolean;
preflight: boolean;
}
export interface CorsConfigReq extends CorsConfig {
websiteID: number;
}
}
+8
View File
@@ -359,3 +359,11 @@ export const execComposer = (req: Website.ExecComposer) => {
export const batchOpreate = (req: Website.BatchOperate) => {
return http.post(`/websites/batch/operate`, req);
};
export const getCorsConfig = (id: number) => {
return http.get<Website.CorsConfig>(`/websites/cors/${id}`);
};
export const updateCorsConfig = (req: Website.CorsConfigReq) => {
return http.post(`/websites/cors/update`, req);
};
+1 -1
View File
@@ -2414,7 +2414,7 @@ const message = {
ipFromExample3: '如果不确定可以填 0.0.0.0/0ipv4 ::/0ipv6 [注意允许任意来源 IP 不安全]',
http3Helper:
'HTTP/3 HTTP/2 的升级版本提供更快的连接速度和更好的性能但是不是所有浏览器都支持 HTTP/3开启后可能会导致部分浏览器无法访问',
cors: '跨域访问(CORS)',
cors: '跨域访问',
enableCors: '开启跨域',
allowOrigins: '允许访问的域名',
allowMethods: '允许的请求方法',
@@ -0,0 +1,102 @@
<template>
<el-row>
<el-col :xs="24" :sm="18" :md="18" :lg="14" :xl="14">
<el-form
ref="corsForm"
label-position="right"
label-width="150px"
:model="corsSetting"
:rules="rules"
v-loading="loading"
>
<CorsSetting
v-model="corsSetting.cors"
:config="{
allowOrigins: corsSetting.allowOrigins,
allowMethods: corsSetting.allowMethods,
allowHeaders: corsSetting.allowHeaders,
allowCredentials: corsSetting.allowCredentials,
preflight: corsSetting.preflight,
}"
enable-size="small"
@update:config="updateonfig"
></CorsSetting>
<el-form-item>
<el-button type="primary" @click="submit()">
{{ $t('commons.button.save') }}
</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<script lang="ts" setup>
import { getCorsConfig, updateCorsConfig } from '@/api/modules/website';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import CorsSetting from '@/views/website/website/cors/index.vue';
import { FormInstance } from 'element-plus';
const props = defineProps({
id: {
type: Number,
default: 0,
},
});
const rules = ref({
allowOrigins: [Rules.requiredInput],
});
const corsForm = ref<FormInstance>();
const loading = ref(false);
const corsSetting = ref({
cors: false,
allowOrigins: '*',
allowMethods: 'GET,POST,OPTIONS,PUT,DELETE',
allowHeaders: '',
allowCredentials: false,
preflight: true,
websiteID: props.id,
});
const updateonfig = (config: any) => {
corsSetting.value.allowOrigins = config.allowOrigins;
corsSetting.value.allowMethods = config.allowMethods;
corsSetting.value.allowHeaders = config.allowHeaders;
corsSetting.value.allowCredentials = config.allowCredentials;
corsSetting.value.preflight = config.preflight;
};
const submit = async () => {
const isValid = await corsForm.value?.validate();
if (!isValid) return;
corsSetting.value.websiteID = props.id;
try {
loading.value = true;
await updateCorsConfig(corsSetting.value);
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
} catch (error) {
return;
} finally {
loading.value = false;
}
};
const getCors = () => {
getCorsConfig(props.id).then((res: any) => {
if (res.data) {
corsSetting.value = res.data;
}
});
};
onMounted(() => {
getCors();
});
</script>
@@ -1,40 +1,43 @@
<template>
<div :style="{ '--main-height': mainHeight + 'px' }">
<el-tabs tab-position="left" v-model="tabIndex" v-if="id > 0" class="custom-tabs" ref="tabsRef">
<el-tab-pane :label="$t('website.domainConfig')">
<el-tab-pane :label="$t('website.domainConfig')" name="0">
<Domain :key="id" :id="id" v-if="tabIndex == '0'"></Domain>
</el-tab-pane>
<el-tab-pane :label="$t('website.sitePath')">
<el-tab-pane :label="$t('website.sitePath')" name="1">
<SitePath :id="id" v-if="tabIndex == '1'"></SitePath>
</el-tab-pane>
<el-tab-pane :label="$t('website.defaultDoc')">
<el-tab-pane :label="$t('website.defaultDoc')" name="2">
<Default :id="id" v-if="tabIndex == '2'"></Default>
</el-tab-pane>
<el-tab-pane :label="$t('website.rate')">
<el-tab-pane :label="$t('website.rate')" name="3">
<LimitConn :id="id" v-if="tabIndex == '3'"></LimitConn>
</el-tab-pane>
<el-tab-pane :label="$t('website.proxy')">
<el-tab-pane :label="$t('website.proxy')" name="4">
<Proxy :id="id" v-if="tabIndex == '4'"></Proxy>
</el-tab-pane>
<el-tab-pane :label="$t('website.loadBalance')">
<el-tab-pane :label="$t('website.loadBalance')" name="5">
<LoadBalance :id="id" v-if="tabIndex == '5'"></LoadBalance>
</el-tab-pane>
<el-tab-pane :label="$t('website.basicAuth')">
<el-tab-pane :label="$t('website.basicAuth')" name="6">
<AuthBasic :id="id" v-if="tabIndex == '6'"></AuthBasic>
</el-tab-pane>
<el-tab-pane :label="'HTTPS'">
<el-tab-pane :label="$t('website.cors')" name="16">
<Cors :id="id" v-if="tabIndex == '16'"></Cors>
</el-tab-pane>
<el-tab-pane :label="'HTTPS'" name="7">
<HTTPS :id="id" v-if="tabIndex == '7'"></HTTPS>
</el-tab-pane>
<el-tab-pane :label="$t('website.realIP')">
<el-tab-pane :label="$t('website.realIP')" name="8">
<RealIP :id="id" v-if="tabIndex == '8'"></RealIP>
</el-tab-pane>
<el-tab-pane :label="$t('website.rewrite')">
<el-tab-pane :label="$t('website.rewrite')" name="9">
<Rewrite :id="id" v-if="tabIndex == '9'"></Rewrite>
</el-tab-pane>
<el-tab-pane :label="$t('website.antiLeech')">
<el-tab-pane :label="$t('website.antiLeech')" name="10">
<AntiLeech :id="id" v-if="tabIndex == '10'"></AntiLeech>
</el-tab-pane>
<el-tab-pane :label="$t('website.redirect')">
<el-tab-pane :label="$t('website.redirect')" name="11">
<Redirect :id="id" v-if="tabIndex == '11'"></Redirect>
</el-tab-pane>
@@ -77,6 +80,7 @@ import LoadBalance from './load-balance/index.vue';
import PHP from './php/index.vue';
import RealIP from './real-ip/index.vue';
import Resource from './resource/index.vue';
import Cors from './cors/index.vue';
const props = defineProps({
website: {
@@ -123,39 +123,20 @@
</el-collapse-transition>
<el-divider content-position="left">{{ $t('website.cors') }}</el-divider>
<div class="flex justify-between items-center py-3">
<div class="flex flex-col gap-1">
<span class="font-medium">{{ $t('website.enableCors') }}</span>
</div>
<el-switch v-model="proxy.cors" size="large" @change="changeCors(proxy.cors)" />
</div>
<el-collapse-transition>
<div v-if="proxy.cors" class="mt-4">
<el-form-item :label="$t('website.allowOrigins')" prop="allowOrigins">
<el-input v-model="proxy.allowOrigins" type="textarea" placeholder="*"></el-input>
</el-form-item>
<el-form-item :label="$t('website.allowMethods')" prop="allowMethods">
<el-input
v-model="proxy.allowMethods"
type="textarea"
placeholder="GET,POST,OPTIONS,PUT,DELETE"
></el-input>
</el-form-item>
<el-form-item :label="$t('website.allowHeaders')" prop="allowHeaders">
<el-input v-model="proxy.allowHeaders" type="textarea"></el-input>
</el-form-item>
<el-form-item :label="$t('website.allowCredentials')" prop="allowCredentials">
<el-switch v-model="proxy.allowCredentials" />
</el-form-item>
<el-form-item :label="$t('website.preflight')" prop="preflight">
<el-switch v-model="proxy.preflight" />
<span class="input-help">{{ $t('website.preflightHleper') }}</span>
</el-form-item>
</div>
</el-collapse-transition>
<CorsSetting
v-model="proxy.cors"
:config="{
allowOrigins: proxy.allowOrigins,
allowMethods: proxy.allowMethods,
allowHeaders: proxy.allowHeaders,
allowCredentials: proxy.allowCredentials,
preflight: proxy.preflight,
}"
enable-size="large"
@update:config="updateCorsConfig"
></CorsSetting>
<el-divider content-position="left">{{ $t('website.replace') }}</el-divider>
<div>
<div v-for="(replace, index) in replaces" :key="index" class="mb-3">
<el-row :gutter="16">
@@ -217,6 +198,7 @@ import { Website } from '@/api/interface/website';
import { Units } from '@/global/mimetype';
import { isDomain } from '@/utils/util';
import { Delete, Plus } from '@element-plus/icons-vue';
import CorsSetting from '@/views/website/website/cors/index.vue';
const proxyForm = ref<FormInstance>();
const rules = ref({
@@ -303,22 +285,6 @@ const changeCache = (cache: boolean) => {
}
};
const changeCors = (cors: boolean) => {
if (cors) {
proxy.value.allowOrigins = '*';
proxy.value.allowMethods = 'GET,POST,OPTIONS,PUT,DELETE';
proxy.value.allowHeaders = '';
proxy.value.allowCredentials = false;
proxy.value.preflight = true;
} else {
proxy.value.allowOrigins = '';
proxy.value.allowMethods = '';
proxy.value.allowHeaders = '';
proxy.value.allowCredentials = false;
proxy.value.preflight = true;
}
};
const addReplaces = () => {
replaces.value.push({ key: '', value: '' });
};
@@ -335,6 +301,14 @@ const getProxyHost = () => {
}
};
const updateCorsConfig = (config: any) => {
proxy.value.allowOrigins = config.allowOrigins;
proxy.value.allowMethods = config.allowMethods;
proxy.value.allowHeaders = config.allowHeaders;
proxy.value.allowCredentials = config.allowCredentials;
proxy.value.preflight = config.preflight;
};
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid) => {
@@ -0,0 +1,126 @@
<template>
<div>
<div class="flex justify-between items-center py-3" v-if="enableSize == 'large'">
<div class="flex flex-col gap-1">
<span class="font-medium">{{ $t('website.enableCors') }}</span>
</div>
<el-switch v-model="corsEnabled" size="large" @change="handleCorsChange" />
</div>
<el-form-item :label="$t('website.enableCors')" v-if="enableSize == 'small'">
<el-switch v-model="corsEnabled" size="large" @change="handleCorsChange" />
</el-form-item>
<el-collapse-transition>
<div v-if="corsEnabled" class="mt-4">
<el-form-item :label="$t('website.allowOrigins')" prop="allowOrigins">
<el-input
v-model="corsConfig.allowOrigins"
type="textarea"
placeholder="*"
@input="emitUpdate"
></el-input>
</el-form-item>
<el-form-item :label="$t('website.allowMethods')" prop="allowMethods">
<el-input
v-model="corsConfig.allowMethods"
type="textarea"
placeholder="GET,POST,OPTIONS,PUT,DELETE"
@input="emitUpdate"
></el-input>
</el-form-item>
<el-form-item :label="$t('website.allowHeaders')" prop="allowHeaders">
<el-input v-model="corsConfig.allowHeaders" type="textarea" @input="emitUpdate"></el-input>
</el-form-item>
<el-form-item :label="$t('website.allowCredentials')" prop="allowCredentials">
<el-switch v-model="corsConfig.allowCredentials" @change="emitUpdate" />
</el-form-item>
<el-form-item :label="$t('website.preflight')" prop="preflight">
<el-switch v-model="corsConfig.preflight" @change="emitUpdate" />
<span class="input-help">{{ $t('website.preflightHleper') }}</span>
</el-form-item>
</div>
</el-collapse-transition>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
interface CorsConfig {
allowOrigins: string;
allowMethods: string;
allowHeaders: string;
allowCredentials: boolean;
preflight: boolean;
}
interface Props {
modelValue: boolean;
config: CorsConfig;
enableSize: string;
}
const props = withDefaults(defineProps<Props>(), {
modelValue: false,
config: () => ({
allowOrigins: '*',
allowMethods: 'GET,POST,OPTIONS,PUT,DELETE',
allowHeaders: '',
allowCredentials: false,
preflight: true,
}),
enableSize: 'large',
});
const emit = defineEmits(['update:modelValue', 'update:config']);
const corsEnabled = ref(props.modelValue);
const corsConfig = ref<CorsConfig>({ ...props.config });
watch(
() => props.modelValue,
(val) => {
corsEnabled.value = val;
},
);
watch(
() => props.config,
(val) => {
corsConfig.value = { ...val };
},
{ deep: true },
);
const handleCorsChange = (enabled: boolean) => {
emit('update:modelValue', enabled);
if (enabled) {
corsConfig.value = {
allowOrigins: '*',
allowMethods: 'GET,POST,OPTIONS,PUT,DELETE',
allowHeaders: '',
allowCredentials: false,
preflight: true,
};
} else {
corsConfig.value = {
allowOrigins: '',
allowMethods: '',
allowHeaders: '',
allowCredentials: false,
preflight: true,
};
}
emitUpdate();
};
const emitUpdate = () => {
emit('update:config', corsConfig.value);
};
</script>