cloudinary / cloudinary_js

Cloudinary JavaScript library
MIT License
328 stars 224 forks source link

Base64 remote image overlays containing url-unsafe characters / 404 errors #152

Closed joshuatz closed 3 years ago

joshuatz commented 5 years ago

I ran into a rather specific issue Cloudinary core / jquery-file-upload, where trying to overlay specific remote image URLs was failing and producing 400/404 errors. I realized it was because when the remote image URL was base64 encoded, the resulting string contained a slash ("/"), which was getting interpreted as a transformation chain. Example link :https://res.cloudinary.com/demo/image/upload/l_fetch:aHR0cHM6Ly9naXRodWIuY29tL25wbS5wbmc/c2l6ZT0yMDA=/c_scale,h_400,w_400/flowers .

I couldn't find anything in the documentation or support pages on how to avoid this scenario; most text talks about escaping URLs before passing them into the SDK, but not the other way around. Using something like encodeURIComponent before passing the URL to the SDK does nothing, understandably, since it doesn't change the fact that the base64 encoded string will end up with a slash. Not to mention that Util.base64EncodeURL actually uses decodeURI before passing the string to base64Encode.

After a little trial and error, I was able to get around this by using underscores to replace the slashes. I threw together a quick demo, here, which shows both the broken base64 encoding, as well as the working version with underscores.

My knowledge on this is rather limited, but it seems to me that you guys are probably using a URL-safe version of base64 (aka "base64url" aka RFC-4648) decoding server-side, which is why it is accepting my use of "_" instead of "/". However, on the cloudinary_js side, it looks like you are using btoa() as the default, which does not use RFC-4648 and will include slashes, as well as other url-unsafe characters. [EDIT: Buffer (buf.toString('base64')) also does not use the url-safe variant, and would need to be modified]

https://github.com/cloudinary/cloudinary_js/blob/918997eb10fd46d3d0a2ca87b2f20f04011a13eb/src/util/baseutil.js#L206-L213

The quick solution might be to modify the output from btoa with something like

return btoa(string).replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');

As a side note, this probably affects very few users, since it basically only happens when you have a question mark in the URL before encoding it, and many image URLs don't include querystrings.

shirlymanor commented 5 years ago

It indeed looks like an encoding issue on our end. I've forward it to our dev team to investigate. In the midtime, your solution seems like the right workaround. Thank you

eyalktCloudinary commented 3 years ago

Closing this issue due to the time elapsed. Please feel free to either re-open the issue or contact our support at http://support.cloudinary.com