Last active
December 6, 2024 07:49
-
-
Save sanbiv/f932f27210479b98c0751c7f2bba96a1 to your computer and use it in GitHub Desktop.
Telegram WebApp: validate initData
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package telegram | |
import ( | |
"crypto/hmac" | |
"crypto/sha256" | |
"encoding/hex" | |
"encoding/json" | |
"errors" | |
"fmt" | |
"net/url" | |
"sort" | |
"strconv" | |
"strings" | |
) | |
type TelegramInitData struct { | |
AuthDate int | |
QueryID string | |
User TelegramInitDataUser | |
} | |
type TelegramInitDataUser struct { | |
ID int | |
FirstName string | |
LastName string | |
Username string | |
LanguageCode string | |
} | |
func hmacSha256(data, secret string) string { | |
h := hmac.New(sha256.New, []byte(secret)) | |
// Write Data to it | |
h.Write([]byte(data)) | |
return string(h.Sum(nil)) | |
} | |
func sortedKeys(qs url.Values) []string { | |
result := make([]string, 0, len(qs)) | |
for k := range qs { | |
result = append(result, k) | |
} | |
sort.Strings(result) | |
return result | |
} | |
func buildCheckString(qs url.Values) string { | |
keys := sortedKeys(qs) | |
values := make([]string, 0) | |
for _, k := range keys { | |
if k == "hash" { | |
continue | |
} | |
values = append(values, fmt.Sprintf("%s=%s", k, qs.Get(k))) | |
} | |
return strings.Join(values, "\n") | |
} | |
// ValidateTelegramInitData validates Web App input https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app | |
func ValidateTelegramInitData(initDataString, botToken string) (*TelegramInitData, error) { | |
//initDataString := r.URL.Query().Get("tgInitData") | |
if initDataString == "" { | |
return nil, errors.New("initData is empty") | |
} | |
qs, err := url.ParseQuery(initDataString) | |
if err != nil { | |
return nil, errors.New("initData is not a valid query string") | |
} | |
hash := qs.Get("hash") | |
checkString := buildCheckString(qs) | |
// WebAppData is needed. See: https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app | |
secretKey := hmacSha256(botToken, "WebAppData") | |
dataHash := hex.EncodeToString([]byte(hmacSha256(checkString, secretKey))) | |
//dataHash := hmacSha256(checkString, secretKey) | |
if dataHash == hash { | |
// data is from Telegram | |
authDate, _ := strconv.Atoi(qs.Get("auth_date")) | |
uid, _ := strconv.Atoi(qs.Get("user.id")) | |
userData := map[string]any{} | |
err := json.Unmarshal([]byte(qs.Get("user")), &userData) | |
if err != nil { | |
return nil, errors.New("initData.user is not a valid json") | |
} | |
initData := &TelegramInitData{ | |
AuthDate: authDate, | |
QueryID: qs.Get("query_id"), | |
User: TelegramInitDataUser{ | |
ID: uid, | |
FirstName: userData["first_name"].(string), | |
LastName: userData["last_name"].(string), | |
Username: userData["username"].(string), | |
LanguageCode: userData["language_code"].(string), | |
}, | |
} | |
return initData, nil | |
} | |
return nil, errors.New("initData is invalid") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment