package main import ( "context" "encoding/base64" "fmt" "os" "os/exec" "strings" "github.com/nbd-wtf/go-nostr" "github.com/urfave/cli/v3" "golang.org/x/exp/slices" ) var curlFlags []string var curl = &cli.Command{ Name: "curl", Usage: "calls curl but with a nip98 header", Description: "accepts all flags and arguments exactly as they would be passed to curl.", Flags: defaultKeyFlags, DisableSliceFlagSeparator: true, Action: func(ctx context.Context, c *cli.Command) error { kr, _, err := gatherKeyerFromArguments(ctx, c) if err != nil { return err } // cowboy parsing of curl flags to get the data we need for nip98 var url string var method string var presumedMethod string curlBodyBuildingFlags := []string{ "-d", "--data", "--data-binary", "--data-ascii", "--data-raw", "--data-urlencode", "-F", "--form", "--form-string", "--form-escape", "--upload-file", } nextIsMethod := false for _, f := range curlFlags { if nextIsMethod { method = f method, _ = strings.CutPrefix(method, `"`) method, _ = strings.CutSuffix(method, `"`) method = strings.ToUpper(method) } else if strings.HasPrefix(f, "https://") || strings.HasPrefix(f, "http://") { url = f } else if f == "--request" || f == "-X" { nextIsMethod = true continue } else if slices.Contains(curlBodyBuildingFlags, f) || slices.ContainsFunc(curlBodyBuildingFlags, func(s string) bool { return strings.HasPrefix(f, s) }) { presumedMethod = "POST" } nextIsMethod = false } if url == "" { return fmt.Errorf("can't create nip98 event: target url is empty") } if method == "" { if presumedMethod != "" { method = presumedMethod } else { method = "GET" } } // make and sign event evt := nostr.Event{ Kind: 27235, CreatedAt: nostr.Now(), Tags: nostr.Tags{ {"u", url}, {"method", method}, }, } if err := kr.SignEvent(ctx, &evt); err != nil { return err } // the first 2 indexes of curlFlags were reserved for this curlFlags[0] = "-H" curlFlags[1] = fmt.Sprintf("Authorization: Nostr %s", base64.StdEncoding.EncodeToString([]byte(evt.String()))) // call curl cmd := exec.Command("curl", curlFlags...) cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Run() return nil }, } func realCurl() error { curlFlags = make([]string, 2, max(len(os.Args)-4, 2)) keyFlags := make([]string, 0, 5) for i := 0; i < len(os.Args[2:]); i++ { arg := os.Args[i+2] if slices.ContainsFunc(defaultKeyFlags, func(f cli.Flag) bool { bareArg, _ := strings.CutPrefix(arg, "-") bareArg, _ = strings.CutPrefix(bareArg, "-") return slices.Contains(f.Names(), bareArg) }) { keyFlags = append(keyFlags, arg) if arg != "--prompt-sec" { i++ val := os.Args[i+2] keyFlags = append(keyFlags, val) } } else { curlFlags = append(curlFlags, arg) } } return curl.Run(context.Background(), keyFlags) }