├── .github ├── FUNDING.yml └── workflows │ └── auto-update.yml ├── .gitignore ├── README.md ├── bad-domains.json ├── domains-list.json ├── domains.json ├── domains.txt └── scripts ├── package-lock.json ├── package.json └── update.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: WalshyDev 2 | custom: https://paypal.me/walshblob -------------------------------------------------------------------------------- /.github/workflows/auto-update.yml: -------------------------------------------------------------------------------- 1 | on: 2 | schedule: 3 | - cron: '*/30 * * * *' 4 | workflow_dispatch: {} 5 | 6 | jobs: 7 | runner: 8 | runs-on: ubuntu-latest 9 | name: Update domains 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Setup node 13 | uses: actions/setup-node@v2 14 | with: 15 | node-version: 17 16 | - name: 'Run my scripts' 17 | run: | 18 | git config user.name "github-actions[bot]" 19 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" 20 | cd scripts 21 | npm ci 22 | npm run update -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /scripts/node_modules/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discord Bad Domains 2 | 3 | This repo holds three lists; Discord's "bad domains" list with the associated domain (if found), my list of phishing/scamming sites and my list with their hashes. 4 | 5 | ## Developer or Bot Developer? 6 | If you wish to check against the list for auto-banning you can with: 7 | ``` 8 | POST https://bad-domains.walshy.dev/check 9 | 10 | Content-Type: application/json 11 | 12 | {"domain": "example.com"} 13 | ``` 14 | 15 | which will return: 16 | ```json 17 | { 18 | "badDomain": true|false, 19 | "detection": "discord|community", 20 | } 21 | ``` 22 | 23 | You can decide what to do based on the result. The fields are as follows: 24 | * `badDomain`: If the domain is found in the community or official list. 25 | * `detection`: The method of detection. `discord` means it's on the official banned list; `community` means it's on the community list. 26 | 27 | ### Want to help? 28 | If you wish to submit a bad domain then simply send a request like so: 29 | 30 | ``` 31 | POST https://bad-domains.walshy.dev/report 32 | 33 | Content-Type: application/json 34 | 35 | {"domain": "bad-domain.com"} 36 | ``` 37 | 38 | This will check against the bad domain list and if it's a match, update the list. Otherwise, it will report it to me and I will manually review. 39 | 40 | ## Access the lists 41 | Unlimited access to `bad-domains.json` and `domains.txt` with the following endpoints: 42 | 43 | * GET https://bad-domains.walshy.dev/bad-domains.json 44 | * GET https://bad-domains.walshy.dev/domains.txt (or https://bad-domains.walshy.dev/domains.json if you prefer) -------------------------------------------------------------------------------- /scripts/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scripts", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "scripts", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "dateformat": "^5.0.2", 13 | "node-fetch": "^3.1.0", 14 | "simple-git": "^2.48.0" 15 | } 16 | }, 17 | "node_modules/@kwsites/file-exists": { 18 | "version": "1.1.1", 19 | "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", 20 | "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", 21 | "dependencies": { 22 | "debug": "^4.1.1" 23 | } 24 | }, 25 | "node_modules/@kwsites/promise-deferred": { 26 | "version": "1.1.1", 27 | "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", 28 | "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" 29 | }, 30 | "node_modules/data-uri-to-buffer": { 31 | "version": "4.0.0", 32 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", 33 | "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", 34 | "engines": { 35 | "node": ">= 12" 36 | } 37 | }, 38 | "node_modules/dateformat": { 39 | "version": "5.0.2", 40 | "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-5.0.2.tgz", 41 | "integrity": "sha512-h9vywpuz+ReixnJTwFx5JLtZpS8eLCbRm8shwwKkCKOZA547N6yoMtD3W91Z6+NFZ8wOaZlcaCcK/w+kELhSVg==", 42 | "engines": { 43 | "node": ">=12.20" 44 | } 45 | }, 46 | "node_modules/debug": { 47 | "version": "4.3.3", 48 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", 49 | "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", 50 | "dependencies": { 51 | "ms": "2.1.2" 52 | }, 53 | "engines": { 54 | "node": ">=6.0" 55 | }, 56 | "peerDependenciesMeta": { 57 | "supports-color": { 58 | "optional": true 59 | } 60 | } 61 | }, 62 | "node_modules/fetch-blob": { 63 | "version": "3.1.3", 64 | "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.3.tgz", 65 | "integrity": "sha512-ax1Y5I9w+9+JiM+wdHkhBoxew+zG4AJ2SvAD1v1szpddUIiPERVGBxrMcB2ZqW0Y3PP8bOWYv2zqQq1Jp2kqUQ==", 66 | "funding": [ 67 | { 68 | "type": "github", 69 | "url": "https://github.com/sponsors/jimmywarting" 70 | }, 71 | { 72 | "type": "paypal", 73 | "url": "https://paypal.me/jimmywarting" 74 | } 75 | ], 76 | "dependencies": { 77 | "web-streams-polyfill": "^3.0.3" 78 | }, 79 | "engines": { 80 | "node": "^12.20 || >= 14.13" 81 | } 82 | }, 83 | "node_modules/formdata-polyfill": { 84 | "version": "4.0.10", 85 | "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", 86 | "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", 87 | "dependencies": { 88 | "fetch-blob": "^3.1.2" 89 | }, 90 | "engines": { 91 | "node": ">=12.20.0" 92 | } 93 | }, 94 | "node_modules/ms": { 95 | "version": "2.1.2", 96 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 97 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 98 | }, 99 | "node_modules/node-fetch": { 100 | "version": "3.1.1", 101 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.1.1.tgz", 102 | "integrity": "sha512-SMk+vKgU77PYotRdWzqZGTZeuFKlsJ0hu4KPviQKkfY+N3vn2MIzr0rvpnYpR8MtB3IEuhlEcuOLbGvLRlA+yg==", 103 | "dependencies": { 104 | "data-uri-to-buffer": "^4.0.0", 105 | "fetch-blob": "^3.1.3", 106 | "formdata-polyfill": "^4.0.10" 107 | }, 108 | "engines": { 109 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 110 | }, 111 | "funding": { 112 | "type": "opencollective", 113 | "url": "https://opencollective.com/node-fetch" 114 | } 115 | }, 116 | "node_modules/simple-git": { 117 | "version": "2.48.0", 118 | "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.48.0.tgz", 119 | "integrity": "sha512-z4qtrRuaAFJS4PUd0g+xy7aN4y+RvEt/QTJpR184lhJguBA1S/LsVlvE/CM95RsYMOFJG3NGGDjqFCzKU19S/A==", 120 | "dependencies": { 121 | "@kwsites/file-exists": "^1.1.1", 122 | "@kwsites/promise-deferred": "^1.1.1", 123 | "debug": "^4.3.2" 124 | }, 125 | "funding": { 126 | "type": "github", 127 | "url": "https://github.com/sponsors/steveukx/" 128 | } 129 | }, 130 | "node_modules/web-streams-polyfill": { 131 | "version": "3.2.0", 132 | "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz", 133 | "integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==", 134 | "engines": { 135 | "node": ">= 8" 136 | } 137 | } 138 | }, 139 | "dependencies": { 140 | "@kwsites/file-exists": { 141 | "version": "1.1.1", 142 | "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", 143 | "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", 144 | "requires": { 145 | "debug": "^4.1.1" 146 | } 147 | }, 148 | "@kwsites/promise-deferred": { 149 | "version": "1.1.1", 150 | "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", 151 | "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" 152 | }, 153 | "data-uri-to-buffer": { 154 | "version": "4.0.0", 155 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", 156 | "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==" 157 | }, 158 | "dateformat": { 159 | "version": "5.0.2", 160 | "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-5.0.2.tgz", 161 | "integrity": "sha512-h9vywpuz+ReixnJTwFx5JLtZpS8eLCbRm8shwwKkCKOZA547N6yoMtD3W91Z6+NFZ8wOaZlcaCcK/w+kELhSVg==" 162 | }, 163 | "debug": { 164 | "version": "4.3.3", 165 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", 166 | "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", 167 | "requires": { 168 | "ms": "2.1.2" 169 | } 170 | }, 171 | "fetch-blob": { 172 | "version": "3.1.3", 173 | "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.3.tgz", 174 | "integrity": "sha512-ax1Y5I9w+9+JiM+wdHkhBoxew+zG4AJ2SvAD1v1szpddUIiPERVGBxrMcB2ZqW0Y3PP8bOWYv2zqQq1Jp2kqUQ==", 175 | "requires": { 176 | "web-streams-polyfill": "^3.0.3" 177 | } 178 | }, 179 | "formdata-polyfill": { 180 | "version": "4.0.10", 181 | "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", 182 | "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", 183 | "requires": { 184 | "fetch-blob": "^3.1.2" 185 | } 186 | }, 187 | "ms": { 188 | "version": "2.1.2", 189 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 190 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 191 | }, 192 | "node-fetch": { 193 | "version": "3.1.1", 194 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.1.1.tgz", 195 | "integrity": "sha512-SMk+vKgU77PYotRdWzqZGTZeuFKlsJ0hu4KPviQKkfY+N3vn2MIzr0rvpnYpR8MtB3IEuhlEcuOLbGvLRlA+yg==", 196 | "requires": { 197 | "data-uri-to-buffer": "^4.0.0", 198 | "fetch-blob": "^3.1.3", 199 | "formdata-polyfill": "^4.0.10" 200 | } 201 | }, 202 | "simple-git": { 203 | "version": "2.48.0", 204 | "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.48.0.tgz", 205 | "integrity": "sha512-z4qtrRuaAFJS4PUd0g+xy7aN4y+RvEt/QTJpR184lhJguBA1S/LsVlvE/CM95RsYMOFJG3NGGDjqFCzKU19S/A==", 206 | "requires": { 207 | "@kwsites/file-exists": "^1.1.1", 208 | "@kwsites/promise-deferred": "^1.1.1", 209 | "debug": "^4.3.2" 210 | } 211 | }, 212 | "web-streams-polyfill": { 213 | "version": "3.2.0", 214 | "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz", 215 | "integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==" 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scripts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "update.js", 6 | "type": "module", 7 | "scripts": { 8 | "update": "node update.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "MIT", 13 | "dependencies": { 14 | "dateformat": "^5.0.2", 15 | "node-fetch": "^3.1.0", 16 | "simple-git": "^2.48.0" 17 | } 18 | } -------------------------------------------------------------------------------- /scripts/update.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import fs from 'fs/promises'; 3 | import fetch from 'node-fetch'; 4 | import dateFormat from 'dateformat'; 5 | import simpleGit from 'simple-git'; 6 | 7 | // We want it to be ran from root not scripts 8 | const git = simpleGit({ baseDir: path.resolve('..') }); 9 | 10 | const BASE = 'https://bad-domains-v2.walshy.dev'; 11 | 12 | async function run() { 13 | console.log('Fetching...'); 14 | const { total, found } = await writeBadDomains(); 15 | await fetchAndWrite('/domains-list.json', '../domains-list.json'); 16 | await fetchAndWrite('/domains.json', '../domains.json'); 17 | await fetchAndWrite('/domains.txt', '../domains.txt'); 18 | 19 | console.log('Pushing!'); 20 | const percent = ((found / total) * 100).toFixed(2); 21 | const commitMessage = `${dateFormat(new Date(), 'yyyy-mm-dd')} - Updated domains (Found ${found}/${total} - ${percent}%)`; 22 | await tryAndPush( 23 | ['bad-domains.json', 'domains-list.json', 'domains.txt', 'domains.json'], 24 | commitMessage 25 | ); 26 | 27 | console.log('Done! :)'); 28 | } 29 | 30 | async function callApi(path) { 31 | const res = await fetch(`${BASE}${path}`); 32 | 33 | if (res.headers.get('content-type') === 'application/json') { 34 | return { type: 'json', body: await res.json() }; 35 | } else { 36 | return { type: 'text', body: await res.text() }; 37 | } 38 | } 39 | 40 | async function fetchAndWrite(apiPath, filePath) { 41 | const resp = await callApi(apiPath); 42 | 43 | if (resp.type === 'json') { 44 | await fs.writeFile(path.resolve(filePath), JSON.stringify(resp.body, null, 4)); 45 | } else { 46 | await fs.writeFile(path.resolve(filePath), resp.body); 47 | } 48 | } 49 | 50 | async function writeBadDomains() { 51 | const resp = await callApi('/bad-domains.json'); 52 | 53 | const obj = resp.body; 54 | 55 | await fs.writeFile(path.resolve('../bad-domains.json'), JSON.stringify(obj, null, 4)); 56 | 57 | const totalHashes = Object.keys(obj).length; 58 | const foundHashes = Object.keys(obj).filter(key => obj[key] !== null).length; 59 | 60 | console.log(`Found ${foundHashes} of ${totalHashes} hashes`); 61 | return { total: totalHashes, found: foundHashes }; 62 | } 63 | 64 | async function tryAndPush(files, commitMessage) { 65 | try { 66 | const result = await git.status(); 67 | if (result.files.length === 0) { 68 | console.log('No changes to commit'); 69 | return; 70 | } 71 | 72 | await git.add(files); 73 | await git.commit(commitMessage); 74 | await git.push('origin', 'main'); 75 | } catch(e) { 76 | console.error(e); 77 | } 78 | } 79 | 80 | run(); --------------------------------------------------------------------------------