Skip to content

Commit 72e2068

Browse files
committed
Update Tg bot related function
1 parent 8791c87 commit 72e2068

27 files changed

+533
-56
lines changed

.github/workflows/release.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,4 @@ jobs:
144144
upload_url: ${{ needs.release.outputs.upload_url }}
145145
asset_path: x-ui-linux-s390x.tar.gz
146146
asset_name: x-ui-linux-s390x.tar.gz
147-
asset_content_type: application/gzip
147+
asset_content_type: application/gzip

README.md

+40
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
- 流量统计,限制流量,限制到期时间
1212
- 可自定义 xray 配置模板
1313
- 支持 https 访问面板(自备域名 + ssl 证书)
14+
- 支持一键SSL证书申请且自动续签
1415
- 更多高级配置项,详见面板
1516

17+
1618
# 安装&升级
1719
```
1820
bash <(curl -Ls https://raw.githubusercontent.com/vaxilu/x-ui/master/install.sh)
@@ -58,6 +60,44 @@ docker run -itd --network=host \
5860
```shell
5961
docker build -t x-ui .
6062
```
63+
## SSL证书申请
64+
>此功能与教程由[FranzKafkaYu](https://github.com/FranzKafkaYu)提供
65+
66+
脚本内置SSL证书申请功能,使用该脚本申请证书,需满足以下条件:
67+
- 知晓Cloudflare 注册邮箱
68+
- 知晓Cloudflare Global API Key
69+
- 域名已通过cloudflare进行解析到当前服务器
70+
71+
获取Cloudflare Global API Key的方法:
72+
![](media/bda84fbc2ede834deaba1c173a932223.png)
73+
![](media/d13ffd6a73f938d1037d0708e31433bf.png)
74+
75+
使用时只需输入`域名`, `邮箱`, `API KEY`即可,示意图如下:
76+
![](media/2022-04-04_141259.png)
77+
78+
注意事项:
79+
- 该脚本使用DNS API进行证书申请
80+
- 默认使用Let'sEncrypt作为CA方
81+
- 证书安装目录为/root/cert目录
82+
- 本脚本申请证书均为泛域名证书
83+
84+
## Tg机器人使用
85+
>此功能与教程由[FranzKafkaYu](https://github.com/FranzKafkaYu)提供
86+
87+
X-UI支持通过Tg机器人实现每日流量通知,面板登录提醒等功能,使用Tg机器人,需要自行申请
88+
具体申请教程可以参考[博客链接](https://coderfan.net/how-to-use-telegram-bot-to-alarm-you-when-someone-login-into-your-vps.html)
89+
使用说明:在面板后台或通过脚本设置机器人相关参数,具体包括
90+
- Tg机器人Token
91+
- Tg机器人ChatId
92+
- Tg机器人周期运行时间,采用crontab语法
93+
94+
参考示例:
95+
每小时定时通知
96+
![](media/2022-04-17_110907.png)
97+
每分钟的第30s通知
98+
![](media/2022-04-17_111321.png)
99+
效果示意图:
100+
![](media/2022-04-17_111705.png)
61101

62102
## 建议系统
63103
- CentOS 7+

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/gin-contrib/sessions v0.0.3
1010
github.com/gin-gonic/gin v1.7.1
1111
github.com/go-ole/go-ole v1.2.5 // indirect
12+
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 // indirect
1213
github.com/nicksnyder/go-i18n/v2 v2.1.2
1314
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
1415
github.com/robfig/cron/v3 v3.0.1

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87
7070
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
7171
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
7272
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
73+
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
74+
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
7375
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
7476
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
7577
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=

install.sh

+8-8
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ install_base() {
8383

8484
#This function will be called when user installed x-ui out of sercurity
8585
config_after_install() {
86-
echo -e "${yellow}出于安全考虑,安装完成后需要强制修改端口与账户密码${plain}"
87-
read -p "请设置您的账户名:" config_account
88-
echo -e "${yellow}您的账户名将设定为:${config_account}${plain}"
89-
read -p "请设置您的账户密码:" config_password
90-
echo -e "${yellow}您的账户密码将设定为:${config_password}${plain}"
91-
read -p "请设置面板访问端口:" config_port
92-
echo -e "${yellow}您的面板访问端口将设定为:${config_port}${plain}"
93-
read -p "确认设定完成?[y/n]": config_confirm
86+
echo -e "${yellow}出于安全考虑,安装/更新完成后需要强制修改端口与账户密码${plain}"
87+
read -p "确认是否继续?[y/n]": config_confirm
9488
if [[ x"${config_confirm}" == x"y" || x"${config_confirm}" == x"Y" ]]; then
89+
read -p "请设置您的账户名:" config_account
90+
echo -e "${yellow}您的账户名将设定为:${config_account}${plain}"
91+
read -p "请设置您的账户密码:" config_password
92+
echo -e "${yellow}您的账户密码将设定为:${config_password}${plain}"
93+
read -p "请设置面板访问端口:" config_port
94+
echo -e "${yellow}您的面板访问端口将设定为:${config_port}${plain}"
9595
echo -e "${yellow}确认设定,设定中${plain}"
9696
/usr/local/x-ui/x-ui setting -username ${config_account} -password ${config_password}
9797
echo -e "${yellow}账户密码设定完成${plain}"

main.go

+105-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"flag"
55
"fmt"
6-
"github.com/op/go-logging"
76
"log"
87
"os"
98
"os/signal"
@@ -16,6 +15,8 @@ import (
1615
"x-ui/web"
1716
"x-ui/web/global"
1817
"x-ui/web/service"
18+
19+
"github.com/op/go-logging"
1920
)
2021

2122
func runWebServer() {
@@ -50,6 +51,7 @@ func runWebServer() {
5051
}
5152

5253
sigCh := make(chan os.Signal, 1)
54+
//信号量捕获处理
5355
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGKILL)
5456
for {
5557
sig := <-sigCh
@@ -90,6 +92,90 @@ func resetSetting() {
9092
}
9193
}
9294

95+
func showSetting(show bool) {
96+
if show {
97+
settingService := service.SettingService{}
98+
port, err := settingService.GetPort()
99+
if err != nil {
100+
fmt.Println("get current port fialed,error info:", err)
101+
}
102+
userService := service.UserService{}
103+
userModel, err := userService.GetFirstUser()
104+
if err != nil {
105+
fmt.Println("get current user info failed,error info:", err)
106+
}
107+
username := userModel.Username
108+
userpasswd := userModel.Password
109+
if (username == "") || (userpasswd == "") {
110+
fmt.Println("current username or password is empty")
111+
}
112+
fmt.Println("current pannel settings as follows:")
113+
fmt.Println("username:", username)
114+
fmt.Println("userpasswd:", userpasswd)
115+
fmt.Println("port:", port)
116+
}
117+
}
118+
119+
func updateTgbotEnableSts(status bool) {
120+
settingService := service.SettingService{}
121+
currentTgSts, err := settingService.GetTgbotenabled()
122+
if err != nil {
123+
fmt.Println(err)
124+
return
125+
}
126+
logger.Infof("current enabletgbot status[%v],need update to status[%v]", currentTgSts, status)
127+
if currentTgSts != status {
128+
err := settingService.SetTgbotenabled(status)
129+
if err != nil {
130+
fmt.Println(err)
131+
return
132+
} else {
133+
logger.Infof("SetTgbotenabled[%v] success", status)
134+
}
135+
}
136+
return
137+
}
138+
139+
func updateTgbotSetting(tgBotToken string, tgBotChatid int, tgBotRuntime string) {
140+
err := database.InitDB(config.GetDBPath())
141+
if err != nil {
142+
fmt.Println(err)
143+
return
144+
}
145+
146+
settingService := service.SettingService{}
147+
148+
if tgBotToken != "" {
149+
err := settingService.SetTgBotToken(tgBotToken)
150+
if err != nil {
151+
fmt.Println(err)
152+
return
153+
} else {
154+
logger.Info("updateTgbotSetting tgBotToken success")
155+
}
156+
}
157+
158+
if tgBotRuntime != "" {
159+
err := settingService.SetTgbotRuntime(tgBotRuntime)
160+
if err != nil {
161+
fmt.Println(err)
162+
return
163+
} else {
164+
logger.Infof("updateTgbotSetting tgBotRuntime[%s] success", tgBotRuntime)
165+
}
166+
}
167+
168+
if tgBotChatid != 0 {
169+
err := settingService.SetTgBotChatId(tgBotChatid)
170+
if err != nil {
171+
fmt.Println(err)
172+
return
173+
} else {
174+
logger.Info("updateTgbotSetting tgBotChatid success")
175+
}
176+
}
177+
}
178+
93179
func updateSetting(port int, username string, password string) {
94180
err := database.InitDB(config.GetDBPath())
95181
if err != nil {
@@ -137,11 +223,21 @@ func main() {
137223
var port int
138224
var username string
139225
var password string
226+
var tgbottoken string
227+
var tgbotchatid int
228+
var enabletgbot bool
229+
var tgbotRuntime string
140230
var reset bool
141-
settingCmd.BoolVar(&reset, "reset", false, "reset all setting")
231+
var show bool
232+
settingCmd.BoolVar(&reset, "reset", false, "reset all settings")
233+
settingCmd.BoolVar(&show, "show", false, "show current settings")
142234
settingCmd.IntVar(&port, "port", 0, "set panel port")
143235
settingCmd.StringVar(&username, "username", "", "set login username")
144236
settingCmd.StringVar(&password, "password", "", "set login password")
237+
settingCmd.StringVar(&tgbottoken, "tgbottoken", "", "set telegrame bot token")
238+
settingCmd.StringVar(&tgbotRuntime, "tgbotRuntime", "", "set telegrame bot cron time")
239+
settingCmd.IntVar(&tgbotchatid, "tgbotchatid", 0, "set telegrame bot chat id")
240+
settingCmd.BoolVar(&enabletgbot, "enabletgbot", false, "enable telegram bot notify")
145241

146242
oldUsage := flag.Usage
147243
flag.Usage = func() {
@@ -188,6 +284,13 @@ func main() {
188284
} else {
189285
updateSetting(port, username, password)
190286
}
287+
if show {
288+
showSetting(show)
289+
}
290+
updateTgbotEnableSts(enabletgbot)
291+
if (tgbottoken != "") || (tgbotchatid != 0) || (tgbotRuntime != "") {
292+
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
293+
}
191294
default:
192295
fmt.Println("except 'run' or 'v2-ui' or 'setting' subcommands")
193296
fmt.Println()

media/2022-04-04_141259.png

19.1 KB
Loading

media/2022-04-17_110907.png

20.5 KB
Loading

media/2022-04-17_111321.png

19.6 KB
Loading

media/2022-04-17_111705.png

35.8 KB
Loading

media/2022-04-17_111910.png

30.5 KB
Loading
25.7 KB
Loading
22.6 KB
Loading

util/common/format.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package common
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func FormatTraffic(trafficBytes int64) (size string) {
8+
if trafficBytes < 1024 {
9+
return fmt.Sprintf("%.2fB", float64(trafficBytes)/float64(1))
10+
} else if trafficBytes < (1024 * 1024) {
11+
return fmt.Sprintf("%.2fKB", float64(trafficBytes)/float64(1024))
12+
} else if trafficBytes < (1024 * 1024 * 1024) {
13+
return fmt.Sprintf("%.2fMB", float64(trafficBytes)/float64(1024*1024))
14+
} else if trafficBytes < (1024 * 1024 * 1024 * 1024) {
15+
return fmt.Sprintf("%.2fGB", float64(trafficBytes)/float64(1024*1024*1024))
16+
} else if trafficBytes < (1024 * 1024 * 1024 * 1024 * 1024) {
17+
return fmt.Sprintf("%.2fTB", float64(trafficBytes)/float64(1024*1024*1024*1024))
18+
} else {
19+
return fmt.Sprintf("%.2fEB", float64(trafficBytes)/float64(1024*1024*1024*1024*1024))
20+
}
21+
}

util/common/stringUtil.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package common
2+
3+
import "sort"
4+
5+
func IsSubString(target string, str_array []string) bool {
6+
sort.Strings(str_array)
7+
index := sort.SearchStrings(str_array, target)
8+
return index < len(str_array) && str_array[index] == target
9+
}

web/assets/js/model/models.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ class AllSetting {
163163
this.webCertFile = "";
164164
this.webKeyFile = "";
165165
this.webBasePath = "/";
166-
166+
this.tgBotToken = "";
167+
this.tgBotChatId = 0;
168+
this.tgRunTime = "";
167169
this.xrayTemplateConfig = "";
168170

169171
this.timeLocation = "Asia/Shanghai";

web/controller/index.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package controller
22

33
import (
4-
"github.com/gin-gonic/gin"
54
"net/http"
5+
"time"
66
"x-ui/logger"
7+
"x-ui/web/job"
78
"x-ui/web/service"
89
"x-ui/web/session"
10+
11+
"github.com/gin-gonic/gin"
912
)
1013

1114
type LoginForm struct {
@@ -59,6 +62,10 @@ func (a *IndexController) login(c *gin.Context) {
5962
logger.Infof("wrong username or password: \"%s\" \"%s\"", form.Username, form.Password)
6063
pureJsonMsg(c, false, "用户名或密码错误")
6164
return
65+
} else {
66+
timeStr := time.Now().Format("2006-01-02 15:04:05")
67+
logger.Infof("%s login success,Ip Address:%s\n", form.Username, getRemoteIp(c))
68+
job.NewStatsNotifyJob().UserLoginNotify(form.Username, getRemoteIp(c), timeStr)
6269
}
6370

6471
err = session.SetLoginUser(c, user)

web/entity/entity.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ type Pager struct {
2727
}
2828

2929
type AllSetting struct {
30-
WebListen string `json:"webListen" form:"webListen"`
31-
WebPort int `json:"webPort" form:"webPort"`
32-
WebCertFile string `json:"webCertFile" form:"webCertFile"`
33-
WebKeyFile string `json:"webKeyFile" form:"webKeyFile"`
34-
WebBasePath string `json:"webBasePath" form:"webBasePath"`
35-
30+
WebListen string `json:"webListen" form:"webListen"`
31+
WebPort int `json:"webPort" form:"webPort"`
32+
WebCertFile string `json:"webCertFile" form:"webCertFile"`
33+
WebKeyFile string `json:"webKeyFile" form:"webKeyFile"`
34+
WebBasePath string `json:"webBasePath" form:"webBasePath"`
35+
TgBotToken string `json:"tgBotToken" form:"tgBotToken"`
36+
TgBotChatId int `json:"tgBotChatId" form:"tgBotChatId"`
37+
TgRunTime string `json:"tgRunTime" form:"tgRunTime"`
3638
XrayTemplateConfig string `json:"xrayTemplateConfig" form:"xrayTemplateConfig"`
3739

3840
TimeLocation string `json:"timeLocation" form:"timeLocation"`

web/html/xui/setting.html

+8-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,14 @@
7171
<setting-list-item type="textarea" title="xray 配置模版" desc="以该模版为基础生成最终的 xray 配置文件,重启面板生效" v-model="allSetting.xrayTemplateConfig"></setting-list-item>
7272
</a-list>
7373
</a-tab-pane>
74-
<a-tab-pane key="4" tab="其他设置">
74+
<a-tab-pane key="4" tab="TG提醒相关设置">
75+
<a-list item-layout="horizontal" style="background: white">
76+
<setting-list-item type="text" title="电报机器人TOKEN" desc="重启面板生效" v-model="allSetting.tgBotToken"></setting-list-item>
77+
<setting-list-item type="number" title="电报机器人ChatId" desc="重启面板生效" v-model.number="allSetting.tgBotChatId"></setting-list-item>
78+
<setting-list-item type="text" title="电报机器人通知时间" desc="采用Crontab定时格式" v-model="allSetting.tgRunTime"></setting-list-item>
79+
</a-list>
80+
</a-tab-pane>
81+
<a-tab-pane key="5" tab="其他设置">
7582
<a-list item-layout="horizontal" style="background: white">
7683
<setting-list-item type="text" title="时区" desc="定时任务按照该时区的时间运行,重启面板生效" v-model="allSetting.timeLocation"></setting-list-item>
7784
</a-list>

0 commit comments

Comments
 (0)