diff --git a/backend/mpc-system/test_signing_parties_api.go b/backend/mpc-system/test_signing_parties_api.go new file mode 100644 index 00000000..ba12f16e --- /dev/null +++ b/backend/mpc-system/test_signing_parties_api.go @@ -0,0 +1,293 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/google/uuid" +) + +type Claims struct { + SessionID string `json:"session_id"` + PartyID string `json:"party_id"` + TokenType string `json:"token_type"` + jwt.RegisteredClaims +} + +func generateAccessToken(secretKey, userID, username string) (string, error) { + now := time.Now() + claims := Claims{ + PartyID: username, + TokenType: "access", + RegisteredClaims: jwt.RegisteredClaims{ + ID: uuid.New().String(), + Issuer: "mpc-system", + Subject: userID, + IssuedAt: jwt.NewNumericDate(now), + NotBefore: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(24 * time.Hour)), + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString([]byte(secretKey)) +} + +func makeRequest(method, url string, body interface{}, token, apiKey string) (int, []byte, error) { + var reqBody io.Reader + if body != nil { + jsonData, err := json.Marshal(body) + if err != nil { + return 0, nil, err + } + reqBody = bytes.NewBuffer(jsonData) + } + + req, err := http.NewRequest(method, url, reqBody) + if err != nil { + return 0, nil, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-API-Key", apiKey) + req.Header.Set("Authorization", "Bearer "+token) + + client := &http.Client{Timeout: 10 * time.Second} + resp, err := client.Do(req) + if err != nil { + return 0, nil, err + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return 0, nil, err + } + + return resp.StatusCode, respBody, nil +} + +func main() { + // Get JWT secret from environment or use test value + jwtSecret := os.Getenv("JWT_SECRET_KEY") + if jwtSecret == "" { + jwtSecret = "change_this_jwt_secret_key_to_random_value_min_32_chars" + } + + // Generate access token + token, err := generateAccessToken(jwtSecret, "admin", "admin") + if err != nil { + fmt.Printf("Failed to generate token: %v\n", err) + os.Exit(1) + } + + // Get API key from environment or use test value + apiKey := os.Getenv("MPC_API_KEY") + if apiKey == "" { + apiKey = "test-api-key" + } + + // Use the wallet created from keygen test + username := "wallet-83a6d1d3" + baseURL := "http://localhost:4000/api/v1/accounts/by-username/" + username + "/signing-config" + + fmt.Println("===========================================") + fmt.Println("Testing Signing Parties Configuration APIs") + fmt.Println("===========================================") + fmt.Printf("Username: %s\n\n", username) + + // Test 1: GET - Query current signing parties configuration + fmt.Println("--------------------------------------------") + fmt.Println("Test 1: GET signing-config (Query)") + fmt.Println("--------------------------------------------") + status, body, err := makeRequest("GET", baseURL, nil, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Extract active parties from the response for later tests + var activeParties []string + var result map[string]interface{} + json.Unmarshal(body, &result) + if parties, ok := result["active_parties"].([]interface{}); ok { + for _, p := range parties { + if s, ok := p.(string); ok { + activeParties = append(activeParties, s) + } + } + } + fmt.Printf("\nActive parties found: %v\n", activeParties) + + if len(activeParties) < 2 { + fmt.Println("\nError: Need at least 2 active parties for testing") + os.Exit(1) + } + + // Test 2: POST - Set signing parties (select first 2 parties) + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 2: POST signing-config (Set)") + fmt.Println("--------------------------------------------") + signingParties := activeParties[:2] // Select first 2 parties + setData := map[string]interface{}{ + "party_ids": signingParties, + } + fmt.Printf("Setting signing parties to: %v\n", signingParties) + status, body, err = makeRequest("POST", baseURL, setData, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Test 3: GET - Query again to verify it was set + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 3: GET signing-config (Verify Set)") + fmt.Println("--------------------------------------------") + status, body, err = makeRequest("GET", baseURL, nil, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Test 4: POST again - Should fail (already configured) + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 4: POST signing-config (Should Fail - Already Set)") + fmt.Println("--------------------------------------------") + status, body, err = makeRequest("POST", baseURL, setData, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d (expected 409 Conflict)\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Test 5: PUT - Update signing parties (use different combination if possible) + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 5: PUT signing-config (Update)") + fmt.Println("--------------------------------------------") + var updateParties []string + if len(activeParties) >= 3 { + // If we have 3 parties, use parties 2 and 3 (different combination) + updateParties = []string{activeParties[1], activeParties[2]} + } else { + // Otherwise, reverse the order + updateParties = []string{signingParties[1], signingParties[0]} + } + updateData := map[string]interface{}{ + "party_ids": updateParties, + } + fmt.Printf("Updating signing parties to: %v\n", updateParties) + status, body, err = makeRequest("PUT", baseURL, updateData, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Test 6: GET - Query to verify update + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 6: GET signing-config (Verify Update)") + fmt.Println("--------------------------------------------") + status, body, err = makeRequest("GET", baseURL, nil, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Test 7: DELETE - Clear signing parties configuration + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 7: DELETE signing-config (Clear)") + fmt.Println("--------------------------------------------") + status, body, err = makeRequest("DELETE", baseURL, nil, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Test 8: GET - Query to verify cleared + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 8: GET signing-config (Verify Cleared)") + fmt.Println("--------------------------------------------") + status, body, err = makeRequest("GET", baseURL, nil, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Test 9: DELETE again - Should fail (not configured) + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 9: DELETE signing-config (Should Fail - Not Configured)") + fmt.Println("--------------------------------------------") + status, body, err = makeRequest("DELETE", baseURL, nil, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d (expected 404 Not Found)\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + // Test 10: PUT when not configured - Should fail + fmt.Println("\n--------------------------------------------") + fmt.Println("Test 10: PUT signing-config (Should Fail - Not Configured)") + fmt.Println("--------------------------------------------") + status, body, err = makeRequest("PUT", baseURL, setData, token, apiKey) + if err != nil { + fmt.Printf("Error: %v\n", err) + } else { + fmt.Printf("Status: %d (expected 404 Not Found)\n", status) + var result map[string]interface{} + json.Unmarshal(body, &result) + prettyJSON, _ := json.MarshalIndent(result, "", " ") + fmt.Printf("Response:\n%s\n", prettyJSON) + } + + fmt.Println("\n===========================================") + fmt.Println("All tests completed!") + fmt.Println("===========================================") +}