Kiwidirect - A Firefox extension for smart redirection of Kiwi Farms links - One Weird Trick to fix all dead links

  • Happy Easter!

Does it work?

  • Yes

    Votes: 2 3.9%
  • No

    Votes: 0 0.0%
  • Nice try CIA

    Votes: 26 51.0%
  • Waiting for the Minecraft mod

    Votes: 23 45.1%

  • Total voters
    51

Flaming Dumpster

O Kees, where art thou?
True & Honest Fan
kiwifarms.net
Joined
Jun 12, 2020

Kiwidirect​

What is this shit?​

This is a Firefox extension that'll redirect you to your preferred Kiwi Farms domain. It basically sniffs any HTTP requests to kiwifarms.net, sneed.today, kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion and rewrites them to whatever domain you specify on the fly. This works for web pages and media so assets that have been inadvertently hardcoded to a domain will also load (e.g. chat avatars on sneed.today).

Cool, how do I get it?​

Download the attached .zip file and install it manually from about:addons. It is signed by Mozilla but only for private distribution as I rate the chances of it being approved for AMO distribution at 0%.

I installed it, now what?​

The purple Kiwi Farms Tor icon should now be in your toolbar (or may be hidden under extensions) and you can use that to enable/disable it and set your preferred domain. The extension defaults to .onion so remember to configure this straight away if you're on clearnet.

Known issues​

  1. Tor Browser chads will see an error on the options page asking them to set webextensions.storage.sync.enabled to true in about:config. You can ignore this but the extension will just default to always being on and with the .onion as the preferred domain.
  2. I had to put in some bullshit to mangle the .onion anti-DDoS cookie as same-site being 'strict' caused it to not send the cookie after redirection and needlessly trigger a new challenge. The bullshit basically deletes the cookie and immediately recreates it with a more relaxed same-site policy but this hasn't been run through its paces 100% so it might be buggy.

But I'm a Chrome cuck!​

The extension does actually support Chromium (I tested with Brave) but it's just buggy and I don't know how to fix the issues.
  • If you edit the settings, it won't take effect until an HTTP request has been made. This is because I could not find a way to reliably update the instance/enabled properties as the storage onChanged event for some reason doesn't work. So if you change to sneed.today and click a link, it might take you to the .onion first instead, then it'll work on the second attempt.
  • Sometimes it just won't redirect pages but will redirect the assets. This seems to be due to caching as CTRL+F5 fixes it. I could not reliably reproduce the issue and it seemed to sometimes affect pages I hadn't even loaded previously so preloading might be partly to blame.
  • Brave intercepts .onion URLs before I have a chance to redirect by default. Disabling "Private window with Tor" in brave://settings/privacy seems to stop this.
If you want to try it out, open extensions and enable Developer mode, then drag the zip into the window (You may need to refresh first). It'll bitch about an error but that's just a warning related to a Firefox-specific property in the manifest.

Why does this require so many permissions?

The extension requests permission to run on all pages as host_permissions (which would limit the scope) is only supported on manifest v3, which is not supported on Firefox ESR (which is what Tor Browser uses). The onBeforeRequest listener is configured to only run on Kiwi Farms related URLs and should not mess with any other websites.
Fixed in 0.0.14. I was a dumbass and doing it wrong.

It also requests access to cookies to help resolve issue #2. It won't touch your cookies if you're on clearnet as Kiwiflare doesn't have a strict same-site policy for its cookies.

Updates?​

Check this thread for updates. Since this is privately distributed with no update URL in the manifest, there's no way to automatically update it.

Source?​

Unpack the zip. There's no obfuscation or minifying going on. Trigger Warning: I'm not a JavaScript programmer and hacked this together using a couple of old Invidious redirect extensions so the code is kinda shit.

License?​

MIT+NIGGER
 

Attachments

Last edited:
I'm not an expert but the javascript looks safe. I don't see anything that could be harmful as long as the URLs being redirected to aren't. (and it only redirects to official KF URLs)
background.js
JavaScript:
var isChrome = browser === undefined;
var onionDomain = "kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion"

