// ==UserScript==
// @name NIP-07 Relay Auth Filter
// @namespace http://tampermonkey.net
// @version 1.0
// @description Block NIP-42 auth and extra maybe encryption
// @match *://chachi.chat/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
"use strict";
// Disable encryption for site
const ALLOW_DECRYPT = false;
const ALLOW_ENCRYPT = false;
// Block all auth requests except for these relays
const RELAY_AUTH_WHITELIST = [
'pyramid.fiatjaf.com',
'nostr.land',
'nostr.wine'
];
function wrapNipObject(nip, allowDecrypt, allowEncrypt) {
if (!nip) return nip;
const wrapped = { ...nip };
if (typeof nip.decrypt === "function") {
wrapped.decrypt = async function (...args) {
if (!allowDecrypt) throw new Error("Decrypt blocked by filter");
return nip.decrypt.apply(nip, args);
};
}
if (typeof nip.encrypt === "function") {
wrapped.encrypt = async function (...args) {
if (!allowEncrypt) throw new Error("Encrypt blocked by filter");
return nip.encrypt.apply(nip, args);
};
}
return wrapped;
}
function wrapNostr(nostr) {
if (!nostr || typeof nostr.signEvent !== "function") return nostr;
const originalSignEvent = nostr.signEvent.bind(nostr);
const wrapped = { ...nostr };
wrapped.signEvent = async function (event) {
// Block relay auth (kind 22242) for non-whitelisted relays
if (event.kind === 22242) {
const relay = event.tags?.find(t => t[0] === 'relay')?.[1];
if (relay && URL.canParse(relay)) {
const url = new URL(relay);
if (!RELAY_AUTH_WHITELIST.includes(url.hostname)) {
throw new Error("Relay auth blocked: relay not in whitelist");
}
}
}
return originalSignEvent(event);
};
// Wrap nip04 and nip44 objects
if (nostr.nip04) wrapped.nip04 = wrapNipObject(nostr.nip04, ALLOW_DECRYPT, ALLOW_ENCRYPT);
if (nostr.nip44) wrapped.nip44 = wrapNipObject(nostr.nip44, ALLOW_DECRYPT, ALLOW_ENCRYPT);
return wrapped;
}
// Intercept window.nostr assignments
let nostrValue = window.nostr;
Object.defineProperty(window, "nostr", {
get: () => nostrValue,
set: (value) => {
nostrValue = value && typeof value.signEvent === "function" ? wrapNostr(value) : value;
},
configurable: true,
enumerable: true
});
// Wrap existing window.nostr if present
if (window.nostr) window.nostr = wrapNostr(window.nostr);
// Check again after page load + 1s
window.addEventListener("load", () => {
setTimeout(() => {
if (window.nostr && typeof window.nostr.signEvent === "function") {
const isWrapped = window.nostr.signEvent.toString().includes("RELAY_AUTH_WHITELIST");
if (!isWrapped) window.nostr = wrapNostr(window.nostr);
}
}, 1000);
});
})();
// @name NIP-07 Relay Auth Filter
// @namespace http://tampermonkey.net
// @version 1.0
// @description Block NIP-42 auth and extra maybe encryption
// @match *://chachi.chat/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
"use strict";
// Disable encryption for site
const ALLOW_DECRYPT = false;
const ALLOW_ENCRYPT = false;
// Block all auth requests except for these relays
const RELAY_AUTH_WHITELIST = [
'pyramid.fiatjaf.com',
'nostr.land',
'nostr.wine'
];
function wrapNipObject(nip, allowDecrypt, allowEncrypt) {
if (!nip) return nip;
const wrapped = { ...nip };
if (typeof nip.decrypt === "function") {
wrapped.decrypt = async function (...args) {
if (!allowDecrypt) throw new Error("Decrypt blocked by filter");
return nip.decrypt.apply(nip, args);
};
}
if (typeof nip.encrypt === "function") {
wrapped.encrypt = async function (...args) {
if (!allowEncrypt) throw new Error("Encrypt blocked by filter");
return nip.encrypt.apply(nip, args);
};
}
return wrapped;
}
function wrapNostr(nostr) {
if (!nostr || typeof nostr.signEvent !== "function") return nostr;
const originalSignEvent = nostr.signEvent.bind(nostr);
const wrapped = { ...nostr };
wrapped.signEvent = async function (event) {
// Block relay auth (kind 22242) for non-whitelisted relays
if (event.kind === 22242) {
const relay = event.tags?.find(t => t[0] === 'relay')?.[1];
if (relay && URL.canParse(relay)) {
const url = new URL(relay);
if (!RELAY_AUTH_WHITELIST.includes(url.hostname)) {
throw new Error("Relay auth blocked: relay not in whitelist");
}
}
}
return originalSignEvent(event);
};
// Wrap nip04 and nip44 objects
if (nostr.nip04) wrapped.nip04 = wrapNipObject(nostr.nip04, ALLOW_DECRYPT, ALLOW_ENCRYPT);
if (nostr.nip44) wrapped.nip44 = wrapNipObject(nostr.nip44, ALLOW_DECRYPT, ALLOW_ENCRYPT);
return wrapped;
}
// Intercept window.nostr assignments
let nostrValue = window.nostr;
Object.defineProperty(window, "nostr", {
get: () => nostrValue,
set: (value) => {
nostrValue = value && typeof value.signEvent === "function" ? wrapNostr(value) : value;
},
configurable: true,
enumerable: true
});
// Wrap existing window.nostr if present
if (window.nostr) window.nostr = wrapNostr(window.nostr);
// Check again after page load + 1s
window.addEventListener("load", () => {
setTimeout(() => {
if (window.nostr && typeof window.nostr.signEvent === "function") {
const isWrapped = window.nostr.signEvent.toString().includes("RELAY_AUTH_WHITELIST");
if (!isWrapped) window.nostr = wrapNostr(window.nostr);
}
}, 1000);
});
})();