From f4d197084cd0d50ed0c73a4b838a2c882a9bcc05 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Tue, 12 Mar 2024 11:36:19 -0400 Subject: [PATCH] Fix profile image webp issue (#551) --- go.mod | 13 +++++++------ go.sum | 13 +++++++++++++ routes/global_state.go | 5 ++++- routes/media.go | 30 +++++++++++++++++++++--------- routes/transaction.go | 23 ++++++++++++++++++++++- 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index cdcecd6d..d4235bf8 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,8 @@ require ( github.com/stretchr/testify v1.8.0 github.com/tyler-smith/go-bip39 v1.1.0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/image v0.15.0 + golang.org/x/sync v0.1.0 google.golang.org/api v0.46.0 gopkg.in/DataDog/dd-trace-go.v1 v1.29.0 ) @@ -108,13 +109,13 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect go.opencensus.io v0.23.0 // indirect golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect - golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/net v0.6.0 // indirect golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c // indirect - golang.org/x/sys v0.0.0-20221010170243-090e33056c14 // indirect - golang.org/x/text v0.3.6 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.6.0 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab // indirect diff --git a/go.sum b/go.sum index 00904dfa..d04b4ea6 100644 --- a/go.sum +++ b/go.sum @@ -628,7 +628,10 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= +golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -655,6 +658,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -703,6 +707,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -729,6 +735,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -792,6 +800,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -802,6 +812,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -862,6 +874,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/routes/global_state.go b/routes/global_state.go index c478695c..3f761b3b 100644 --- a/routes/global_state.go +++ b/routes/global_state.go @@ -980,7 +980,10 @@ func (gs *GlobalState) Get(key []byte) (value []byte, _err error) { err := gs.GlobalStateDB.View(func(txn *badger.Txn) error { item, err := txn.Get(key) if err != nil { - return nil + if errors.Is(err, badger.ErrKeyNotFound) { + return nil + } + return err } retValue, err = item.ValueCopy(nil) if err != nil { diff --git a/routes/media.go b/routes/media.go index dc502821..95e25746 100644 --- a/routes/media.go +++ b/routes/media.go @@ -8,6 +8,8 @@ import ( "encoding/json" "fmt" "github.com/gorilla/mux" + "github.com/pkg/errors" + "golang.org/x/image/webp" "image" "io" "net/http" @@ -51,7 +53,7 @@ func (fes *APIServer) uploadSingleImage(image string, extension string) (_imageU if extension != ".gif" { var imageBytes []byte - imageBytes, err = resizeAndConvertFromEncodedImageContent(image, 1000) + imageBytes, err = resizeAndConvertFromEncodedImageContent(image, 1000, extension) if err != nil { return "", err } @@ -78,36 +80,46 @@ func getEncodedImageContent(encodedImageString string) string { return encodedImageString[strings.Index(encodedImageString, ",")+1:] } -func resizeAndConvertToWebp(encodedImageString string, maxDim uint) (_image []byte, _err error) { +func resizeAndConvertToWebp(encodedImageString string, maxDim uint, extension string) (_image []byte, _err error) { // Extract the relevant portion of the base64 encoded string and process the image. encodedImageContent := getEncodedImageContent(encodedImageString) - return resizeAndConvertFromEncodedImageContent(encodedImageContent, maxDim) + return resizeAndConvertFromEncodedImageContent(encodedImageContent, maxDim, extension) } // Prevent pixel flood attack. This function checks the image size before processing it. // Reference: https://github.com/h2non/bimg/issues/394#issuecomment-1015932411 -func validateImageSize(encodedImageContentBytes []byte) error { +func validateImageSize(encodedImageContentBytes []byte, extension string) error { byteReader := bytes.NewReader(encodedImageContentBytes) - imageConfig, _, err := image.DecodeConfig(byteReader) + var imageConfig image.Config + var err error + if extension == ".webp" { + imageConfig, err = webp.DecodeConfig(byteReader) + } else { + imageConfig, _, err = image.DecodeConfig(byteReader) + } if err != nil { - return err + return errors.Wrap(err, "validateImageSize: Problem decoding image config") } if imageConfig.Width > bimg.MaxSize || imageConfig.Height > bimg.MaxSize { - return fmt.Errorf("image too large. Max dimensions are %v x %v. ImageConfig dimensions are %v x %v", + return fmt.Errorf("validateImageSize: image too large. Max dimensions are %v x %v. ImageConfig dimensions are %v x %v", bimg.MaxSize, bimg.MaxSize, imageConfig.Width, imageConfig.Height) } return nil } -func resizeAndConvertFromEncodedImageContent(encodedImageContent string, maxDim uint) (_image []byte, _err error) { +func resizeAndConvertFromEncodedImageContent( + encodedImageContent string, + maxDim uint, + extension string, +) (_image []byte, _err error) { // always strip metadata processOptions := bimg.Options{StripMetadata: true} decodedBytes, err := base64.StdEncoding.DecodeString(encodedImageContent) if err != nil { return nil, err } - if err = validateImageSize(decodedBytes); err != nil { + if err = validateImageSize(decodedBytes, extension); err != nil { return nil, err } imgBytes, err := bimg.NewImage(decodedBytes).Process(processOptions) diff --git a/routes/transaction.go b/routes/transaction.go index 66571e32..e5c12cde 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -337,8 +337,29 @@ func (fes *APIServer) UpdateProfile(ww http.ResponseWriter, req *http.Request) { // If an image is set on the request then resize it. // Convert image to base64 by stripping the data: prefix. if requestData.NewProfilePic != "" { + // split on base64 to get the extension + extensionSplit := strings.Split(requestData.NewProfilePic, ";base64") + if len(extensionSplit) != 2 { + _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Problem parsing profile pic extension: %v", err)) + return + } + extension := extensionSplit[0] + switch { + case strings.Contains(extension, "image/png"): + extension = ".png" + case strings.Contains(extension, "image/jpeg"): + extension = ".jpeg" + case strings.Contains(extension, "image/webp"): + extension = ".webp" + case strings.Contains(extension, "image/gif"): + extension = ".gif" + default: + _AddBadRequestError(ww, fmt.Sprintf("UpdateProfile: Unsupported image type: %v", extension)) + return + } var resizedImageBytes []byte - resizedImageBytes, err = resizeAndConvertToWebp(requestData.NewProfilePic, uint(fes.Params.MaxProfilePicDimensions)) + resizedImageBytes, err = resizeAndConvertToWebp( + requestData.NewProfilePic, uint(fes.Params.MaxProfilePicDimensions), extension) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("Problem resizing profile picture: %v", err)) return