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