Files

117 lines
3.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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()
}