mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-20 11:36:06 +00:00
feat(api-docs): generate response examples from Go structs; fix SS2022 PSK regen (#4996)
Stop hand-writing OpenAPI response examples, which kept drifting from the real payloads (clients/traffic missing fields, inbounds/list exposing userId which is json:"-", the fictional inbound-443 tag instead of the real in-<port>-<transport> form).
tools/openapigen now emits frontend/src/generated/examples.ts: a per-struct example instance built from type defaults, validate oneof/min bounds, and example: struct tags, with nested-ref expansion and a cycle guard. build-openapi.mjs composes the {success,obj} envelope from it for any endpoint annotated with responseSchema (+ responseSchemaArray for lists); the hand-written response is dropped for those. Service DTOs InboundOption/ApiTokenView/ProbeResultUI are added to the walker.
#4996: client password regeneration now produces a valid Shadowsocks 2022 PSK (correct base64 length per cipher) when an SS2022 inbound is attached, in both the single and bulk client forms; backend surfaces ssMethod on /inbounds/options so the UI can pick the right length.
Also: Swagger UI persists the Authorization token across reloads (persistAuthorization).
This commit is contained in:
@@ -17,11 +17,11 @@ type ApiTokenService struct{}
|
||||
const apiTokenLength = 48
|
||||
|
||||
type ApiTokenView struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Token string `json:"token,omitempty"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
Id int `json:"id" example:"2"`
|
||||
Name string `json:"name" example:"central-panel-a"`
|
||||
Token string `json:"token,omitempty" example:"new-token-string"`
|
||||
Enabled bool `json:"enabled" example:"true"`
|
||||
CreatedAt int64 `json:"createdAt" example:"1736000000"`
|
||||
}
|
||||
|
||||
// toView builds the metadata view returned by List. It never carries the
|
||||
|
||||
+26
-7
@@ -356,12 +356,13 @@ func (s *InboundService) annotateFallbackParents(db *gorm.DB, inbounds []*model.
|
||||
}
|
||||
|
||||
type InboundOption struct {
|
||||
Id int `json:"id"`
|
||||
Remark string `json:"remark"`
|
||||
Tag string `json:"tag"`
|
||||
Protocol string `json:"protocol"`
|
||||
Port int `json:"port"`
|
||||
TlsFlowCapable bool `json:"tlsFlowCapable"`
|
||||
Id int `json:"id" example:"1"`
|
||||
Remark string `json:"remark" example:"VLESS-443"`
|
||||
Tag string `json:"tag" example:"in-443-tcp"`
|
||||
Protocol string `json:"protocol" example:"vless"`
|
||||
Port int `json:"port" example:"443"`
|
||||
TlsFlowCapable bool `json:"tlsFlowCapable" example:"true"`
|
||||
SsMethod string `json:"ssMethod"`
|
||||
}
|
||||
|
||||
func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error) {
|
||||
@@ -373,9 +374,10 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
|
||||
Protocol string `gorm:"column:protocol"`
|
||||
Port int `gorm:"column:port"`
|
||||
StreamSettings string `gorm:"column:stream_settings"`
|
||||
Settings string `gorm:"column:settings"`
|
||||
}
|
||||
err := db.Table("inbounds").
|
||||
Select("id, remark, tag, protocol, port, stream_settings").
|
||||
Select("id, remark, tag, protocol, port, stream_settings, settings").
|
||||
Where("user_id = ?", userId).
|
||||
Order("id ASC").
|
||||
Scan(&rows).Error
|
||||
@@ -391,11 +393,28 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
|
||||
Protocol: r.Protocol,
|
||||
Port: r.Port,
|
||||
TlsFlowCapable: inboundCanEnableTlsFlow(r.Protocol, r.StreamSettings),
|
||||
SsMethod: inboundShadowsocksMethod(r.Protocol, r.Settings),
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// inboundShadowsocksMethod extracts settings.method for Shadowsocks inbounds so
|
||||
// the client UI can generate a valid PSK (base64 of the method's key length)
|
||||
// for Shadowsocks 2022 ciphers. Returns "" for non-Shadowsocks inbounds.
|
||||
func inboundShadowsocksMethod(protocol, settings string) string {
|
||||
if protocol != string(model.Shadowsocks) || settings == "" {
|
||||
return ""
|
||||
}
|
||||
var s struct {
|
||||
Method string `json:"method"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(settings), &s); err != nil {
|
||||
return ""
|
||||
}
|
||||
return s.Method
|
||||
}
|
||||
|
||||
// inboundCanEnableTlsFlow mirrors Inbound.canEnableTlsFlow() from the frontend:
|
||||
// XTLS Vision is only valid for VLESS on TCP with tls or reality.
|
||||
func inboundCanEnableTlsFlow(protocol, streamSettings string) bool {
|
||||
|
||||
+7
-7
@@ -635,13 +635,13 @@ func (s *NodeService) Probe(ctx context.Context, n *model.Node) (HeartbeatPatch,
|
||||
}
|
||||
|
||||
type ProbeResultUI struct {
|
||||
Status string `json:"status"`
|
||||
LatencyMs int `json:"latencyMs"`
|
||||
XrayVersion string `json:"xrayVersion"`
|
||||
PanelVersion string `json:"panelVersion"`
|
||||
CpuPct float64 `json:"cpuPct"`
|
||||
MemPct float64 `json:"memPct"`
|
||||
UptimeSecs uint64 `json:"uptimeSecs"`
|
||||
Status string `json:"status" example:"online"`
|
||||
LatencyMs int `json:"latencyMs" example:"42"`
|
||||
XrayVersion string `json:"xrayVersion" example:"25.10.31"`
|
||||
PanelVersion string `json:"panelVersion" example:"v3.x.x"`
|
||||
CpuPct float64 `json:"cpuPct" example:"12.5"`
|
||||
MemPct float64 `json:"memPct" example:"45.2"`
|
||||
UptimeSecs uint64 `json:"uptimeSecs" example:"86400"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user