tgf / internal /bot /validator.go
Mohammad Shahid
.
f592c10
package bot
import (
"context"
"fmt"
"strings"
"time"
"github.com/celestix/gotgproto"
"github.com/celestix/gotgproto/sessionMaker"
"github.com/glebarez/sqlite"
"go.uber.org/zap"
)
// BotInfo contains information about a validated bot
type BotInfo struct {
ID int64 `json:"id"`
Username string `json:"username"`
FirstName string `json:"first_name"`
IsBot bool `json:"is_bot"`
}
// BotValidator handles bot token validation
type BotValidator struct {
log *zap.Logger
}
// NewBotValidator creates a new bot validator
func NewBotValidator(log *zap.Logger) *BotValidator {
return &BotValidator{
log: log.Named("BotValidator"),
}
}
// ValidateBotToken validates a bot token and returns bot information
func (bv *BotValidator) ValidateBotToken(token string) (*BotInfo, error) {
// Basic token format validation
if !bv.isValidTokenFormat(token) {
return nil, fmt.Errorf("invalid token format")
}
// Create a temporary client to test the token
_, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Use a temporary session file
tempSessionPath := fmt.Sprintf("/tmp/validate_%d.session", time.Now().UnixNano())
client, err := gotgproto.NewClient(
0, // We don't need API ID/Hash for bot validation
"",
gotgproto.ClientTypeBot(token),
&gotgproto.ClientOpts{
Session: sessionMaker.SqlSession(
sqlite.Open(tempSessionPath),
),
DisableCopyright: true,
},
)
if err != nil {
bv.log.Error("Failed to create validation client", zap.Error(err))
return nil, fmt.Errorf("invalid bot token: %w", err)
}
// Clean up the temporary session
defer func() {
if client != nil {
client.Stop()
}
}()
// Get bot information
self := client.Self
if self == nil {
return nil, fmt.Errorf("failed to get bot information")
}
if !self.Bot {
return nil, fmt.Errorf("token belongs to a user account, not a bot")
}
botInfo := &BotInfo{
ID: self.ID,
Username: self.Username,
FirstName: self.FirstName,
IsBot: self.Bot,
}
bv.log.Info("Successfully validated bot token",
zap.Int64("botID", botInfo.ID),
zap.String("username", botInfo.Username))
return botInfo, nil
}
// isValidTokenFormat checks if the token has the correct format
func (bv *BotValidator) isValidTokenFormat(token string) bool {
// Bot tokens have format: {bot_id}:{auth_token}
// Example: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz
if len(token) < 35 || len(token) > 50 {
return false
}
parts := strings.Split(token, ":")
if len(parts) != 2 {
return false
}
// First part should be numeric (bot ID)
botID := parts[0]
if len(botID) < 8 || len(botID) > 12 {
return false
}
for _, char := range botID {
if char < '0' || char > '9' {
return false
}
}
// Second part should be the auth token (alphanumeric + some special chars)
authToken := parts[1]
if len(authToken) < 25 || len(authToken) > 40 {
return false
}
return true
}
// TestBotPermissions tests if the bot has necessary permissions
func (bv *BotValidator) TestBotPermissions(token string) error {
// This could be extended to test specific permissions
// For now, just validate that we can create a client
_, err := bv.ValidateBotToken(token)
return err
}