commit
d529b51631
@ -216,19 +216,19 @@
|
||||
</a-col>
|
||||
<a-col :sm="24" :lg="12">
|
||||
<a-card title='3X-UI' hoverable>
|
||||
<a rel="noopener" href="https://github.com/MHSanaei/3x-ui/releases" target="_blank">
|
||||
<a rel="noopener" href="https://github.com/xeefei/3x-ui/releases" target="_blank">
|
||||
<a-tag color="green">
|
||||
<span>v{{ .cur_ver }}</span>
|
||||
</a-tag>
|
||||
</a>
|
||||
<a rel="noopener" href="https://t.me/XrayUI" target="_blank">
|
||||
<a rel="noopener" href="https://t.me/is_Chat_Bot" target="_blank">
|
||||
<a-tag color="green">
|
||||
<span>@XrayUI</span>
|
||||
<span>TG私聊交流</span>
|
||||
</a-tag>
|
||||
</a>
|
||||
<a rel="noopener" href="https://github.com/MHSanaei/3x-ui/wiki" target="_blank">
|
||||
<a rel="noopener" href="https://t.me/XUI_CN" target="_blank">
|
||||
<a-tag color="purple">
|
||||
<span>{{ i18n "pages.index.documentation" }}</span>
|
||||
<span>〔3X-UI〕中文交流群</span>
|
||||
</a-tag>
|
||||
</a>
|
||||
</a-card>
|
||||
@ -784,4 +784,4 @@
|
||||
},
|
||||
});
|
||||
</script>
|
||||
{{ template "page/body_end" .}}
|
||||
{{ template "page/body_end" .}}
|
||||
|
||||
167
web/html/navigation.html
Normal file
167
web/html/navigation.html
Normal file
@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>实用导航&技巧</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #151F31;
|
||||
color: white;
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
}
|
||||
.sidebar {
|
||||
width: 150px;
|
||||
background-color: #151F31;
|
||||
padding: 20px;
|
||||
}
|
||||
.sidebar h2 {
|
||||
color: #fff;
|
||||
margin-top: 0;
|
||||
}
|
||||
.sidebar button {
|
||||
background-color: #2C3E56;
|
||||
color: #008000; /* 绿色字体 */
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-radius: 15px; /* 增加圆角幅度 */
|
||||
font-weight: bold; /* 加粗字体 */
|
||||
}
|
||||
.sidebar button:hover {
|
||||
background-color: #4A90E2;
|
||||
}
|
||||
.sidebar .friend-links {
|
||||
margin-top: auto;
|
||||
text-align: center;
|
||||
margin-bottom: 12px; /* 调整友情链接下边距 */
|
||||
}
|
||||
.sidebar .friend-links a {
|
||||
color: #0080FF; /* 蓝色字体 */
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.separator {
|
||||
width: 15px;
|
||||
background-color: #34495e;
|
||||
}
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
padding-top: 0; /* 移除顶部空白 */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="sidebar">
|
||||
<button onclick="history.back()">返回上一步</button>
|
||||
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
||||
<div class="friend-links">
|
||||
<a href="https://chat.openai.com/">ChatGPT</a>
|
||||
<a href="https://github.com/xeefei/3x-ui">项目地址</a>
|
||||
<a href="https://t.me/XUI_CN">3X-UI交流群</a>
|
||||
<a href="https://www.youtube.com/results?search_query=4k%E6%B5%8B%E9%80%9F">油管4K测速</a>
|
||||
<a href="https://whatismyipaddress.com/">我的IP查询</a>
|
||||
<a href="https://translate.google.com/?hl=zh-CN">Google翻译</a>
|
||||
<a href="https://xtls.github.io/">Project X</a>
|
||||
<a href="https://t.me/Kensimon_xee">预留&占位</a>
|
||||
<a href="https://t.me/is_Chat_Bot">联系作者</a>
|
||||
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
||||
<button onclick="window.scrollTo(0, 0)">回滚至顶部</button>
|
||||
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
||||
<button onclick="history.back()">返回到面板</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="content">
|
||||
<h3>一、【3x-ui】中文交流群:<a href="https://t.me/XUI_CN">https://t.me/XUI_CN</a></h3>
|
||||
<h3> 【3x-ui】详细安装流程步骤:<a href="https://xeefei.github.io/xufei/2024/05/3x-ui/">https://xeefei.github.io/xufei/2024/05/3x-ui/</a></h3>
|
||||
|
||||
<h3>二、判断VPS服务器的IP是否【送中】?</h3>
|
||||
<p>***点击打开:<a href="https://music.youtube.com/">https://music.youtube.com/</a>,能正常打开访问,就代表【没送中】,反之就是送中了。</p>
|
||||
<p>***如果送中了如何解决去【拉回来】?</p>
|
||||
<p>1:关闭/取消登录了谷歌账户的APP定位权限/授权;2:将常用的一个谷歌账号的位置记录功能打开;3:在电脑上打开Chrome/谷歌浏览器,登录开了位置记录功能的谷歌账号,安装Location Guard拓展插件<a href="https://chrome.google.com/webstore/detail/location-guard/cfohepagpmnodfdmjliccbbigdkfcgia">https://chrome.google.com/webstore/detail/location-guard/cfohepagpmnodfdmjliccbbigdkfcgia</a>(也可在其他支持此插件的浏览器使用);4:打开Location Guard插件,选择Fixed Location,并在给出的地图上单击,即可标记上你想要IP所处的国家/地区
|
||||
Google IP定位错误,使用Location Guard修改;5:转换到Options选项,Default level默认设置为Use fixed location;6:打开谷歌地图google.com/maps,点击右下角定位授权图标,使google maps获取当前“我的GPS位置”
|
||||
Google IP定位错误,使用Location Guard修改GPS位置地址;7:谷歌搜索my ip,即可看到谷歌IP定位到了刚才地图上标记的位置;8:在此网页向谷歌报告IP问题:<a href="https://support.google.com/websearch/workflow/9308722">https://support.google.com/websearch/workflow/9308722</a></p>
|
||||
|
||||
<h3>三、在自己的VPS服务器部署【订阅转换】功能</h3>
|
||||
<p>如何把vless/vmess等协议转换成Clash/Surge等软件支持的格式?
|
||||
1、进入脚本输入x-ui命令调取面板,选择第【24】选项安装订阅转换模块,
|
||||
2、等待安装【订阅转换】成功之后,访问地址:你的IP:18080(端口号)进行转换,
|
||||
3、因为在转换过程中需要调取后端API,所以请确保端口25500是打开放行的,
|
||||
4、在得到【转换链接】之后,只要你的VPS服务器25500端口是能ping通的,就能导入Clash/Surge等软件成功下载配置,
|
||||
5、此功能集成到3x-ui面板中,是为了保证安全,通过调取24选项把【订阅转换】功能部署在自己的VPS中,不会造成链接泄露。</p>
|
||||
|
||||
<h3>四、如何保护自己的IP不被墙被封?</h3>
|
||||
<p>1、使用的代理协议要安全,加密是必备,推荐使用vless+reality+vision协议组合,
|
||||
2、因为有时节点会共享,在不同的地区,多个省份之间不要共同连接同一个IP,
|
||||
3、连接同一个IP就算了,不要同一个端口,不要同IP+同端口到处漫游,要分开,
|
||||
4、同一台VPS,不要在一天内一直大流量去下载东西使用,不要流量过高要切换,
|
||||
5、创建【入站协议】的时候,尽量用【高位端口】,比如40000--65000之间的端口号。
|
||||
提醒:为什么在特殊时期,比如:两会,春节等被封得最严重最惨?
|
||||
尼玛同一个IP+同一个端口号,多个省份去漫游,跟开飞机场一样!不封你,封谁的IP和端口?
|
||||
总结:不要多终端/多省份/多个朋友/共同使用同一个IP和端口号!使用3x-ui多创建几个【入站】,
|
||||
多做几条备用,各用各的!各行其道才比较安全!GFW的思维模式是干掉机场,机场的特征个人用户不要去沾染,自然IP就保护好了。</p>
|
||||
|
||||
<h3>五、检测IP纯净度的方法:</h3>
|
||||
<p>网址:<a href="https://scamalytics.com/">https://scamalytics.com/</a>,输入IP进行检测,看【欺诈分数】,分数越高IP越脏。</p>
|
||||
|
||||
<h3>六、常见的软件工具:</h3>
|
||||
<ol>
|
||||
<p>1、Windows系统v2rayN:<a href="https://github.com/2dust/v2rayN">https://github.com/2dust/v2rayN</a></p>
|
||||
<p>2、安卓手机版【v2rayNG】:<a href="https://github.com/2dust/v2rayNG">https://github.com/2dust/v2rayNG</a></p>
|
||||
<p>3、苹果手机IOS【小火箭】:<a href="https://apple02.com/">https://apple02.com/</a></p>
|
||||
<p>4、苹果MacOS电脑【Clash Verge】:<a href="https://github.com/clash-verge-rev/clash-verge-rev/releases">https://github.com/clash-verge-rev/clash-verge-rev/releases</a></p>
|
||||
</ol>
|
||||
|
||||
<h3>七、查看节点【指定端口】的网络连接数/命令:</h3>
|
||||
<p>netstat -ntu | grep :节点端口 | grep ESTABLISHED | awk '{print $5}'</p>
|
||||
|
||||
<h3>八、用3x-ui如何实现【自己偷自己】?</h3>
|
||||
<p>其实很简单,只要你为面板设置了证书,
|
||||
开启了HTTPS登录,就可以将3x-ui自身作为web server,
|
||||
无需Nginx等,这里给一个示例:
|
||||
其中目标网站(Dest)请填写面板监听端口,
|
||||
可选域名(SNI)填写面板登录域名,
|
||||
如果您使用其他web server(如nginx)等,
|
||||
将目标网站改为对应监听端口也可。
|
||||
需要说明的是,如果您处于白名单地区,自己“偷”自己并不适合你;其次,可选域名一项实际上可以填写任意SNI,只要客户端保持一致即可,不过并不推荐这样做。</p>
|
||||
|
||||
<h3>九、【接码】网站:</h3>
|
||||
<p>网址:<a href="https://sms-activate.org/cn">https://sms-activate.org/cn</a>,直接注册账号购买。</p>
|
||||
|
||||
<h3>十、一些MJJ经常逛的网站和群组:</h3>
|
||||
<ol>
|
||||
<p>1、NodeSeek论坛:<a href="https://www.nodeseek.com/">https://www.nodeseek.com/</a></p>
|
||||
<p>2、V2EX论坛:<a href="https://www.v2ex.com/">https://www.v2ex.com/</a></p>
|
||||
<p>3、搬瓦工TG群:<a href="https://t.me/BWHOfficial">https://t.me/BWHOfficial</a></p>
|
||||
<p>4、Xray的官方群:<a href="https://t.me/projectXray">https://t.me/projectXray</a></p>
|
||||
<p>5、Dmit交流群:<a href="https://t.me/DmitChat">https://t.me/DmitChat</a></p>
|
||||
<p>6、白丝云用户群:<a href="https://t.me/+VHZLKELTQyzPNgOV">https://t.me/+VHZLKELTQyzPNgOV</a></p>
|
||||
<p>7、NameSilo域名注册:<a href="https://www.namesilo.com/">https://www.namesilo.com/</a></p>
|
||||
</ol>
|
||||
|
||||
<h3>十一、若此项目对你有帮助,你正想购买VPS的话,可以走一下我的AFF:</h3>
|
||||
<ol>
|
||||
<p>1、搬瓦工GIA线路:<a href="https://bandwagonhost.com/aff.php?aff=75015">https://bandwagonhost.com/aff.php?aff=75015</a></p>
|
||||
<p>2、Dmit高端GIA:<a href="https://www.dmit.io/aff.php?aff=9326">https://www.dmit.io/aff.php?aff=9326</a></p>
|
||||
<p>3、白丝云【4837】:<a href="https://cloudsilk.io/aff.php?aff=706">https://cloudsilk.io/aff.php?aff=706</a></p>
|
||||
</ol>
|
||||
|
||||
<h3>十二、若需要进行GV保号,请主动发信息到:+1 215 346 6666</h3>
|
||||
|
||||
<h3>十三、项目〔声明和注意〕</h3>
|
||||
<ol>
|
||||
<p>1、声明: 此项目仅供个人学习、交流使用,请遵守当地法律法规,勿用于非法用途;请勿用于生产环境;</a></p>
|
||||
<p>2、注意: 在使用此项目和〔教程〕过程中,若因违反以上声明使用规则而产生的一切后果由使用者自负。</a></p>
|
||||
</ol>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -414,13 +413,13 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var settings map[string]any
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(data.Settings), &settings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
interfaceClients := settings["clients"].([]any)
|
||||
interfaceClients := settings["clients"].([]interface{})
|
||||
existEmail, err := s.checkEmailsExistForClients(clients)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -451,13 +450,13 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
var oldSettings map[string]any
|
||||
var oldSettings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
oldClients := oldSettings["clients"].([]any)
|
||||
oldClients := oldSettings["clients"].([]interface{})
|
||||
oldClients = append(oldClients, interfaceClients...)
|
||||
|
||||
oldSettings["clients"] = oldClients
|
||||
@ -490,7 +489,7 @@ func (s *InboundService) AddInboundClient(data *model.Inbound) (bool, error) {
|
||||
if oldInbound.Protocol == "shadowsocks" {
|
||||
cipher = oldSettings["method"].(string)
|
||||
}
|
||||
err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]any{
|
||||
err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{
|
||||
"email": client.Email,
|
||||
"id": client.ID,
|
||||
"security": client.Security,
|
||||
@ -520,7 +519,7 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool,
|
||||
logger.Error("Load Old Data Error")
|
||||
return false, err
|
||||
}
|
||||
var settings map[string]any
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(oldInbound.Settings), &settings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -535,11 +534,11 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool,
|
||||
client_key = "email"
|
||||
}
|
||||
|
||||
interfaceClients := settings["clients"].([]any)
|
||||
var newClients []any
|
||||
interfaceClients := settings["clients"].([]interface{})
|
||||
var newClients []interface{}
|
||||
needApiDel := false
|
||||
for _, client := range interfaceClients {
|
||||
c := client.(map[string]any)
|
||||
c := client.(map[string]interface{})
|
||||
c_id := c[client_key].(string)
|
||||
if c_id == clientId {
|
||||
email, _ = c["email"].(string)
|
||||
@ -589,12 +588,8 @@ func (s *InboundService) DelInboundClient(inboundId int, clientId string) (bool,
|
||||
logger.Debug("Client deleted by api:", email)
|
||||
needRestart = false
|
||||
} else {
|
||||
if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", email)) {
|
||||
logger.Debug("User is already deleted. Nothing to do more...")
|
||||
} else {
|
||||
logger.Debug("Error in deleting client by api:", err1)
|
||||
needRestart = true
|
||||
}
|
||||
logger.Debug("Unable to del client by api:", err1)
|
||||
needRestart = true
|
||||
}
|
||||
s.xrayApi.Close()
|
||||
}
|
||||
@ -608,13 +603,13 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||
return false, err
|
||||
}
|
||||
|
||||
var settings map[string]any
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(data.Settings), &settings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
interfaceClients := settings["clients"].([]any)
|
||||
interfaceClients := settings["clients"].([]interface{})
|
||||
|
||||
oldInbound, err := s.GetInbound(data.Id)
|
||||
if err != nil {
|
||||
@ -628,7 +623,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||
|
||||
oldEmail := ""
|
||||
newClientId := ""
|
||||
clientIndex := -1
|
||||
clientIndex := 0
|
||||
for index, oldClient := range oldClients {
|
||||
oldClientId := ""
|
||||
if oldInbound.Protocol == "trojan" {
|
||||
@ -649,7 +644,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||
}
|
||||
|
||||
// Validate new client ID
|
||||
if newClientId == "" || clientIndex == -1 {
|
||||
if newClientId == "" {
|
||||
return false, common.NewError("empty client ID")
|
||||
}
|
||||
|
||||
@ -663,12 +658,12 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||
}
|
||||
}
|
||||
|
||||
var oldSettings map[string]any
|
||||
var oldSettings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
settingsClients := oldSettings["clients"].([]any)
|
||||
settingsClients := oldSettings["clients"].([]interface{})
|
||||
settingsClients[clientIndex] = interfaceClients[0]
|
||||
oldSettings["clients"] = settingsClients
|
||||
|
||||
@ -718,14 +713,10 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||
if oldClients[clientIndex].Enable {
|
||||
err1 := s.xrayApi.RemoveUser(oldInbound.Tag, oldEmail)
|
||||
if err1 == nil {
|
||||
logger.Debug("Old client deleted by api:", oldEmail)
|
||||
logger.Debug("Old client deleted by api:", clients[0].Email)
|
||||
} else {
|
||||
if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", oldEmail)) {
|
||||
logger.Debug("User is already deleted. Nothing to do more...")
|
||||
} else {
|
||||
logger.Debug("Error in deleting client by api:", err1)
|
||||
needRestart = true
|
||||
}
|
||||
logger.Debug("Error in deleting client by api:", err1)
|
||||
needRestart = true
|
||||
}
|
||||
}
|
||||
if clients[0].Enable {
|
||||
@ -733,7 +724,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
|
||||
if oldInbound.Protocol == "shadowsocks" {
|
||||
cipher = oldSettings["method"].(string)
|
||||
}
|
||||
err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]any{
|
||||
err1 := s.xrayApi.AddUser(string(oldInbound.Protocol), oldInbound.Tag, map[string]interface{}{
|
||||
"email": clients[0].Email,
|
||||
"id": clients[0].ID,
|
||||
"security": clients[0].Security,
|
||||
@ -810,7 +801,7 @@ func (s *InboundService) addInboundTraffic(tx *gorm.DB, traffics []*xray.Traffic
|
||||
for _, traffic := range traffics {
|
||||
if traffic.IsInbound {
|
||||
err = tx.Model(&model.Inbound{}).Where("tag = ?", traffic.Tag).
|
||||
Updates(map[string]any{
|
||||
Updates(map[string]interface{}{
|
||||
"up": gorm.Expr("up + ?", traffic.Up),
|
||||
"down": gorm.Expr("down + ?", traffic.Down),
|
||||
}).Error
|
||||
@ -894,13 +885,13 @@ func (s *InboundService) adjustTraffics(tx *gorm.DB, dbClientTraffics []*xray.Cl
|
||||
return nil, err
|
||||
}
|
||||
for inbound_index := range inbounds {
|
||||
settings := map[string]any{}
|
||||
settings := map[string]interface{}{}
|
||||
json.Unmarshal([]byte(inbounds[inbound_index].Settings), &settings)
|
||||
clients, ok := settings["clients"].([]any)
|
||||
clients, ok := settings["clients"].([]interface{})
|
||||
if ok {
|
||||
var newClients []any
|
||||
var newClients []interface{}
|
||||
for client_index := range clients {
|
||||
c := clients[client_index].(map[string]any)
|
||||
c := clients[client_index].(map[string]interface{})
|
||||
for traffic_index := range dbClientTraffics {
|
||||
if dbClientTraffics[traffic_index].ExpiryTime < 0 && c["email"] == dbClientTraffics[traffic_index].Email {
|
||||
oldExpiryTime := c["expiryTime"].(float64)
|
||||
@ -910,7 +901,7 @@ func (s *InboundService) adjustTraffics(tx *gorm.DB, dbClientTraffics []*xray.Cl
|
||||
break
|
||||
}
|
||||
}
|
||||
newClients = append(newClients, any(c))
|
||||
newClients = append(newClients, interface{}(c))
|
||||
}
|
||||
settings["clients"] = newClients
|
||||
modifiedSettings, err := json.MarshalIndent(settings, "", " ")
|
||||
@ -952,7 +943,7 @@ func (s *InboundService) autoRenewClients(tx *gorm.DB) (bool, int64, error) {
|
||||
var clientsToAdd []struct {
|
||||
protocol string
|
||||
tag string
|
||||
client map[string]any
|
||||
client map[string]interface{}
|
||||
}
|
||||
|
||||
for _, traffic := range traffics {
|
||||
@ -963,11 +954,11 @@ func (s *InboundService) autoRenewClients(tx *gorm.DB) (bool, int64, error) {
|
||||
return false, 0, err
|
||||
}
|
||||
for inbound_index := range inbounds {
|
||||
settings := map[string]any{}
|
||||
settings := map[string]interface{}{}
|
||||
json.Unmarshal([]byte(inbounds[inbound_index].Settings), &settings)
|
||||
clients := settings["clients"].([]any)
|
||||
clients := settings["clients"].([]interface{})
|
||||
for client_index := range clients {
|
||||
c := clients[client_index].(map[string]any)
|
||||
c := clients[client_index].(map[string]interface{})
|
||||
for traffic_index, traffic := range traffics {
|
||||
if traffic.Email == c["email"].(string) {
|
||||
newExpiryTime := traffic.ExpiryTime
|
||||
@ -984,14 +975,14 @@ func (s *InboundService) autoRenewClients(tx *gorm.DB) (bool, int64, error) {
|
||||
struct {
|
||||
protocol string
|
||||
tag string
|
||||
client map[string]any
|
||||
client map[string]interface{}
|
||||
}{
|
||||
protocol: string(inbounds[inbound_index].Protocol),
|
||||
tag: inbounds[inbound_index].Tag,
|
||||
client: c,
|
||||
})
|
||||
}
|
||||
clients[client_index] = any(c)
|
||||
clients[client_index] = interface{}(c)
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -1046,8 +1037,12 @@ func (s *InboundService) disableInvalidInbounds(tx *gorm.DB) (bool, int64, error
|
||||
if err1 == nil {
|
||||
logger.Debug("Inbound disabled by api:", tag)
|
||||
} else {
|
||||
logger.Debug("Error in disabling inbound by api:", err1)
|
||||
needRestart = true
|
||||
if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", tag)) {
|
||||
logger.Debug("User is already disabled. Nothing to do more...")
|
||||
} else {
|
||||
logger.Debug("Error in disabling client by api:", err1)
|
||||
needRestart = true
|
||||
}
|
||||
}
|
||||
}
|
||||
s.xrayApi.Close()
|
||||
@ -1148,7 +1143,7 @@ func (s *InboundService) AddClientStat(tx *gorm.DB, inboundId int, client *model
|
||||
func (s *InboundService) UpdateClientStat(tx *gorm.DB, email string, client *model.Client) error {
|
||||
result := tx.Model(xray.ClientTraffic{}).
|
||||
Where("email = ?", email).
|
||||
Updates(map[string]any{
|
||||
Updates(map[string]interface{}{
|
||||
"enable": true,
|
||||
"email": client.Email,
|
||||
"total": client.TotalGB,
|
||||
@ -1259,18 +1254,18 @@ func (s *InboundService) SetClientTelegramUserID(trafficId int, tgId int64) (boo
|
||||
return false, common.NewError("Client Not Found For Email:", clientEmail)
|
||||
}
|
||||
|
||||
var settings map[string]any
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(inbound.Settings), &settings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
clients := settings["clients"].([]any)
|
||||
var newClients []any
|
||||
clients := settings["clients"].([]interface{})
|
||||
var newClients []interface{}
|
||||
for client_index := range clients {
|
||||
c := clients[client_index].(map[string]any)
|
||||
c := clients[client_index].(map[string]interface{})
|
||||
if c["email"] == clientEmail {
|
||||
c["tgId"] = tgId
|
||||
newClients = append(newClients, any(c))
|
||||
newClients = append(newClients, interface{}(c))
|
||||
}
|
||||
}
|
||||
settings["clients"] = newClients
|
||||
@ -1344,18 +1339,18 @@ func (s *InboundService) ToggleClientEnableByEmail(clientEmail string) (bool, bo
|
||||
return false, false, common.NewError("Client Not Found For Email:", clientEmail)
|
||||
}
|
||||
|
||||
var settings map[string]any
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(inbound.Settings), &settings)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
clients := settings["clients"].([]any)
|
||||
var newClients []any
|
||||
clients := settings["clients"].([]interface{})
|
||||
var newClients []interface{}
|
||||
for client_index := range clients {
|
||||
c := clients[client_index].(map[string]any)
|
||||
c := clients[client_index].(map[string]interface{})
|
||||
if c["email"] == clientEmail {
|
||||
c["enable"] = !clientOldEnabled
|
||||
newClients = append(newClients, any(c))
|
||||
newClients = append(newClients, interface{}(c))
|
||||
}
|
||||
}
|
||||
settings["clients"] = newClients
|
||||
@ -1406,18 +1401,18 @@ func (s *InboundService) ResetClientIpLimitByEmail(clientEmail string, count int
|
||||
return false, common.NewError("Client Not Found For Email:", clientEmail)
|
||||
}
|
||||
|
||||
var settings map[string]any
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(inbound.Settings), &settings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
clients := settings["clients"].([]any)
|
||||
var newClients []any
|
||||
clients := settings["clients"].([]interface{})
|
||||
var newClients []interface{}
|
||||
for client_index := range clients {
|
||||
c := clients[client_index].(map[string]any)
|
||||
c := clients[client_index].(map[string]interface{})
|
||||
if c["email"] == clientEmail {
|
||||
c["limitIp"] = count
|
||||
newClients = append(newClients, any(c))
|
||||
newClients = append(newClients, interface{}(c))
|
||||
}
|
||||
}
|
||||
settings["clients"] = newClients
|
||||
@ -1463,18 +1458,18 @@ func (s *InboundService) ResetClientExpiryTimeByEmail(clientEmail string, expiry
|
||||
return false, common.NewError("Client Not Found For Email:", clientEmail)
|
||||
}
|
||||
|
||||
var settings map[string]any
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(inbound.Settings), &settings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
clients := settings["clients"].([]any)
|
||||
var newClients []any
|
||||
clients := settings["clients"].([]interface{})
|
||||
var newClients []interface{}
|
||||
for client_index := range clients {
|
||||
c := clients[client_index].(map[string]any)
|
||||
c := clients[client_index].(map[string]interface{})
|
||||
if c["email"] == clientEmail {
|
||||
c["expiryTime"] = expiry_time
|
||||
newClients = append(newClients, any(c))
|
||||
newClients = append(newClients, interface{}(c))
|
||||
}
|
||||
}
|
||||
settings["clients"] = newClients
|
||||
@ -1523,18 +1518,18 @@ func (s *InboundService) ResetClientTrafficLimitByEmail(clientEmail string, tota
|
||||
return false, common.NewError("Client Not Found For Email:", clientEmail)
|
||||
}
|
||||
|
||||
var settings map[string]any
|
||||
var settings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(inbound.Settings), &settings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
clients := settings["clients"].([]any)
|
||||
var newClients []any
|
||||
clients := settings["clients"].([]interface{})
|
||||
var newClients []interface{}
|
||||
for client_index := range clients {
|
||||
c := clients[client_index].(map[string]any)
|
||||
c := clients[client_index].(map[string]interface{})
|
||||
if c["email"] == clientEmail {
|
||||
c["totalGB"] = totalGB * 1024 * 1024 * 1024
|
||||
newClients = append(newClients, any(c))
|
||||
newClients = append(newClients, interface{}(c))
|
||||
}
|
||||
}
|
||||
settings["clients"] = newClients
|
||||
@ -1552,7 +1547,7 @@ func (s *InboundService) ResetClientTrafficByEmail(clientEmail string) error {
|
||||
|
||||
result := db.Model(xray.ClientTraffic{}).
|
||||
Where("email = ?", clientEmail).
|
||||
Updates(map[string]any{"enable": true, "up": 0, "down": 0})
|
||||
Updates(map[string]interface{}{"enable": true, "up": 0, "down": 0})
|
||||
|
||||
err := result.Error
|
||||
if err != nil {
|
||||
@ -1583,14 +1578,14 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) (bool, e
|
||||
s.xrayApi.Init(p.GetAPIPort())
|
||||
cipher := ""
|
||||
if string(inbound.Protocol) == "shadowsocks" {
|
||||
var oldSettings map[string]any
|
||||
var oldSettings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(inbound.Settings), &oldSettings)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
cipher = oldSettings["method"].(string)
|
||||
}
|
||||
err1 := s.xrayApi.AddUser(string(inbound.Protocol), inbound.Tag, map[string]any{
|
||||
err1 := s.xrayApi.AddUser(string(inbound.Protocol), inbound.Tag, map[string]interface{}{
|
||||
"email": client.Email,
|
||||
"id": client.ID,
|
||||
"security": client.Security,
|
||||
@ -1635,7 +1630,7 @@ func (s *InboundService) ResetAllClientTraffics(id int) error {
|
||||
|
||||
result := db.Model(xray.ClientTraffic{}).
|
||||
Where(whereText, id).
|
||||
Updates(map[string]any{"enable": true, "up": 0, "down": 0})
|
||||
Updates(map[string]interface{}{"enable": true, "up": 0, "down": 0})
|
||||
|
||||
err := result.Error
|
||||
return err
|
||||
@ -1646,7 +1641,7 @@ func (s *InboundService) ResetAllTraffics() error {
|
||||
|
||||
result := db.Model(model.Inbound{}).
|
||||
Where("user_id > ?", 0).
|
||||
Updates(map[string]any{"up": 0, "down": 0})
|
||||
Updates(map[string]interface{}{"up": 0, "down": 0})
|
||||
|
||||
err := result.Error
|
||||
return err
|
||||
@ -1682,17 +1677,17 @@ func (s *InboundService) DelDepletedClients(id int) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var oldSettings map[string]any
|
||||
var oldSettings map[string]interface{}
|
||||
err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldClients := oldSettings["clients"].([]any)
|
||||
var newClients []any
|
||||
oldClients := oldSettings["clients"].([]interface{})
|
||||
var newClients []interface{}
|
||||
for _, client := range oldClients {
|
||||
deplete := false
|
||||
c := client.(map[string]any)
|
||||
c := client.(map[string]interface{})
|
||||
for _, email := range emails {
|
||||
if email == c["email"].(string) {
|
||||
deplete = true
|
||||
@ -1908,14 +1903,14 @@ func (s *InboundService) MigrationRequirements() {
|
||||
return
|
||||
}
|
||||
for inbound_index := range inbounds {
|
||||
settings := map[string]any{}
|
||||
settings := map[string]interface{}{}
|
||||
json.Unmarshal([]byte(inbounds[inbound_index].Settings), &settings)
|
||||
clients, ok := settings["clients"].([]any)
|
||||
clients, ok := settings["clients"].([]interface{})
|
||||
if ok {
|
||||
// Fix Client configuration problems
|
||||
var newClients []any
|
||||
var newClients []interface{}
|
||||
for client_index := range clients {
|
||||
c := clients[client_index].(map[string]any)
|
||||
c := clients[client_index].(map[string]interface{})
|
||||
|
||||
// Add email='' if it is not exists
|
||||
if _, ok := c["email"]; !ok {
|
||||
@ -1924,7 +1919,7 @@ func (s *InboundService) MigrationRequirements() {
|
||||
|
||||
// Convert string tgId to int64
|
||||
if _, ok := c["tgId"]; ok {
|
||||
var tgId any = c["tgId"]
|
||||
var tgId interface{} = c["tgId"]
|
||||
if tgIdStr, ok2 := tgId.(string); ok2 {
|
||||
tgIdInt64, err := strconv.ParseInt(strings.ReplaceAll(tgIdStr, " ", ""), 10, 64)
|
||||
if err == nil {
|
||||
@ -1939,7 +1934,7 @@ func (s *InboundService) MigrationRequirements() {
|
||||
c["flow"] = ""
|
||||
}
|
||||
}
|
||||
newClients = append(newClients, any(c))
|
||||
newClients = append(newClients, interface{}(c))
|
||||
}
|
||||
settings["clients"] = newClients
|
||||
modifiedSettings, err := json.MarshalIndent(settings, "", " ")
|
||||
@ -1986,14 +1981,14 @@ func (s *InboundService) MigrationRequirements() {
|
||||
}
|
||||
|
||||
for _, ep := range externalProxy {
|
||||
var reverses any
|
||||
var stream map[string]any
|
||||
var reverses interface{}
|
||||
var stream map[string]interface{}
|
||||
json.Unmarshal(ep.StreamSettings, &stream)
|
||||
if tlsSettings, ok := stream["tlsSettings"].(map[string]any); ok {
|
||||
if settings, ok := tlsSettings["settings"].(map[string]any); ok {
|
||||
if domains, ok := settings["domains"].([]any); ok {
|
||||
if tlsSettings, ok := stream["tlsSettings"].(map[string]interface{}); ok {
|
||||
if settings, ok := tlsSettings["settings"].(map[string]interface{}); ok {
|
||||
if domains, ok := settings["domains"].([]interface{}); ok {
|
||||
for _, domain := range domains {
|
||||
if domainMap, ok := domain.(map[string]any); ok {
|
||||
if domainMap, ok := domain.(map[string]interface{}); ok {
|
||||
domainMap["forceTls"] = "same"
|
||||
domainMap["port"] = ep.Port
|
||||
domainMap["dest"] = domainMap["domain"].(string)
|
||||
@ -2026,37 +2021,3 @@ func (s *InboundService) MigrateDB() {
|
||||
func (s *InboundService) GetOnlineClients() []string {
|
||||
return p.GetOnlineClients()
|
||||
}
|
||||
|
||||
func (s *InboundService) FilterAndSortClientEmails(emails []string) ([]string, []string, error) {
|
||||
db := database.GetDB()
|
||||
|
||||
// Step 1: Get ClientTraffic records for emails in the input list
|
||||
var clients []xray.ClientTraffic
|
||||
err := db.Where("email IN ?", emails).Find(&clients).Error
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Step 2: Sort clients by (Up + Down) descending
|
||||
sort.Slice(clients, func(i, j int) bool {
|
||||
return (clients[i].Up + clients[i].Down) > (clients[j].Up + clients[j].Down)
|
||||
})
|
||||
|
||||
// Step 3: Extract sorted valid emails and track found ones
|
||||
validEmails := make([]string, 0, len(clients))
|
||||
found := make(map[string]bool)
|
||||
for _, client := range clients {
|
||||
validEmails = append(validEmails, client.Email)
|
||||
found[client.Email] = true
|
||||
}
|
||||
|
||||
// Step 4: Identify emails that were not found in the database
|
||||
extraEmails := make([]string, 0)
|
||||
for _, email := range emails {
|
||||
if !found[email] {
|
||||
extraEmails = append(extraEmails, email)
|
||||
}
|
||||
}
|
||||
|
||||
return validEmails, extraEmails, nil
|
||||
}
|
||||
|
||||
@ -24,60 +24,56 @@ import (
|
||||
var xrayTemplateConfig string
|
||||
|
||||
var defaultValueMap = map[string]string{
|
||||
"xrayTemplateConfig": xrayTemplateConfig,
|
||||
"webListen": "",
|
||||
"webDomain": "",
|
||||
"webPort": "2053",
|
||||
"webCertFile": "",
|
||||
"webKeyFile": "",
|
||||
"secret": random.Seq(32),
|
||||
"webBasePath": "/",
|
||||
"sessionMaxAge": "60",
|
||||
"pageSize": "50",
|
||||
"expireDiff": "0",
|
||||
"trafficDiff": "0",
|
||||
"remarkModel": "-ieo",
|
||||
"timeLocation": "Local",
|
||||
"tgBotEnable": "false",
|
||||
"tgBotToken": "",
|
||||
"tgBotProxy": "",
|
||||
"tgBotAPIServer": "",
|
||||
"tgBotChatId": "",
|
||||
"tgRunTime": "@daily",
|
||||
"tgBotBackup": "false",
|
||||
"tgBotLoginNotify": "true",
|
||||
"tgCpu": "80",
|
||||
"tgLang": "en-US",
|
||||
"twoFactorEnable": "false",
|
||||
"twoFactorToken": "",
|
||||
"subEnable": "false",
|
||||
"subTitle": "",
|
||||
"subListen": "",
|
||||
"subPort": "2096",
|
||||
"subPath": "/sub/",
|
||||
"subDomain": "",
|
||||
"subCertFile": "",
|
||||
"subKeyFile": "",
|
||||
"subUpdates": "12",
|
||||
"subEncrypt": "true",
|
||||
"subShowInfo": "true",
|
||||
"subURI": "",
|
||||
"subJsonPath": "/json/",
|
||||
"subJsonURI": "",
|
||||
"subJsonFragment": "",
|
||||
"subJsonNoises": "",
|
||||
"subJsonMux": "",
|
||||
"subJsonRules": "",
|
||||
"datepicker": "gregorian",
|
||||
"warp": "",
|
||||
"externalTrafficInformEnable": "false",
|
||||
"externalTrafficInformURI": "",
|
||||
"xrayTemplateConfig": xrayTemplateConfig,
|
||||
"webListen": "",
|
||||
"webDomain": "",
|
||||
"webPort": "2053",
|
||||
"webCertFile": "",
|
||||
"webKeyFile": "",
|
||||
"secret": random.Seq(32),
|
||||
"webBasePath": "/",
|
||||
"sessionMaxAge": "60",
|
||||
"pageSize": "50",
|
||||
"expireDiff": "0",
|
||||
"trafficDiff": "0",
|
||||
"remarkModel": "-ieo",
|
||||
"timeLocation": "Asia/Shanghai",
|
||||
"tgBotEnable": "false",
|
||||
"tgBotToken": "",
|
||||
"tgBotProxy": "",
|
||||
"tgBotAPIServer": "",
|
||||
"tgBotChatId": "",
|
||||
"tgRunTime": "@daily",
|
||||
"tgBotBackup": "false",
|
||||
"tgBotLoginNotify": "true",
|
||||
"tgCpu": "30",
|
||||
"tgLang": "zh-Hans",
|
||||
"secretEnable": "false",
|
||||
"subEnable": "false",
|
||||
"subListen": "",
|
||||
"subPort": "2096",
|
||||
"subPath": "/sub/",
|
||||
"subDomain": "",
|
||||
"subCertFile": "",
|
||||
"subKeyFile": "",
|
||||
"subUpdates": "12",
|
||||
"subEncrypt": "true",
|
||||
"subShowInfo": "true",
|
||||
"subURI": "",
|
||||
"subJsonPath": "/json/",
|
||||
"subJsonURI": "",
|
||||
"subJsonFragment": "",
|
||||
"subJsonNoises": "",
|
||||
"subJsonMux": "",
|
||||
"subJsonRules": "",
|
||||
"datepicker": "gregorian",
|
||||
"warp": "",
|
||||
}
|
||||
|
||||
type SettingService struct{}
|
||||
|
||||
func (s *SettingService) GetDefaultJsonConfig() (any, error) {
|
||||
var jsonData any
|
||||
func (s *SettingService) GetDefaultJsonConfig() (interface{}, error) {
|
||||
var jsonData interface{}
|
||||
err := json.Unmarshal([]byte(xrayTemplateConfig), &jsonData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -167,7 +163,8 @@ func (s *SettingService) ResetSettings() error {
|
||||
return err
|
||||
}
|
||||
return db.Model(model.User{}).
|
||||
Where("1 = 1").Error
|
||||
Where("1 = 1").
|
||||
Update("login_secret", "").Error
|
||||
}
|
||||
|
||||
func (s *SettingService) getSetting(key string) (*model.Setting, error) {
|
||||
@ -318,22 +315,6 @@ func (s *SettingService) GetTgLang() (string, error) {
|
||||
return s.getString("tgLang")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTwoFactorEnable() (bool, error) {
|
||||
return s.getBool("twoFactorEnable")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetTwoFactorEnable(value bool) error {
|
||||
return s.setBool("twoFactorEnable", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetTwoFactorToken() (string, error) {
|
||||
return s.getString("twoFactorToken")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetTwoFactorToken(value string) error {
|
||||
return s.setString("twoFactorToken", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetPort() (int, error) {
|
||||
return s.getInt("webPort")
|
||||
}
|
||||
@ -374,6 +355,14 @@ func (s *SettingService) GetRemarkModel() (string, error) {
|
||||
return s.getString("remarkModel")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSecretStatus() (bool, error) {
|
||||
return s.getBool("secretEnable")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetSecretStatus(value bool) error {
|
||||
return s.setBool("secretEnable", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSecret() ([]byte, error) {
|
||||
secret, err := s.getString("secret")
|
||||
if secret == defaultValueMap["secret"] {
|
||||
@ -427,10 +416,6 @@ func (s *SettingService) GetSubEnable() (bool, error) {
|
||||
return s.getBool("subEnable")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSubTitle() (string, error) {
|
||||
return s.getString("subTitle")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetSubListen() (string, error) {
|
||||
return s.getString("subListen")
|
||||
}
|
||||
@ -511,22 +496,6 @@ func (s *SettingService) SetWarp(data string) error {
|
||||
return s.setString("warp", data)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetExternalTrafficInformEnable() (bool, error) {
|
||||
return s.getBool("externalTrafficInformEnable")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetExternalTrafficInformEnable(value bool) error {
|
||||
return s.setBool("externalTrafficInformEnable", value)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetExternalTrafficInformURI() (string, error) {
|
||||
return s.getString("externalTrafficInformURI")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetExternalTrafficInformURI(InformURI string) error {
|
||||
return s.setString("externalTrafficInformURI", InformURI)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetIpLimitEnable() (bool, error) {
|
||||
accessLogPath, err := xray.GetAccessLogPath()
|
||||
if err != nil {
|
||||
@ -556,8 +525,8 @@ func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {
|
||||
return common.Combine(errs...)
|
||||
}
|
||||
|
||||
func (s *SettingService) GetDefaultXrayConfig() (any, error) {
|
||||
var jsonData any
|
||||
func (s *SettingService) GetDefaultXrayConfig() (interface{}, error) {
|
||||
var jsonData interface{}
|
||||
err := json.Unmarshal([]byte(xrayTemplateConfig), &jsonData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -565,25 +534,24 @@ func (s *SettingService) GetDefaultXrayConfig() (any, error) {
|
||||
return jsonData, nil
|
||||
}
|
||||
|
||||
func (s *SettingService) GetDefaultSettings(host string) (any, error) {
|
||||
type settingFunc func() (any, error)
|
||||
func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) {
|
||||
type settingFunc func() (interface{}, error)
|
||||
settings := map[string]settingFunc{
|
||||
"expireDiff": func() (any, error) { return s.GetExpireDiff() },
|
||||
"trafficDiff": func() (any, error) { return s.GetTrafficDiff() },
|
||||
"pageSize": func() (any, error) { return s.GetPageSize() },
|
||||
"defaultCert": func() (any, error) { return s.GetCertFile() },
|
||||
"defaultKey": func() (any, error) { return s.GetKeyFile() },
|
||||
"tgBotEnable": func() (any, error) { return s.GetTgbotEnabled() },
|
||||
"subEnable": func() (any, error) { return s.GetSubEnable() },
|
||||
"subTitle": func() (any, error) { return s.GetSubTitle() },
|
||||
"subURI": func() (any, error) { return s.GetSubURI() },
|
||||
"subJsonURI": func() (any, error) { return s.GetSubJsonURI() },
|
||||
"remarkModel": func() (any, error) { return s.GetRemarkModel() },
|
||||
"datepicker": func() (any, error) { return s.GetDatepicker() },
|
||||
"ipLimitEnable": func() (any, error) { return s.GetIpLimitEnable() },
|
||||
"expireDiff": func() (interface{}, error) { return s.GetExpireDiff() },
|
||||
"trafficDiff": func() (interface{}, error) { return s.GetTrafficDiff() },
|
||||
"pageSize": func() (interface{}, error) { return s.GetPageSize() },
|
||||
"defaultCert": func() (interface{}, error) { return s.GetCertFile() },
|
||||
"defaultKey": func() (interface{}, error) { return s.GetKeyFile() },
|
||||
"tgBotEnable": func() (interface{}, error) { return s.GetTgbotEnabled() },
|
||||
"subEnable": func() (interface{}, error) { return s.GetSubEnable() },
|
||||
"subURI": func() (interface{}, error) { return s.GetSubURI() },
|
||||
"subJsonURI": func() (interface{}, error) { return s.GetSubJsonURI() },
|
||||
"remarkModel": func() (interface{}, error) { return s.GetRemarkModel() },
|
||||
"datepicker": func() (interface{}, error) { return s.GetDatepicker() },
|
||||
"ipLimitEnable": func() (interface{}, error) { return s.GetIpLimitEnable() },
|
||||
}
|
||||
|
||||
result := make(map[string]any)
|
||||
result := make(map[string]interface{})
|
||||
|
||||
for key, fn := range settings {
|
||||
value, err := fn()
|
||||
@ -595,7 +563,6 @@ func (s *SettingService) GetDefaultSettings(host string) (any, error) {
|
||||
|
||||
if result["subEnable"].(bool) && (result["subURI"].(string) == "" || result["subJsonURI"].(string) == "") {
|
||||
subURI := ""
|
||||
subTitle, _ := s.GetSubTitle()
|
||||
subPort, _ := s.GetSubPort()
|
||||
subPath, _ := s.GetSubPath()
|
||||
subJsonPath, _ := s.GetSubJsonPath()
|
||||
@ -622,9 +589,6 @@ func (s *SettingService) GetDefaultSettings(host string) (any, error) {
|
||||
if result["subURI"].(string) == "" {
|
||||
result["subURI"] = subURI + subPath
|
||||
}
|
||||
if result["subTitle"].(string) == "" {
|
||||
result["subTitle"] = subTitle
|
||||
}
|
||||
if result["subJsonURI"].(string) == "" {
|
||||
result["subJsonURI"] = subURI + subJsonPath
|
||||
}
|
||||
|
||||
1147
web/service/tgbot.go
1147
web/service/tgbot.go
File diff suppressed because it is too large
Load Diff
@ -4,8 +4,6 @@
|
||||
"confirm" = "确定"
|
||||
"cancel" = "取消"
|
||||
"close" = "关闭"
|
||||
"create" = "创建"
|
||||
"update" = "更新"
|
||||
"copy" = "复制"
|
||||
"copied" = "已复制"
|
||||
"download" = "下载"
|
||||
@ -28,11 +26,9 @@
|
||||
"edit" = "编辑"
|
||||
"delete" = "删除"
|
||||
"reset" = "重置"
|
||||
"noData" = "无数据。"
|
||||
"copySuccess" = "复制成功"
|
||||
"sure" = "确定"
|
||||
"encryption" = "加密"
|
||||
"useIPv4ForHost" = "使用 IPv4 连接主机"
|
||||
"transmission" = "传输"
|
||||
"host" = "主机"
|
||||
"path" = "路径"
|
||||
@ -48,13 +44,12 @@
|
||||
"monitor" = "监听"
|
||||
"certificate" = "数字证书"
|
||||
"fail" = "失败"
|
||||
"comment" = "评论"
|
||||
"success" = "成功"
|
||||
"getVersion" = "获取版本"
|
||||
"install" = "安装"
|
||||
"clients" = "客户端"
|
||||
"usage" = "使用情况"
|
||||
"twoFactorCode" = "代码"
|
||||
"secretToken" = "安全密钥"
|
||||
"remained" = "剩余"
|
||||
"security" = "安全"
|
||||
"secAlertTitle" = "安全警报"
|
||||
@ -65,22 +60,15 @@
|
||||
"secAlertPanelURI" = "面板默认 URI 路径不安全。请配置复杂的 URI 路径。"
|
||||
"secAlertSubURI" = "订阅默认 URI 路径不安全。请配置复杂的 URI 路径。"
|
||||
"secAlertSubJsonURI" = "订阅 JSON 默认 URI 路径不安全。请配置复杂的 URI 路径。"
|
||||
"emptyDnsDesc" = "未添加DNS服务器。"
|
||||
"emptyFakeDnsDesc" = "未添加Fake DNS服务器。"
|
||||
"emptyBalancersDesc" = "未添加负载均衡器。"
|
||||
"emptyReverseDesc" = "未添加反向代理。"
|
||||
"somethingWentWrong" = "出了点问题"
|
||||
|
||||
[menu]
|
||||
"theme" = "主题"
|
||||
"dark" = "暗色"
|
||||
"ultraDark" = "超暗色"
|
||||
"dashboard" = "系统状态"
|
||||
"inbounds" = "入站列表"
|
||||
"settings" = "面板设置"
|
||||
"xray" = "Xray 设置"
|
||||
"xray" = "Xray设置"
|
||||
"logout" = "退出登录"
|
||||
"link" = "管理"
|
||||
"navigation" = "实用导航"
|
||||
|
||||
[pages.login]
|
||||
"hello" = "你好"
|
||||
@ -91,64 +79,39 @@
|
||||
"invalidFormData" = "数据格式错误"
|
||||
"emptyUsername" = "请输入用户名"
|
||||
"emptyPassword" = "请输入密码"
|
||||
"wrongUsernameOrPassword" = "用户名、密码或双重验证码无效。"
|
||||
"successLogin" = "您已成功登录您的账户。"
|
||||
"wrongUsernameOrPassword" = "用户名或密码错误"
|
||||
"successLogin" = "登录"
|
||||
|
||||
[pages.index]
|
||||
"title" = "系统状态"
|
||||
"cpu" = "CPU"
|
||||
"logicalProcessors" = "逻辑处理器"
|
||||
"frequency" = "频率"
|
||||
"swap" = "交换分区"
|
||||
"storage" = "存储"
|
||||
"memory" = "内存"
|
||||
"threads" = "线程"
|
||||
"hard" = "磁盘"
|
||||
"xrayStatus" = "Xray"
|
||||
"stopXray" = "停止"
|
||||
"restartXray" = "重启"
|
||||
"xraySwitch" = "版本"
|
||||
"xraySwitchClick" = "选择你要切换到的版本"
|
||||
"xraySwitchClickDesk" = "请谨慎选择,因为较旧版本可能与当前配置不兼容"
|
||||
"xrayStatusUnknown" = "未知"
|
||||
"xrayStatusRunning" = "运行中"
|
||||
"xrayStatusStop" = "停止"
|
||||
"xrayStatusError" = "错误"
|
||||
"xrayErrorPopoverTitle" = "运行Xray时发生错误"
|
||||
"operationHours" = "系统正常运行时间"
|
||||
"systemLoad" = "系统负载"
|
||||
"systemLoadDesc" = "过去 1、5 和 15 分钟的系统平均负载"
|
||||
"connectionTcpCountDesc" = "系统中所有 TCP 连接数"
|
||||
"connectionUdpCountDesc" = "系统中所有 UDP 连接数"
|
||||
"connectionCount" = "连接数"
|
||||
"ipAddresses" = "IP地址"
|
||||
"toggleIpVisibility" = "切换IP可见性"
|
||||
"overallSpeed" = "整体速度"
|
||||
"upload" = "上传"
|
||||
"download" = "下载"
|
||||
"totalData" = "总数据"
|
||||
"sent" = "已发送"
|
||||
"received" = "已接收"
|
||||
"documentation" = "文档"
|
||||
"xraySwitchVersionDialog" = "您确定要更改Xray版本吗?"
|
||||
"xraySwitchVersionDialogDesc" = "这将把Xray版本更改为#version#。"
|
||||
"xraySwitchVersionPopover" = "Xray 更新成功"
|
||||
"geofileUpdateDialog" = "您确定要更新地理文件吗?"
|
||||
"geofileUpdateDialogDesc" = "这将更新 #filename# 文件。"
|
||||
"geofileUpdatePopover" = "地理文件更新成功"
|
||||
"upSpeed" = "总上传速度"
|
||||
"downSpeed" = "总下载速度"
|
||||
"totalSent" = "系统启动以来发送的总数据量"
|
||||
"totalReceive" = "系统启动以来接收的总数据量"
|
||||
"xraySwitchVersionDialog" = "切换 Xray 版本"
|
||||
"xraySwitchVersionDialogDesc" = "是否切换 Xray 版本至"
|
||||
"dontRefresh" = "安装中,请勿刷新此页面"
|
||||
"logs" = "日志"
|
||||
"config" = "配置"
|
||||
"backup" = "备份"
|
||||
"backup" = "备份和恢复"
|
||||
"backupTitle" = "备份和恢复数据库"
|
||||
"backupDescription" = "恢复数据库之前建议进行备份"
|
||||
"exportDatabase" = "备份"
|
||||
"exportDatabaseDesc" = "点击下载包含当前数据库备份的 .db 文件到您的设备。"
|
||||
"importDatabase" = "恢复"
|
||||
"importDatabaseDesc" = "点击选择并上传设备中的 .db 文件以从备份恢复数据库。"
|
||||
"importDatabaseSuccess" = "数据库导入成功"
|
||||
"importDatabaseError" = "导入数据库时出错"
|
||||
"readDatabaseError" = "读取数据库时出错"
|
||||
"getDatabaseError" = "检索数据库时出错"
|
||||
"getConfigError" = "检索配置文件时出错"
|
||||
|
||||
[pages.inbounds]
|
||||
"title" = "入站列表"
|
||||
@ -167,16 +130,14 @@
|
||||
"resetTraffic" = "重置流量"
|
||||
"addInbound" = "添加入站"
|
||||
"generalActions" = "通用操作"
|
||||
"autoRefresh" = "自动刷新"
|
||||
"autoRefreshInterval" = "间隔"
|
||||
"create" = "添加"
|
||||
"update" = "修改"
|
||||
"modifyInbound" = "修改入站"
|
||||
"deleteInbound" = "删除入站"
|
||||
"deleteInboundContent" = "确定要删除入站吗?"
|
||||
"deleteClient" = "删除客户端"
|
||||
"deleteClientContent" = "确定要删除客户端吗?"
|
||||
"resetTrafficContent" = "确定要重置流量吗?"
|
||||
"inboundUpdateSuccess" = "入站连接已成功更新。"
|
||||
"inboundCreateSuccess" = "入站连接已成功创建。"
|
||||
"copyLink" = "复制链接"
|
||||
"address" = "地址"
|
||||
"network" = "网络"
|
||||
@ -211,14 +172,16 @@
|
||||
"delDepletedClientsTitle" = "删除流量耗尽的客户端"
|
||||
"delDepletedClientsContent" = "确定要删除所有流量耗尽的客户端吗?"
|
||||
"email" = "电子邮件"
|
||||
"emailDesc" = "电子邮件必须完全唯一"
|
||||
"emailDesc" = "电子邮件必须确保唯一"
|
||||
"IPLimit" = "IP 限制"
|
||||
"IPLimitDesc" = "如果数量超过设置值,则禁用入站流量。(0 = 禁用)"
|
||||
"IPLimitlog" = "IP 日志"
|
||||
"IPLimitlogDesc" = "IP 历史日志(要启用被禁用的入站流量,请清除日志)"
|
||||
"IPLimitlogclear" = "清除日志"
|
||||
"setDefaultCert" = "从面板设置证书"
|
||||
"telegramDesc" = "请提供Telegram聊天ID。(在机器人中使用'/id'命令)或(@userinfobot"
|
||||
"xtlsDesc" = "Xray 核心需要 1.7.5"
|
||||
"realityDesc" = "Xray 核心需要 1.8.0 及以上版本"
|
||||
"telegramDesc" = "请提供Telegram聊天ID。(在机器人中使用'/id'命令或跟@userinfobot机器人对话获取)"
|
||||
"subscriptionDesc" = "要找到你的订阅 URL,请导航到“详细信息”。此外,你可以为多个客户端使用相同的名称。"
|
||||
"info" = "信息"
|
||||
"same" = "相同"
|
||||
@ -247,21 +210,6 @@
|
||||
|
||||
[pages.inbounds.toasts]
|
||||
"obtain" = "获取"
|
||||
"updateSuccess" = "更新成功"
|
||||
"logCleanSuccess" = "日志已清除"
|
||||
"inboundsUpdateSuccess" = "入站连接已成功更新"
|
||||
"inboundUpdateSuccess" = "入站连接已成功更新"
|
||||
"inboundCreateSuccess" = "入站连接已成功创建"
|
||||
"inboundDeleteSuccess" = "入站连接已成功删除"
|
||||
"inboundClientAddSuccess" = "已添加入站客户端"
|
||||
"inboundClientDeleteSuccess" = "入站客户端已删除"
|
||||
"inboundClientUpdateSuccess" = "入站客户端已更新"
|
||||
"delDepletedClientsSuccess" = "所有耗尽客户端已删除"
|
||||
"resetAllClientTrafficSuccess" = "客户端所有流量已重置"
|
||||
"resetAllTrafficSuccess" = "所有流量已重置"
|
||||
"resetInboundClientTrafficSuccess" = "流量已重置"
|
||||
"trafficGetError" = "获取流量数据时出错"
|
||||
"getNewX25519CertError" = "获取X25519证书时出错。"
|
||||
|
||||
[pages.inbounds.stream.general]
|
||||
"request" = "请求"
|
||||
@ -284,12 +232,11 @@
|
||||
"infoDesc" = "此处的所有更改都需要保存并重启面板才能生效"
|
||||
"restartPanel" = "重启面板"
|
||||
"restartPanelDesc" = "确定要重启面板吗?若重启后无法访问面板,请前往服务器查看面板日志信息"
|
||||
"restartPanelSuccess" = "面板已成功重启"
|
||||
"actions" = "操作"
|
||||
"resetDefaultConfig" = "重置为默认配置"
|
||||
"panelSettings" = "常规"
|
||||
"securitySettings" = "安全设定"
|
||||
"TGBotSettings" = "Telegram 机器人配置"
|
||||
"TGBotSettings" = "Telegram机器人配置"
|
||||
"panelListeningIP" = "面板监听 IP"
|
||||
"panelListeningIPDesc" = "默认留空监听所有 IP"
|
||||
"panelListeningDomain" = "面板监听域名"
|
||||
@ -297,10 +244,12 @@
|
||||
"panelPort" = "面板监听端口"
|
||||
"panelPortDesc" = "重启面板生效"
|
||||
"publicKeyPath" = "面板证书公钥文件路径"
|
||||
"publicKeyPathDesc" = "填写一个 '/' 开头的绝对路径"
|
||||
"DefaultpublicKeyPath" = "/root/.acme.sh/域名_ecc/域名.cer"
|
||||
"publicKeyPathDesc" = "填写一个 '/' 开头的绝对路径,〔acme方式〕请自行在填入时修改域名"
|
||||
"privateKeyPath" = "面板证书密钥文件路径"
|
||||
"privateKeyPathDesc" = "填写一个 '/' 开头的绝对路径"
|
||||
"panelUrlPath" = "面板 url 根路径"
|
||||
"DefaultprivateKeyPath" = "/root/.acme.sh/域名_ecc/域名.key"
|
||||
"privateKeyPathDesc" = "填写一个 '/' 开头的绝对路径,〔acme方式〕请自行在填入时修改域名"
|
||||
"panelUrlPath" = "面板登录访问路径"
|
||||
"panelUrlPathDesc" = "必须以 '/' 开头,以 '/' 结尾"
|
||||
"pageSize" = "分页大小"
|
||||
"pageSizeDesc" = "定义入站表的页面大小。设置 0 表示禁用"
|
||||
@ -316,7 +265,7 @@
|
||||
"telegramBotEnable" = "启用 Telegram 机器人"
|
||||
"telegramBotEnableDesc" = "启用 Telegram 机器人功能"
|
||||
"telegramToken" = "Telegram 机器人令牌(token)"
|
||||
"telegramTokenDesc" = "从 '@BotFather' 获取的 Telegram 机器人令牌"
|
||||
"telegramTokenDesc" = "跟 '@BotFather' 对话获取的 Telegram 机器人令牌"
|
||||
"telegramProxy" = "SOCKS5 Proxy"
|
||||
"telegramProxyDesc" = "启用 SOCKS5 代理连接到 Telegram(根据指南调整设置)"
|
||||
"telegramAPIServer" = "Telegram API Server"
|
||||
@ -342,8 +291,6 @@
|
||||
"subSettings" = "订阅设置"
|
||||
"subEnable" = "启用订阅服务"
|
||||
"subEnableDesc" = "启用订阅服务功能"
|
||||
"subTitle" = "订阅标题"
|
||||
"subTitleDesc" = "在VPN客户端中显示的标题"
|
||||
"subListen" = "监听 IP"
|
||||
"subListenDesc" = "订阅服务监听的 IP 地址(留空表示监听所有 IP)"
|
||||
"subPort" = "监听端口"
|
||||
@ -364,10 +311,6 @@
|
||||
"subShowInfoDesc" = "客户端应用中将显示剩余流量和日期信息"
|
||||
"subURI" = "反向代理 URI"
|
||||
"subURIDesc" = "用于代理后面的订阅 URL 的 URI 路径"
|
||||
"externalTrafficInformEnable" = "外部交通通知"
|
||||
"externalTrafficInformEnableDesc" = "每次流量更新时通知外部 API"
|
||||
"externalTrafficInformURI" = "外部流量通知 URI"
|
||||
"externalTrafficInformURIDesc" = "流量更新将发送到此 URI"
|
||||
"fragment" = "分片"
|
||||
"fragmentDesc" = "启用 TLS hello 数据包分片"
|
||||
"fragmentSett" = "设置"
|
||||
@ -378,30 +321,19 @@
|
||||
"muxSett" = "复用器设置"
|
||||
"direct" = "直接连接"
|
||||
"directDesc" = "直接与特定国家的域或IP范围建立连接"
|
||||
"notifications" = "通知"
|
||||
"certs" = "证书"
|
||||
"externalTraffic" = "外部流量"
|
||||
"dateAndTime" = "日期和时间"
|
||||
"proxyAndServer" = "代理和服务器"
|
||||
"intervals" = "间隔"
|
||||
"information" = "信息"
|
||||
"language" = "语言"
|
||||
"telegramBotLanguage" = "Telegram 机器人语言"
|
||||
|
||||
|
||||
[pages.xray]
|
||||
"title" = "Xray 配置"
|
||||
"save" = "保存"
|
||||
"restart" = "重新启动 Xray"
|
||||
"restartSuccess" = "Xray 已成功重新启动"
|
||||
"stopSuccess" = "Xray 已成功停止"
|
||||
"restartError" = "重启Xray时发生错误。"
|
||||
"stopError" = "停止Xray时发生错误。"
|
||||
"basicTemplate" = "基础配置"
|
||||
"advancedTemplate" = "高级配置"
|
||||
"generalConfigs" = "常规配置"
|
||||
"generalConfigsDesc" = "这些选项将决定常规配置"
|
||||
"logConfigs" = "日志"
|
||||
"logConfigsDesc" = "日志可能会影响服务器的性能,建议仅在需要时启用"
|
||||
"blockConfigs" = "防护屏蔽"
|
||||
"blockConfigsDesc" = "这些选项将阻止用户连接到特定协议和网站"
|
||||
"basicRouting" = "基本路由"
|
||||
"blockConnectionsConfigsDesc" = "这些选项将根据特定的请求国家阻止流量。"
|
||||
@ -421,6 +353,9 @@
|
||||
"RoutingStrategy" = "配置路由域策略"
|
||||
"RoutingStrategyDesc" = "设置 DNS 解析的整体路由策略"
|
||||
"Torrent" = "屏蔽 BitTorrent 协议"
|
||||
"TorrentDesc" = "禁止使用 BitTorrent"
|
||||
"Family" = "家庭保护"
|
||||
"FamilyDesc" = "屏蔽成人内容和恶意网站"
|
||||
"Inbounds" = "入站规则"
|
||||
"InboundsDesc" = "接受来自特定客户端的流量"
|
||||
"Outbounds" = "出站规则"
|
||||
@ -439,15 +374,9 @@
|
||||
"dnsLogDesc" = "是否启用 DNS 查询日志"
|
||||
"maskAddress" = "隐藏地址"
|
||||
"maskAddressDesc" = "IP 地址掩码,启用时会自动替换日志中出现的 IP 地址。"
|
||||
"statistics" = "统计"
|
||||
"statsInboundUplink" = "入站上传统计"
|
||||
"statsInboundUplinkDesc" = "启用所有入站代理的上行流量统计收集。"
|
||||
"statsInboundDownlink" = "入站下载统计"
|
||||
"statsInboundDownlinkDesc" = "启用所有入站代理的下行流量统计收集。"
|
||||
"statsOutboundUplink" = "出站上传统计"
|
||||
"statsOutboundUplinkDesc" = "启用所有出站代理的上行流量统计收集。"
|
||||
"statsOutboundDownlink" = "出站下载统计"
|
||||
"statsOutboundDownlinkDesc" = "启用所有出站代理的下行流量统计收集。"
|
||||
|
||||
[pages.navigation]
|
||||
"title" = "实用导航"
|
||||
|
||||
[pages.xray.rules]
|
||||
"first" = "置顶"
|
||||
@ -455,7 +384,7 @@
|
||||
"up" = "向上"
|
||||
"down" = "向下"
|
||||
"source" = "来源"
|
||||
"dest" = "目的地址"
|
||||
"dest" = "目标地址"
|
||||
"inbound" = "入站"
|
||||
"outbound" = "出站"
|
||||
"balancer" = "负载均衡"
|
||||
@ -463,6 +392,18 @@
|
||||
"add" = "添加规则"
|
||||
"edit" = "编辑规则"
|
||||
"useComma" = "逗号分隔的项目"
|
||||
"DomainMatcher" = "域匹配类型"
|
||||
"SourceIPs" = "源IP"
|
||||
"SourcePort" = "源端口"
|
||||
"Network" = "网络类型"
|
||||
"Protocol" = "传输协议"
|
||||
"Attributes" = "属性"
|
||||
"Domain" = "域地址"
|
||||
"User" = "用户"
|
||||
"Port" = "端口"
|
||||
"InboundTag" = "入站 Tag"
|
||||
"OutboundTag" = "出站 Tag"
|
||||
"BalancerTag" = "负载均衡 Tag"
|
||||
|
||||
[pages.xray.outbound]
|
||||
"addOutbound" = "添加出站"
|
||||
@ -477,7 +418,6 @@
|
||||
"type" = "类型"
|
||||
"bridge" = "Bridge"
|
||||
"portal" = "Portal"
|
||||
"link" = "链接"
|
||||
"intercon" = "互连"
|
||||
"settings" = "设置"
|
||||
"accountInfo" = "帐户信息"
|
||||
@ -506,26 +446,12 @@
|
||||
"enableDesc" = "启用内置 DNS 服务器"
|
||||
"tag" = "DNS 入站标签"
|
||||
"tagDesc" = "此标签将在路由规则中可用作入站标签"
|
||||
"clientIp" = "客户端IP"
|
||||
"clientIpDesc" = "用于在DNS查询期间通知服务器指定的IP位置"
|
||||
"disableCache" = "禁用缓存"
|
||||
"disableCacheDesc" = "禁用DNS缓存"
|
||||
"disableFallback" = "禁用回退"
|
||||
"disableFallbackDesc" = "禁用回退DNS查询"
|
||||
"disableFallbackIfMatch" = "匹配时禁用回退"
|
||||
"disableFallbackIfMatchDesc" = "当DNS服务器的匹配域名列表命中时,禁用回退DNS查询"
|
||||
"strategy" = "查询策略"
|
||||
"strategyDesc" = "解析域名的总体策略"
|
||||
"add" = "添加服务器"
|
||||
"edit" = "编辑服务器"
|
||||
"domains" = "域"
|
||||
"expectIPs" = "预期 IP"
|
||||
"unexpectIPs" = "意外IP"
|
||||
"useSystemHosts" = "使用系统Hosts"
|
||||
"useSystemHostsDesc" = "使用已安装系统的hosts文件"
|
||||
"usePreset" = "使用模板"
|
||||
"dnsPresetTitle" = "DNS模板"
|
||||
"dnsPresetFamily" = "家庭"
|
||||
|
||||
[pages.xray.fakedns]
|
||||
"add" = "添加假 DNS"
|
||||
@ -534,31 +460,19 @@
|
||||
"poolSize" = "池大小"
|
||||
|
||||
[pages.settings.security]
|
||||
"admin" = "管理员凭据"
|
||||
"twoFactor" = "双重验证"
|
||||
"twoFactorEnable" = "启用2FA"
|
||||
"twoFactorEnableDesc" = "增加额外的验证层以提高安全性。"
|
||||
"twoFactorModalSetTitle" = "启用双重认证"
|
||||
"twoFactorModalDeleteTitle" = "停用双重认证"
|
||||
"twoFactorModalSteps" = "要设定双重认证,请执行以下步骤:"
|
||||
"twoFactorModalFirstStep" = "1. 在认证应用程序中扫描此QR码,或复制QR码附近的令牌并粘贴到应用程序中"
|
||||
"twoFactorModalSecondStep" = "2. 输入应用程序中的验证码"
|
||||
"twoFactorModalRemoveStep" = "输入应用程序中的验证码以移除双重认证。"
|
||||
"twoFactorModalChangeCredentialsTitle" = "更改凭据"
|
||||
"twoFactorModalChangeCredentialsStep" = "输入应用程序中的代码以更改管理员凭据。"
|
||||
"twoFactorModalSetSuccess" = "双因素认证已成功建立"
|
||||
"twoFactorModalDeleteSuccess" = "双因素认证已成功删除"
|
||||
"twoFactorModalError" = "验证码错误"
|
||||
"admin" = "管理员"
|
||||
"secret" = "安全令牌"
|
||||
"loginSecurity" = "登录安全"
|
||||
"loginSecurityDesc" = "添加额外的身份验证以提高安全性"
|
||||
"secretToken" = "安全令牌"
|
||||
"secretTokenDesc" = "请将此令牌存储在安全的地方。此令牌用于登录,丢失无法恢复。"
|
||||
|
||||
[pages.settings.toasts]
|
||||
"modifySettings" = "参数已更改。"
|
||||
"getSettings" = "获取参数时发生错误"
|
||||
"modifyUserError" = "更改管理员凭据时发生错误。"
|
||||
"modifyUser" = "您已成功更改管理员凭据。"
|
||||
"modifySettings" = "修改设置"
|
||||
"getSettings" = "获取设置"
|
||||
"modifyUser" = "修改管理员"
|
||||
"originalUserPassIncorrect" = "原用户名或原密码错误"
|
||||
"userPassMustBeNotEmpty" = "新用户名和新密码不能为空"
|
||||
"getOutboundTrafficError" = "获取出站流量错误"
|
||||
"resetOutboundTrafficError" = "重置出站流量错误"
|
||||
|
||||
[tgbot]
|
||||
"keyboardClosed" = "❌ 自定义键盘已关闭!"
|
||||
@ -582,23 +496,20 @@
|
||||
|
||||
[tgbot.commands]
|
||||
"unknown" = "❗ 未知命令"
|
||||
"pleaseChoose" = "👇 请选择:\r\n"
|
||||
"pleaseChoose" = "👇请〔按照需求〕选择下方按钮:\r\n"
|
||||
"help" = "🤖 欢迎使用本机器人!它旨在为您提供来自服务器的特定数据,并允许您进行必要的修改。\r\n\r\n"
|
||||
"start" = "👋 你好,<i>{{ .Firstname }}</i>。\r\n"
|
||||
"welcome" = "🤖 欢迎来到 <b>{{ .Hostname }}</b> 管理机器人。\r\n"
|
||||
"status" = "✅ 机器人正常运行!"
|
||||
"usage" = "❗ 请输入要搜索的文本!"
|
||||
"getID" = "🆔 您的 ID 为:<code>{{ .ID }}</code>"
|
||||
"helpAdminCommands" = "要重新启动 Xray Core:\r\n<code>/restart</code>\r\n\r\n要搜索客户电子邮件:\r\n<code>/usage [电子邮件]</code>\r\n\r\n要搜索入站(带有客户统计数据):\r\n<code>/inbound [备注]</code>\r\n\r\nTelegram聊天ID:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "要重新启动 Xray Core:\r\n<code>/restart force</code>\r\n\r\n要搜索客户电子邮件:\r\n<code>/usage [电子邮件]</code>\r\n\r\n要搜索入站(带有客户统计数据):\r\n<code>/inbound [备注]</code>\r\n\r\nTelegram聊天ID:\r\n<code>/id</code>"
|
||||
"helpAdminCommands" = "要重新启动Xray Core:\r\n<code>/restart force</code>\r\n\r\n要搜索客户电子邮件:\r\n<code>/usage [电子邮件]</code>\r\n\r\n要搜索入站(带有客户统计数据):\r\n<code>/inbound [备注]</code>\r\n\r\n要获取Telegram聊天ID:\r\n<code>/id</code>"
|
||||
"helpClientCommands" = "要搜索统计数据,请使用以下命令:\r\n<code>/usage [电子邮件]</code>\r\n\r\nTelegram聊天ID:\r\n<code>/id</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart</code>"
|
||||
"restartUsage" = "\r\n\r\n<code>/restart force</code>"
|
||||
"restartSuccess" = "✅ 操作成功!"
|
||||
"restartFailed" = "❗ 操作错误。\r\n\r\n<code>错误: {{ .Error }}</code>."
|
||||
"xrayNotRunning" = "❗ Xray Core 未运行。"
|
||||
"startDesc" = "显示主菜单"
|
||||
"helpDesc" = "机器人帮助"
|
||||
"statusDesc" = "检查机器人状态"
|
||||
"idDesc" = "显示您的 Telegram ID"
|
||||
|
||||
[tgbot.messages]
|
||||
"cpuThreshold" = "🔴 CPU 使用率为 {{ .Percent }}%,超过阈值 {{ .Threshold }}%"
|
||||
@ -609,7 +520,7 @@
|
||||
"report" = "🕰 定时报告:{{ .RunTime }}\r\n"
|
||||
"datetime" = "⏰ 日期时间:{{ .DateTime }}\r\n"
|
||||
"hostname" = "💻 主机名:{{ .Hostname }}\r\n"
|
||||
"version" = "🚀 X-UI 版本:{{ .Version }}\r\n"
|
||||
"version" = "🚀 3X-UI 版本:{{ .Version }}\r\n"
|
||||
"xrayVersion" = "📡 Xray 版本: {{ .XrayVersion }}\r\n"
|
||||
"ipv6" = "🌐 IPv6:{{ .IPv6 }}\r\n"
|
||||
"ipv4" = "🌐 IPv4:{{ .IPv4 }}\r\n"
|
||||
@ -632,7 +543,7 @@
|
||||
"active" = "💡 激活:{{ .Enable }}\r\n"
|
||||
"enabled" = "🚨 已启用:{{ .Enable }}\r\n"
|
||||
"online" = "🌐 连接状态:{{ .Status }}\r\n"
|
||||
"email" = "📧 邮箱:{{ .Email }}\r\n"
|
||||
"email" = "📧 邮箱(用户):{{ .Email }}\r\n"
|
||||
"upload" = "🔼 上传↑:{{ .Upload }}\r\n"
|
||||
"download" = "🔽 下载↓:{{ .Download }}\r\n"
|
||||
"total" = "📊 总计:{{ .UpDown }} / {{ .Total }}\r\n"
|
||||
@ -647,26 +558,6 @@
|
||||
"yes" = "✅ 是的"
|
||||
"no" = "❌ 没有"
|
||||
|
||||
"received_id" = "🔑📥 ID 已更新。"
|
||||
"received_password" = "🔑📥 密码已更新。"
|
||||
"received_email" = "📧📥 邮箱已更新。"
|
||||
"received_comment" = "💬📥 评论已更新。"
|
||||
"id_prompt" = "🔑 默认 ID: {{ .ClientId }}\n\n请输入您的 ID。"
|
||||
"pass_prompt" = "🔑 默认密码: {{ .ClientPassword }}\n\n请输入您的密码。"
|
||||
"email_prompt" = "📧 默认邮箱: {{ .ClientEmail }}\n\n请输入您的邮箱。"
|
||||
"comment_prompt" = "💬 默认评论: {{ .ClientComment }}\n\n请输入您的评论。"
|
||||
"inbound_client_data_id" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 邮箱: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日期: {{ .ClientExp }}\n🌐 IP 限制: {{ .IpLimit }}\n💬 备注: {{ .ClientComment }}\n\n你现在可以将客户添加到入站了!"
|
||||
"inbound_client_data_pass" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 密码: {{ .ClientPass }}\n📧 邮箱: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日期: {{ .ClientExp }}\n🌐 IP 限制: {{ .IpLimit }}\n💬 备注: {{ .ClientComment }}\n\n你现在可以将客户添加到入站了!"
|
||||
"cancel" = "❌ 进程已取消!\n\n您可以随时使用 /start 重新开始。 🔄"
|
||||
"error_add_client" = "⚠️ 错误:\n\n {{ .error }}"
|
||||
"using_default_value" = "好的,我会使用默认值。 😊"
|
||||
"incorrect_input" ="您的输入无效。\n短语应连续输入,不能有空格。\n正确示例: aaaaaa\n错误示例: aaa aaa 🚫"
|
||||
"AreYouSure" = "你确定吗?🤔"
|
||||
"SuccessResetTraffic" = "📧 邮箱: {{ .ClientEmail }}\n🏁 结果: ✅ 成功"
|
||||
"FailedResetTraffic" = "📧 邮箱: {{ .ClientEmail }}\n🏁 结果: ❌ 失败 \n\n🛠️ 错误: [ {{ .ErrorMessage }} ]"
|
||||
"FinishProcess" = "🔚 所有客户的流量重置已完成。"
|
||||
|
||||
|
||||
[tgbot.buttons]
|
||||
"closeKeyboard" = "❌ 关闭键盘"
|
||||
"cancel" = "❌ 取消"
|
||||
@ -677,12 +568,12 @@
|
||||
"confirmRemoveTGUser" = "✅ 确认移除 Telegram 用户?"
|
||||
"confirmToggle" = "✅ 确认启用/禁用用户?"
|
||||
"dbBackup" = "获取数据库备份"
|
||||
"serverUsage" = "服务器使用情况"
|
||||
"serverUsage" = "服务器状态"
|
||||
"getInbounds" = "获取入站信息"
|
||||
"depleteSoon" = "即将耗尽"
|
||||
"clientUsage" = "获取使用情况"
|
||||
"onlines" = "在线客户端"
|
||||
"commands" = "命令"
|
||||
"commands" = "常用命令"
|
||||
"refresh" = "🔄 刷新"
|
||||
"clearIPs" = "❌ 清除 IP"
|
||||
"removeTGUser" = "❌ 移除 Telegram 用户"
|
||||
@ -694,25 +585,13 @@
|
||||
"ipLimit" = "🔢 IP 限制"
|
||||
"setTGUser" = "👤 设置 Telegram 用户"
|
||||
"toggle" = "🔘 启用/禁用"
|
||||
"custom" = "🔢 风俗"
|
||||
"custom" = "🔢 自定义输入"
|
||||
"confirmNumber" = "✅ 确认: {{ .Num }}"
|
||||
"confirmNumberAdd" = "✅ 确认添加:{{ .Num }}"
|
||||
"limitTraffic" = "🚧 流量限制"
|
||||
"getBanLogs" = "禁止日志"
|
||||
"allClients" = "所有客户"
|
||||
|
||||
"addClient" = "添加客户"
|
||||
"submitDisable" = "提交为禁用 ☑️"
|
||||
"submitEnable" = "提交为启用 ✅"
|
||||
"use_default" = "🏷️ 使用默认"
|
||||
"change_id" = "⚙️🔑 ID"
|
||||
"change_password" = "⚙️🔑 密码"
|
||||
"change_email" = "⚙️📧 邮箱"
|
||||
"change_comment" = "⚙️💬 评论"
|
||||
"ResetAllTraffics" = "重置所有流量"
|
||||
"SortedTrafficUsageReport" = "排序的流量使用报告"
|
||||
|
||||
|
||||
[tgbot.answers]
|
||||
"successfulOperation" = "✅ 成功!"
|
||||
"errorOperation" = "❗ 操作错误。"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user