mirror of
https://github.com/willnorris/imageproxy.git
synced 2024-12-16 21:56:43 -05:00
add support for multiple signature keys (#209)
This commit is contained in:
parent
3bdd0fe8ed
commit
ef09c1ba31
3 changed files with 44 additions and 21 deletions
|
@ -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 referrers = flag.String("referrers", "", "comma separated list of allowed referring hosts")
|
||||||
var baseURL = flag.String("baseURL", "", "default base URL for relative remote URLs")
|
var baseURL = flag.String("baseURL", "", "default base URL for relative remote URLs")
|
||||||
var cache tieredCache
|
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 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 timeout = flag.Duration("timeout", 0, "time limit for requests served by this proxy")
|
||||||
var verbose = flag.Bool("verbose", false, "print verbose logging messages")
|
var verbose = flag.Bool("verbose", false, "print verbose logging messages")
|
||||||
|
@ -58,6 +58,7 @@ var userAgent = flag.String("userAgent", "willnorris/imageproxy", "specify the u
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.Var(&cache, "cache", "location to cache images (see https://github.com/willnorris/imageproxy#cache)")
|
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() {
|
func main() {
|
||||||
|
@ -77,18 +78,7 @@ func main() {
|
||||||
if *contentTypes != "" {
|
if *contentTypes != "" {
|
||||||
p.ContentTypes = strings.Split(*contentTypes, ",")
|
p.ContentTypes = strings.Split(*contentTypes, ",")
|
||||||
}
|
}
|
||||||
if *signatureKey != "" {
|
p.SignatureKeys = signatureKeyList
|
||||||
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
|
|
||||||
}
|
|
||||||
if *baseURL != "" {
|
if *baseURL != "" {
|
||||||
var err error
|
var err error
|
||||||
p.DefaultBaseURL, err = url.Parse(*baseURL)
|
p.DefaultBaseURL, err = url.Parse(*baseURL)
|
||||||
|
@ -112,6 +102,27 @@ func main() {
|
||||||
log.Fatal(http.ListenAndServe(*addr, nil))
|
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
|
// tieredCache allows specifying multiple caches via flags, which will create
|
||||||
// tiered caches using the twotier package.
|
// tiered caches using the twotier package.
|
||||||
type tieredCache struct {
|
type tieredCache struct {
|
||||||
|
|
|
@ -64,8 +64,9 @@ type Proxy struct {
|
||||||
// The Logger used by the image proxy
|
// The Logger used by the image proxy
|
||||||
Logger *log.Logger
|
Logger *log.Logger
|
||||||
|
|
||||||
// SignatureKey is the HMAC key used to verify signed requests.
|
// SignatureKeys is a list of HMAC keys used to verify signed requests.
|
||||||
SignatureKey []byte
|
// Any of them can be used to verify signed requests.
|
||||||
|
SignatureKeys [][]byte
|
||||||
|
|
||||||
// Allow images to scale beyond their original dimensions.
|
// Allow images to scale beyond their original dimensions.
|
||||||
ScaleUp bool
|
ScaleUp bool
|
||||||
|
@ -258,7 +259,7 @@ func (p *Proxy) allowed(r *Request) error {
|
||||||
return errDeniedHost
|
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
|
return nil // no allowed hosts or signature key, all requests accepted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,9 +267,11 @@ func (p *Proxy) allowed(r *Request) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(p.SignatureKey) > 0 && validSignature(p.SignatureKey, r) {
|
for _, signatureKey := range p.SignatureKeys {
|
||||||
|
if len(signatureKey) > 0 && validSignature(signatureKey, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return errNotAllowed
|
return errNotAllowed
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,13 @@ func TestCopyHeader(t *testing.T) {
|
||||||
|
|
||||||
func TestAllowed(t *testing.T) {
|
func TestAllowed(t *testing.T) {
|
||||||
allowHosts := []string{"good"}
|
allowHosts := []string{"good"}
|
||||||
key := []byte("c0ffee")
|
key := [][]byte{
|
||||||
|
[]byte("c0ffee"),
|
||||||
|
}
|
||||||
|
multipleKey := [][]byte{
|
||||||
|
[]byte("c0ffee"),
|
||||||
|
[]byte("beer"),
|
||||||
|
}
|
||||||
|
|
||||||
genRequest := func(headers map[string]string) *http.Request {
|
genRequest := func(headers map[string]string) *http.Request {
|
||||||
req := &http.Request{Header: make(http.Header)}
|
req := &http.Request{Header: make(http.Header)}
|
||||||
|
@ -132,7 +138,7 @@ func TestAllowed(t *testing.T) {
|
||||||
allowHosts []string
|
allowHosts []string
|
||||||
denyHosts []string
|
denyHosts []string
|
||||||
referrers []string
|
referrers []string
|
||||||
key []byte
|
keys [][]byte
|
||||||
request *http.Request
|
request *http.Request
|
||||||
allowed bool
|
allowed bool
|
||||||
}{
|
}{
|
||||||
|
@ -151,7 +157,10 @@ func TestAllowed(t *testing.T) {
|
||||||
|
|
||||||
// signature key
|
// 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, 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, 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},
|
{"http://test/image", emptyOptions, nil, nil, nil, key, nil, false},
|
||||||
|
|
||||||
// allowHosts and signature
|
// allowHosts and signature
|
||||||
|
@ -169,7 +178,7 @@ func TestAllowed(t *testing.T) {
|
||||||
p := NewProxy(nil, nil)
|
p := NewProxy(nil, nil)
|
||||||
p.AllowHosts = tt.allowHosts
|
p.AllowHosts = tt.allowHosts
|
||||||
p.DenyHosts = tt.denyHosts
|
p.DenyHosts = tt.denyHosts
|
||||||
p.SignatureKey = tt.key
|
p.SignatureKeys = tt.keys
|
||||||
p.Referrers = tt.referrers
|
p.Referrers = tt.referrers
|
||||||
|
|
||||||
u, err := url.Parse(tt.url)
|
u, err := url.Parse(tt.url)
|
||||||
|
|
Loading…
Reference in a new issue