package control import ( "bytes" "context" "encoding/json" "io" "net/http" "net/http/httptest" "path/filepath" "testing" "time" rvboxv1 "github.com/rvbox/rvbox/gen/go/rvbox/v1" "github.com/rvbox/rvbox/internal/server/store" "google.golang.org/protobuf/encoding/protojson" ) func TestJSONRPCUnaryMatchesControlService_HP_CTL_15(t *testing.T) { persistence, err := store.Open(context.Background(), store.Options{DataDir: filepath.Join(t.TempDir(), "state"), BusyTimeout: time.Second}) if err != nil { t.Fatal(err) } defer persistence.Close() registerControlClient(t, persistence, "win-a", rvboxv1.Platform_PLATFORM_WINDOWS, rvboxv1.ShellType_SHELL_POWERSHELL, 9) service, err := NewService(Options{Store: persistence, CursorKey: bytesKey()}) if err != nil { t.Fatal(err) } handler := httptest.NewServer(NewJSONRPCHandler(service, 1<<20)) defer handler.Close() requestID := fixedIssue(0xaf).String() params, err := protojson.Marshal(&rvboxv1.RunCommandRequest{TargetClientId: "win-a", RequestId: requestID, Spec: &rvboxv1.ExecutionSpec{Source: &rvboxv1.ExecutionSpec_CommandText{CommandText: "echo rpc"}}}) if err != nil { t.Fatal(err) } body, _ := json.Marshal(map[string]any{"jsonrpc": "2.0", "id": 7, "method": "runCommand", "params": json.RawMessage(params)}) response, err := http.Post(handler.URL, "application/json", bytes.NewReader(body)) if err != nil { t.Fatal(err) } defer response.Body.Close() encoded, _ := io.ReadAll(response.Body) var envelope struct { Result json.RawMessage `json:"result"` Error json.RawMessage `json:"error"` } if err := json.Unmarshal(encoded, &envelope); err != nil || len(envelope.Error) != 0 { t.Fatalf("JSON-RPC response = %s, %v", encoded, err) } result := &rvboxv1.RunCommandResponse{} if err := protojson.Unmarshal(envelope.Result, result); err != nil || result.GetIssueUuid() != requestID { t.Fatalf("JSON-RPC result = %s, %v", envelope.Result, err) } unknown, _ := json.Marshal(map[string]any{"jsonrpc": "2.0", "id": "x", "method": "notARealMethod", "params": map[string]any{}}) unknownResponse, err := http.Post(handler.URL, "application/json", bytes.NewReader(unknown)) if err != nil { t.Fatal(err) } defer unknownResponse.Body.Close() unknownBody, _ := io.ReadAll(unknownResponse.Body) if !bytes.Contains(unknownBody, []byte(`-32601`)) { t.Fatalf("unknown method response = %s", unknownBody) } } func TestJSONRPCRejectsOversizeAndMalformedRequests_BH_CTL_16(t *testing.T) { persistence, err := store.Open(context.Background(), store.Options{DataDir: filepath.Join(t.TempDir(), "state"), BusyTimeout: time.Second}) if err != nil { t.Fatal(err) } defer persistence.Close() service, err := NewService(Options{Store: persistence, CursorKey: bytesKey()}) if err != nil { t.Fatal(err) } handler := httptest.NewServer(NewJSONRPCHandler(service, 16)) defer handler.Close() response, err := http.Post(handler.URL, "application/json", bytes.NewReader([]byte(`{"jsonrpc":"2.0","id":1,"method":"listClients","params":{}}`))) if err != nil { t.Fatal(err) } defer response.Body.Close() body, _ := io.ReadAll(response.Body) if !bytes.Contains(body, []byte(`-32600`)) { t.Fatalf("oversize response = %s", body) } malformed, err := http.Post(handler.URL, "application/json", bytes.NewReader([]byte(`{"jsonrpc":"2.0","id":1,"method":"listClients","params":{}}`[:16]))) if err != nil { t.Fatal(err) } defer malformed.Body.Close() malformedBody, _ := io.ReadAll(malformed.Body) if !bytes.Contains(malformedBody, []byte(`-32700`)) { t.Fatalf("malformed response = %s", malformedBody) } }