feat: Add endpoint to list agent VLESS nodes based on the server's public URL and introduce a configuration option for the public URL.

This commit is contained in:
Haitao Pan 2026-01-31 13:52:31 +08:00
parent 31fac873ce
commit ccb0bada22
3 changed files with 69 additions and 0 deletions

View File

@ -66,6 +66,7 @@ type handler struct {
tokenService *auth.TokenService
oauthProviders map[string]auth.OAuthProvider
oauthFrontendURL string
publicURL string
}
type mfaChallenge struct {
@ -188,6 +189,13 @@ func WithOAuthProviders(providers map[string]auth.OAuthProvider) Option {
}
}
// WithServerPublicURL configures the public URL of the account service.
func WithServerPublicURL(url string) Option {
return func(h *handler) {
h.publicURL = url
}
}
// WithOAuthFrontendURL configures the frontend URL for OAuth2 redirects.
func WithOAuthFrontendURL(url string) Option {
return func(h *handler) {
@ -253,6 +261,8 @@ func RegisterRoutes(r *gin.Engine, opts ...Option) {
authProtected.POST("/mfa/disable", h.disableMFA)
authProtected.GET("/mfa/status", h.mfaStatus)
authProtected.GET("/agent/nodes", h.listAgentNodes)
authProtected.POST("/password/reset", h.requestPasswordReset)
authProtected.POST("/password/reset/confirm", h.confirmPasswordReset)

56
api/user_agents.go Normal file
View File

@ -0,0 +1,56 @@
package api
import (
"net/http"
"net/url"
"strconv"
"github.com/gin-gonic/gin"
)
type vlessNode struct {
Name string `json:"name"`
Address string `json:"address"`
Port int `json:"port,omitempty"`
Users []string `json:"users,omitempty"`
Transport string `json:"transport,omitempty"`
Path string `json:"path,omitempty"`
Mode string `json:"mode,omitempty"`
Security string `json:"security,omitempty"`
}
func (h *handler) listAgentNodes(c *gin.Context) {
// For now, valid nodes are derived from the server's public URL.
// We currently assume the server itself exposes a VLESS/XHTTP endpoint.
// In the future, we might retrieve this from the agent registry if agents report their public IPs.
nodes := make([]vlessNode, 0)
if h.publicURL != "" {
u, err := url.Parse(h.publicURL)
if err == nil {
hostname := u.Hostname()
portStr := u.Port()
port := 443
if portStr != "" {
if p, err := strconv.Atoi(portStr); err == nil {
port = p
}
} else if u.Scheme == "http" {
port = 80
}
// Add "Global Acceleration" node (representing the main server)
nodes = append(nodes, vlessNode{
Name: "Global Acceleration",
Address: hostname,
Port: port, // Default port, client will adjust based on transport if needed
Transport: "xhttp",
Path: "/split",
Security: "tls",
})
}
}
c.JSON(http.StatusOK, nodes)
}

View File

@ -290,7 +290,10 @@ func runServer(ctx context.Context, cfg *config.Config, logger *slog.Logger) err
api.WithEmailVerification(cfg.Auth.Enable),
api.WithTokenService(tokenService),
api.WithOAuthProviders(oauthProviders),
api.WithTokenService(tokenService),
api.WithOAuthProviders(oauthProviders),
api.WithOAuthFrontendURL(cfg.Auth.OAuth.FrontendURL),
api.WithServerPublicURL(cfg.Server.PublicURL),
)
if agentRegistry != nil {