fix(contacts): show photos that have no TYPE parameter - #5565
Conversation
The TYPE parameter of PHOTO is optional, but getPhotoUrl() called toLowerCase() on it unconditionally. Contacts stored e.g. as 'PHOTO;ENCODING=b:…' (without TYPE) threw a TypeError and showed initials instead of the photo, while other CardDAV clients displayed them fine. Detect the image type from the magic bytes of the base64 data when the TYPE parameter is missing. Unknown signatures fall back to jpeg, which browsers happily content-sniff in an img element anyway. Also log the contact itself in getPhotoUrl() error messages instead of the undefined this.contact. Resolves nextcloud#5401 Assisted-by: Claude:claude-fable-5 Signed-off-by: MiMoHo <37556964+MiMoHo@users.noreply.github.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
| const signature = Object.keys(signatures).find((signature) => photoB64Data.startsWith(signature)) | ||
| // browsers detect raster images in an img element from the content, | ||
| // so a wrong subtype still renders fine | ||
| return signature ? signatures[signature] : 'jpeg' |
There was a problem hiding this comment.
@SebastianKrupinski: I don't know if we should do such a fallback here. I think adding a warning or something like this would make more sense?
|
Hey @MiMoHo, thank you very much for your first PR here! Looks pretty good and useful to me. But additional colleagues will have a look into it as well. |
Address review feedback on nextcloud#5565: instead of silently assuming JPEG for a PHOTO whose magic bytes match no known signature, log a warning so the guess is visible in the console. The fallback itself stays, as browsers content-sniff raster images in an img element regardless of the declared subtype. Add a test for the unknown-signature path, closing the coverage gap codecov reported on the fallback branch. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: MiMoHo <37556964+MiMoHo@users.noreply.github.com>
|
Hello there, We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 Thank you for contributing to Nextcloud and we hope to hear from you soon! (If you believe you should not receive this message, you can add yourself to the blocklist.) |
Summary
Contact photos stored without an explicit
TYPEparameter, e.g.were not displayed:
getPhotoUrl()calledphotoType.toLowerCase()on the missing parameter and threwso the app fell back to initials, while other CardDAV clients (eM Client, iOS Contacts) display these photos fine. The
TYPEparameter is optional per RFC 2426/6350.Changes
TYPEparameter is missing, detect the image type from the magic bytes of the base64 data (png, jpeg, gif, webp, bmp, svg). SVG detected this way still goes through the existingsanitizeSVGpath.jpeg: browsers content-sniff raster images in animgelement, so a wrong subtype still renders — before this change the app just threw.getPhotoUrl()referencedthis.contact, which does not exist on theContactclass and always loggedundefined; they now logthis.Checklist
TYPE, binary photo withoutTYPE(png + jpeg magic bytes), vCard 4.0 data-URI photonpm run lintclean for the touched files, production build succeedsResolve #5401
🤖 Generated with Claude Code