138 lines
4.1 KiB
Go
138 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/nacorid/naco-api/internal/server"
|
|
)
|
|
|
|
func main() {
|
|
facilitatorURL := os.Getenv("X402_FACILITATOR_URL")
|
|
if facilitatorURL == "" {
|
|
facilitatorURL = "https://api.cdp.coinbase.com/platform/v2/x402"
|
|
}
|
|
|
|
isMogami := strings.Contains(facilitatorURL, "mogami.tech")
|
|
isPayAI := strings.Contains(facilitatorURL, "payai.network")
|
|
isCDP := strings.Contains(facilitatorURL, "cdp.coinbase.com")
|
|
|
|
var req *http.Request
|
|
var err error
|
|
|
|
if isMogami || isPayAI {
|
|
// Mogami and PayAI facilitators don't require auth
|
|
req, err = http.NewRequestWithContext(context.Background(), "GET", facilitatorURL+"/supported", nil)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
if isPayAI {
|
|
fmt.Println("Using PayAI facilitator (no auth)")
|
|
} else {
|
|
fmt.Println("Using Mogami facilitator (no auth)")
|
|
}
|
|
} else if isCDP {
|
|
keyName := os.Getenv("CDP_API_KEY_ID")
|
|
privateKeyPEM := os.Getenv("CDP_API_SECRET")
|
|
|
|
if keyName == "" || privateKeyPEM == "" {
|
|
fmt.Fprintf(os.Stderr, "CDP_API_KEY_ID and CDP_API_SECRET must be set for CDP facilitator\n")
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Debug: print key info
|
|
fmt.Fprintf(os.Stderr, "DEBUG: keyName=%s, secretLen=%d\n", keyName, len(privateKeyPEM))
|
|
fmt.Fprintf(os.Stderr, "DEBUG: secretStart=%s\n", privateKeyPEM[:min(80, len(privateKeyPEM))])
|
|
fmt.Fprintf(os.Stderr, "DEBUG: hasLiteralNewline=%v, hasActualNewline=%v\n",
|
|
strings.Contains(privateKeyPEM, "\\n"),
|
|
strings.Contains(privateKeyPEM, "\n"))
|
|
|
|
// Test key parsing manually first
|
|
processedPEM := strings.ReplaceAll(privateKeyPEM, "\\n", "\n")
|
|
fmt.Fprintf(os.Stderr, "DEBUG: after replaceAll, startsWith=%s\n", processedPEM[:min(50, len(processedPEM))])
|
|
|
|
block, _ := pem.Decode([]byte(processedPEM))
|
|
if block != nil {
|
|
fmt.Fprintf(os.Stderr, "DEBUG: pem block type=%s, bytes=%d\n", block.Type, len(block.Bytes))
|
|
if strings.Contains(block.Type, "EC PRIVATE KEY") {
|
|
if _, err := x509.ParseECPrivateKey(block.Bytes); err == nil {
|
|
fmt.Fprintf(os.Stderr, "DEBUG: parsed as SEC1 EC key\n")
|
|
} else if parsed, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
|
|
fmt.Fprintf(os.Stderr, "DEBUG: parsed as PKCS8 key, type=%T\n", parsed)
|
|
}
|
|
}
|
|
}
|
|
|
|
auth, err := server.NewCDPAuth(keyName, privateKeyPEM)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to create CDP auth: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Fprintf(os.Stderr, "DEBUG: auth created, signingMethod=%v\n", auth.GetSigningMethod())
|
|
|
|
headers, err := auth.GetAuthHeaders(context.Background())
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to get auth headers: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Debug: print generated tokens
|
|
for name, header := range map[string]string{
|
|
"Verify": headers.Verify["Authorization"],
|
|
"Settle": headers.Settle["Authorization"],
|
|
"Supported": headers.Supported["Authorization"],
|
|
} {
|
|
if len(header) > 7 {
|
|
token := header[7:] // strip "Bearer "
|
|
if parts := strings.Split(token, "."); len(parts) == 3 {
|
|
if payload, err := base64.RawURLEncoding.DecodeString(parts[1]); err == nil {
|
|
fmt.Fprintf(os.Stderr, "DEBUG: %s token claims: %s\n", name, string(payload))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
req, err = http.NewRequestWithContext(context.Background(), "GET", facilitatorURL+"/supported", nil)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
for k, v := range headers.Supported {
|
|
req.Header.Set(k, v)
|
|
}
|
|
fmt.Println("Using CDP facilitator (with auth)")
|
|
} else {
|
|
fmt.Fprintf(os.Stderr, "Unknown facilitator URL: %s\n", facilitatorURL)
|
|
os.Exit(1)
|
|
}
|
|
|
|
httpClient := &http.Client{
|
|
Timeout: 30 * time.Second,
|
|
}
|
|
resp, err := httpClient.Do(req)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
maxBytes := int64(5 * 1024 * 1024)
|
|
body, err := io.ReadAll(io.LimitReader(resp.Body, maxBytes))
|
|
if err != nil {
|
|
fmt.Printf("failed reading response body: %v", err)
|
|
}
|
|
|
|
fmt.Printf("Status: %d\n", resp.StatusCode)
|
|
fmt.Printf("Response: %s\n", body)
|
|
}
|