package rpc import ( "bytes" "encoding/json" "io" "strings" "unicode/utf8" ) type envelope struct { Version int `json:"v"` Type string `json:"type"` ID string `json:"id,omitempty"` Method string `json:"method,omitempty"` Params json.RawMessage `json:"params,omitempty"` Result json.RawMessage `json:"result,omitempty"` Error *Error `json:"error,omitempty"` TimeoutMS int64 `json:"timeoutMs,omitempty"` } func validName(s string, max int) bool { if s == "" || len(s) > max { return false } for _, c := range s { if !(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || strings.ContainsRune("._-/:", c)) { return false } } return true } func validError(e *Error) bool { return e != nil && validName(e.Code, 64) && len(e.Message) <= 1024 && utf8.ValidString(e.Message) } func decode(data []byte, limit int) (envelope, error) { var e envelope if len(data) > limit || !utf8.Valid(data) { return e, ErrProtocol } // Reject duplicate keys at every depth instead of accepting last-key-wins. scan := json.NewDecoder(bytes.NewReader(data)) scan.UseNumber() if err := uniqueValue(scan, 0); err != nil { return e, ErrProtocol } if _, err := scan.Token(); err != io.EOF { return e, ErrProtocol } d := json.NewDecoder(bytes.NewReader(data)) d.DisallowUnknownFields() if err := d.Decode(&e); err != nil { return e, ErrProtocol } if e.Version != 1 || e.TimeoutMS < 0 || e.TimeoutMS > int64((24*60*60)*1000) { return e, ErrProtocol } switch e.Type { case "call": if !validName(e.ID, 64) || !validName(e.Method, 128) || len(e.Params) == 0 || len(e.Result) != 0 || e.Error != nil { return e, ErrProtocol } case "event": if e.ID != "" || !validName(e.Method, 128) || len(e.Params) == 0 || len(e.Result) != 0 || e.Error != nil || e.TimeoutMS != 0 { return e, ErrProtocol } case "reply": if !validName(e.ID, 64) || e.Method != "" || len(e.Params) != 0 || e.TimeoutMS != 0 || (len(e.Result) == 0) == (e.Error == nil) || (e.Error != nil && !validError(e.Error)) { return e, ErrProtocol } case "cancel": if !validName(e.ID, 64) || e.Method != "" || len(e.Params) != 0 || len(e.Result) != 0 || e.Error != nil || e.TimeoutMS != 0 { return e, ErrProtocol } default: return e, ErrProtocol } return e, nil } func uniqueValue(d *json.Decoder, depth int) error { if depth > 32 { return ErrProtocol } t, err := d.Token() if err != nil { return err } delim, ok := t.(json.Delim) if !ok { return nil } switch delim { case '{': seen := make(map[string]bool) for d.More() { k, err := d.Token() if err != nil { return err } key, ok := k.(string) if !ok || seen[key] { return ErrProtocol } seen[key] = true if err := uniqueValue(d, depth+1); err != nil { return err } } t, err = d.Token() if err != nil || t != json.Delim('}') { return ErrProtocol } case '[': for d.More() { if err := uniqueValue(d, depth+1); err != nil { return err } } t, err = d.Token() if err != nil || t != json.Delim(']') { return ErrProtocol } default: return ErrProtocol } return nil }