function createBlockingRequest(url, domain) {
    // Chrome doesn't seem to care about sameSite for the anti-DDoS PoW cookie
    // Thank goodness as I would have to rewrite a bunch of it to work with Chrome anyway
    if (domain === onionDomain && !isChrome) {
        browser.cookies.getAll({
            url: `https://${onionDomain}`,
            name: "z_ddos_pow", firstPartyDomain: onionDomain
        }).then(
            (cookie) => {
                // Track whether we're just cleaning up a stale PoW that has doubled up
                let cookieCleanup = false;
                if (cookie === null) return;
                // Doubled up on cookies, gotta delete one. FF defaults to the oldest thankfully
                if (cookie.length > 1) cookieCleanup = true;
                // Nothing needs to be done
                if (cookie.length === 1 && cookie[0].sameSite !== "strict") return;
                console.log("Recreating .onion DDoS PoW cookie with sameSite no_restriction", cookieCleanup)
                let pow_val = cookie[0].value;
                // Delete the cookie and recreate it with a more relaxed sameSite attribute
                browser.cookies.remove({
                    url: `https:/${onionDomain}`,
                    name: "z_ddos_pow",
                    firstPartyDomain: onionDomain
                }).then(() => {
                    if (cookieCleanup) return;
                    browser.cookies.set({
                        url: `https://${onionDomain}`,
                        name: "z_ddos_pow",
                        firstPartyDomain: onionDomain,
                        value: pow_val,
                        sameSite: "no_restriction",
                        domain: `.${onionDomain}` // Needs the . so it gets sent to uploads, no-cookie, etc.
                    })
                })
            })
    }
    if (url.host.includes(domain)) return;
    // Try to preserve uploads, no-cookie, etc. subdomain
    let parts = url.host.split('.');
    // Man, what a lousy hack
    if (parts[0] === "no-cookie" || parts[0] === "uploads") {
        domain = `${parts[0]}.${domain}`
    }
    // Basically if we don't try and be clever, we end up with uploads.blahblah.onion becoming -> chucksfarm.net
    return {redirectUrl: url.href.replace(url.host, domain)}
}

var enabled = true, instance = onionDomain,
    browser = browser || chrome;

browser.webRequest.onBeforeRequest.addListener(request => {
        const url = new URL(request.url);

        let config = {
            enabled: true,
            instance: onionDomain
        }

        // Hacky cancerous Chrome workarounds
        // Basically there's an issue where I can't block the request until I get the storage result
        // So the lousy workaround is to store the value as a global and refetch it each time
        // This causes a bug where the value doesn't take effect until the 2nd page load, but I can't find an acceptable
        // workaround as storage.onChanged isn't firing for unknown reasons and every answer on Google is useless
        if (isChrome) {
            browser.storage.sync.get({
                enabled: true,
                instance: onionDomain
            }, function (cfg) {
                enabled = cfg.enabled;
                instance = cfg.instance;
            });
            return createBlockingRequest(url, instance);
        }
        return browser.storage.sync.get(config).then((res) => {
            if (res.enabled) {
                return createBlockingRequest(url, res.instance);
            }
        }, (error) => {
            // Tor browser turns off the storage sync API by default
            // so just default to Tor mode for these guys
            console.log(`Failed to retrieve settings. Defaulting to onion redirect. Error was: ${error}`);
            return createBlockingRequest(url, onionDomain)
        });
    },
    {
        "urls": ["*://*.kiwifarms.net/*", "*://*.sneed.today/*", "*://*.kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion/*"],
        "types": [
            "main_frame",
            "sub_frame",
            "image",
            "media"
        ]
    },
    ["blocking"]
);

options.js
JavaScript:
var isChrome = browser === undefined;
var browser = browser || chrome

function showMessage(msg) {
    document.getElementById('message').classList.remove('hidden');
    document.getElementById('message').textContent = msg;
}

function saveOptions(e) {
    e.preventDefault();
    var enabled = document.querySelector("#enabled").checked;
    var instance = document.querySelector("#instance").value.trim();
    instance = instance.replace(/^https?:?\/?\/?/, '').replace('\/$');
    if (!instance) {
        showMessage("You must specify a domain");
        return;
    }

    let data = {
        enabled: enabled,
        instance: instance
    }

    console.log(`Saving data. Enabled = ${enabled}, Instance = ${instance}`);
    if(chrome !== undefined) {
        chrome.storage.sync.set(data, () => showMessage("Saved!"));
        return;
    }
    browser.storage.sync.set(data).then(() => {
        showMessage("Saved!");
    }, (error) => {
        showMessage(error)
    });
}

function restoreOptions() {
    function setCurrentChoice(result) {
        document.querySelector("#enabled").checked = result.enabled;
        document.querySelector("#instance").value = result.instance;
    }

    function onError(error) {
        showMessage(error);
    }

    let defaults = {
        enabled: true,
        instance: 'kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion',
    }

    if (isChrome) {
        chrome.storage.sync.get(defaults, (items) => {setCurrentChoice(items)})
        return;
    }
    let getting = browser.storage.sync.get(defaults);
    getting.then(setCurrentChoice, onError);
}

