Viewing imgur through Duckduckgo

In a previous article, I explained how to bypass imgur's country-wide ban by using a cheap VPS as a socks5 proxy. While this worked, it came with the downside that I had to keep an SSH session open at all times.

Not long ago, another imgur-related thread popped up on r/morocco. I was about to suggest my workaround, but then I realized that not everyone has a VPS lying around. In addition to this, other users already suggested using a VPN; an admittedly easier solution.

I looked into it again and discovered that this issue wasn't limited to INWI. People from other countries suffer from the same problem. During my research I landed on this meta stackoverflow thread. This suggestion in particular caught my eye :

I tested it, and it worked as described. Hmm... maybe I could create a browser extension that prepends https://proxy.duckduckgo.com/iu/?u= to any imgur.com links it finds in the DOM ? I opened ChatGPT and star... just kidding. I searched for a similar extension and found that it already exists. But since I suffer from the NIH syndrome, I got nerd sniped into writing one myself. The premise was easy enough : find all img and a tags whose src or href attribute starts with https://i.imgur.com or https://imgur.com, prepend the proxy URL to it, and assign the resulting value to the attribute. After some trial and error, I came up with this code :

proxify("img[src^='https://i.imgur.com']", 'src', 'https://i.imgur.com', 'https://proxy.duckduckgo.com/iu/?u=https://i.imgur.com/');
proxify("img[src^='https://imgur.com']", 'src', 'https://imgur.com', 'https://proxy.duckduckgo.com/iu/?u=https://i.imgur.com/');
proxify("img[src^='https://i.stack.imgur.com']", 'src', 'https://i.stack.imgur.com', 'https://proxy.duckduckgo.com/iu/?u=https://i.stack.imgur.com/');

proxify("a[href^='https://i.imgur.com']", 'href', 'https://i.imgur.com', 'https://proxy.duckduckgo.com/iu/?u=https://i.imgur.com/');
proxify("a[href^='https://imgur.com']", 'href', 'https://imgur.com', 'https://proxy.duckduckgo.com/iu/?u=https://i.imgur.com/');
proxify("a[href^='https://i.stack.imgur.com']", 'href', 'https://i.stack.imgur.com', 'https://proxy.duckduckgo.com/iu/?u=https://i.stack.imgur.com/');

function proxify(selector, attribute, search, replace) {
    document.querySelectorAll(selector).forEach(node => {
        const value = node.getAttribute(attribute);
        if(value.startsWith(search)) {
            node.setAttribute(attribute, value.replace(search, replace));
        }
    });
}

After saving it as duck.js, I added the following minimalistic manifest :

{

  "manifest_version": 2,
  "name": "Imgur Duck proxy",
  "version": "1.0",

  "description": "Unblocks imgur images by loading them through DuckDuckGo's proxy",

  "icons": {},

  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["duck.js"]
    }
  ]

}

I then tested it by loading it into Firefox's about:debugging URL :

And it worked... with a caveat. The DOM elements that are visible when the page is loaded are handled as expected, but dynamically added imgur links or images are not affected. I tested this with the following code :

<html>
    <head>
        <script type="text/javascript">
            setTimeout(() => {
                const image = document.createElement('img');
                image.setAttribute('src', 'https://i.imgur.com/aEFogmG.jpg');
                image.setAttribute('title', 'raccoon and fawn friends');
                image.setAttribute('alt', 'raccoon and fawn friends');

                const link = document.createElement('a');
                link.setAttribute('href', 'https://i.imgur.com/aEFogmG.jpg');
                link.appendChild(image);

                document.querySelector('main').appendChild(link);
            }, 2000);
        </script>
    </head>
    <body>
        <main style="display: flex; flex-direction: column">
            <a href="https://i.imgur.com/aEFogmG.jpg">
                <img
                    src="https://i.imgur.com/aEFogmG.jpg"
                    alt="raccoon and fawn friends"
                    title="raccoon and fawn friends"
                />
            </a>
            <p>Dynamically added image:</p>
        </main>
    </body>
</html>

With this result :

Courtesy of reddit user astralrig96

The embedded image loaded successfully thanks to the extension. The second image failed to load and displayed the alt attribute as a fall back. Normally this would be a deal breaker, but I realized that opening the link to https://i.imgur.com/aEFogmG.jpg does display the image. I looked into it and realized that it's because Firefox puts the image inside an HTML document, which makes it compatible with the extension :

Good enough for me ! The next step was to make the extension permanent so that I wouldn't have to load it on every new firefox instance. To solve this, I published it on Mozilla's addon marketplace then installed it as a regular extension once it got approved. At the time of writing it's still experimental, but you can test it here. I'll update this article with a Github link once I get CD sorted out and once I fix the bug relevant to the dynamically added DOM elements I haven't figured out CD yet but here's the official repo with CI.

Conclusion

While it worked for direct imgur links, the downside of this approach is that DuckDuckGo only proxies direct image links. This rules out things like comments, albums and even gifv. A good compromise between using this extension and a full blown SSH tunnel would be to set up an HTTPS proxy on the VPS, this way I wouldn't have to open an SSH session for this purpose. But that will be the subject of a future article.

Commentaires

Posts les plus consultés de ce blog

Writing a fast(er) youtube downloader

My experience with Win by Inwi

Porting a Golang and Rust CLI tool to D