mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-02-04 04:30:05 +00:00
feat: update to go1.24 & support listening https (#1002)
* feat: support listening https * refactor * modernize * support snake case in config * more precise control of config fields * update goreleaser config * remove kubeyaml * fix: expose agent_secret * chore
This commit is contained in:
@@ -175,10 +175,10 @@ type pHandlerFunc[S ~[]E, E any] func(c *gin.Context) (*model.Value[S], error)
|
||||
// gorm errors here instead
|
||||
type gormError struct {
|
||||
msg string
|
||||
a []interface{}
|
||||
a []any
|
||||
}
|
||||
|
||||
func newGormError(format string, args ...interface{}) error {
|
||||
func newGormError(format string, args ...any) error {
|
||||
return &gormError{
|
||||
msg: format,
|
||||
a: args,
|
||||
@@ -191,10 +191,10 @@ func (ge *gormError) Error() string {
|
||||
|
||||
type wsError struct {
|
||||
msg string
|
||||
a []interface{}
|
||||
a []any
|
||||
}
|
||||
|
||||
func newWsError(format string, args ...interface{}) error {
|
||||
func newWsError(format string, args ...any) error {
|
||||
return &wsError{
|
||||
msg: format,
|
||||
a: args,
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
|
||||
"github.com/nezhahq/nezha/model"
|
||||
"github.com/nezhahq/nezha/pkg/utils"
|
||||
"github.com/nezhahq/nezha/pkg/websocketx"
|
||||
"github.com/nezhahq/nezha/proto"
|
||||
"github.com/nezhahq/nezha/service/rpc"
|
||||
@@ -48,7 +48,7 @@ func createFM(c *gin.Context) (*model.CreateFMResponse, error) {
|
||||
|
||||
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
||||
|
||||
fmData, _ := utils.Json.Marshal(&model.TaskFM{
|
||||
fmData, _ := json.Marshal(&model.TaskFM{
|
||||
StreamID: streamId,
|
||||
})
|
||||
if err := server.TaskStream.Send(&proto.Task{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
jwt "github.com/appleboy/gin-jwt/v2"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/goccy/go-json"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
|
||||
@@ -48,8 +48,8 @@ func initParams() *jwt.GinJWTMiddleware {
|
||||
}
|
||||
}
|
||||
|
||||
func payloadFunc() func(data interface{}) jwt.MapClaims {
|
||||
return func(data interface{}) jwt.MapClaims {
|
||||
func payloadFunc() func(data any) jwt.MapClaims {
|
||||
return func(data any) jwt.MapClaims {
|
||||
if v, ok := data.(string); ok {
|
||||
return jwt.MapClaims{
|
||||
model.CtxKeyAuthorizedUser: v,
|
||||
@@ -59,8 +59,8 @@ func payloadFunc() func(data interface{}) jwt.MapClaims {
|
||||
}
|
||||
}
|
||||
|
||||
func identityHandler() func(c *gin.Context) interface{} {
|
||||
return func(c *gin.Context) interface{} {
|
||||
func identityHandler() func(c *gin.Context) any {
|
||||
return func(c *gin.Context) any {
|
||||
claims := jwt.ExtractClaims(c)
|
||||
userId := claims[model.CtxKeyAuthorizedUser].(string)
|
||||
var user model.User
|
||||
@@ -80,8 +80,8 @@ func identityHandler() func(c *gin.Context) interface{} {
|
||||
// @Produce json
|
||||
// @Success 200 {object} model.CommonResponse[model.LoginResponse]
|
||||
// @Router /login [post]
|
||||
func authenticator() func(c *gin.Context) (interface{}, error) {
|
||||
return func(c *gin.Context) (interface{}, error) {
|
||||
func authenticator() func(c *gin.Context) (any, error) {
|
||||
return func(c *gin.Context) (any, error) {
|
||||
var loginVals model.LoginRequest
|
||||
if err := c.ShouldBind(&loginVals); err != nil {
|
||||
return "", jwt.ErrMissingLoginValues
|
||||
@@ -113,8 +113,8 @@ func authenticator() func(c *gin.Context) (interface{}, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func authorizator() func(data interface{}, c *gin.Context) bool {
|
||||
return func(data interface{}, c *gin.Context) bool {
|
||||
func authorizator() func(data any, c *gin.Context) bool {
|
||||
return func(data any, c *gin.Context) bool {
|
||||
_, ok := data.(*model.User)
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/jinzhu/copier"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/nezhahq/nezha/model"
|
||||
"github.com/nezhahq/nezha/pkg/utils"
|
||||
pb "github.com/nezhahq/nezha/proto"
|
||||
"github.com/nezhahq/nezha/service/singleton"
|
||||
)
|
||||
@@ -81,13 +81,13 @@ func updateServer(c *gin.Context) (any, error) {
|
||||
s.DDNSProfiles = sf.DDNSProfiles
|
||||
s.OverrideDDNSDomains = sf.OverrideDDNSDomains
|
||||
|
||||
ddnsProfilesRaw, err := utils.Json.Marshal(s.DDNSProfiles)
|
||||
ddnsProfilesRaw, err := json.Marshal(s.DDNSProfiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.DDNSProfilesRaw = string(ddnsProfilesRaw)
|
||||
|
||||
overrideDomainsRaw, err := utils.Json.Marshal(sf.OverrideDDNSDomains)
|
||||
overrideDomainsRaw, err := json.Marshal(sf.OverrideDDNSDomains)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -281,10 +281,7 @@ func setServerConfig(c *gin.Context) (*model.ServerTaskResponse, error) {
|
||||
var respMu sync.Mutex
|
||||
|
||||
for i := 0; i < len(servers); i += 10 {
|
||||
end := i + 10
|
||||
if end > len(servers) {
|
||||
end = len(servers)
|
||||
}
|
||||
end := min(i+10, len(servers))
|
||||
group := servers[i:end]
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
// @Success 200 {object} model.CommonResponse[model.ServiceResponse]
|
||||
// @Router /service [get]
|
||||
func showService(c *gin.Context) (*model.ServiceResponse, error) {
|
||||
res, err, _ := requestGroup.Do("list-service", func() (interface{}, error) {
|
||||
res, err, _ := requestGroup.Do("list-service", func() (any, error) {
|
||||
singleton.AlertsLock.RLock()
|
||||
defer singleton.AlertsLock.RUnlock()
|
||||
stats := singleton.ServiceSentinelShared.CopyStats()
|
||||
@@ -41,8 +41,8 @@ func showService(c *gin.Context) (*model.ServiceResponse, error) {
|
||||
}
|
||||
|
||||
return &model.ServiceResponse{
|
||||
Services: res.([]interface{})[0].(map[uint64]model.ServiceResponseItem),
|
||||
CycleTransferStats: res.([]interface{})[1].(map[uint64]model.CycleTransferStats),
|
||||
Services: res.([]any)[0].(map[uint64]model.ServiceResponseItem),
|
||||
CycleTransferStats: res.([]any)[1].(map[uint64]model.CycleTransferStats),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ import (
|
||||
// @Security BearerAuth
|
||||
// @Tags common
|
||||
// @Produce json
|
||||
// @Success 200 {object} model.CommonResponse[model.SettingResponse[model.Config]]
|
||||
// @Success 200 {object} model.CommonResponse[model.SettingResponse]
|
||||
// @Router /setting [get]
|
||||
func listConfig(c *gin.Context) (model.SettingResponse[any], error) {
|
||||
func listConfig(c *gin.Context) (*model.SettingResponse, error) {
|
||||
u, authorized := c.Get(model.CtxKeyAuthorizedUser)
|
||||
var isAdmin bool
|
||||
if authorized {
|
||||
@@ -30,30 +30,29 @@ func listConfig(c *gin.Context) (model.SettingResponse[any], error) {
|
||||
config := *singleton.Conf
|
||||
config.Language = strings.Replace(config.Language, "_", "-", -1)
|
||||
|
||||
conf := model.SettingResponse[any]{
|
||||
Config: config,
|
||||
conf := model.SettingResponse{
|
||||
Config: model.Setting{
|
||||
ConfigForGuests: config.ConfigForGuests,
|
||||
ConfigDashboard: config.ConfigDashboard,
|
||||
},
|
||||
Version: singleton.Version,
|
||||
FrontendTemplates: singleton.FrontendTemplates,
|
||||
}
|
||||
|
||||
if !authorized || !isAdmin {
|
||||
configForGuests := model.ConfigForGuests{
|
||||
Language: config.Language,
|
||||
SiteName: config.SiteName,
|
||||
CustomCode: config.CustomCode,
|
||||
CustomCodeDashboard: config.CustomCodeDashboard,
|
||||
Oauth2Providers: config.Oauth2Providers,
|
||||
}
|
||||
configForGuests := config.ConfigForGuests
|
||||
if authorized {
|
||||
configForGuests.TLS = singleton.Conf.TLS
|
||||
configForGuests.AgentTLS = singleton.Conf.AgentTLS
|
||||
configForGuests.InstallHost = singleton.Conf.InstallHost
|
||||
}
|
||||
conf = model.SettingResponse[any]{
|
||||
Config: configForGuests,
|
||||
conf = model.SettingResponse{
|
||||
Config: model.Setting{
|
||||
ConfigForGuests: configForGuests,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return conf, nil
|
||||
return &conf, nil
|
||||
}
|
||||
|
||||
// Edit config
|
||||
@@ -98,7 +97,7 @@ func updateConfig(c *gin.Context) (any, error) {
|
||||
singleton.Conf.CustomCode = sf.CustomCode
|
||||
singleton.Conf.CustomCodeDashboard = sf.CustomCodeDashboard
|
||||
singleton.Conf.RealIPHeader = sf.RealIPHeader
|
||||
singleton.Conf.TLS = sf.TLS
|
||||
singleton.Conf.AgentTLS = sf.AgentTLS
|
||||
singleton.Conf.UserTemplate = sf.UserTemplate
|
||||
|
||||
if err := singleton.Conf.Save(); err != nil {
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
|
||||
"github.com/nezhahq/nezha/model"
|
||||
"github.com/nezhahq/nezha/pkg/utils"
|
||||
"github.com/nezhahq/nezha/pkg/websocketx"
|
||||
"github.com/nezhahq/nezha/proto"
|
||||
"github.com/nezhahq/nezha/service/rpc"
|
||||
@@ -46,7 +46,7 @@ func createTerminal(c *gin.Context) (*model.CreateTerminalResponse, error) {
|
||||
|
||||
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
||||
|
||||
terminalData, _ := utils.Json.Marshal(&model.TerminalTask{
|
||||
terminalData, _ := json.Marshal(&model.TerminalTask{
|
||||
StreamID: streamId,
|
||||
})
|
||||
if err := server.TaskStream.Send(&proto.Task{
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"golang.org/x/sync/singleflight"
|
||||
@@ -157,7 +158,7 @@ func serverStream(c *gin.Context) (any, error) {
|
||||
var requestGroup singleflight.Group
|
||||
|
||||
func getServerStat(withPublicNote, authorized bool) ([]byte, error) {
|
||||
v, err, _ := requestGroup.Do(fmt.Sprintf("serverStats::%t", authorized), func() (interface{}, error) {
|
||||
v, err, _ := requestGroup.Do(fmt.Sprintf("serverStats::%t", authorized), func() (any, error) {
|
||||
var serverList []*model.Server
|
||||
if authorized {
|
||||
serverList = singleton.ServerShared.GetSortedList()
|
||||
@@ -183,7 +184,7 @@ func getServerStat(withPublicNote, authorized bool) ([]byte, error) {
|
||||
})
|
||||
}
|
||||
|
||||
return utils.Json.Marshal(model.StreamServerData{
|
||||
return json.Marshal(model.StreamServerData{
|
||||
Now: time.Now().Unix() * 1000,
|
||||
Online: singleton.GetOnlineUserCount(),
|
||||
Servers: servers,
|
||||
|
||||
@@ -2,7 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"embed"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -16,8 +18,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/ory/graceful"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
|
||||
"github.com/nezhahq/nezha/cmd/dashboard/controller"
|
||||
"github.com/nezhahq/nezha/cmd/dashboard/controller/waf"
|
||||
@@ -133,20 +133,54 @@ func main() {
|
||||
controller.InitUpgrader()
|
||||
|
||||
muxHandler := newHTTPandGRPCMux(httpHandler, grpcHandler)
|
||||
http2Server := &http2.Server{}
|
||||
muxServer := &http.Server{Handler: h2c.NewHandler(muxHandler, http2Server), ReadHeaderTimeout: time.Second * 5}
|
||||
muxServerHTTP := &http.Server{
|
||||
Handler: muxHandler,
|
||||
ReadHeaderTimeout: time.Second * 5,
|
||||
}
|
||||
muxServerHTTP.Protocols = new(http.Protocols)
|
||||
muxServerHTTP.Protocols.SetHTTP1(true)
|
||||
muxServerHTTP.Protocols.SetUnencryptedHTTP2(true)
|
||||
|
||||
var muxServerHTTPS *http.Server
|
||||
if singleton.Conf.HTTPS.ListenPort != 0 {
|
||||
muxServerHTTPS = &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", singleton.Conf.ListenHost, singleton.Conf.HTTPS.ListenPort),
|
||||
Handler: muxHandler,
|
||||
ReadHeaderTimeout: time.Second * 5,
|
||||
TLSConfig: &tls.Config{
|
||||
InsecureSkipVerify: singleton.Conf.HTTPS.InsecureTLS,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
errChan := make(chan error, 2)
|
||||
|
||||
if err := graceful.Graceful(func() error {
|
||||
log.Printf("NEZHA>> Dashboard::START ON %s:%d", singleton.Conf.ListenHost, singleton.Conf.ListenPort)
|
||||
return muxServer.Serve(l)
|
||||
if singleton.Conf.HTTPS.ListenPort != 0 {
|
||||
go func() {
|
||||
errChan <- muxServerHTTPS.ListenAndServeTLS(singleton.Conf.HTTPS.TLSCertPath, singleton.Conf.HTTPS.TLSKeyPath)
|
||||
}()
|
||||
log.Printf("NEZHA>> Dashboard::START ON %s:%d", singleton.Conf.ListenHost, singleton.Conf.HTTPS.ListenPort)
|
||||
}
|
||||
go func() {
|
||||
errChan <- muxServerHTTP.Serve(l)
|
||||
}()
|
||||
return <-errChan
|
||||
}, func(c context.Context) error {
|
||||
log.Println("NEZHA>> Graceful::START")
|
||||
singleton.RecordTransferHourlyUsage()
|
||||
log.Println("NEZHA>> Graceful::END")
|
||||
return muxServer.Shutdown(c)
|
||||
err := muxServerHTTPS.Shutdown(c)
|
||||
return errors.Join(muxServerHTTP.Shutdown(c), err)
|
||||
}); err != nil {
|
||||
log.Printf("NEZHA>> ERROR: %v", err)
|
||||
if errors.Unwrap(err) != nil {
|
||||
log.Printf("NEZHA>> ERROR HTTPS: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
close(errChan)
|
||||
}
|
||||
|
||||
func newHTTPandGRPCMux(httpHandler http.Handler, grpcHandler http.Handler) http.Handler {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/peer"
|
||||
@@ -27,7 +28,7 @@ func ServeRPC() *grpc.Server {
|
||||
return server
|
||||
}
|
||||
|
||||
func waf(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
func waf(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
realip, _ := ctx.Value(model.CtxKeyRealIP{}).(string)
|
||||
if err := model.CheckIP(singleton.DB, realip); err != nil {
|
||||
return nil, err
|
||||
@@ -35,7 +36,7 @@ func waf(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handl
|
||||
return handler(ctx, req)
|
||||
}
|
||||
|
||||
func getRealIp(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
func getRealIp(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
var ip, connectingIp string
|
||||
p, ok := peer.FromContext(ctx)
|
||||
if ok {
|
||||
@@ -133,20 +134,20 @@ func ServeNAT(w http.ResponseWriter, r *http.Request, natConfig *model.NAT) {
|
||||
streamId, err := uuid.GenerateUUID()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
w.Write([]byte(fmt.Sprintf("stream id error: %v", err)))
|
||||
w.Write(fmt.Appendf(nil, "stream id error: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
rpcService.NezhaHandlerSingleton.CreateStream(streamId)
|
||||
defer rpcService.NezhaHandlerSingleton.CloseStream(streamId)
|
||||
|
||||
taskData, err := utils.Json.Marshal(model.TaskNAT{
|
||||
taskData, err := json.Marshal(model.TaskNAT{
|
||||
StreamID: streamId,
|
||||
Host: natConfig.Host,
|
||||
})
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
w.Write([]byte(fmt.Sprintf("task data error: %v", err)))
|
||||
w.Write(fmt.Appendf(nil, "task data error: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -155,20 +156,20 @@ func ServeNAT(w http.ResponseWriter, r *http.Request, natConfig *model.NAT) {
|
||||
Data: string(taskData),
|
||||
}); err != nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
w.Write([]byte(fmt.Sprintf("send task error: %v", err)))
|
||||
w.Write(fmt.Appendf(nil, "send task error: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
wWrapped, err := utils.NewRequestWrapper(r, w)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
w.Write([]byte(fmt.Sprintf("request wrapper error: %v", err)))
|
||||
w.Write(fmt.Appendf(nil, "request wrapper error: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
if err := rpcService.NezhaHandlerSingleton.UserConnected(streamId, wWrapped); err != nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
w.Write([]byte(fmt.Sprintf("user connected error: %v", err)))
|
||||
w.Write(fmt.Appendf(nil, "user connected error: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user