document.addEventListener("DOMContentLoaded", restoreOptions);
document.querySelector("form").addEventListener("submit", saveOptions);
 
I'm not an expert but the javascript looks safe. I don't see anything that could be harmful as long as the URLs being redirected to aren't. (and it only redirects to official KF URLs)
The average user can probably read the code faster than my OP so I appreciate you posting it for others to review.
console.log("Recreating .onion DDoS PoW cookie with sameSite no_restriction", cookieCleanup)
lol you can tell I'm not a JavaScript person as I haven't got that ingrained habit of using semicolons everywhere.
 
I've decided to make something similar, but as a simple brute force userscript:

JavaScript:
// ==UserScript==
// @name        KF Make All Links Relative
// @namespace   kiwifarms
// @match       http*://kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion/*
// @match       http*://sneed.today/*
// @match       http*://kiwifarms.net/*
// @grant       none
// @version     1.0
// @author      Slav Power
// @description Convert every KF URL into a relative one
// ==/UserScript==

window.onload = function() { // Run the function after page loads
  [...document.querySelectorAll("a")].forEach(x => kfrelative(x)) // Run the kfrelative function for every link element on the page
  function kfrelative(x) { // The function that's ran for every link element found
    if (x.href.indexOf(/.*kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion.*/ || /.*sneed.today.*/ || /.*kiwifarms.net.*/)) { // Check if a found URL comes from one of KF domains
       x.href = x.href.replace(/^([^.]+)([^\/]+)/,"") // Use RegEx to remove everything in the link URL from the beggining until the first found dot (http and domain name) and then until the first found forward slash (TLD) leaving only a single forward slash in the beginning making the URL relative
    };
  };
}

Since XenForo supports relative links, you can just cut off the entire domain name and make every single KF URL work on the currently viewed domain. It's not very complex, it only affects links, it only runs when the page is fully loaded, but it works and that's what matters.
 
Since XenForo supports relative links, you can just cut off the entire domain name and make every single KF URL work on the currently viewed domain. It's not very complex, it only affects links, it only runs when the page is fully loaded, but it works and that's what matters.
I made a bookmarklet a while ago to redirect back but it gets screwed over by the .onion anti-DDoS cookie. It'd probably work alright on clearnet though. Obviously just gotta replace .onion with sneed.today
JavaScript:
javascript:location.hostname.includes("kiwifarms.net")?location.assign("https://kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion"+location.pathname+location.search+location.hash):location.assign("http://kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion");

Anyway I'm contemplating updating this with a context menu option that lets you generate bbcode with all the alternative site links. e.g. right click on a post URL, "Copy link as BBCode" and it'll generate Tor, sneed.today and .net links nicely formatted. If I make a new release, I'll also fix the permissions so it doesn't request "run on all sites" anymore.
 
  • Like
Reactions: Vecr and Lord Xenu
Wouldn't modifying the hosts file be a better way of doing this without installing a userscript engine? You could map kiwifarms.net to sneed.today (or whichever domain the mirror/ mirrors are on) - this would probably not work with Tor, but I don't think that modifying the Tor Browser is a good idea.
 
Wouldn't modifying the hosts file be a better way of doing this without installing a userscript engine? You could map kiwifarms.net to sneed.today (or whichever domain the mirror/ mirrors are on) - this would probably not work with Tor, but I don't think that modifying the Tor Browser is a good idea.
I checked and the clearnet IP is not configured with a certificate for kiwifarms.net so at the very least you'll get annoying cert errors. You'd basically need to bookmark kiwifarms.net, no-cookie.kiwifarms.net and uploads.kiwifarms.net then accept the certificate errors one by one every single time your browser gets angry. I tried and got caught in a loop of accepting certs then getting hit by the service worker's error page.
 
  • Informative
Reactions: 888Flux
I checked and the clearnet IP is not configured with a certificate for kiwifarms.net so at the very least you'll get annoying cert errors. You'd basically need to bookmark kiwifarms.net, no-cookie.kiwifarms.net and uploads.kiwifarms.net then accept the certificate errors one by one every single time your browser gets angry. I tried and got caught in a loop of accepting certs then getting hit by the service worker's error page.
That would make sense, I forgot about the DDoS frontend which probably wouldn't work if the kiwifarms.net DNS record was overwritten
 
  • Like
Reactions: Flaming Dumpster

Update!​

