mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-25 04:17:15 +00:00
chore(build): bump Go toolchain to 1.27.0
Go 1.27.0 shipped on 2026-08-19. Raise the go directive and the builder image so Docker and release builds pick it up; every CI job already reads the version from go.mod, and golangci-lint v2.13.1 release binaries are themselves built with go1.27.0, so the lint job needs no pin change.
This commit is contained in:
@@ -103,7 +103,7 @@ func TestCatalogCoalescesConcurrentRefresh(t *testing.T) {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
close(source.release)
|
||||
for i := 0; i < 2; i++ {
|
||||
for range 2 {
|
||||
if err := <-errc; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func validHostname(host string) bool {
|
||||
if host == "" || len(host) > 253 || net.ParseIP(host) != nil || strings.HasSuffix(host, ".") {
|
||||
return false
|
||||
}
|
||||
for _, label := range strings.Split(host, ".") {
|
||||
for label := range strings.SplitSeq(host, ".") {
|
||||
if label == "" || len(label) > 63 || label[0] == '-' || label[len(label)-1] == '-' {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -387,10 +387,10 @@ func jsonMux(global, override string) string {
|
||||
}
|
||||
|
||||
func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_util.RawMessage, client model.Client, mux string) json_util.RawMessage {
|
||||
outbound := Outbound{}
|
||||
outbound := Outbound{
|
||||
|
||||
outbound.Protocol = string(inbound.Protocol)
|
||||
outbound.Tag = "proxy"
|
||||
Protocol: string(inbound.Protocol),
|
||||
Tag: "proxy"}
|
||||
if mux != "" {
|
||||
outbound.Mux = json_util.RawMessage(mux)
|
||||
}
|
||||
@@ -410,9 +410,9 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_ut
|
||||
}
|
||||
|
||||
func (s *SubJsonService) genVless(subReq *SubService, inbound *model.Inbound, streamSettings json_util.RawMessage, client model.Client, mux string) json_util.RawMessage {
|
||||
outbound := Outbound{}
|
||||
outbound.Protocol = string(inbound.Protocol)
|
||||
outbound.Tag = "proxy"
|
||||
outbound := Outbound{
|
||||
Protocol: string(inbound.Protocol),
|
||||
Tag: "proxy"}
|
||||
if mux != "" {
|
||||
outbound.Mux = json_util.RawMessage(mux)
|
||||
}
|
||||
@@ -490,10 +490,10 @@ func (s *SubJsonService) genServer(subReq *SubService, inbound *model.Inbound, s
|
||||
}
|
||||
|
||||
func (s *SubJsonService) genHy(inbound *model.Inbound, newStream map[string]any, client model.Client, mux string) json_util.RawMessage {
|
||||
outbound := Outbound{}
|
||||
outbound := Outbound{
|
||||
|
||||
outbound.Protocol = string(inbound.Protocol)
|
||||
outbound.Tag = "proxy"
|
||||
Protocol: string(inbound.Protocol),
|
||||
Tag: "proxy"}
|
||||
|
||||
if mux != "" {
|
||||
outbound.Mux = json_util.RawMessage(mux)
|
||||
|
||||
@@ -25,8 +25,9 @@ func initMutDB(t *testing.T) {
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
}
|
||||
|
||||
//go:fix inline
|
||||
func externalLinkEnabled(v bool) *bool {
|
||||
return &v
|
||||
return new(v)
|
||||
}
|
||||
|
||||
// --- json_service.go:40 — rules are merged into routing only when non-empty ---
|
||||
@@ -312,7 +313,7 @@ func TestGetClientExternalLinksBySubId(t *testing.T) {
|
||||
if err := db.Create(&model.ClientExternalLink{ClientId: rec.Id, Kind: model.ExternalLinkKindLink, Value: "trojan://a", Remark: "first", SortIndex: 1}).Error; err != nil {
|
||||
t.Fatalf("seed link a: %v", err)
|
||||
}
|
||||
if err := db.Create(&model.ClientExternalLink{ClientId: rec.Id, Kind: model.ExternalLinkKindLink, Value: "trojan://disabled", Remark: "disabled", Enable: externalLinkEnabled(false), SortIndex: 3}).Error; err != nil {
|
||||
if err := db.Create(&model.ClientExternalLink{ClientId: rec.Id, Kind: model.ExternalLinkKindLink, Value: "trojan://disabled", Remark: "disabled", Enable: new(false), SortIndex: 3}).Error; err != nil {
|
||||
t.Fatalf("seed disabled link: %v", err)
|
||||
}
|
||||
if err := db.Create(&model.ClientExternalLink{ClientId: rec.Id, Kind: model.ExternalLinkKindLink, Value: "trojan://expired", Remark: "expired", ExpiryTime: time.Now().Add(-time.Hour).UnixMilli(), SortIndex: 4}).Error; err != nil {
|
||||
|
||||
@@ -370,8 +370,8 @@ func normalizeHappRouting(body []byte) (string, error) {
|
||||
|
||||
payload := ""
|
||||
for _, prefix := range []string{"happ://routing/onadd/", "happ://routing/add/"} {
|
||||
if strings.HasPrefix(text, prefix) {
|
||||
payload = strings.TrimPrefix(text, prefix)
|
||||
if after, ok := strings.CutPrefix(text, prefix); ok {
|
||||
payload = after
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,11 +155,11 @@ func (a *APIController) enforceTokenScope(c *gin.Context) {
|
||||
|
||||
func relAPIPath(fullPath string) string {
|
||||
const marker = "/panel/api"
|
||||
i := strings.Index(fullPath, marker)
|
||||
if i < 0 {
|
||||
_, after, ok := strings.Cut(fullPath, marker)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return fullPath[i+len(marker):]
|
||||
return after
|
||||
}
|
||||
|
||||
// initRouter sets up the API routes for inbounds, server, and other endpoints.
|
||||
|
||||
@@ -2,6 +2,7 @@ package job
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -16,7 +17,7 @@ type ipLimitAllowlist struct {
|
||||
// skipped: the validator uses these same rules, so only a hand-edited DB differs.
|
||||
func parseIpLimitAllowlist(raw string) ipLimitAllowlist {
|
||||
var list ipLimitAllowlist
|
||||
for _, field := range strings.Split(raw, ",") {
|
||||
for field := range strings.SplitSeq(raw, ",") {
|
||||
field = strings.TrimSpace(field)
|
||||
if field == "" {
|
||||
continue
|
||||
@@ -52,10 +53,8 @@ func (l ipLimitAllowlist) contains(ip string) bool {
|
||||
return false
|
||||
}
|
||||
addr = addr.Unmap()
|
||||
for _, allowed := range l.addrs {
|
||||
if allowed == addr {
|
||||
return true
|
||||
}
|
||||
if slices.Contains(l.addrs, addr) {
|
||||
return true
|
||||
}
|
||||
for _, prefix := range l.prefixes {
|
||||
if prefix.Contains(addr) {
|
||||
|
||||
@@ -46,8 +46,8 @@ func (c *AutoHttpsConn) readRequest() bool {
|
||||
}
|
||||
resp := http.Response{
|
||||
Header: http.Header{},
|
||||
}
|
||||
resp.StatusCode = http.StatusTemporaryRedirect
|
||||
|
||||
StatusCode: http.StatusTemporaryRedirect}
|
||||
location := fmt.Sprintf("https://%v%v", request.Host, request.RequestURI)
|
||||
resp.Header.Set("Location", location)
|
||||
_ = resp.Write(c.Conn)
|
||||
|
||||
@@ -7,10 +7,6 @@ import (
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
)
|
||||
|
||||
func externalLinkBool(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
||||
func TestSetExternalLinksPersistsEnableState(t *testing.T) {
|
||||
setupBulkDB(t)
|
||||
db := database.GetDB()
|
||||
@@ -22,8 +18,8 @@ func TestSetExternalLinksPersistsEnableState(t *testing.T) {
|
||||
}
|
||||
|
||||
if err := svc.SetExternalLinksForRecord(rec.Id, []ExternalLinkInput{
|
||||
{Kind: model.ExternalLinkKindLink, Value: "trojan://pw@example.com:443#on", Remark: "Primary", Enable: externalLinkBool(true), ExpiryTime: 1767225600000},
|
||||
{Kind: model.ExternalLinkKindSubscription, Value: "https://provider.example/sub", Remark: "Provider", Enable: externalLinkBool(false), NamePrefix: "[zjh] "},
|
||||
{Kind: model.ExternalLinkKindLink, Value: "trojan://pw@example.com:443#on", Remark: "Primary", Enable: new(true), ExpiryTime: 1767225600000},
|
||||
{Kind: model.ExternalLinkKindSubscription, Value: "https://provider.example/sub", Remark: "Provider", Enable: new(false), NamePrefix: "[zjh] "},
|
||||
{Kind: model.ExternalLinkKindLink, Value: "trojan://pw@example.net:443#default"},
|
||||
}); err != nil {
|
||||
t.Fatalf("set external links: %v", err)
|
||||
@@ -76,7 +72,7 @@ func TestSetExternalLinksPreservesFetchStatus(t *testing.T) {
|
||||
}
|
||||
|
||||
if err := svc.SetExternalLinksForRecord(rec.Id, []ExternalLinkInput{
|
||||
{Kind: row.Kind, Value: row.Value, Remark: "new", Enable: externalLinkBool(true)},
|
||||
{Kind: row.Kind, Value: row.Value, Remark: "new", Enable: new(true)},
|
||||
}); err != nil {
|
||||
t.Fatalf("set external links: %v", err)
|
||||
}
|
||||
|
||||
@@ -4,15 +4,14 @@ import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
)
|
||||
|
||||
func TestClientWithAttachmentsMarshalJSONIncludesExtras(t *testing.T) {
|
||||
c := ClientWithAttachments{
|
||||
ClientRecord: model.ClientRecord{Id: 1, Email: "alice@example.com"},
|
||||
InboundIds: []int{3, 5},
|
||||
Traffic: &xray.ClientTraffic{Email: "alice@example.com", Up: 1024, Down: 4096, Enable: true},
|
||||
Id: 1, Email: "alice@example.com",
|
||||
InboundIds: []int{3, 5},
|
||||
Traffic: &xray.ClientTraffic{Email: "alice@example.com", Up: 1024, Down: 4096, Enable: true},
|
||||
}
|
||||
out, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
@@ -39,8 +38,8 @@ func TestClientWithAttachmentsMarshalJSONIncludesExtras(t *testing.T) {
|
||||
|
||||
func TestClientWithAttachmentsMarshalJSONOmitsAbsentTraffic(t *testing.T) {
|
||||
c := ClientWithAttachments{
|
||||
ClientRecord: model.ClientRecord{Id: 1, Email: "bob@example.com"},
|
||||
InboundIds: nil,
|
||||
Id: 1, Email: "bob@example.com",
|
||||
InboundIds: nil,
|
||||
}
|
||||
out, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
|
||||
@@ -118,7 +118,7 @@ func TestAutoRenewClients_CalendarModeClampsShortMonths(t *testing.T) {
|
||||
func firstBillingMidnightAfter(t *testing.T, from time.Time, day int, loc *time.Location) time.Time {
|
||||
t.Helper()
|
||||
cur := time.Date(from.Year(), from.Month(), from.Day(), 0, 0, 0, 0, loc)
|
||||
for i := 0; i < 400; i++ {
|
||||
for range 400 {
|
||||
cur = cur.AddDate(0, 0, 1)
|
||||
want := day
|
||||
if last := time.Date(cur.Year(), cur.Month()+1, 0, 0, 0, 0, 0, loc).Day(); want > last {
|
||||
|
||||
@@ -187,7 +187,7 @@ func TestEnsureMasterClientCertConcurrentFirstUseMintsOneCredential(t *testing.T
|
||||
}
|
||||
close(start)
|
||||
var first crypto.CertKeyPEM
|
||||
for i := 0; i < callers; i++ {
|
||||
for i := range callers {
|
||||
credential := <-results
|
||||
if err := <-errs; err != nil {
|
||||
t.Fatalf("caller %d: %v", i, err)
|
||||
|
||||
@@ -103,10 +103,7 @@ func sliceBounds(total, offset, limit int) (int, int) {
|
||||
if limit <= 0 || limit > MaxPageSize {
|
||||
limit = MaxPageSize
|
||||
}
|
||||
to := offset + limit
|
||||
if to > total {
|
||||
to = total
|
||||
}
|
||||
to := min(offset+limit, total)
|
||||
return offset, to
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user