From ca8fe71a0a8aefed0dab1473b0005bc96c90fe01 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Tue, 11 Jun 2019 17:45:25 +0000 Subject: [PATCH] refactor imageproxy-sign to make testing easier --- cmd/imageproxy-sign/main.go | 35 ++++++++++------- cmd/imageproxy-sign/main_test.go | 66 ++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 14 deletions(-) diff --git a/cmd/imageproxy-sign/main.go b/cmd/imageproxy-sign/main.go index ecbb5d6..b7803dc 100644 --- a/cmd/imageproxy-sign/main.go +++ b/cmd/imageproxy-sign/main.go @@ -6,6 +6,7 @@ import ( "crypto/hmac" "crypto/sha256" "encoding/base64" + "errors" "flag" "fmt" "io/ioutil" @@ -17,38 +18,44 @@ import ( "willnorris.com/go/imageproxy" ) -var key = flag.String("key", "@/etc/imageproxy.key", "signing key, or file containing key prefixed with '@'") +var signingKey = flag.String("key", "@/etc/imageproxy.key", "signing key, or file containing key prefixed with '@'") var urlOnly = flag.Bool("url", false, "only sign the URL value, do not include options") func main() { flag.Parse() + u := flag.Arg(0) - if flag.NArg() < 1 { - fmt.Println("imageproxy-sign url [key]") + sig, err := sign(*signingKey, u, *urlOnly) + if err != nil { + fmt.Println(err) os.Exit(1) } - u := parseURL(flag.Arg(0)) + fmt.Printf("url: %v\n", u) + fmt.Printf("signature: %v\n", base64.URLEncoding.EncodeToString(sig)) +} + +func sign(key string, s string, urlOnly bool) ([]byte, error) { + if s == "" { + return nil, errors.New("imageproxy-sign url [key]") + } + + u := parseURL(s) if u == nil { - fmt.Printf("unable to parse URL: %v\n", flag.Arg(0)) - os.Exit(1) + return nil, fmt.Errorf("unable to parse URL: %v", s) } - if *urlOnly { + if urlOnly { u.Fragment = "" } - k, err := parseKey(*key) + k, err := parseKey(key) if err != nil { - fmt.Printf("error parsing key: %v", err) - os.Exit(1) + return nil, fmt.Errorf("error parsing key: %v", err) } mac := hmac.New(sha256.New, []byte(k)) mac.Write([]byte(u.String())) - sig := mac.Sum(nil) - - fmt.Printf("url: %v\n", u) - fmt.Printf("signature: %v\n", base64.URLEncoding.EncodeToString(sig)) + return mac.Sum(nil), nil } func parseKey(s string) ([]byte, error) { diff --git a/cmd/imageproxy-sign/main_test.go b/cmd/imageproxy-sign/main_test.go index 3244a72..ff03cbd 100644 --- a/cmd/imageproxy-sign/main_test.go +++ b/cmd/imageproxy-sign/main_test.go @@ -1,10 +1,76 @@ package main import ( + "io/ioutil" "net/url" + "os" + "reflect" "testing" ) +var key = "secret" + +func TestSign(t *testing.T) { + s := "http://example.com/image.jpg#0x0" + + got, err := sign(key, s, false) + if err != nil { + t.Errorf("sign(%q, %q, false) returned error: %v", key, s, err) + } + want := []byte{0xc3, 0x4c, 0x45, 0xb5, 0x75, 0x84, 0x76, 0xdf, 0xd9, 0x6b, 0x12, 0xa4, 0x84, 0x8f, 0x37, 0xc6, 0x2d, 0x8b, 0x8d, 0x77, 0xda, 0x6, 0xf8, 0xb5, 0x10, 0xc9, 0x96, 0x3c, 0x6e, 0x13, 0xda, 0xf0} + if !reflect.DeepEqual(got, want) { + t.Errorf("sign(%q, %q, true) returned %v, want %v", key, s, got, want) + } +} + +func TestSign_URLOnly(t *testing.T) { + s := "http://example.com/image.jpg#0x0" + + got, err := sign(key, s, true) + if err != nil { + t.Errorf("sign(%q, %q, true) returned error: %v", key, s, err) + } + want := []byte{0x93, 0xea, 0x5d, 0x23, 0x68, 0xa0, 0xfc, 0x50, 0x8e, 0x91, 0x7, 0xbf, 0x3e, 0xb3, 0x1f, 0x49, 0xf7, 0x1d, 0x81, 0xf1, 0x74, 0xfe, 0x25, 0x36, 0xfc, 0x74, 0xf8, 0x81, 0x15, 0xf5, 0x58, 0x40} + if !reflect.DeepEqual(got, want) { + t.Errorf("sign(%q, %q, true) returned %v, want %v", key, s, got, want) + } +} + +func TestParseKey(t *testing.T) { + k, err := parseKey(key) + got := string(k) + if err != nil { + t.Errorf("parseKey(%q) returned error: %v", key, err) + } + if want := key; got != want { + t.Errorf("parseKey(%q) returned %v, want %v", key, got, want) + } +} + +func TestParseKey_FilePath(t *testing.T) { + f, err := ioutil.TempFile("", "key") + if err != nil { + t.Errorf("error creating temp file: %v", err) + } + defer func() { + f.Close() + os.Remove(f.Name()) + }() + + if _, err := f.WriteString(key); err != nil { + t.Errorf("error writing to temp file: %v", err) + } + path := "@" + f.Name() + k, err := parseKey(path) + got := string(k) + if err != nil { + t.Errorf("parseKey(%q) returned error: %v", path, err) + } + if want := key; got != want { + t.Errorf("parseKey(%q) returned %v, want %v", path, got, want) + } +} + func TestParseURL(t *testing.T) { tests := []struct { input, output string