您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
This script will check and add TLDs from HaGeZi Most Abused TLDs (Aggressive) list and allowlist to your NextDNS profile when you visit the profile page. The process can be checked in the browser console.
// ==UserScript== // @name HaGeZi Most Abused TLDs to NextDNS // @namespace vietthe.dev // @match https://my.nextdns.io/* // @grant none // @version 1.0.5 // @license MIT // @author Salad // @compatible firefox Violentmonkey // @compatible firefox Tampermonkey // @compatible chrome Violentmonkey // @compatible chrome Tampermonkey // @compatible opera Violentmonkey // @compatible opera Tampermonkey // @compatible safari Stay // @compatible edge Violentmonkey // @compatible edge Tampermonkey // @compatible brave Violentmonkey // @compatible brave Tampermonkey // @description This script will check and add TLDs from HaGeZi Most Abused TLDs (Aggressive) list and allowlist to your NextDNS profile when you visit the profile page. The process can be checked in the browser console. // @icon data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAFOklEQVRogbXaXaicRxkH8N/sJmnSlOZIDC1CJRCseETFK72qFBpFvJQUpAptFdorL0pKkV540AvxQm8sokdsY6ISjNVCxSBUiSLRoq0XYpEqGGmbUGxPTmKO52N35/Fi93zsnvdrPzIw7Owzzzzz/z/zzLwz77zJzUgL0TLvsDV3oKfnigddk1LMuqvWrA2CY+6x7qzkT3hR26IfmL8ZXaWZWzwTn8ZTuENIAiEL/xQ+4+H08iy7mx2Bp+OIPb4geVI4aDNYYpD75beFx6x4zhfT9Vl0Oz2BZ2JO23E8LNyLW0rA93NyXfYLnHLI792fVqfpfnICp+Og5H7hIXxIuL0UdHH5LbyoZ9H7/NK9qTsJjAoCkTzvgGWHtOyT7ZW8U/JB4T7huDDXEOxweff/K8J5PRdkf9N2TdbBumXXLKS18Qn8KD6BE/iA7DDmMCe0xwZcDX5YRkd2VVgW/iP7M844mV5qTuCH8ajkq8JhMdAZ7qQZ6NyAyKjOqDzLuIzPeTxdqCdwOj4ieU5yZ4F3xvfwaF2ZrE6e/V1y3BPp9Z1whx9kC7FH8knhiDzwQoz8VpXr6spkVfLt/G49x42kYQLz9uOY0N5iv2l8NBeBHRd8kZ2iNj2EA8IxJ6K9E/KeEULtgWI/jRMelMfzOOFSXp9kt3qH1oBSAYEVaUs27iozC/BldrZz27uG5+0wgX2SDa3K1WMWICcB369vu1pFYFWStG7aSjJuKO2uS94zhHjXHCAGBMYBT/16Pj34PralqhFYk9wibc3+nUaqQE4aElGgU01q13NrmMB+oTswebNCosoJuUKnn7NLVQQ2hKQ781AZZ7Sq7CRdR7c0Cgi0ZV0bMwdfpLMpG8/O+g6tAgIHdF23OnWoVOnsBNpk1LbbBFarCSzrym5IDUDWdTwt+FGd/q70hoVUQWBJx5yrQtg+kE8Wy+NO5HqdDWHZSBrZjaYsW5L1SjdWUSJvstuMCXX65Q3J26MEdj/IuCJbE25r7LEmYVVmp4n9ft2acKWeQM9lYVW4bQzjTSZhuW4z+arwRj2BrktaVoQjM/d2k/qyNsmSjsujcHe/WvyXN2SvV56OymJ4+ABSd8Iqb1vc30WLqVNPYDF1ZL8unWDTgi+byGWTd1t+fhfWQgLQ8/OhlajOm+OuMKOAy+TbsiXrftOcQPZX2Uu1Ht+Zy4e+2NtFI1W+hJ51qvjlVjGB/vPgO3olwKYFWQV+d7iuyE4X4iwlAD0vyF6p9FLR6JSF06i8rrydL2j5x/gE9npTeFbWaTxJm8qL7BTpcEN41l27txCbqfrt9JfibuFXsqMMDNPsuVCmX9Reaf1FLZ9yKpUSqL5i+lp6Vfb1rVEo8lLRsNeF0GjbYof8FyerwNcTgGXfF87I8kThUka8uryq5ytOpz/UwasnsJg6woLsd7Ugy1eScSZyFn5i3fdqsRnnhuax+KiuU8J7G8dzVXwXl0O4KDzgx+nfTWA1v2b9Zvqj8Ijwl6GVZLpQGfY854WHmoJnkjuyR2Jey7eFe+w8tTGp16EnnNXxhHNp15a5Ko1/0f3d9IrwgOynspXa1aR+tVmSfcucR8cFzzS3lCfigDmfHYTVh0XBO9Wd/43I6Ai/xVPu9vzoYb1pmu6eeCFaXnOX8HnZSQZ3C1XA+79vCl+238884y0m/4Zidjf1D8ZR2ZP4uHAn9o2A/p/+kfCcjm84l5Zm0e1sv5U4EW0Hzeu5T/YxvF/o4mXZBXu94IxL03h8NM3+Yw/6oXXJ7TYckmW3Wva0G7MEvpn+DxZzjNuWWt/KAAAAAElFTkSuQmCC // ==/UserScript== /* jshint esversion:2020 */ (async () => { class Utility { static sleep(ms = 500) { return new Promise((resolve) => setTimeout(() => resolve(), ms)) } static toHex(text) { let hex = '' for (let i = 0; i < text.length; i++) { const charCode = text.charCodeAt(i) const hexCode = charCode.toString(16).padStart(2, '0') hex += hexCode } return hex } } class Helper { static getProfileId() { return location.pathname.split("/")[1] } static async getAbusedTlds() { const content = await fetch("https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/spam-tlds-adblock.txt").then((res) => res.text()) const tlds = content.trim().match(/^\|\|(xn--)?\w+\^$/gm).map((e) => e.slice(2, -1)) return tlds } static async getAggressiveAbusedTlds() { const content = await fetch("https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/spam-tlds-onlydomains.txt").then((res) => res.text()) const tlds = content.trim().match(/^\|\|(xn--)?\w+\^$/gm) return tlds } static async getTldAllowlist() { const content = await fetch("https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/spam-tlds-allow-onlydomains.txt").then(res => res.text()) const domains = content.trim().split("\n") return domains } } class NextApi { apiHost = "https://api.nextdns.io" constructor(profileId) { this.profileId = profileId } request(path, options) { return fetch(`${this.apiHost}${path}`, { headers: { "Content-Type": "application/json", ...options?.headers, }, mode: "cors", credentials: "include", ...options, }) } getSecurity() { return this.request(`/profiles/${this.profileId}/security`).then((res) => res.json()) } getAllowlist() { return this.request(`/profiles/${this.profileId}/allowlist`).then((res) => res.json()) } addTld(tld) { return this.request(`/profiles/${this.profileId}/security/tlds`, { method: "POST", body: JSON.stringify({ id: tld }), }) } removeTld(tld) { return this.request(`/profiles/${this.profileId}/security/tlds/hex:${Utility.toHex(tld)}`, { method: "DELETE", }) } allowlistDomain(domain) { return this.request(`/profiles/${this.profileId}/allowlist`, { method: "POST", body: JSON.stringify({ active: true, id: domain }), }) } } const run = async () => { const profileId = Helper.getProfileId() const nextApi = new NextApi(profileId) const invalidTlds = ["non"] const currentTlds = (await nextApi.getSecurity()).data.tlds.map(({ id }) => id) const currentAllowlist = (await nextApi.getAllowlist()).data.map(({ id }) => id) const tlds = await Helper.getAbusedTlds() const tldAllowlist = await Helper.getTldAllowlist() const tldsToAdd = tlds.filter((e) => !currentTlds.includes(e) && !invalidTlds.includes(e)) const domainsToAllowlist = tldAllowlist.filter((e) => !currentAllowlist.includes(e)) let index = 1 console.info({ currentTlds, currentAllowlist, tldsToAdd, domainsToAllowlist }) for (const tld of tldsToAdd) { console.info(`Adding .${tld} to TLD blocklist (${index}/${tldsToAdd.length})`) await nextApi.addTld(tld) await Utility.sleep() index++ } index = 1 for (const domain of domainsToAllowlist) { console.info(`Adding ${domain} to allowlist (${index}/${domainsToAllowlist.length})`) await nextApi.allowlistDomain(domain) await Utility.sleep() index++ } } const onUrlChange = async () => { const profileIdExists = location.pathname.split("/").length >= 3 if (!profileIdExists) return console.info("HaGeZi Most Abused TLDs to NextDNS is running...") await run() console.info("Done.") } navigation.addEventListener("navigatesuccess", onUrlChange) onUrlChange() })()