Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go.mod1
-rw-r--r--web/service/tgbot.go946
-rw-r--r--web/translation/translate.en_US.toml23
-rw-r--r--web/translation/translate.es_ES.toml25
-rw-r--r--web/translation/translate.fa_IR.toml25
-rw-r--r--web/translation/translate.id_ID.toml25
-rw-r--r--web/translation/translate.ja_JP.toml25
-rw-r--r--web/translation/translate.pt_BR.toml25
-rw-r--r--web/translation/translate.ru_RU.toml25
-rw-r--r--web/translation/translate.tr_TR.toml25
-rw-r--r--web/translation/translate.uk_UA.toml25
-rw-r--r--web/translation/translate.vi_VN.toml25
-rw-r--r--web/translation/translate.zh_CN.toml25
-rw-r--r--web/translation/translate.zh_TW.toml25
14 files changed, 1201 insertions, 44 deletions
diff --git a/go.mod b/go.mod
index a014b0c7..43ac4d44 100644
--- a/go.mod
+++ b/go.mod
@@ -7,6 +7,7 @@ require (
github.com/gin-contrib/sessions v1.0.2
github.com/gin-gonic/gin v1.10.0
github.com/goccy/go-json v0.10.5
+ github.com/google/uuid v1.6.0
github.com/mymmrac/telego v0.32.0
github.com/nicksnyder/go-i18n/v2 v2.5.1
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
diff --git a/web/service/tgbot.go b/web/service/tgbot.go
index 9e217124..3764d71a 100644
--- a/web/service/tgbot.go
+++ b/web/service/tgbot.go
@@ -1,12 +1,16 @@
package service
import (
+ "crypto/rand"
"embed"
+ "encoding/base64"
"errors"
"fmt"
+ "math/big"
"net"
"net/url"
"os"
+ "regexp"
"strconv"
"strings"
"time"
@@ -20,8 +24,7 @@ import (
"x-ui/web/locale"
"x-ui/xray"
- "slices"
-
+ "github.com/google/uuid"
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
tu "github.com/mymmrac/telego/telegoutil"
@@ -30,14 +33,38 @@ import (
)
var (
- bot *telego.Bot
- botHandler *th.BotHandler
- adminIds []int64
- isRunning bool
- hostname string
- hashStorage *global.HashStorage
+ bot *telego.Bot
+ botHandler *th.BotHandler
+ adminIds []int64
+ isRunning bool
+ hostname string
+ hashStorage *global.HashStorage
+ handler *th.Handler
+
+ // clients data to adding new client
+ receiver_inbound_ID int
+ client_Id string
+ client_Flow string
+ client_Email string
+ client_LimitIP int
+ client_TotalGB int64
+ client_ExpiryTime int64
+ client_Enable bool
+ client_TgID string
+ client_SubID string
+ client_Comment string
+ client_Reset int
+ client_Security string
+ client_ShPassword string
+ client_TrPassword string
+ client_Method string
+
)
+
+var userStates = make(map[int64]string)
+
+
type LoginStatus byte
const (
@@ -46,6 +73,8 @@ const (
EmptyTelegramUserID = int64(0)
)
+
+
type Tgbot struct {
inboundService InboundService
settingService SettingService
@@ -54,6 +83,7 @@ type Tgbot struct {
lastStatus *Status
}
+
func (t *Tgbot) NewTgbot() *Tgbot {
return new(Tgbot)
}
@@ -223,36 +253,161 @@ func (t *Tgbot) OnReceive() {
botHandler, _ = th.NewBotHandler(bot, updates)
botHandler.HandleMessage(func(_ *telego.Bot, message telego.Message) {
+ delete(userStates, message.Chat.ID)
t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.keyboardClosed"), tu.ReplyKeyboardRemove())
}, th.TextEqual(t.I18nBot("tgbot.buttons.closeKeyboard")))
botHandler.HandleMessage(func(_ *telego.Bot, message telego.Message) {
+ delete(userStates, message.Chat.ID)
t.answerCommand(&message, message.Chat.ID, checkAdmin(message.From.ID))
}, th.AnyCommand())
botHandler.HandleCallbackQuery(func(_ *telego.Bot, query telego.CallbackQuery) {
+ delete(userStates,query.Message.GetChat().ID)
t.answerCallback(&query, checkAdmin(query.From.ID))
}, th.AnyCallbackQueryWithMessage())
botHandler.HandleMessage(func(_ *telego.Bot, message telego.Message) {
- if message.UsersShared != nil {
- if checkAdmin(message.From.ID) {
- for _, sharedUser := range message.UsersShared.Users {
- userID := sharedUser.UserID
- needRestart, err := t.inboundService.SetClientTelegramUserID(message.UsersShared.RequestID, userID)
- if needRestart {
- t.xrayService.SetToNeedRestart()
- }
- output := ""
- if err != nil {
- output += t.I18nBot("tgbot.messages.selectUserFailed")
- } else {
- output += t.I18nBot("tgbot.messages.userSaved")
+ if userState, exists := userStates[message.Chat.ID]; exists {
+ switch userState {
+ case "awaiting_id":
+ if client_Id == strings.TrimSpace(message.Text) {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ inbound, _ := t.inboundService.GetInbound(receiver_inbound_ID)
+ message_text, _ := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+ t.addClient(message.Chat.ID, message_text)
+ return
+ }
+
+ client_Id = strings.TrimSpace(message.Text)
+ if t.isSingleWord(client_Id) {
+ userStates[message.Chat.ID] = "awaiting_id"
+
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+
+ t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup)
+ } else {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_id"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ inbound, _ := t.inboundService.GetInbound(receiver_inbound_ID)
+ message_text, _ := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+ t.addClient(message.Chat.ID, message_text)
+ }
+ case "awaiting_password_tr":
+ if client_TrPassword == strings.TrimSpace(message.Text) {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ return
+ }
+
+ client_TrPassword = strings.TrimSpace(message.Text)
+ if t.isSingleWord(client_TrPassword) {
+ userStates[message.Chat.ID] = "awaiting_password_tr"
+
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+
+ t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup)
+ } else {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_password"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ inbound, _ := t.inboundService.GetInbound(receiver_inbound_ID)
+ message_text, _ := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+ t.addClient(message.Chat.ID, message_text)
+ }
+ case "awaiting_password_sh":
+ if client_ShPassword == strings.TrimSpace(message.Text) {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ return
+ }
+
+ client_ShPassword = strings.TrimSpace(message.Text)
+ if t.isSingleWord(client_ShPassword) {
+ userStates[message.Chat.ID] = "awaiting_password_sh"
+
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+
+ t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup)
+ } else {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_password"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ inbound, _ := t.inboundService.GetInbound(receiver_inbound_ID)
+ message_text, _ := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+ t.addClient(message.Chat.ID, message_text)
+ }
+ case "awaiting_email":
+ if client_Email == strings.TrimSpace(message.Text) {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ return
+ }
+
+ client_Email = strings.TrimSpace(message.Text)
+ if t.isSingleWord(client_Email) {
+ userStates[message.Chat.ID] = "awaiting_email"
+
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+
+ t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup)
+ } else {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_email"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ inbound, _ := t.inboundService.GetInbound(receiver_inbound_ID)
+ message_text, _ := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+ t.addClient(message.Chat.ID, message_text)
+ }
+ case "awaiting_comment":
+ if client_Comment == strings.TrimSpace(message.Text) {
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ return
+ }
+
+ client_Comment = strings.TrimSpace(message.Text)
+ t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_comment"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, message.Chat.ID)
+ inbound, _ := t.inboundService.GetInbound(receiver_inbound_ID)
+ message_text, _ := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+ t.addClient(message.Chat.ID, message_text)
+ }
+
+ } else {
+ if message.UsersShared != nil {
+ if checkAdmin(message.From.ID) {
+ for _, sharedUser := range message.UsersShared.Users {
+ userID := sharedUser.UserID
+ needRestart, err := t.inboundService.SetClientTelegramUserID(message.UsersShared.RequestID, userID)
+ if needRestart {
+ t.xrayService.SetToNeedRestart()
+ }
+ output := ""
+ if err != nil {
+ output += t.I18nBot("tgbot.messages.selectUserFailed")
+ } else {
+ output += t.I18nBot("tgbot.messages.userSaved")
+ }
+ t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove())
}
- t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove())
+ } else {
+ t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.noResult"), tu.ReplyKeyboardRemove())
}
- } else {
- t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.noResult"), tu.ReplyKeyboardRemove())
}
}
}, th.AnyMessage())
@@ -344,9 +499,31 @@ func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool
}
}
+
+func (t *Tgbot) randomLowerAndNum(length int) string {
+ charset := "abcdefghijklmnopqrstuvwxyz0123456789"
+ bytes := make([]byte, length)
+ for i := range bytes {
+ randomIndex, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
+ bytes[i] = charset[randomIndex.Int64()]
+ }
+ return string(bytes)
+}
+
+
+func (t *Tgbot) randomShadowSocksPassword() string {
+ array := make([]byte, 32)
+ _, err := rand.Read(array)
+ if err != nil {
+ return t.randomLowerAndNum(32)
+ }
+ return base64.StdEncoding.EncodeToString(array)
+}
+
+
func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) {
chatId := callbackQuery.Message.GetChat().ID
-
+
if isAdmin {
// get query from hash storage
decodedQuery, err := t.decodeQuery(callbackQuery.Data)
@@ -507,6 +684,78 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
}
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
+ case "add_client_limit_traffic_c":
+ limitTraffic, _ := strconv.Atoi(dataArray[1])
+ client_TotalGB = int64(limitTraffic) * 1024 * 1024 * 1024
+ messageId := callbackQuery.Message.GetMessageID()
+ inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
+ if err != nil {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
+ return
+ }
+ message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+
+ t.addClient(chatId,message_text,messageId)
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
+ case "add_client_limit_traffic_in":
+ if len(dataArray) >= 2 {
+ oldInputNumber, err := strconv.Atoi(dataArray[1])
+ inputNumber := oldInputNumber
+ if err == nil {
+ if len(dataArray) == 3 {
+ num, err := strconv.Atoi(dataArray[2])
+ if err == nil {
+ if num == -2 {
+ inputNumber = 0
+ } else if num == -1 {
+ if inputNumber > 0 {
+ inputNumber = (inputNumber / 10)
+ }
+ } else {
+ inputNumber = (inputNumber * 10) + num
+ }
+ }
+ if inputNumber == oldInputNumber {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
+ return
+ }
+ if inputNumber >= 999999 {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
+ return
+ }
+ }
+ inlineKeyboard := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmNumberAdd", "Num=="+strconv.Itoa(inputNumber))).WithCallbackData(t.encodeQuery("add_client_limit_traffic_c "+strconv.Itoa(inputNumber))),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("1").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 1")),
+ tu.InlineKeyboardButton("2").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 2")),
+ tu.InlineKeyboardButton("3").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 3")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("4").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 4")),
+ tu.InlineKeyboardButton("5").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 5")),
+ tu.InlineKeyboardButton("6").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 6")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("7").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 7")),
+ tu.InlineKeyboardButton("8").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 8")),
+ tu.InlineKeyboardButton("9").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 9")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("🔄").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" -2")),
+ tu.InlineKeyboardButton("0").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 0")),
+ tu.InlineKeyboardButton("⬅️").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" -1")),
+ ),
+ )
+ t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
+ return
+ }
+ }
case "reset_exp":
inlineKeyboard := tu.InlineKeyboard(
tu.InlineKeyboardRow(
@@ -638,6 +887,90 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
}
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
t.searchClient(chatId, email, callbackQuery.Message.GetMessageID())
+ case "add_client_reset_exp_c":
+ client_ExpiryTime = 0
+ days, _ := strconv.Atoi(dataArray[1])
+ var date int64 = 0
+ if client_ExpiryTime > 0 {
+ if client_ExpiryTime-time.Now().Unix()*1000 < 0 {
+ date = -int64(days * 24 * 60 * 60000)
+ } else {
+ date = client_ExpiryTime + int64(days*24*60*60000)
+ }
+ } else {
+ date = client_ExpiryTime - int64(days*24*60*60000)
+ }
+ client_ExpiryTime = date
+
+ messageId := callbackQuery.Message.GetMessageID()
+ inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
+ if err != nil {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
+ return
+ }
+ message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+
+ t.addClient(chatId,message_text,messageId)
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
+ case "add_client_reset_exp_in":
+ if len(dataArray) >= 2 {
+ oldInputNumber, err := strconv.Atoi(dataArray[1])
+ inputNumber := oldInputNumber
+ if err == nil {
+ if len(dataArray) == 3 {
+ num, err := strconv.Atoi(dataArray[2])
+ if err == nil {
+ if num == -2 {
+ inputNumber = 0
+ } else if num == -1 {
+ if inputNumber > 0 {
+ inputNumber = (inputNumber / 10)
+ }
+ } else {
+ inputNumber = (inputNumber * 10) + num
+ }
+ }
+ if inputNumber == oldInputNumber {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation"))
+ return
+ }
+ if inputNumber >= 999999 {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation"))
+ return
+ }
+ }
+ inlineKeyboard := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmNumber", "Num=="+strconv.Itoa(inputNumber))).WithCallbackData(t.encodeQuery("add_client_reset_exp_c "+strconv.Itoa(inputNumber))),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("1").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 1")),
+ tu.InlineKeyboardButton("2").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 2")),
+ tu.InlineKeyboardButton("3").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 3")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("4").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 4")),
+ tu.InlineKeyboardButton("5").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 5")),
+ tu.InlineKeyboardButton("6").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 6")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("7").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 7")),
+ tu.InlineKeyboardButton("8").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 8")),
+ tu.InlineKeyboardButton("9").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 9")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("🔄").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" -2")),
+ tu.InlineKeyboardButton("0").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 0")),
+ tu.InlineKeyboardButton("⬅️").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" -1")),
+ ),
+ )
+ t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
+ return
+ }
+ }
case "ip_limit":
inlineKeyboard := tu.InlineKeyboard(
tu.InlineKeyboardRow(
@@ -838,7 +1171,40 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
return
}
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseClient", "Inbound=="+inbound.Remark), clients)
+ case "add_client_to":
+ // assign default values to clients variables
+ client_Id = uuid.New().String()
+ client_Flow = ""
+ client_Email = t.randomLowerAndNum(8)
+ client_LimitIP = 0
+ client_TotalGB = 0
+ client_ExpiryTime = 0
+ client_Enable = true
+ client_TgID = ""
+ client_SubID = t.randomLowerAndNum(16)
+ client_Comment = ""
+ client_Reset = 0
+ client_Security="auto"
+ client_ShPassword=t.randomShadowSocksPassword()
+ client_TrPassword=t.randomLowerAndNum(10)
+ client_Method=""
+ inboundId := dataArray[1]
+ inboundIdInt, err := strconv.Atoi(inboundId)
+ if err != nil {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
+ return
+ }
+ receiver_inbound_ID = inboundIdInt
+ inbound, err := t.inboundService.GetInbound(inboundIdInt)
+ if err != nil {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
+ return
+ }
+
+ message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+
+ t.addClient(chatId, message_text)
}
return
} else {
@@ -892,11 +1258,325 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
case "commands":
t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.commands"))
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.helpAdminCommands"))
+ case "add_client":
+ // assign default values to clients variables
+ client_Id = uuid.New().String()
+ client_Flow = ""
+ client_Email = t.randomLowerAndNum(8)
+ client_LimitIP = 0
+ client_TotalGB = 0
+ client_ExpiryTime = 0
+ client_Enable = true
+ client_TgID = ""
+ client_SubID = t.randomLowerAndNum(16)
+ client_Comment = ""
+ client_Reset = 0
+ client_Security="auto"
+ client_ShPassword=t.randomShadowSocksPassword()
+ client_TrPassword=t.randomLowerAndNum(10)
+ client_Method=""
+
+ inbounds, err := t.getInboundsAddClient()
+ if err != nil {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
+ return
+ }
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.addClient"))
+ t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds)
+ case "add_client_ch_default_email":
+ t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
+ userStates[chatId] = "awaiting_email"
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+ prompt_message := t.I18nBot("tgbot.messages.email_prompt", "ClientEmail=="+client_Email)
+ t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
+ case "add_client_ch_default_id":
+ t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
+ userStates[chatId] = "awaiting_id"
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+ prompt_message := t.I18nBot("tgbot.messages.id_prompt", "ClientId=="+client_Id)
+ t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
+ case "add_client_ch_default_pass_tr":
+ t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
+ userStates[chatId] = "awaiting_password_tr"
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+ prompt_message := t.I18nBot("tgbot.messages.pass_prompt", "ClientPassword=="+client_TrPassword)
+ t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
+ case "add_client_ch_default_pass_sh":
+ t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
+ userStates[chatId] = "awaiting_password_sh"
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+ prompt_message := t.I18nBot("tgbot.messages.pass_prompt", "ClientPassword=="+client_ShPassword)
+ t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
+ case "add_client_ch_default_comment":
+ t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
+ userStates[chatId] = "awaiting_comment"
+ cancel_btn_markup := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"),
+ ),
+ )
+ prompt_message := t.I18nBot("tgbot.messages.comment_prompt", "ClientComment=="+client_Comment)
+ t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup)
+ case "add_client_ch_default_traffic":
+ inlineKeyboard := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 0")),
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_limit_traffic_in 0")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("1 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 1")),
+ tu.InlineKeyboardButton("5 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 5")),
+ tu.InlineKeyboardButton("10 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 10")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("20 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 20")),
+ tu.InlineKeyboardButton("30 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 30")),
+ tu.InlineKeyboardButton("40 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 40")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("50 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 50")),
+ tu.InlineKeyboardButton("60 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 60")),
+ tu.InlineKeyboardButton("80 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 80")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton("100 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 100")),
+ tu.InlineKeyboardButton("150 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 150")),
+ tu.InlineKeyboardButton("200 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 200")),
+ ),
+ )
+ t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
+ case "add_client_ch_default_exp":
+ inlineKeyboard := tu.InlineKeyboard(
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 0")),
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_reset_exp_in 0")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 7 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 7")),
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 10 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 10")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 14 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 14")),
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 20 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 20")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 1 "+t.I18nBot("tgbot.month")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 30")),
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 3 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 90")),
+ ),
+ tu.InlineKeyboardRow(
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 6 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 180")),
+ tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 12 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 365")),
+ ),
+ )
+ t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard)
+ case "add_client_default_info":
+ t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
+ t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove())
+ delete(userStates, chatId)
+ inbound, _ := t.inboundService.GetInbound(receiver_inbound_ID)
+ message_text, _ := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+ t.addClient(chatId, message_text)
+ case "add_client_cancel":
+ delete(userStates, chatId)
+ t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
+ t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.cancel"), 3, tu.ReplyKeyboardRemove())
+ case "add_client_default_traffic_exp":
+ messageId := callbackQuery.Message.GetMessageID()
+ inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
+ if err != nil {
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error())
+ return
+ }
+ message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol)
+ t.addClient(chatId,message_text,messageId)
+ t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+client_Email))
+ case "add_client_submit_disable":
+ client_Enable = false
+ _, err := t.SubmitAddClient()
+ if err != nil {
+ errorMessage := fmt.Sprintf("%v", err)
+ t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.error_add_client", "error=="+errorMessage), tu.ReplyKeyboardRemove())
+ } else {
+ t.deleteMessageTgBot(chatId, callbackQuery.Message.GetMessageID())
+ t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.successfulOperation"), tu.ReplyKeyboardRemove())
+ }
+ }
+}
+
+
+func (t *Tgbot) BuildInboundClientDataMessage(inbound_remark string ,protocol model.Protocol) (string, error) {
+ var message string
+
+ currentTime := time.Now()
+ timestampMillis := currentTime.UnixNano() / int64(time.Millisecond)
+
+ expiryTime := ""
+ diff := client_ExpiryTime/1000 - timestampMillis
+ if client_ExpiryTime == 0 {
+ expiryTime = t.I18nBot("tgbot.unlimited")
+ } else if diff > 172800 {
+ expiryTime = time.Unix((client_ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05")
+ } else if client_ExpiryTime < 0 {
+ expiryTime = fmt.Sprintf("%d %s", client_ExpiryTime/-86400000, t.I18nBot("tgbot.days"))
+ } else {
+ expiryTime = fmt.Sprintf("%d %s", diff/3600, t.I18nBot("tgbot.hours"))
+ }
+
+ traffic_value := ""
+ if client_TotalGB == 0 {
+ traffic_value = "♾️ Unlimited(Reset)"
+ }else {
+ traffic_value = common.FormatTraffic(client_TotalGB)
+ }
+
+ switch protocol {
+ case model.VMESS, model.VLESS:
+ message = t.I18nBot("tgbot.messages.inbound_client_data_id", "InboundRemark=="+inbound_remark,"ClientId=="+client_Id,"ClientEmail=="+client_Email,"ClientTraffic=="+traffic_value,"ClientExp=="+expiryTime,"ClientComment=="+client_Comment)
+
+ case model.Trojan:
+ message = t.I18nBot("tgbot.messages.inbound_client_data_pass", "InboundRemark=="+inbound_remark,"ClientPass=="+client_TrPassword,"ClientEmail=="+client_Email,"ClientTraffic=="+traffic_value,"ClientExp=="+expiryTime,"ClientComment=="+client_Comment)
+
+ case model.Shadowsocks:
+ message = t.I18nBot("tgbot.messages.inbound_client_data_pass", "InboundRemark=="+inbound_remark,"ClientPass=="+client_ShPassword,"ClientEmail=="+client_Email,"ClientTraffic=="+traffic_value,"ClientExp=="+expiryTime,"ClientComment=="+client_Comment)
+
+ default:
+ return "", errors.New("unknown protocol")
+ }
+
+ return message, nil
+}
+
+
+func (t *Tgbot) BuildJSONForProtocol(protocol model.Protocol) (string, error) {
+ var jsonString string
+
+ switch protocol {
+ case model.VMESS:
+ jsonString = fmt.Sprintf(`{
+ "clients": [{
+ "id": "%s",
+ "security": "%s",
+ "email": "%s",
+ "limitIp": %d,
+ "totalGB": %d,
+ "expiryTime": %d,
+ "enable": %t,
+ "tgId": "%s",
+ "subId": "%s",
+ "comment": "%s",
+ "reset": %d
+ }]
+ }`, client_Id, client_Security, client_Email, client_LimitIP, client_TotalGB, client_ExpiryTime, client_Enable, client_TgID, client_SubID, client_Comment, client_Reset)
+
+ case model.VLESS:
+ jsonString = fmt.Sprintf(`{
+ "clients": [{
+ "id": "%s",
+ "flow": "%s",
+ "email": "%s",
+ "limitIp": %d,
+ "totalGB": %d,
+ "expiryTime": %d,
+ "enable": %t,
+ "tgId": "%s",
+ "subId": "%s",
+ "comment": "%s",
+ "reset": %d
+ }]
+ }`, client_Id, client_Flow, client_Email, client_LimitIP, client_TotalGB, client_ExpiryTime, client_Enable, client_TgID, client_SubID, client_Comment, client_Reset)
+
+ case model.Trojan:
+ jsonString = fmt.Sprintf(`{
+ "clients": [{
+ "password": "%s",
+ "email": "%s",
+ "limitIp": %d,
+ "totalGB": %d,
+ "expiryTime": %d,
+ "enable": %t,
+ "tgId": "%s",
+ "subId": "%s",
+ "comment": "%s",
+ "reset": %d
+ }]
+ }`, client_TrPassword, client_Email, client_LimitIP, client_TotalGB, client_ExpiryTime, client_Enable, client_TgID, client_SubID, client_Comment, client_Reset)
+
+ case model.Shadowsocks:
+ jsonString = fmt.Sprintf(`{
+ "clients": [{
+ "method": "%s",
+ "password": "%s",
+ "email": "%s",
+ "limitIp": %d,
+ "totalGB": %d,
+ "expiryTime": %d,
+ "enable": %t,
+ "tgId": "%s",
+ "subId": "%s",
+ "comment": "%s",
+ "reset": %d
+ }]
+ }`, client_Method, client_ShPassword, client_Email, client_LimitIP, client_TotalGB, client_ExpiryTime, client_Enable, client_TgID, client_SubID, client_Comment, client_Reset)
+
+ default:
+ return "", errors.New("unknown protocol")
+ }
+
+ return jsonString, nil
+}
+
+
+func (t *Tgbot) SubmitAddClient() (bool, error) {
+
+
+ inbound, err := t.inboundService.GetInbound(receiver_inbound_ID)
+ if err != nil {
+ logger.Warning("getIboundClients run failed:", err)
+ return false, errors.New(t.I18nBot("tgbot.answers.getInboundsFailed"))
}
+
+
+
+ jsonString, err := t.BuildJSONForProtocol(inbound.Protocol)
+
+ newInbound := &model.Inbound{
+ Id: receiver_inbound_ID,
+ Settings: jsonString,
+ }
+
+
+ return t.inboundService.AddInboundClient(newInbound)
}
func checkAdmin(tgId int64) bool {
- return slices.Contains(adminIds, tgId)
+ for _, adminId := range adminIds {
+ if adminId == tgId {
+ return true
+ }