mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-11-16 11:42:43 +08:00
feat: add external-controller-cors
can config allow-origins
and allow-private-network
Some checks are pending
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
Some checks are pending
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
This commit is contained in:
parent
264713571d
commit
fc9d5cfee9
|
@ -107,6 +107,12 @@ type Controller struct {
|
||||||
ExternalUI string
|
ExternalUI string
|
||||||
ExternalDohServer string
|
ExternalDohServer string
|
||||||
Secret string
|
Secret string
|
||||||
|
Cors Cors
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cors struct {
|
||||||
|
AllowOrigins []string
|
||||||
|
AllowPrivateNetwork bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Experimental config
|
// Experimental config
|
||||||
|
@ -191,6 +197,11 @@ type Config struct {
|
||||||
TLS *TLS
|
TLS *TLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RawCors struct {
|
||||||
|
AllowOrigins []string `yaml:"allow-origins" json:"allow-origins"`
|
||||||
|
AllowPrivateNetwork bool `yaml:"allow-private-network" json:"allow-private-network"`
|
||||||
|
}
|
||||||
|
|
||||||
type RawDNS struct {
|
type RawDNS struct {
|
||||||
Enable bool `yaml:"enable" json:"enable"`
|
Enable bool `yaml:"enable" json:"enable"`
|
||||||
PreferH3 bool `yaml:"prefer-h3" json:"prefer-h3"`
|
PreferH3 bool `yaml:"prefer-h3" json:"prefer-h3"`
|
||||||
|
@ -368,6 +379,7 @@ type RawConfig struct {
|
||||||
ExternalControllerPipe string `yaml:"external-controller-pipe" json:"external-controller-pipe"`
|
ExternalControllerPipe string `yaml:"external-controller-pipe" json:"external-controller-pipe"`
|
||||||
ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"`
|
ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"`
|
||||||
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
|
ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"`
|
||||||
|
ExternalControllerCors RawCors `yaml:"external-controller-cors" json:"external-controller-cors"`
|
||||||
ExternalUI string `yaml:"external-ui" json:"external-ui"`
|
ExternalUI string `yaml:"external-ui" json:"external-ui"`
|
||||||
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
|
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
|
||||||
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
|
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
|
||||||
|
@ -541,6 +553,10 @@ func DefaultRawConfig() *RawConfig {
|
||||||
OverrideDest: true,
|
OverrideDest: true,
|
||||||
},
|
},
|
||||||
ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip",
|
ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip",
|
||||||
|
ExternalControllerCors: RawCors{
|
||||||
|
AllowOrigins: []string{"*"},
|
||||||
|
AllowPrivateNetwork: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,6 +791,10 @@ func parseController(cfg *RawConfig) (*Controller, error) {
|
||||||
ExternalControllerUnix: cfg.ExternalControllerUnix,
|
ExternalControllerUnix: cfg.ExternalControllerUnix,
|
||||||
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
||||||
ExternalDohServer: cfg.ExternalDohServer,
|
ExternalDohServer: cfg.ExternalDohServer,
|
||||||
|
Cors: Cors{
|
||||||
|
AllowOrigins: cfg.ExternalControllerCors.AllowOrigins,
|
||||||
|
AllowPrivateNetwork: cfg.ExternalControllerCors.AllowPrivateNetwork,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,12 @@ external-controller: 0.0.0.0:9093 # RESTful API 监听地址
|
||||||
external-controller-tls: 0.0.0.0:9443 # RESTful API HTTPS 监听地址,需要配置 tls 部分配置文件
|
external-controller-tls: 0.0.0.0:9443 # RESTful API HTTPS 监听地址,需要配置 tls 部分配置文件
|
||||||
# secret: "123456" # `Authorization:Bearer ${secret}`
|
# secret: "123456" # `Authorization:Bearer ${secret}`
|
||||||
|
|
||||||
|
# RESTful API CORS标头配置
|
||||||
|
external-controller-cors:
|
||||||
|
allow-origins:
|
||||||
|
- *
|
||||||
|
allow-private-network: true
|
||||||
|
|
||||||
# RESTful API Unix socket 监听地址( windows版本大于17063也可以使用,即大于等于1803/RS4版本即可使用 )
|
# RESTful API Unix socket 监听地址( windows版本大于17063也可以使用,即大于等于1803/RS4版本即可使用 )
|
||||||
# !!!注意: 从Unix socket访问api接口不会验证secret, 如果开启请自行保证安全问题 !!!
|
# !!!注意: 从Unix socket访问api接口不会验证secret, 如果开启请自行保证安全问题 !!!
|
||||||
# 测试方法: curl -v --unix-socket "mihomo.sock" http://localhost/
|
# 测试方法: curl -v --unix-socket "mihomo.sock" http://localhost/
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -8,7 +8,6 @@ require (
|
||||||
github.com/coreos/go-iptables v0.7.0
|
github.com/coreos/go-iptables v0.7.0
|
||||||
github.com/dlclark/regexp2 v1.11.4
|
github.com/dlclark/regexp2 v1.11.4
|
||||||
github.com/go-chi/chi/v5 v5.1.0
|
github.com/go-chi/chi/v5 v5.1.0
|
||||||
github.com/go-chi/cors v1.2.1
|
|
||||||
github.com/go-chi/render v1.0.3
|
github.com/go-chi/render v1.0.3
|
||||||
github.com/gobwas/ws v1.4.0
|
github.com/gobwas/ws v1.4.0
|
||||||
github.com/gofrs/uuid/v5 v5.3.0
|
github.com/gofrs/uuid/v5 v5.3.0
|
||||||
|
@ -37,6 +36,7 @@ require (
|
||||||
github.com/openacid/low v0.1.21
|
github.com/openacid/low v0.1.21
|
||||||
github.com/oschwald/maxminddb-golang v1.12.0
|
github.com/oschwald/maxminddb-golang v1.12.0
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.4.0
|
github.com/puzpuzpuz/xsync/v3 v3.4.0
|
||||||
|
github.com/sagernet/cors v1.2.1
|
||||||
github.com/sagernet/fswatch v0.1.1
|
github.com/sagernet/fswatch v0.1.1
|
||||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a
|
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a
|
||||||
github.com/sagernet/sing v0.5.0-alpha.13
|
github.com/sagernet/sing v0.5.0-alpha.13
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -42,8 +42,6 @@ github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXb
|
||||||
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
|
||||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
|
||||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||||
|
@ -160,6 +158,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||||
|
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
||||||
|
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
||||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||||
|
|
|
@ -59,6 +59,10 @@ func applyRoute(cfg *config.Config) {
|
||||||
PrivateKey: cfg.TLS.PrivateKey,
|
PrivateKey: cfg.TLS.PrivateKey,
|
||||||
DohServer: cfg.Controller.ExternalDohServer,
|
DohServer: cfg.Controller.ExternalDohServer,
|
||||||
IsDebug: cfg.General.LogLevel == log.DEBUG,
|
IsDebug: cfg.General.LogLevel == log.DEBUG,
|
||||||
|
Cors: route.Cors{
|
||||||
|
AllowOrigins: cfg.Controller.Cors.AllowOrigins,
|
||||||
|
AllowPrivateNetwork: cfg.Controller.Cors.AllowPrivateNetwork,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,10 @@ import (
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/go-chi/cors"
|
|
||||||
"github.com/go-chi/render"
|
"github.com/go-chi/render"
|
||||||
"github.com/gobwas/ws"
|
"github.com/gobwas/ws"
|
||||||
"github.com/gobwas/ws/wsutil"
|
"github.com/gobwas/ws/wsutil"
|
||||||
|
"github.com/sagernet/cors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -58,6 +58,22 @@ type Config struct {
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
DohServer string
|
DohServer string
|
||||||
IsDebug bool
|
IsDebug bool
|
||||||
|
Cors Cors
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cors struct {
|
||||||
|
AllowOrigins []string
|
||||||
|
AllowPrivateNetwork bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cors) Apply(r chi.Router) {
|
||||||
|
r.Use(cors.New(cors.Options{
|
||||||
|
AllowedOrigins: c.AllowOrigins,
|
||||||
|
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"},
|
||||||
|
AllowedHeaders: []string{"Content-Type", "Authorization"},
|
||||||
|
AllowPrivateNetwork: c.AllowPrivateNetwork,
|
||||||
|
MaxAge: 300,
|
||||||
|
}).Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReCreateServer(cfg *Config) {
|
func ReCreateServer(cfg *Config) {
|
||||||
|
@ -73,16 +89,9 @@ func SetUIPath(path string) {
|
||||||
uiPath = C.Path.Resolve(path)
|
uiPath = C.Path.Resolve(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func router(isDebug bool, secret string, dohServer string) *chi.Mux {
|
func router(isDebug bool, secret string, dohServer string, cors Cors) *chi.Mux {
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
corsM := cors.New(cors.Options{
|
cors.Apply(r)
|
||||||
AllowedOrigins: []string{"*"},
|
|
||||||
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"},
|
|
||||||
AllowedHeaders: []string{"Content-Type", "Authorization"},
|
|
||||||
MaxAge: 300,
|
|
||||||
})
|
|
||||||
r.Use(setPrivateNetworkAccess)
|
|
||||||
r.Use(corsM.Handler)
|
|
||||||
if isDebug {
|
if isDebug {
|
||||||
r.Mount("/debug", func() http.Handler {
|
r.Mount("/debug", func() http.Handler {
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
@ -151,7 +160,7 @@ func start(cfg *Config) {
|
||||||
log.Infoln("RESTful API listening at: %s", l.Addr().String())
|
log.Infoln("RESTful API listening at: %s", l.Addr().String())
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: router(cfg.IsDebug, cfg.Secret, cfg.DohServer),
|
Handler: router(cfg.IsDebug, cfg.Secret, cfg.DohServer, cfg.Cors),
|
||||||
}
|
}
|
||||||
httpServer = server
|
httpServer = server
|
||||||
if err = server.Serve(l); err != nil {
|
if err = server.Serve(l); err != nil {
|
||||||
|
@ -183,7 +192,7 @@ func startTLS(cfg *Config) {
|
||||||
|
|
||||||
log.Infoln("RESTful API tls listening at: %s", l.Addr().String())
|
log.Infoln("RESTful API tls listening at: %s", l.Addr().String())
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: router(cfg.IsDebug, cfg.Secret, cfg.DohServer),
|
Handler: router(cfg.IsDebug, cfg.Secret, cfg.DohServer, cfg.Cors),
|
||||||
TLSConfig: &tls.Config{
|
TLSConfig: &tls.Config{
|
||||||
Certificates: []tls.Certificate{c},
|
Certificates: []tls.Certificate{c},
|
||||||
},
|
},
|
||||||
|
@ -232,7 +241,7 @@ func startUnix(cfg *Config) {
|
||||||
log.Infoln("RESTful API unix listening at: %s", l.Addr().String())
|
log.Infoln("RESTful API unix listening at: %s", l.Addr().String())
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: router(cfg.IsDebug, "", cfg.DohServer),
|
Handler: router(cfg.IsDebug, "", cfg.DohServer, cfg.Cors),
|
||||||
}
|
}
|
||||||
unixServer = server
|
unixServer = server
|
||||||
if err = server.Serve(l); err != nil {
|
if err = server.Serve(l); err != nil {
|
||||||
|
@ -263,7 +272,7 @@ func startPipe(cfg *Config) {
|
||||||
log.Infoln("RESTful API pipe listening at: %s", l.Addr().String())
|
log.Infoln("RESTful API pipe listening at: %s", l.Addr().String())
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: router(cfg.IsDebug, "", cfg.DohServer),
|
Handler: router(cfg.IsDebug, "", cfg.DohServer, cfg.Cors),
|
||||||
}
|
}
|
||||||
pipeServer = server
|
pipeServer = server
|
||||||
if err = server.Serve(l); err != nil {
|
if err = server.Serve(l); err != nil {
|
||||||
|
@ -272,15 +281,6 @@ func startPipe(cfg *Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPrivateNetworkAccess(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
|
|
||||||
w.Header().Add("Access-Control-Allow-Private-Network", "true")
|
|
||||||
}
|
|
||||||
next.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeEuqal(a, b string) bool {
|
func safeEuqal(a, b string) bool {
|
||||||
aBuf := utils.ImmutableBytesFromString(a)
|
aBuf := utils.ImmutableBytesFromString(a)
|
||||||
bBuf := utils.ImmutableBytesFromString(b)
|
bBuf := utils.ImmutableBytesFromString(b)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user