fix(avatar): sniff avatar image bytes for the cached MIME type#773
Merged
Conversation
PEP avatar fetches in Profile.ts hardcoded image/png when caching, so animated GIF/WebP/APNG avatars were stored as a Blob typed image/png. Browsers content-sniff <img> so they still rendered, but consumers that trust blob.type (the GIF freeze-frame extractor, notification avatar file extensions) were misled. Add sniffImageMimeType() which reads the magic bytes (PNG, APNG via the acTL chunk, GIF, WebP, JPEG) and use it at the three PEP cacheAvatar sites: fetchAvatarData, fetchOccupantAvatar, and fetchOwnAvatar (where it also overrides a mislabeled <info type>). Unknown formats fall back to image/png.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PEP (XEP-0084) avatar fetches in
Profile.tshardcodedimage/pngwhen caching, so animated GIF/WebP/APNG avatars were stored as a Blob typedimage/png. Browsers content-sniff<img>so they still rendered, but any consumer that trustsblob.typewas misled.This derives the real type from the image's magic bytes rather than the hardcoded/advertised one — the authoritative source, and robust against clients that mislabel their avatars.
Changes
packages/fluux-sdk/src/utils/imageType.ts—sniffImageMimeType(base64)detects PNG, APNG (animated PNG, via theacTLchunk beforeIDAT), GIF, WebP and JPEG from magic bytes; returnsnullfor unrecognized data so callers fall back toimage/png.cacheAvatarsites inProfile.ts:fetchAvatarData(contacts),fetchOccupantAvatar(MUC occupants), andfetchOwnAvatar(own avatar — the sniffed type also overrides a mislabeled<info type>).Effect on consumers of
blob.typeAvatar.tsxextracts a static first frame only whenblob.type === 'image/gif'. Correctly typing GIF avatars activates that freeze-frame path (previously they were typed png and kept animating); decode failures fall back to animating, so there is no hard regression.notificationAvatar.tsderives a notification file extension fromblob.type; correct types yield correct extensions instead of defaulting everything to.png.vCard-temp paths still trust the advertised
<TYPE>(defaulting to png when absent) — out of scope here, but the same util could harden them.