5 次代码提交 095ebccbb0 ... 2e363445fc

作者 SHA1 备注 提交日期
  mhsanaei 2e363445fc update dependencies 1 周之前
  mhsanaei 33d983bc20 New - maskAddress , dnslog 1 周之前
  mhsanaei 3e7c7831bc Email Validation - new pattern 1 周之前
  mhsanaei 374d49eb92 Iplimit - improved 1 周之前
  mhsanaei 663cf5649f Session - default 60 minute (minimum) 1 周之前

+ 7 - 7
go.mod

@@ -7,7 +7,7 @@ require (
 	github.com/gin-contrib/sessions v1.0.1
 	github.com/gin-gonic/gin v1.10.0
 	github.com/goccy/go-json v0.10.3
-	github.com/mymmrac/telego v0.31.2
+	github.com/mymmrac/telego v0.31.3
 	github.com/nicksnyder/go-i18n/v2 v2.4.0
 	github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
 	github.com/pelletier/go-toml/v2 v2.2.3
@@ -17,7 +17,7 @@ require (
 	github.com/xtls/xray-core v1.8.24
 	go.uber.org/atomic v1.11.0
 	golang.org/x/text v0.18.0
-	google.golang.org/grpc v1.66.1
+	google.golang.org/grpc v1.66.2
 	gorm.io/driver/sqlite v1.5.6
 	gorm.io/gorm v1.25.12
 )
@@ -40,7 +40,7 @@ require (
 	github.com/go-playground/validator/v10 v10.22.1 // indirect
 	github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
 	github.com/google/btree v1.1.3 // indirect
-	github.com/google/pprof v0.0.0-20240903155634-a8630aee4ab9 // indirect
+	github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 // indirect
 	github.com/gorilla/context v1.1.2 // indirect
 	github.com/gorilla/securecookie v1.1.2 // indirect
 	github.com/gorilla/sessions v1.4.0 // indirect
@@ -52,7 +52,7 @@ require (
 	github.com/klauspost/compress v1.17.9 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
-	github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 // indirect
+	github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-sqlite3 v1.14.23 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -79,19 +79,19 @@ require (
 	github.com/valyala/fastjson v1.6.4 // indirect
 	github.com/vishvananda/netlink v1.3.0 // indirect
 	github.com/vishvananda/netns v0.0.4 // indirect
-	github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d // indirect
+	github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect
 	github.com/yusufpapurcu/wmi v1.2.4 // indirect
 	go.uber.org/mock v0.4.0 // indirect
 	go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
 	golang.org/x/arch v0.10.0 // indirect
 	golang.org/x/crypto v0.27.0 // indirect
-	golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
+	golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
 	golang.org/x/mod v0.21.0 // indirect
 	golang.org/x/net v0.29.0 // indirect
 	golang.org/x/sync v0.8.0 // indirect
 	golang.org/x/sys v0.25.0 // indirect
 	golang.org/x/time v0.6.0 // indirect
-	golang.org/x/tools v0.24.0 // indirect
+	golang.org/x/tools v0.25.0 // indirect
 	golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect

+ 14 - 14
go.sum

@@ -98,8 +98,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20240903155634-a8630aee4ab9 h1:q5g0N9eal4bmJwXHC5z0QCKs8qhS35hFfq0BAYsIwZI=
-github.com/google/pprof v0.0.0-20240903155634-a8630aee4ab9/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 h1:c5FlPPgxOn7kJz3VoPLkQYQXGBS3EklQ4Zfi57uOuqQ=
+github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
 github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
 github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -140,8 +140,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
-github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 h1:5RK988zAqB3/AN3opGfRpoQgAVqr6/A5+qRTi67VUZY=
-github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
+github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
+github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
 github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -158,8 +158,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/mymmrac/telego v0.31.2 h1:srvQOQtb5ZswmqIr03VuAkIF076bi25n7fyQ51Ifstw=
-github.com/mymmrac/telego v0.31.2/go.mod h1:dyuyrOIagRstnm2ZNWuVilPdsslQyEgwYww9zkDqdJU=
+github.com/mymmrac/telego v0.31.3 h1:yZlD+dm+1W6p3OmCG8K+MbS02Y6paUgwPnqfZN3RWQQ=
+github.com/mymmrac/telego v0.31.3/go.mod h1:coOoqXVmjFnwBlzusjfEezbQ7RH9wQnDowJdMm+bnEo=
 github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
 github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
 github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
@@ -273,8 +273,8 @@ github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQ
 github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
 github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
 github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
-github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg=
-github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
+github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
+github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
 github.com/xtls/xray-core v1.8.24 h1:Y2NumdlnJ9C9gvh1Ivs2+73ui5XQgB70wZXYCiI9DyY=
 github.com/xtls/xray-core v1.8.24/go.mod h1:cWIOI6iBBOsB0HHU9PGhaiBhaMPfiktUjwA0IWolWJc=
 github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
@@ -296,8 +296,8 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
 golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
-golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -350,8 +350,8 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
-golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
+golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
 golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
 golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
 golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
@@ -374,8 +374,8 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
 google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
-google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
+google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
+google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
 google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

+ 1 - 1
web/assets/js/model/setting.js

@@ -7,7 +7,7 @@ class AllSetting {
         this.webCertFile = "";
         this.webKeyFile = "";
         this.webBasePath = "/";
-        this.sessionMaxAge = 0;
+        this.sessionMaxAge = 60;
         this.pageSize = 50;
         this.expireDiff = 0;
         this.trafficDiff = 0;

+ 0 - 4
web/controller/index.go

@@ -83,10 +83,6 @@ func (a *IndexController) login(c *gin.Context) {
 		logger.Warning("Unable to get session's max age from DB")
 	}
 
-	if sessionMaxAge <= 0 {
-		sessionMaxAge = 60
-	}
-
 	err = session.SetMaxAge(c, sessionMaxAge*60)
 	if err != nil {
 		logger.Warning("Unable to set session's max age")

+ 1 - 1
web/html/xui/settings.html

@@ -138,7 +138,7 @@
                   <setting-list-item type="text" title='{{ i18n "pages.settings.publicKeyPath"}}' desc='{{ i18n "pages.settings.publicKeyPathDesc"}}' v-model="allSetting.webCertFile"></setting-list-item>
                   <setting-list-item type="text" title='{{ i18n "pages.settings.privateKeyPath"}}' desc='{{ i18n "pages.settings.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item>
                   <setting-list-item type="text" title='{{ i18n "pages.settings.panelUrlPath"}}' desc='{{ i18n "pages.settings.panelUrlPathDesc"}}' v-model="allSetting.webBasePath"></setting-list-item>
-                  <setting-list-item type="number" title='{{ i18n "pages.settings.sessionMaxAge" }}' desc='{{ i18n "pages.settings.sessionMaxAgeDesc" }}' v-model="allSetting.sessionMaxAge" :min="0"></setting-list-item>
+                  <setting-list-item type="number" title='{{ i18n "pages.settings.sessionMaxAge" }}' desc='{{ i18n "pages.settings.sessionMaxAgeDesc" }}' v-model="allSetting.sessionMaxAge" :min="60"></setting-list-item>
                   <setting-list-item type="number" title='{{ i18n "pages.settings.pageSize" }}' desc='{{ i18n "pages.settings.pageSizeDesc" }}' v-model="allSetting.pageSize" :min="0" :step="5"></setting-list-item>
                   <setting-list-item type="number" title='{{ i18n "pages.settings.expireTimeDiff" }}' desc='{{ i18n "pages.settings.expireTimeDiffDesc" }}' v-model="allSetting.expireDiff" :min="0"></setting-list-item>
                   <setting-list-item type="number" title='{{ i18n "pages.settings.trafficDiff" }}' desc='{{ i18n "pages.settings.trafficDiffDesc" }}' v-model="allSetting.trafficDiff" :min="0"></setting-list-item>

+ 53 - 25
web/html/xui/xray.html

@@ -163,8 +163,8 @@
                         </a-col>
                         <a-col :lg="24" :xl="12">
                           <template>
-                            <a-select v-model="setLogLevel" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
-                              <a-select-option v-for="s in logLevel" :value="s">[[ s ]]</a-select-option>
+                            <a-select v-model="logLevel" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
+                                <a-select-option v-for="s in log.loglevel" :value="s">[[ s ]]</a-select-option>
                             </a-select>
                           </template>
                         </a-col>
@@ -178,7 +178,8 @@
                         <a-col :lg="24" :xl="12">
                           <template>
                             <a-select v-model="accessLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
-                              <a-select-option v-for="s in access" :key="s" :value="s">[[ s ]]</a-select-option>
+                                <a-select-option value=''>Empty</a-select-option>
+                                <a-select-option v-for="s in log.access" :value="s">[[ s ]]</a-select-option>
                             </a-select>
                           </template>
                         </a-col>
@@ -192,11 +193,28 @@
                         <a-col :lg="24" :xl="12">
                           <template>
                             <a-select v-model="errorLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
-                              <a-select-option v-for="s in error" :key="s" :value="s">[[ s ]]</a-select-option>
+                                <a-select-option value=''>Empty</a-select-option>
+                                <a-select-option v-for="s in log.error" :value="s">[[ s ]]</a-select-option>
                             </a-select>
                           </template>
                         </a-col>
                       </a-row>
+                      <a-row style="padding: 10px 20px">
+                        <a-col :lg="24" :xl="12">
+                          <a-list-item-meta title='{{ i18n "pages.xray.maskAddress" }}'
+                            description='{{ i18n "pages.xray.maskAddressDesc" }}'>
+                          </a-list-item-meta>
+                        </a-col>
+                        <a-col :lg="24" :xl="12">
+                          <template>
+                            <a-select v-model="maskAddressLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
+                                <a-select-option value=''>Empty</a-select-option>
+                                <a-select-option v-for="s in log.maskAddress" :value="s">[[ s ]]</a-select-option>
+                            </a-select>
+                          </template>
+                        </a-col>
+                      </a-row>
+                      <setting-list-item type="switch" title='{{ i18n "pages.xray.dnsLog"}}' desc='{{ i18n "pages.xray.dnsLogDesc"}}' v-model="dnslog"></setting-list-item>
                     </a-list-item>
                   </a-collapse-panel>
                   <a-collapse-panel header='{{ i18n "pages.xray.blockConfigs"}}'>
@@ -791,9 +809,13 @@
                 protocol: "freedom"
             },
             routingDomainStrategies: ["AsIs", "IPIfNonMatch", "IPOnDemand"],
-            logLevel: ["none" , "debug" , "info" , "warning", "error"],
-            access: [],
-            error: [],
+            log: {
+                loglevel: ["none", "debug", "info", "warning", "error"],
+                access: ["none", "./access.log"],
+                error: ["none", "./error.log"],
+                dnsLog: false,
+                maskAddress: ["quarter", "half", "full"],
+            },
             settingsData: {
                 protocols: {
                     bittorrent: ["bittorrent"],
@@ -1519,27 +1541,11 @@
             templateSettings: {
                 get: function () {
                     const parsedSettings = this.xraySetting ? JSON.parse(this.xraySetting) : null;
-                    let accessLogPath = "./access.log";
-                    let errorLogPath = "./error.log";
-
-                    if (parsedSettings && parsedSettings.log) {
-                        if (parsedSettings.log.access && parsedSettings.log.access !== "none") {
-                            accessLogPath = parsedSettings.log.access;
-                        }
-                        if (parsedSettings.log.error && parsedSettings.log.error !== "none") {
-                            errorLogPath = parsedSettings.log.error;
-                        }
-                    }
-
-                    this.access = ["none", accessLogPath];
-                    this.error = ["none", errorLogPath];
                     return parsedSettings;
                 },
                 set: function (newValue) {
-                    if (newValue && newValue.log) {
+                    if (newValue) {
                         this.xraySetting = JSON.stringify(newValue, null, 2);
-                        this.access = ["none", newValue.log.access || "./access.log"];
-                        this.error = ["none", newValue.log.error || "./error.log"];
                     }
                 },
             },
@@ -1688,7 +1694,7 @@
                     this.templateSettings = newTemplateSettings;
                 }
             },
-            setLogLevel: {
+            logLevel: {
                 get: function () {
                     if (!this.templateSettings || !this.templateSettings.log || !this.templateSettings.log.loglevel) return "warning";
                     return this.templateSettings.log.loglevel;
@@ -1721,6 +1727,28 @@
                     this.templateSettings = newTemplateSettings;
                 }
             },
+            dnslog: {
+                get: function () {
+                    if (!this.templateSettings || !this.templateSettings.log || !this.templateSettings.log.dnsLog) return false;
+                    return this.templateSettings.log.dnsLog;
+                },
+                set: function (newValue) {
+                    newTemplateSettings = this.templateSettings;
+                    newTemplateSettings.log.dnsLog = newValue;
+                    this.templateSettings = newTemplateSettings;
+                }
+            },
+            maskAddressLog: {
+                get: function () {
+                    if (!this.templateSettings || !this.templateSettings.log || !this.templateSettings.log.maskAddress) return "";
+                    return this.templateSettings.log.maskAddress;
+                },
+                set: function (newValue) {
+                    newTemplateSettings = this.templateSettings;
+                    newTemplateSettings.log.maskAddress = newValue;
+                    this.templateSettings = newTemplateSettings;
+                }
+            },
             blockedIPs: {
                 get: function () {
                     return this.templateRuleGetter({ outboundTag: "blocked", property: "ip" });

+ 12 - 10
web/job/check_client_ip_job.go

@@ -36,10 +36,11 @@ func (j *CheckClientIpJob) Run() {
 	}
 
 	shouldClearAccessLog := false
+	iplimitActive := j.hasLimitIp()
 	f2bInstalled := j.checkFail2BanInstalled()
-	isAccessLogAvailable := j.checkAccessLogAvailable()
+	isAccessLogAvailable := j.checkAccessLogAvailable(iplimitActive)
 
-	if j.hasLimitIp() {
+	if iplimitActive {
 		if f2bInstalled && isAccessLogAvailable {
 			shouldClearAccessLog = j.processLogFile()
 		} else {
@@ -123,7 +124,7 @@ func (j *CheckClientIpJob) processLogFile() bool {
 		line := scanner.Text()
 
 		ipRegx, _ := regexp.Compile(`from \[?([0-9a-fA-F:.]+)\]?:\d+ accepted`)
-		emailRegx, _ := regexp.Compile(`email:.+`)
+		emailRegx, _ := regexp.Compile(`email: (\S+)$`)
 
 		matches := ipRegx.FindStringSubmatch(line)
 		if len(matches) > 1 {
@@ -136,7 +137,7 @@ func (j *CheckClientIpJob) processLogFile() bool {
 			if matchesEmail == "" {
 				continue
 			}
-			matchesEmail = strings.TrimSpace(strings.Split(matchesEmail, "email: ")[1])
+			matchesEmail = strings.Split(matchesEmail, "email: ")[1]
 
 			if InboundClientIps[matchesEmail] != nil {
 				if j.contains(InboundClientIps[matchesEmail], ip) {
@@ -174,19 +175,20 @@ func (j *CheckClientIpJob) checkFail2BanInstalled() bool {
 	return err == nil
 }
 
-func (j *CheckClientIpJob) checkAccessLogAvailable() bool {
-	isAvailable := true
+func (j *CheckClientIpJob) checkAccessLogAvailable(iplimitActive bool) bool {
 	accessLogPath, err := xray.GetAccessLogPath()
 	if err != nil {
 		return false
 	}
 
-	switch accessLogPath {
-	case "none", "":
-		isAvailable = false
+	if accessLogPath == "none" || accessLogPath == "" {
+		if iplimitActive {
+			logger.Warning("Access log path is not set, and IP limit is active. Please configure the access log path.")
+		}
+		return false
 	}
 
-	return isAvailable
+	return true
 }
 
 func (j *CheckClientIpJob) checkError(e error) {

+ 2 - 2
web/service/inbound.go

@@ -2031,9 +2031,9 @@ func validateEmail(email string) (bool, error) {
 		return false, errors.New("email contains uppercase letters, please convert to lowercase")
 	}
 
-	emailPattern := `^[a-z0-9._-]+$`
+	emailPattern := `^[a-z0-9@._-]+$`
 	if !regexp.MustCompile(emailPattern).MatchString(email) {
-		return false, errors.New("email contains invalid characters, please use only lowercase letters, digits, dots, dashes, and underscores")
+		return false, errors.New("email contains invalid characters, please use only lowercase letters, digits, and @._-")
 	}
 
 	return true, nil

+ 1 - 1
web/service/setting.go

@@ -32,7 +32,7 @@ var defaultValueMap = map[string]string{
 	"webKeyFile":         "",
 	"secret":             random.Seq(32),
 	"webBasePath":        "/",
-	"sessionMaxAge":      "0",
+	"sessionMaxAge":      "60",
 	"pageSize":           "50",
 	"expireDiff":         "0",
 	"trafficDiff":        "0",

+ 4 - 0
web/translation/translate.en_US.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "The file path for the access log. The special value 'none' disabled access logs"
 "errorLog" = "Error Log"
 "errorLogDesc" = "The file path for the error log. The special value 'none' disabled error logs"
+"dnsLog" = "DNS Log"
+"dnsLogDesc" = "Whether to enable DNS query logs"
+"maskAddress" = "Mask Address"
+"maskAddressDesc" = "IP address mask, when enabled, will automatically replace the IP address that appears in the log."
 
 [pages.xray.rules]
 "first" = "First"

+ 4 - 0
web/translation/translate.es_ES.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "La ruta del archivo para el registro de acceso. El valor especial 'ninguno' deshabilita los registros de acceso"
 "errorLog" = "Registro de Errores"
 "errorLogDesc" = "La ruta del archivo para el registro de errores. El valor especial 'none' desactiva los registros de errores."
+"dnsLog" = "Registro DNS"
+"dnsLogDesc" = "Si habilitar los registros de consulta DNS"
+"maskAddress" = "Enmascarar Dirección"
+"maskAddressDesc" = "Máscara de dirección IP, cuando se habilita, reemplazará automáticamente la dirección IP que aparece en el registro."
 
 [pages.xray.rules]
 "first" = "Primero"

+ 4 - 0
web/translation/translate.fa_IR.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "مسیر فایل برای گزارش دسترسی. مقدار ویژه «هیچ» گزارش‌های دسترسی را غیرفعال میکند."
 "errorLog" = "گزارش خطا"
 "errorLogDesc" = "مسیر فایل برای ورود به سیستم خطا. مقدار ویژه «هیچ» گزارش های خطا را غیرفعال میکند"
+"dnsLog" = "گزارش DNS"
+"dnsLogDesc" = "آیا ثبت‌های درخواست DNS را فعال کنید"
+"maskAddress" = "پنهان کردن آدرس"
+"maskAddressDesc" = "پوشش آدرس IP، هنگامی که فعال می‌شود، به طور خودکار آدرس IP که در لاگ ظاهر می‌شود را جایگزین می‌کند."
 
 [pages.xray.rules]
 "first" = "اولین"

+ 4 - 0
web/translation/translate.id_ID.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "Jalur file untuk log akses. Nilai khusus 'tidak ada' menonaktifkan log akses"
 "errorLog" = "Catatan eror"
 "errorLogDesc" = "Jalur file untuk log kesalahan. Nilai khusus 'tidak ada' menonaktifkan log kesalahan"
+"dnsLog" = "Log DNS"
+"dnsLogDesc" = "Apakah akan mengaktifkan log kueri DNS"
+"maskAddress" = "Alamat Masker"
+"maskAddressDesc" = "Masker alamat IP, ketika diaktifkan, akan secara otomatis mengganti alamat IP yang muncul di log."
 
 [pages.xray.rules]
 "first" = "Pertama"

+ 4 - 0
web/translation/translate.pt_BR.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "O caminho do arquivo para o log de acesso. O valor especial 'none' desativa os logs de acesso."
 "errorLog" = "Log de Erros"
 "errorLogDesc" = "O caminho do arquivo para o log de erros. O valor especial 'none' desativa os logs de erro."
+"dnsLog" = "Log DNS"
+"dnsLogDesc" = "Se ativar logs de consulta DNS"
+"maskAddress" = "Mascarar Endereço"
+"maskAddressDesc" = "Máscara de endereço IP, quando ativado, substitui automaticamente o endereço IP que aparece no log."
 
 [pages.xray.rules]
 "first" = "Primeiro"

+ 4 - 0
web/translation/translate.ru_RU.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "Путь к файлу журнала доступа. Специальное значение «none» отключило журналы доступа."
 "errorLog" = "Журнал ошибок"
 "errorLogDesc" = "Путь к файлу журнала ошибок. Специальное значение «none» отключает журналы ошибок."
+"dnsLog" = "DNS Журнал"
+"dnsLogDesc" = "Включить логи запросов DNS"
+"maskAddress" = "Маскировать Адрес"
+"maskAddressDesc" = "Маска IP-адреса, при активации автоматически заменяет IP-адрес, который появляется в логе."
 
 [pages.xray.rules]
 "first" = "Первый"

+ 4 - 0
web/translation/translate.tr_TR.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "Erişim günlüğü için dosya yolu. 'none' özel değeri erişim günlüklerini devre dışı bırakır"
 "errorLog" = "Hata Günlüğü"
 "errorLogDesc" = "Hata günlüğü için dosya yolu. 'none' özel değeri hata günlüklerini devre dışı bırakır"
+"dnsLog" = "DNS Günlüğü"
+"dnsLogDesc" = "DNS sorgu günlüklerini etkinleştirin"
+"maskAddress" = "Adres Maskesi"
+"maskAddressDesc" = "IP adresi maskesi, etkinleştirildiğinde, günlükte görünen IP adresini otomatik olarak değiştirecektir."
 
 [pages.xray.rules]
 "first" = "İlk"

+ 4 - 0
web/translation/translate.uk_UA.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "Шлях до файлу журналу доступу. Спеціальне значення 'none' вимикає журнали доступу"
 "errorLog" = "Журнал помилок"
 "errorLogDesc" = "Шлях до файлу журналу помилок. Спеціальне значення 'none' вимикає журнали помилок"
+"dnsLog" = "Журнал DNS"
+"dnsLogDesc" = "Чи включити журнали запитів DNS"
+"maskAddress" = "Маскувати Адресу"
+"maskAddressDesc" = "Маска IP-адреси, при активації автоматично замінює IP-адресу, яка з'являється у журналі."
 
 [pages.xray.rules]
 "first" = "Перший"

+ 4 - 0
web/translation/translate.vi_VN.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "Đường dẫn tệp cho nhật ký truy cập. Nhật ký truy cập bị vô hiệu hóa có giá trị đặc biệt 'không'"
 "errorLog" = "Nhật ký lỗi"
 "errorLogDesc" = "Đường dẫn tệp cho nhật ký lỗi. Nhật ký lỗi bị vô hiệu hóa có giá trị đặc biệt 'không'"
+"dnsLog" = "Nhật ký DNS"
+"dnsLogDesc" = "Có bật nhật ký truy vấn DNS không"
+"maskAddress" = "Ẩn Địa Chỉ"
+"maskAddressDesc" = "Mặt nạ địa chỉ IP, khi được bật, sẽ tự động thay thế địa chỉ IP xuất hiện trong nhật ký."
 
 [pages.xray.rules]
 "first" = "Đầu tiên"

+ 4 - 0
web/translation/translate.zh_CN.toml

@@ -422,6 +422,10 @@
 "accessLogDesc" = "访问日志的文件路径。特殊值 'none' 禁用访问日志"
 "errorLog" = "错误日志"
 "errorLogDesc" = "错误日志的文件路径。特殊值 'none' 禁用错误日志"
+"dnsLog" = "DNS 日志"
+"dnsLogDesc" = "是否启用 DNS 查询日志"
+"maskAddress" = "隐藏地址"
+"maskAddressDesc" = "IP 地址掩码,启用时会自动替换日志中出现的 IP 地址。"
 
 [pages.xray.rules]
 "first" = "置顶"