sign.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. package initdata
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha256"
  5. "encoding/hex"
  6. "net/url"
  7. "sort"
  8. "strconv"
  9. "strings"
  10. "time"
  11. )
  12. // Sign signs passed payload using specified key. Function removes such
  13. // technical parameters as "hash" and "auth_date".
  14. func Sign(payload map[string]string, key string, authDate time.Time) string {
  15. pairs := make([]string, 0, len(payload)+1)
  16. // Extract all key-value pairs and add them to pairs slice.
  17. for k, v := range payload {
  18. // Skip technical fields.
  19. if k == "hash" || k == "auth_date" {
  20. continue
  21. }
  22. // Append new pair.
  23. pairs = append(pairs, k+"="+v)
  24. }
  25. // Append sign date.
  26. pairs = append(pairs, "auth_date="+strconv.FormatInt(authDate.Unix(), 10))
  27. // According to docs, we sort all the pairs in alphabetical order.
  28. sort.Strings(pairs)
  29. // Perform signing.
  30. return sign(strings.Join(pairs, "\n"), key)
  31. }
  32. // SignQueryString signs passed query string.
  33. func SignQueryString(qs, key string, authDate time.Time) (string, error) {
  34. // Parse query string.
  35. qp, err := url.ParseQuery(qs)
  36. if err != nil {
  37. return "", err
  38. }
  39. // Convert query params to map[string]string.
  40. m := make(map[string]string, len(qp))
  41. for k, v := range qp {
  42. m[k] = v[0]
  43. }
  44. return Sign(m, key, authDate), nil
  45. }
  46. // Performs payload subscription. Payload itself slice of key-value pairs
  47. // joined with "\n".
  48. func sign(payload, key string) string {
  49. skHmac := hmac.New(sha256.New, []byte("WebAppData"))
  50. skHmac.Write([]byte(key))
  51. impHmac := hmac.New(sha256.New, skHmac.Sum(nil))
  52. impHmac.Write([]byte(payload))
  53. return hex.EncodeToString(impHmac.Sum(nil))
  54. }