Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions cmd/imageproxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var denyHosts = flag.String("denyHosts", "", "comma separated list of denied rem
var referrers = flag.String("referrers", "", "comma separated list of allowed referring hosts")
var baseURL = flag.String("baseURL", "", "default base URL for relative remote URLs")
var cache tieredCache
var signatureKey = flag.String("signatureKey", "", "HMAC key used in calculating request signatures")
var signatureKeyList SignatureKeyList
var scaleUp = flag.Bool("scaleUp", false, "allow images to scale beyond their original dimensions")
var timeout = flag.Duration("timeout", 0, "time limit for requests served by this proxy")
var verbose = flag.Bool("verbose", false, "print verbose logging messages")
Expand All @@ -58,6 +58,7 @@ var userAgent = flag.String("userAgent", "willnorris/imageproxy", "specify the u

func init() {
flag.Var(&cache, "cache", "location to cache images (see https://github.com/willnorris/imageproxy#cache)")
flag.Var(&signatureKeyList, "signatureKey", "HMAC key used in calculating request signatures")
}

func main() {
Expand All @@ -77,18 +78,7 @@ func main() {
if *contentTypes != "" {
p.ContentTypes = strings.Split(*contentTypes, ",")
}
if *signatureKey != "" {
key := []byte(*signatureKey)
if strings.HasPrefix(*signatureKey, "@") {
file := strings.TrimPrefix(*signatureKey, "@")
var err error
key, err = ioutil.ReadFile(file)
if err != nil {
log.Fatalf("error reading signature file: %v", err)
}
}
p.SignatureKey = key
}
p.SignatureKeys = signatureKeyList
if *baseURL != "" {
var err error
p.DefaultBaseURL, err = url.Parse(*baseURL)
Expand All @@ -112,6 +102,27 @@ func main() {
log.Fatal(http.ListenAndServe(*addr, nil))
}

type SignatureKeyList [][]byte

func (skl *SignatureKeyList) String() string {
return fmt.Sprint(*skl)
}

func (skl *SignatureKeyList) Set(value string) error {
key := []byte(value)
if strings.HasPrefix(value, "@") {
file := strings.TrimPrefix(value, "@")
var err error
key, err = ioutil.ReadFile(file)
if err != nil {
log.Fatalf("error reading signature file: %v", err)
}
}

*skl = append(*skl, key)
return nil
}

// tieredCache allows specifying multiple caches via flags, which will create
// tiered caches using the twotier package.
type tieredCache struct {
Expand Down
13 changes: 8 additions & 5 deletions imageproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ type Proxy struct {
// The Logger used by the image proxy
Logger *log.Logger

// SignatureKey is the HMAC key used to verify signed requests.
SignatureKey []byte
// SignatureKeys is a list of HMAC keys used to verify signed requests.
// Any of them can be used to verify signed requests.
SignatureKeys [][]byte

// Allow images to scale beyond their original dimensions.
ScaleUp bool
Expand Down Expand Up @@ -258,16 +259,18 @@ func (p *Proxy) allowed(r *Request) error {
return errDeniedHost
}

if len(p.AllowHosts) == 0 && len(p.SignatureKey) == 0 {
if len(p.AllowHosts) == 0 && len(p.SignatureKeys) == 0 {
return nil // no allowed hosts or signature key, all requests accepted
}

if len(p.AllowHosts) > 0 && hostMatches(p.AllowHosts, r.URL) {
return nil
}

if len(p.SignatureKey) > 0 && validSignature(p.SignatureKey, r) {
return nil
for _, signatureKey := range p.SignatureKeys {
if len(signatureKey) > 0 && validSignature(signatureKey, r) {
return nil
}
}

return errNotAllowed
Expand Down
15 changes: 12 additions & 3 deletions imageproxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,13 @@ func TestCopyHeader(t *testing.T) {

func TestAllowed(t *testing.T) {
allowHosts := []string{"good"}
key := []byte("c0ffee")
key := [][]byte{
[]byte("c0ffee"),
}
multipleKey := [][]byte{
[]byte("c0ffee"),
[]byte("beer"),
}

genRequest := func(headers map[string]string) *http.Request {
req := &http.Request{Header: make(http.Header)}
Expand All @@ -132,7 +138,7 @@ func TestAllowed(t *testing.T) {
allowHosts []string
denyHosts []string
referrers []string
key []byte
keys [][]byte
request *http.Request
allowed bool
}{
Expand All @@ -151,7 +157,10 @@ func TestAllowed(t *testing.T) {

// signature key
{"http://test/image", Options{Signature: "NDx5zZHx7QfE8E-ijowRreq6CJJBZjwiRfOVk_mkfQQ="}, nil, nil, nil, key, nil, true},
{"http://test/image", Options{Signature: "NDx5zZHx7QfE8E-ijowRreq6CJJBZjwiRfOVk_mkfQQ="}, nil, nil, nil, multipleKey, nil, true}, // signed with key "c0ffee"
{"http://test/image", Options{Signature: "FWIawYV4SEyI4zKJMeGugM-eJM1eI_jXPEQ20ZgRe4A="}, nil, nil, nil, multipleKey, nil, true}, // signed with key "beer"
{"http://test/image", Options{Signature: "deadbeef"}, nil, nil, nil, key, nil, false},
{"http://test/image", Options{Signature: "deadbeef"}, nil, nil, nil, multipleKey, nil, false},
{"http://test/image", emptyOptions, nil, nil, nil, key, nil, false},

// allowHosts and signature
Expand All @@ -169,7 +178,7 @@ func TestAllowed(t *testing.T) {
p := NewProxy(nil, nil)
p.AllowHosts = tt.allowHosts
p.DenyHosts = tt.denyHosts
p.SignatureKey = tt.key
p.SignatureKeys = tt.keys
p.Referrers = tt.referrers

u, err := url.Parse(tt.url)
Expand Down