diff --git a/config.go b/config.go index 9f848f27..a6d73cff 100644 --- a/config.go +++ b/config.go @@ -135,6 +135,7 @@ type config struct { Key []byte Salt []byte AllowInsecure bool + SignatureSize int Secret string @@ -176,6 +177,7 @@ var conf = config{ MaxSrcDimension: 8192, MaxSrcResolution: 16800000, AllowInsecure: false, + SignatureSize: 32, Quality: 80, GZipCompression: 5, UserAgent: fmt.Sprintf("imgproxy/%s", version), @@ -222,6 +224,7 @@ func init() { hexEnvConfig(&conf.Key, "IMGPROXY_KEY") hexEnvConfig(&conf.Salt, "IMGPROXY_SALT") + intEnvConfig(&conf.SignatureSize, "IMGPROXY_SIGNATURE_SIZE") hexFileConfig(&conf.Key, *keyPath) hexFileConfig(&conf.Salt, *saltPath) @@ -265,6 +268,9 @@ func init() { warning("Salt is not defined, so signature checking is disabled") conf.AllowInsecure = true } + if conf.SignatureSize < 1 || conf.SignatureSize > 32 { + log.Fatalf("Signature size should be within 1 and 32, now - %d\n", conf.SignatureSize) + } if len(conf.Bind) == 0 { log.Fatalln("Bind address is not defined") diff --git a/crypt.go b/crypt.go index 9344a5c4..8a373d06 100644 --- a/crypt.go +++ b/crypt.go @@ -18,14 +18,20 @@ func validatePath(token, path string) error { return errInvalidTokenEncoding } - mac := hmac.New(sha256.New, conf.Key) - mac.Write(conf.Salt) - mac.Write([]byte(path)) - expectedMAC := mac.Sum(nil) - - if !hmac.Equal(messageMAC, expectedMAC) { + if !hmac.Equal(messageMAC, signatureFor(path)) { return errInvalidToken } return nil } + +func signatureFor(str string) []byte { + mac := hmac.New(sha256.New, conf.Key) + mac.Write(conf.Salt) + mac.Write([]byte(str)) + expectedMAC := mac.Sum(nil) + if conf.SignatureSize < 32 { + return expectedMAC[:conf.SignatureSize] + } + return expectedMAC +} diff --git a/crypt_test.go b/crypt_test.go new file mode 100644 index 00000000..c753ee0f --- /dev/null +++ b/crypt_test.go @@ -0,0 +1,21 @@ +package main + +import ( + "encoding/base64" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSignatureFor(t *testing.T) { + oldSignatureSize := conf.SignatureSize + base64Signature := func(x string) string { return base64.RawURLEncoding.EncodeToString(signatureFor(x)) } + conf.Key = []byte("test-key") + conf.Salt = []byte("test-salt") + assert.Equal(t, "dtLwhdnPPiu_epMl1LrzheLpvHas-4mwvY6L3Z8WwlY", base64Signature("asd")) + assert.Equal(t, "8x1xvzxVqZ3Uz3kEC8gVvBfU0dfU1vKv0Gho8m3Ysgw", base64Signature("qwe")) + conf.SignatureSize = 8 + assert.Equal(t, "dtLwhdnPPis", base64Signature("asd")) + assert.Equal(t, "8x1xvzxVqZ0", base64Signature("qwe")) + conf.SignatureSize = oldSignatureSize +} diff --git a/docs/configuration.md b/docs/configuration.md index dd410732..340bfd96 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -8,6 +8,7 @@ imgproxy allows URLs to be signed with a key and salt. This feature is disabled * `IMGPROXY_KEY`: hex-encoded key; * `IMGPROXY_SALT`: hex-encoded salt; +* `IMGPROXY_SIGNATURE_SIZE`: number of bytes to use for signature before encoding to Base64. Default: 32; You can also specify paths to files with a hex-encoded key and salt (useful in a development environment): @@ -87,7 +88,7 @@ There are two ways to define presets: ##### Using an environment variable -* `IMGPROXY_PRESETS`: set of preset definitions, comma-divided. Example: `default=resize_type:fill/enlarge:1,sharp=sharpen:0.7,blurry=blur:2`. Default: blank. +* `IMGPROXY_PRESETS`: set of preset definitions, comma-divided. Example: `default=resizing_type:fill/enlarge:1,sharp=sharpen:0.7,blurry=blur:2`. Default: blank. ##### Using a command line argument @@ -98,7 +99,7 @@ $ imgproxy -presets /path/to/file/with/presets The file should contain preset definitions, one per line. Lines starting with `#` are treated as comments. Example: ``` -default=resize_type:fill/enlarge:1 +default=resizing_type:fill/enlarge:1 # Sharpen the image to make it look better sharp=sharpen:0.7