package oauth import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "esauth/pkg/repository" "esauth/pkg/service" "esauth/pkg/util" "fmt" "net/http" "sort" "strconv" "strings" "time" "github.com/gin-gonic/gin" ) type TelegramOAuth struct { Service *service.Service Repo *repository.Repository BotId string BotToken string } func (t TelegramOAuth) HandleTelegramOAuthCallback(c *gin.Context) { // Получаем хеш и параметры из запроса. hash := c.Query("hash") // Собираем параметры для формирования data-check-string. params := map[string]string{ "id": c.Query("id"), "first_name": c.Query("first_name"), "last_name": c.Query("last_name"), "username": c.Query("username"), "auth_date": c.Query("auth_date"), "photo_url": c.Query("photo_url"), } // Удаляем пустые значения из параметров. var validParams []string for key, value := range params { if value != "" { validParams = append(validParams, fmt.Sprintf("%s=%s", key, value)) } } // Сортируем параметры в алфавитном порядке. sort.Strings(validParams) dataCheckString := strings.Join(validParams, "\n") // Генерируем секретный ключ через SHA256 от botToken. secretKey := sha256.Sum256([]byte(t.BotToken)) // Вычисляем HMAC-SHA256 от data-check-string с использованием secretKey. h := hmac.New(sha256.New, secretKey[:]) h.Write([]byte(dataCheckString)) calculatedHash := hex.EncodeToString(h.Sum(nil)) // Сравниваем вычисленный хеш с переданным. if calculatedHash != hash { util.NewErrorResponse(c, http.StatusBadRequest, "Invalid hash") return } // Проверка времени auth_date, чтобы избежать устаревших данных. date, _ := strconv.ParseInt(params["auth_date"], 10, 64) if time.Now().Unix()-int64(date) > 86400 { util.NewErrorResponse(c, http.StatusUnauthorized, "Authorization request expired") return } user, _ := t.Repo.FindUser("telegram_id = ?", params["id"]) usertoken := c.Query("usertoken") currentUserId, err := t.Service.ParseToken(usertoken) if err == nil { currentUser, _ := t.Repo.GetUser(currentUserId) if (user.Id != currentUser.Id) && (user.Id != 0) { util.NewErrorResponse(c, http.StatusUnauthorized, fmt.Sprintf("This account already conntected to user %d", user.Id)) return } user = currentUser } if user.Username == "" { user.Username = params["username"] } if user.FirstName == "" { user.FirstName = params["first_name"] } if user.LastName == "" { user.LastName = params["last_name"] } if user.PictureURL == "" { user.PictureURL = params["photo_url"] } if user.Email == "" { user.Email = "" } user.TelegramId = params["id"] _, err = t.Service.CreateUser(&user) if err != nil { t.Service.SaveUser(&user) } tkn, err := t.Service.GenerateToken(user.Id) if err != nil { util.NewErrorResponse(c, http.StatusUnauthorized, err.Error()) return } c.Redirect(http.StatusMovedPermanently, "/?token="+tkn) c.Abort() }