state.mx raw
1 package main
2
3 import (
4 "smesh.lol/web/common/helpers"
5 "smesh.lol/web/common/jsbridge/subtle"
6 "smesh.lol/web/common/jsbridge/sw"
7 )
8
9 // Shared state.
10 var (
11 dmSubIDs map[string]bool
12 dmRelayURLs []string
13 cryptoCBs map[int]func(string, string)
14 nextCryptoID int
15 )
16
17 func initSharedState() {
18 dmSubIDs = map[string]bool{}
19 cryptoCBs = map[int]func(string, string){}
20 }
21
22 func sendToClient(clientID, msg string) {
23 sw.GetClientByID(clientID, func(c sw.Client, ok bool) {
24 if ok {
25 sw.PostMessageJSON(c, msg)
26 }
27 })
28 }
29
30 func broadcastToClients(msg string) {
31 sw.MatchClients(func(c sw.Client) {
32 sw.PostMessageJSON(c, msg)
33 })
34 }
35
36 func genCryptoID() int {
37 nextCryptoID++
38 return nextCryptoID
39 }
40
41 func requestCrypto(clientID, method, peerPubkey, data string, fn func(string, string)) {
42 id := genCryptoID()
43 cryptoCBs[id] = fn
44 broadcastToClients("[\"CRYPTO_REQ\"," + helpers.Itoa(int64(id)) + "," + jstr(method) + "," + jstr(peerPubkey) + "," + jstr(data) + "]")
45 // Timeout: clean up callback if signer never responds.
46 cbID := id
47 sw.SetTimeout(15000, func() {
48 if _, ok := cryptoCBs[cbID]; ok {
49 delete(cryptoCBs, cbID)
50 fn("", "timeout: signer did not respond")
51 }
52 })
53 }
54
55 func jstr(s string) string { return helpers.JsonString(s) }
56
57 func hexTo32(s string) [32]byte {
58 out, _ := helpers.HexDecode32(s)
59 return out
60 }
61
62 func random32() [32]byte {
63 var b [32]byte
64 subtle.RandomBytes(b[:])
65 return b
66 }
67
68 // jsonFieldRaw extracts a raw JSON value for the given key.
69 func jsonFieldRaw(s, key string) string {
70 kq := "\"" + key + "\""
71 for i := 0; i <= len(s)-len(kq); i++ {
72 if s[i:i+len(kq)] == kq {
73 j := i + len(kq)
74 for j < len(s) && (s[j] == ' ' || s[j] == ':') {
75 j++
76 }
77 if j < len(s) {
78 end := skipval(s, j)
79 if end > 0 {
80 return s[j:end]
81 }
82 }
83 }
84 }
85 return ""
86 }
87
88 // mw is a JSON array message walker.
89 type mw struct {
90 s string
91 i int
92 }
93
94 func newMW(s string) mw {
95 w := mw{s: s}
96 for w.i < len(s) && s[w.i] != '[' {
97 w.i++
98 }
99 if w.i < len(s) {
100 w.i++
101 }
102 return w
103 }
104
105 func (w *mw) sep() {
106 for w.i < len(w.s) {
107 c := w.s[w.i]
108 if c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != ',' {
109 break
110 }
111 w.i++
112 }
113 }
114
115 func (w *mw) str() string {
116 w.sep()
117 if w.i >= len(w.s) || w.s[w.i] != '"' {
118 return ""
119 }
120 w.i++
121 start := w.i
122 for w.i < len(w.s) && w.s[w.i] != '"' {
123 if w.s[w.i] == '\\' {
124 w.i++
125 }
126 w.i++
127 }
128 if w.i >= len(w.s) {
129 return ""
130 }
131 result := w.s[start:w.i]
132 w.i++
133 return result
134 }
135
136 func (w *mw) num() int64 {
137 w.sep()
138 neg := false
139 if w.i < len(w.s) && w.s[w.i] == '-' {
140 neg = true
141 w.i++
142 }
143 var n int64
144 for w.i < len(w.s) && w.s[w.i] >= '0' && w.s[w.i] <= '9' {
145 n = n*10 + int64(w.s[w.i]-'0')
146 w.i++
147 }
148 if neg {
149 n = -n
150 }
151 return n
152 }
153
154 func (w *mw) raw() string {
155 w.sep()
156 start := w.i
157 w.i = skipval(w.s, w.i)
158 if w.i < 0 {
159 w.i = len(w.s)
160 return ""
161 }
162 return w.s[start:w.i]
163 }
164
165 func (w *mw) strs() []string {
166 w.sep()
167 if w.i >= len(w.s) || w.s[w.i] != '[' {
168 return nil
169 }
170 w.i++
171 var out []string
172 for {
173 w.sep()
174 if w.i >= len(w.s) {
175 return out
176 }
177 if w.s[w.i] == ']' {
178 w.i++
179 return out
180 }
181 if w.s[w.i] != '"' {
182 return out
183 }
184 w.i++
185 start := w.i
186 for w.i < len(w.s) && w.s[w.i] != '"' {
187 if w.s[w.i] == '\\' {
188 w.i++
189 }
190 w.i++
191 }
192 if w.i < len(w.s) {
193 out = append(out, w.s[start:w.i])
194 w.i++
195 }
196 }
197 }
198
199 func skipval(s string, i int) int {
200 if i >= len(s) {
201 return -1
202 }
203 switch s[i] {
204 case '"':
205 i++
206 for i < len(s) {
207 if s[i] == '\\' {
208 i += 2
209 continue
210 }
211 if s[i] == '"' {
212 return i + 1
213 }
214 i++
215 }
216 return -1
217 case '{':
218 return skipBrack(s, i, '{', '}')
219 case '[':
220 return skipBrack(s, i, '[', ']')
221 case 't':
222 if i+4 <= len(s) {
223 return i + 4
224 }
225 return -1
226 case 'f':
227 if i+5 <= len(s) {
228 return i + 5
229 }
230 return -1
231 case 'n':
232 if i+4 <= len(s) {
233 return i + 4
234 }
235 return -1
236 default:
237 for i < len(s) && s[i] != ',' && s[i] != '}' && s[i] != ']' && s[i] != ' ' && s[i] != '\n' {
238 i++
239 }
240 return i
241 }
242 }
243
244 func skipBrack(s string, i int, open, close byte) int {
245 depth := 1
246 i++
247 inStr := false
248 for i < len(s) && depth > 0 {
249 if inStr {
250 if s[i] == '\\' {
251 i++
252 } else if s[i] == '"' {
253 inStr = false
254 }
255 } else {
256 switch s[i] {
257 case '"':
258 inStr = true
259 case open:
260 depth++
261 case close:
262 depth--
263 }
264 }
265 i++
266 }
267 if depth != 0 {
268 return -1
269 }
270 return i
271 }
272