-
Notifications
You must be signed in to change notification settings - Fork 68
/
common.go
131 lines (108 loc) · 2.83 KB
/
common.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package bot
import (
"crypto/hmac"
"crypto/sha256"
"encoding/json"
"fmt"
"math/rand"
"net/url"
"sort"
"strings"
"sync"
"time"
"github.com/go-telegram/bot/models"
)
// escape special symbols in text for MarkdownV2 parse mode
var shouldBeEscaped = "_*[]()~`>#+-=|{}.!"
// EscapeMarkdown escapes special symbols for Telegram MarkdownV2 syntax
func EscapeMarkdown(s string) string {
var result []rune
for _, r := range s {
if strings.ContainsRune(shouldBeEscaped, r) {
result = append(result, '\\')
}
result = append(result, r)
}
return string(result)
}
// EscapeMarkdownUnescaped escapes unescaped special symbols for Telegram Markdown v2 syntax
func EscapeMarkdownUnescaped(s string) string {
var result []rune
var escaped bool
for _, r := range s {
if r == '\\' {
escaped = !escaped
result = append(result, r)
continue
}
if strings.ContainsRune(shouldBeEscaped, r) && !escaped {
result = append(result, '\\')
}
escaped = false
result = append(result, r)
}
return string(result)
}
// log functions
// random string generator
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
var randSrc = rand.NewSource(time.Now().UnixNano())
var randSrcMx sync.Mutex
// RandomString returns random a-zA-Z string with n length
func RandomString(n int) string {
b := make([]byte, n)
// A randSrc.Int63() generates 63 random bits, enough for letterIdxMax characters!
randSrcMx.Lock()
ch := randSrc.Int63()
randSrcMx.Unlock()
for i, remain := n-1, letterIdxMax; i >= 0; {
if remain == 0 {
randSrcMx.Lock()
ch, remain = randSrc.Int63(), letterIdxMax
randSrcMx.Unlock()
}
if idx := int(ch & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
ch >>= letterIdxBits
remain--
}
return string(b)
}
// ValidateWebappRequest validates request from webapp
func ValidateWebappRequest(values url.Values, token string) (user *models.User, ok bool) {
h := values.Get("hash")
values.Del("hash")
var vals []string
var u models.User
for k, v := range values {
vv, _ := url.QueryUnescape(v[0])
vals = append(vals, k+"="+vv)
if k == "user" {
errDecodeUser := json.Unmarshal([]byte(vv), &u)
if errDecodeUser != nil {
return nil, false
}
}
}
sort.Slice(vals, func(i, j int) bool {
return vals[i] < vals[j]
})
hmac1 := hmac.New(sha256.New, []byte("WebAppData"))
hmac1.Write([]byte(token))
r1 := hmac1.Sum(nil)
data := []byte(strings.Join(vals, "\n"))
hmac2 := hmac.New(sha256.New, r1)
hmac2.Write(data)
r2 := hmac2.Sum(nil)
if h != fmt.Sprintf("%x", r2) {
return nil, false
}
return &u, true
}