diff --git a/_assets/tests/UbuntuMono-Regular.ttf b/_assets/tests/UbuntuMono-Regular.ttf new file mode 100644 index 000000000..fdd309d71 Binary files /dev/null and b/_assets/tests/UbuntuMono-Regular.ttf differ diff --git a/server/handlers.go b/server/handlers.go index e0fc9ce0d..e5717d154 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -353,22 +353,22 @@ func handleAccountImagesImpl(multiaccountsDB *multiaccounts.Database, logger *za if accColorHash == nil { if parsed.PublicKey == "" { logger.Error("handleAccountImagesImpl: no public key for color hash", zap.String("keyUid", parsed.KeyUID)) - return } accColorHash, err = colorhash.GenerateFor(parsed.PublicKey) if err != nil { logger.Error("handleAccountImagesImpl: could not generate color hash", zap.String("keyUid", parsed.KeyUID), zap.Error(err)) - return } } - payload, err = ring.DrawRing(&ring.DrawRingParam{ - Theme: parsed.Theme, ColorHash: accColorHash, ImageBytes: payload, Height: identityImage.Height, Width: identityImage.Width, RingWidth: parsed.RingWidth * enlargeRatio, - }) - if err != nil { - logger.Error("handleAccountImagesImpl: failed to draw ring for account identity", zap.Error(err)) - return + if accColorHash != nil { + payload, err = ring.DrawRing(&ring.DrawRingParam{ + Theme: parsed.Theme, ColorHash: accColorHash, ImageBytes: payload, Height: identityImage.Height, Width: identityImage.Width, RingWidth: parsed.RingWidth * enlargeRatio, + }) + if err != nil { + logger.Error("handleAccountImagesImpl: failed to draw ring for account identity", zap.Error(err)) + return + } } } @@ -499,23 +499,23 @@ func handleAccountInitialsImpl(multiaccountsDB *multiaccounts.Database, logger * if accColorHash == nil { if parsed.PublicKey == "" { logger.Error("handleAccountInitialsImpl: no public key, can't draw ring", zap.String("keyUid", parsed.KeyUID), zap.Error(err)) - return } accColorHash, err = colorhash.GenerateFor(parsed.PublicKey) if err != nil { logger.Error("handleAccountInitialsImpl: failed to generate color hash from pubkey", zap.String("keyUid", parsed.KeyUID), zap.Error(err)) - return } } - payload, err = ring.DrawRing(&ring.DrawRingParam{ - Theme: parsed.Theme, ColorHash: accColorHash, ImageBytes: payload, Height: parsed.BgSize, Width: parsed.BgSize, RingWidth: parsed.RingWidth, - }) + if accColorHash != nil { + payload, err = ring.DrawRing(&ring.DrawRingParam{ + Theme: parsed.Theme, ColorHash: accColorHash, ImageBytes: payload, Height: parsed.BgSize, Width: parsed.BgSize, RingWidth: parsed.RingWidth, + }) - if err != nil { - logger.Error("failed to draw ring for account identity", zap.Error(err)) - return + if err != nil { + logger.Error("handleAccountInitialsImpl: failed to draw ring for account identity", zap.Error(err)) + return + } } } @@ -642,7 +642,7 @@ func handleContactImages(db *sql.DB, logger *zap.Logger) http.HandlerFunc { } if parsed.Ring && parsed.RingWidth == 0 { - logger.Error("handleAccountImagesImpl: no ringWidth.") + logger.Error("handleContactImages: no ringWidth.") return } @@ -692,7 +692,7 @@ func handleContactImages(db *sql.DB, logger *zap.Logger) http.HandlerFunc { if parsed.IndicatorSize != 0 { payload, err = images.AddStatusIndicatorToImage(payload, parsed.IndicatorColor, parsed.IndicatorSize*enlargeRatio, parsed.IndicatorBorder*enlargeRatio, parsed.IndicatorCenterToEdge*enlargeRatio) if err != nil { - logger.Error("handleAccountImagesImpl: failed to draw status-indicator for initials", zap.Error(err)) + logger.Error("handleContactImages: failed to draw status-indicator for initials", zap.Error(err)) return } } diff --git a/server/handlers_test.go b/server/handlers_test.go index 72f3a533c..cb5cd7603 100644 --- a/server/handlers_test.go +++ b/server/handlers_test.go @@ -3,11 +3,21 @@ package server import ( "database/sql" "encoding/json" + "image/color" "net/http" "net/http/httptest" "net/url" + "path/filepath" "testing" + "github.com/status-im/status-go/images" + + "github.com/status-im/status-go/eth-node/crypto" + + "github.com/status-im/status-go/common/dbsetup" + "github.com/status-im/status-go/multiaccounts" + mc "github.com/status-im/status-go/multiaccounts/common" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/suite" "go.uber.org/zap" @@ -545,3 +555,109 @@ func (s *HandlersSuite) TestHandleStatusLinkPreviewThumbnail() { }) } } + +func (s *HandlersSuite) validateResponse(w *httptest.ResponseRecorder) { + s.Require().Equal(http.StatusOK, w.Code) + s.Require().Equal("image/png", w.Header().Get("Content-Type")) + n, err := w.Result().Body.Read(make([]byte, 100)) + s.Require().NoError(err) + s.Require().Greater(n, 0) +} + +// TestHandleAccountInitialsImpl tests the handleAccountInitialsImpl function +func (s *HandlersSuite) TestHandleAccountInitialsImpl() { + // given an account without public key, and request to generate ring with keyUID of the account, + // it should still response with a valid image without ring rather than response with empty image + dbFile := filepath.Join(s.T().TempDir(), "accounts-tests-") + db, err := multiaccounts.InitializeDB(dbFile) + s.Require().NoError(err) + defer db.Close() + keyUID := "0x1" + name := "Lopsided Goodnatured Bedbug" + expected := multiaccounts.Account{Name: name, KeyUID: keyUID, CustomizationColor: mc.CustomizationColorBlue, ColorHash: nil, ColorID: 10, KDFIterations: dbsetup.ReducedKDFIterationsNumber, Timestamp: 1712856359} + s.Require().NoError(db.SaveAccount(expected)) + accounts, err := db.GetAccounts() + s.Require().NoError(err) + s.Require().Len(accounts, 1) + s.Require().Equal(expected, accounts[0]) + + w := httptest.NewRecorder() + f, err := filepath.Abs("../_assets/tests/UbuntuMono-Regular.ttf") + s.Require().NoError(err) + p := ImageParams{ + Ring: true, + RingWidth: 1, + KeyUID: keyUID, + InitialsLength: 2, + BgColor: color.Transparent, + Color: color.Transparent, + FontFile: f, + BgSize: 1, + FontSize: 1, + UppercaseRatio: 1.0, + } + handleAccountInitialsImpl(db, s.logger, w, p) + s.validateResponse(w) + + // pass a public key to generate ring + k, err := crypto.GenerateKey() + s.Require().NoError(err) + p.PublicKey = common.PubkeyToHex(&k.PublicKey) + w = httptest.NewRecorder() + handleAccountInitialsImpl(db, s.logger, w, p) + s.Require().Equal(http.StatusOK, w.Code) +} + +// TestHandleAccountImagesImpl tests the handleAccountImagesImpl function +func (s *HandlersSuite) TestHandleAccountImagesImpl() { + // given an account with identity images and without public key, and request to generate ring with keyUID of the account, + // it should still response with a valid image without ring rather than response with empty image + dbFile := filepath.Join(s.T().TempDir(), "accounts-tests-") + db, err := multiaccounts.InitializeDB(dbFile) + s.Require().NoError(err) + defer db.Close() + keyUID := "0x1" + name := "Lopsided Goodnatured Bedbug" + expected := multiaccounts.Account{ + Name: name, + KeyUID: keyUID, + CustomizationColor: mc.CustomizationColorBlue, + ColorHash: nil, + ColorID: 10, + KDFIterations: dbsetup.ReducedKDFIterationsNumber, + Timestamp: 1712856359, + Images: images.SampleIdentityImageForQRCode(), + } + s.Require().NoError(db.SaveAccount(expected)) + accounts, err := db.GetAccounts() + s.Require().NoError(err) + s.Require().Len(accounts, 1) + s.Require().Equal(expected, accounts[0]) + + w := httptest.NewRecorder() + f, err := filepath.Abs("../_assets/tests/UbuntuMono-Regular.ttf") + s.Require().NoError(err) + p := ImageParams{ + Ring: true, + RingWidth: 1, + KeyUID: keyUID, + InitialsLength: 2, + BgColor: color.Transparent, + Color: color.Transparent, + FontFile: f, + BgSize: 1, + FontSize: 1, + UppercaseRatio: 1.0, + ImageName: images.LargeDimName, + } + handleAccountImagesImpl(db, s.logger, w, p) + s.validateResponse(w) + + // pass a public key to generate ring + k, err := crypto.GenerateKey() + s.Require().NoError(err) + p.PublicKey = common.PubkeyToHex(&k.PublicKey) + w = httptest.NewRecorder() + handleAccountImagesImpl(db, s.logger, w, p) + s.Require().Equal(http.StatusOK, w.Code) +}