state.go raw

   1  package main
   2  
   3  import (
   4  	"common/helpers"
   5  	"common/jsbridge/sw"
   6  )
   7  
   8  // Shared state not yet assigned to a specific domain.
   9  var (
  10  	cryptoCBs    map[int]func(string, string)
  11  	nextCryptoID int
  12  )
  13  
  14  func initSharedState() {
  15  	cryptoCBs = make(map[int]func(string, string))
  16  }
  17  
  18  // cryptoProxy sends a crypto request to the page's signer extension
  19  // and calls cb with (result, error) when CRYPTO_RESULT comes back.
  20  func cryptoProxy(method, peerPubkey, data string, cb func(string, string)) {
  21  	id := nextCryptoID
  22  	nextCryptoID++
  23  	cryptoCBs[id] = cb
  24  	sw.Log("shell: crypto→page " + method + " #" + helpers.Itoa(int64(id)))
  25  	broadcastToClients("[\"CRYPTO_REQ\"," + helpers.Itoa(int64(id)) + "," + jstr(method) + "," + jstr(peerPubkey) + "," + jstr(data) + "]")
  26  	capturedID := id
  27  	sw.SetTimeout(15000, func() {
  28  		if fn, ok := cryptoCBs[capturedID]; ok {
  29  			delete(cryptoCBs, capturedID)
  30  			sw.Log("shell: crypto TIMEOUT #" + helpers.Itoa(int64(capturedID)))
  31  			fn("", "crypto proxy timeout")
  32  		}
  33  	})
  34  }
  35  
  36  // --- Shared utilities ---
  37  
  38  func sendToClient(clientID, msg string) {
  39  	if clientID == "" {
  40  		broadcastToClients(msg)
  41  		return
  42  	}
  43  	sw.GetClientByID(clientID, func(c sw.Client, ok bool) {
  44  		if ok {
  45  			sw.PostMessageJSON(c, msg)
  46  		} else {
  47  			// Client gone (tab closed, reloaded) — broadcast to all windows.
  48  			sw.Log("shell: client gone " + clientID[:8] + "… → broadcast")
  49  			broadcastToClients(msg)
  50  		}
  51  	})
  52  }
  53  
  54  func broadcastToClients(msg string) {
  55  	sw.MatchClients(func(c sw.Client) {
  56  		sw.PostMessageJSON(c, msg)
  57  	})
  58  }
  59  
  60  func jstr(s string) string { return helpers.JsonString(s) }
  61  
  62  // mw is a JSON array message walker for parsing client messages.
  63  type mw struct {
  64  	s string
  65  	i int
  66  }
  67  
  68  func newMW(s string) mw {
  69  	w := mw{s: s}
  70  	for w.i < len(s) && s[w.i] != '[' {
  71  		w.i++
  72  	}
  73  	if w.i < len(s) {
  74  		w.i++
  75  	}
  76  	return w
  77  }
  78  
  79  func (w *mw) sep() {
  80  	for w.i < len(w.s) {
  81  		c := w.s[w.i]
  82  		if c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != ',' {
  83  			break
  84  		}
  85  		w.i++
  86  	}
  87  }
  88  
  89  func (w *mw) str() string {
  90  	w.sep()
  91  	if w.i >= len(w.s) || w.s[w.i] != '"' {
  92  		return ""
  93  	}
  94  	w.i++
  95  	var buf []byte
  96  	hasEsc := false
  97  	start := w.i
  98  	for w.i < len(w.s) && w.s[w.i] != '"' {
  99  		if w.s[w.i] == '\\' && w.i+1 < len(w.s) {
 100  			hasEsc = true
 101  			buf = append(buf, w.s[start:w.i]...)
 102  			w.i++
 103  			switch w.s[w.i] {
 104  			case '"', '\\', '/':
 105  				buf = append(buf, w.s[w.i])
 106  			case 'n':
 107  				buf = append(buf, '\n')
 108  			case 't':
 109  				buf = append(buf, '\t')
 110  			case 'r':
 111  				buf = append(buf, '\r')
 112  			case 'u':
 113  				if w.i+4 < len(w.s) {
 114  					var cp int
 115  					for k := 1; k <= 4; k++ {
 116  						c := w.s[w.i+k]
 117  						cp <<= 4
 118  						if c >= '0' && c <= '9' {
 119  							cp |= int(c - '0')
 120  						} else if c >= 'a' && c <= 'f' {
 121  							cp |= int(c-'a') + 10
 122  						} else if c >= 'A' && c <= 'F' {
 123  							cp |= int(c-'A') + 10
 124  						}
 125  					}
 126  					if cp < 0x80 {
 127  						buf = append(buf, byte(cp))
 128  					} else if cp < 0x800 {
 129  						buf = append(buf, byte(0xC0|(cp>>6)), byte(0x80|(cp&0x3F)))
 130  					} else {
 131  						buf = append(buf, byte(0xE0|(cp>>12)), byte(0x80|((cp>>6)&0x3F)), byte(0x80|(cp&0x3F)))
 132  					}
 133  					w.i += 4
 134  				} else {
 135  					buf = append(buf, '\\', 'u')
 136  				}
 137  			default:
 138  				buf = append(buf, '\\', w.s[w.i])
 139  			}
 140  			w.i++
 141  			start = w.i
 142  			continue
 143  		}
 144  		w.i++
 145  	}
 146  	if w.i >= len(w.s) {
 147  		return ""
 148  	}
 149  	var result string
 150  	if hasEsc {
 151  		buf = append(buf, w.s[start:w.i]...)
 152  		result = string(buf)
 153  	} else {
 154  		result = w.s[start:w.i]
 155  	}
 156  	w.i++
 157  	return result
 158  }
 159  
 160  func (w *mw) num() int64 {
 161  	w.sep()
 162  	neg := false
 163  	if w.i < len(w.s) && w.s[w.i] == '-' {
 164  		neg = true
 165  		w.i++
 166  	}
 167  	var n int64
 168  	for w.i < len(w.s) && w.s[w.i] >= '0' && w.s[w.i] <= '9' {
 169  		n = n*10 + int64(w.s[w.i]-'0')
 170  		w.i++
 171  	}
 172  	if neg {
 173  		n = -n
 174  	}
 175  	return n
 176  }
 177  
 178  func (w *mw) raw() string {
 179  	w.sep()
 180  	start := w.i
 181  	w.i = skipval(w.s, w.i)
 182  	if w.i < 0 {
 183  		w.i = len(w.s)
 184  		return ""
 185  	}
 186  	return w.s[start:w.i]
 187  }
 188  
 189  func (w *mw) strs() []string {
 190  	w.sep()
 191  	if w.i >= len(w.s) || w.s[w.i] != '[' {
 192  		return nil
 193  	}
 194  	w.i++
 195  	var out []string
 196  	for {
 197  		w.sep()
 198  		if w.i >= len(w.s) {
 199  			return out
 200  		}
 201  		if w.s[w.i] == ']' {
 202  			w.i++
 203  			return out
 204  		}
 205  		if w.s[w.i] != '"' {
 206  			return out
 207  		}
 208  		out = append(out, w.str())
 209  	}
 210  }
 211  
 212  func skipval(s string, i int) int {
 213  	if i >= len(s) {
 214  		return -1
 215  	}
 216  	switch s[i] {
 217  	case '"':
 218  		i++
 219  		for i < len(s) {
 220  			if s[i] == '\\' {
 221  				i += 2
 222  				continue
 223  			}
 224  			if s[i] == '"' {
 225  				return i + 1
 226  			}
 227  			i++
 228  		}
 229  		return -1
 230  	case '{':
 231  		return skipBrack(s, i, '{', '}')
 232  	case '[':
 233  		return skipBrack(s, i, '[', ']')
 234  	case 't':
 235  		if i+4 <= len(s) {
 236  			return i + 4
 237  		}
 238  		return -1
 239  	case 'f':
 240  		if i+5 <= len(s) {
 241  			return i + 5
 242  		}
 243  		return -1
 244  	case 'n':
 245  		if i+4 <= len(s) {
 246  			return i + 4
 247  		}
 248  		return -1
 249  	default:
 250  		for i < len(s) && s[i] != ',' && s[i] != '}' && s[i] != ']' && s[i] != ' ' && s[i] != '\n' {
 251  			i++
 252  		}
 253  		return i
 254  	}
 255  }
 256  
 257  func skipBrack(s string, i int, open, close byte) int {
 258  	depth := 1
 259  	i++
 260  	inStr := false
 261  	for i < len(s) && depth > 0 {
 262  		if inStr {
 263  			if s[i] == '\\' {
 264  				i++
 265  			} else if s[i] == '"' {
 266  				inStr = false
 267  			}
 268  		} else {
 269  			switch s[i] {
 270  			case '"':
 271  				inStr = true
 272  			case open:
 273  				depth++
 274  			case close:
 275  				depth--
 276  			}
 277  		}
 278  		i++
 279  	}
 280  	if depth != 0 {
 281  		return -1
 282  	}
 283  	return i
 284  }
 285