I've updated the extension to version 0.0.14 (13 skipped due to being an unlucky number in China)

Change Log​

  • Added support for kiwifarms.pl
  • Fixed the permissions so it no longer requests access to all sites, just Kiwi Farms domains
  • Changed the storage behavior so it falls back to local storage if sync storage isn't available. This means Tor Browser people can edit settings without messing with about:config
  • Added a "Copy Relative URL" context menu item for links. Does what the name suggests and will only appear on Kiwi Farms domains
  • Added .png icons as Chromium browsers don't support .svg icons

Upgrading​

Install over the top of the existing extension and it should Just Work™.
 

Attachments

  • Winner
Reactions: Relinquish
Was going to post my incredibly simple solution but then saw this thread with a much more involved version. For anyone who wants just a simple redirect extension though, here's what I'm using:


manifest.json
JSON:
{
  "manifest_version": 2,
  "name": "KiwiFarms Redirector",
  "version": "6.9.420",
  "description": "This extension redirects KF links to the latest KF URL.",
  "permissions": [
    "webRequest",
    "webRequestBlocking",
    "<all_urls>"
  ],
  "background": {
    "scripts": ["redirect.js"]
  }
}

redirect.js
JavaScript:
const redirectHostnames = ["kiwifarms.net", "sneed.today", "kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion"]; // Add URLs as needed

chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    let url = new URL(details.url);
    if (redirectHostnames.includes(url.hostname)) {
      url.hostname = "kiwifarms.pl";
      return { redirectUrl: url.href };
    }
  },
  { urls: redirectHostnames.map(hostname => `*://${hostname}/*`) },
  ["blocking"]
);


Step 1. Save these 2 files into a folder
Step 2. Load unpackaged extension into browser

Works on Chromium, should work on Firefox I imagine.
 
  • Like
Reactions: Flaming Dumpster
Works on Chromium, should work on Firefox I imagine.
Firefox doesn't let you load extensions from a folder so you have to zip everything up and load it as a temporary extension from about:debugging. It'll stay loaded until you restart the browser, whereupon you need to load it yet again. It's so annoying as it places a lock on the zip file so I have to unload it, zip everything, then load it up again when testing things. Credit to Chromium, it's a lot easier to quickly test changes when you can just point it at a folder and click a single button to reload.

If you want an extension to stay loaded, it must be signed and you're forced to upload your shit to AMO and wait for their bot to auto-approve it. It's amazing Mozilla has engineered a system so retarded it makes Google look good.
if (redirectHostnames.includes(url.hostname)) { url.hostname = "kiwifarms.pl";
So if you check line 43 to 47 of background.js on Kiwidirect, you'll see some hacked up attempt to preserve no-cookie and uploads subdomains.
JavaScript:
    let parts = url.host.split('.');
    if (parts[0] === "no-cookie" || parts[0] === "uploads") {
        domain = `${parts[0]}.${domain}`
    }
You don't strictly need to do that, the site loads fine even if you translate uploads.sneed.today -> kiwifarms.pl but the reason these domains exist is for the sake of CSP.

This is basically stripping away a layer of protection from XSS attacks so you should attempt to make it 1:1. Looping through redirectHostnames and attempting to do a string replacement on url.hostname would do the trick.

It looks fine other than that and would probably work ok on Firefox aside from all the temporary extension bullshit.
 
  • Informative
Reactions: SilenceIsViolence
Damn, haven't used firefox in a long time, that's obnoxious. Good information though, I edited mine to the following to match:

JavaScript:
const redirectHostnames = ["kiwifarms.net", "sneed.today", "kiwifarmsaaf4t2h7gc3dfc5ojhmqruw2nit3uejrpiagrxeuxiyxcyd.onion"]; // Add domains here

chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    let url = new URL(details.url);
    for (let hostname of redirectHostnames) {
      if (url.hostname.endsWith(hostname)) {
        let parts = url.hostname.split('.');
        let subdomain = parts[0] === "no-cookie" || parts[0] === "uploads" ? `${parts[0]}.` : '';
        url.hostname = url.hostname.replace(hostname, `${subdomain}kiwifarms.pl`);
        return { redirectUrl: url.href };
      }
    }
  },
  { urls: redirectHostnames.map(hostname => `*://*.${hostname}/*`) },
  ["blocking"]
);
 
  • Like
Reactions: Flaming Dumpster
Minor update for kiwifarms.st support. Same as before, drop in and it'll install over the top of the existing extension. Remember to update your preferred domain if it was set to .pl since the extension won't do it for you.
 

Attachments

Back