From 5befdc9c851f285000c15abc01a08010c719b307 Mon Sep 17 00:00:00 2001 From: tjpcc Date: Sun, 3 Sep 2023 08:01:38 -0600 Subject: sw-convert and sw-fetch tools --- tools/sw-fetch/main.go | 134 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tools/sw-fetch/main.go (limited to 'tools/sw-fetch') diff --git a/tools/sw-fetch/main.go b/tools/sw-fetch/main.go new file mode 100644 index 0000000..ccf8ac8 --- /dev/null +++ b/tools/sw-fetch/main.go @@ -0,0 +1,134 @@ +package main + +import ( + "crypto/tls" + "fmt" + "io" + "net/url" + "os" + + "tildegit.org/tjp/sliderule" + "tildegit.org/tjp/sliderule/gemini" +) + +const usage = `Resource fetcher for the small web. + +Usage: + sw-fetch (-h | --help) + sw-fetch [-v | --verbose] [-o PATH | --output PATH] [-k | --keyfile PATH] [ -c | --certfile PATH ] [ -s | --skip-verify ] URL + +Options: + -h --help Show this screen. + -v --verbose Display more diagnostic information on standard error. + -o --output PATH Send the fetched resource to PATH instead of standard out. + -k --keyfile PATH Path to the TLS key file to use. + -c --certfile PATH Path to the TLS certificate file to use. + -s --skip-verify Don't verify server TLS certificates. +` + +func main() { + conf := configure() + cl := sliderule.NewClient(conf.clientTLS) + + response, err := cl.Fetch(conf.url.String()) + if err != nil { + fail(err.Error() + "\n") + } + defer func() { + _ = response.Close() + _ = conf.output.Close() + }() + + _, _ = io.Copy(conf.output, response.Body) +} + +type config struct { + verbose bool + output io.WriteCloser + url *url.URL + clientTLS *tls.Config +} + +func configure() config { + if len(os.Args) == 1 { + fail(usage) + } + + conf := config{output: os.Stdout} + key := "" + cert := "" + verify := true + + for i := 1; i <= len(os.Args)-1; i += 1 { + switch os.Args[i] { + case "-h", "--help": + os.Stdout.WriteString(usage) + os.Exit(0) + case "-v", "--verbose": + conf.verbose = true + case "-o", "--output": + if i+1 == len(os.Args)-1 { + fail(usage) + } + + out := os.Args[i+1] + if out != "-" { + output, err := os.OpenFile(out, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + fmt.Println(err.Error()) + failf("'%s' is not a valid path\n", out) + } + conf.output = output + } + + i += 1 + case "-k", "--keyfile": + if i+1 == len(os.Args)-1 { + fail(usage) + } + + i += 1 + key = os.Args[i] + case "-c", "--certfile": + if i+1 == len(os.Args)-1 { + fail(usage) + } + + i += 1 + cert = os.Args[i] + case "-s", "--skip-verify": + verify = false + } + } + + conf.clientTLS = &tls.Config{} + if key != "" || cert != "" { + if key == "" || cert == "" { + fail("-k|--keyfile and -c|--certfile must both be present, or neither\n") + } + tlsConf, err := gemini.FileTLS(cert, key) + if err != nil { + failf("failed to load TLS key pair") + } + conf.clientTLS = tlsConf + } + conf.clientTLS.InsecureSkipVerify = !verify + + u, err := url.Parse(os.Args[len(os.Args)-1]) + if err != nil || u.Scheme == "" { + fail(usage) + } + conf.url = u + + return conf +} + +func fail(msg string) { + os.Stderr.WriteString(msg) + os.Exit(1) +} + +func failf(msg string, args ...any) { + fmt.Fprintf(os.Stderr, msg, args...) + os.Exit(1) +} -- cgit v1.2.3