first commit

This commit is contained in:
Colbster937
2024-07-28 19:39:37 -05:00
commit 93af5dc4ba
22 changed files with 2203 additions and 0 deletions

87
src/commands/check.ts Normal file
View File

@@ -0,0 +1,87 @@
import { Declare, Command, type CommandContext, Options,
createStringOption, Embed,
createBooleanOption} from 'seyfert';
import { MessageFlags } from 'seyfert/lib/types';
import filters from "../modules/filters"
@Options(
{
url: createStringOption({
required:true,
description: "The URL to check",
}),
filter: createStringOption({
required:false,
description: "The filter to check through",
choices: [
{ name: 'All', value: 'all' },
{ name: 'FortiGuard', value: 'fortiguard' },
{ name: 'Palo Alto Systems', value: 'palo' },
{ name: 'Lightspeed', value: 'lightspeed' }
]
}),
show: createBooleanOption({
required:false,
description: "Show the results non-ephemerally",
}),
}
)
@Declare({
name: 'check',
description: 'Check a link against various filters',
contexts: ['BOT_DM', 'GUILD', 'PRIVATE_CHANNEL'],
integrationTypes: ['GUILD_INSTALL', 'USER_INSTALL']
})
export default class FilterCheckCommand extends Command {
async run(ctx: CommandContext) {
const re = new RegExp("^(?:https?:\/\/)?(?:www\.)?([^\/]+)");
// @ts-ignore
let url = re.exec(ctx.options.url)[1];
const embed = new Embed();
embed.setColor('Green')
embed.setTitle(`Results for ${url}:`)
embed.setDescription("Loading...")
await ctx.editOrReply({
embeds:[embed],
// @ts-ignore
flags:ctx.options.show ? undefined : MessageFlags.Ephemeral
});
embed.setDescription("")
embed.setColor('Blue')
// @ts-ignore
if (!ctx.options.filter || ctx.options.filter == "all") {
let results = [await filters.fortiguard(url),await filters.lightspeed(url),await filters.palo(url)]
let formatted = ["Category: " + results[0],`LS Filter: ${results[1][0]}\nLS Rocket: ${results[1][1]}`,`Risk: ${results[2][1]}\nCategory: ${results[2][0].trim().replace(/^\s*$(?:\r\n?|\n)/gm,"")}`]
embed.addFields({name:"FortiGuard",value:formatted[0]},{name:"Lightspeed",value:formatted[1]},{name:"Palo Alto",value:formatted[2]})
} else {
let results;
// @ts-ignore
switch (ctx.options.filter) {
case "palo":
results = await filters.palo(url);
embed.addFields({name:"Palo Alto",value:`Risk: ${results[1]}\nCategory: ${results[0].trim().replace(/^\s*$(?:\r\n?|\n)/gm,"")}`})
break;
case "lightspeed":
results = await filters.lightspeed(url);
embed.addFields({name:"Lightspeed",value:`LS Filter: ${results[0]}\nLS Rocket: ${results[1]}`})
break;
case "fortiguard":
results = await filters.fortiguard(url);
embed.addFields({name:"FortiGuard",value:"Category: " + results})
break;
default:
embed.setDescription("No filter passed")
break;
}
}
await ctx.editOrReply({
embeds:[embed],
flags:MessageFlags.Ephemeral
});
}
}

19
src/commands/ping.ts Normal file
View File

@@ -0,0 +1,19 @@
import { Declare, Command, type CommandContext } from 'seyfert';
@Declare({
name: 'ping',
description: 'Show the ping with discord',
contexts: ['BOT_DM', 'GUILD', 'PRIVATE_CHANNEL'],
integrationTypes: ['GUILD_INSTALL', 'USER_INSTALL']
})
export default class PingCommand extends Command {
async run(ctx: CommandContext) {
// @ts-expect-error average latency between shards
const ping = ctx.client.gateway.latency;
await ctx.write({
content: `Pong! Ping: \`${ping}ms\``
});
}
}

8
src/events/botReady.ts Normal file
View File

@@ -0,0 +1,8 @@
import { createEvent } from "seyfert";
export default createEvent({
data: { once: true, name: "botReady" },
async run(user, client) {
client.logger.info(`${user.username} is ready`);
}
})

12
src/index.ts Normal file
View File

@@ -0,0 +1,12 @@
import { Client } from 'seyfert';
const client = new Client();
if (process.argv.includes("--web")) {
require("./web/api.ts")
}
if (!process.argv.includes("--no-bot")) {
client.start().then(() => client.uploadCommands());
} else {
setInterval(()=>{},100)
}

82
src/modules/filters.ts Normal file
View File

@@ -0,0 +1,82 @@
import cheerio from 'cheerio';
// Lightspeed
async function lightspeedCategorize(num: number) {
let jFile:Blob = Bun.file("src/modules/lightspeed.json")
let catJson = await jFile.json();
for (let i = 0; i < catJson.length;i++) {
if (catJson[i]["CategoryNumber"] == num) {
return catJson[i]["CategoryName"]
}
}
return num // No category
}
async function lightspeed(url:string) {
let res = await fetch("https://production-archive-proxy-api.lightspeedsystems.com/archiveproxy",
{
"method":"POST",
"headers": {
'accept': 'application/json, text/plain, */*',
'accept-language': 'en-US,en;q=0.9',
'authority': 'production-archive-proxy-api.lightspeedsystems.com',
'content-type': 'application/json',
'origin': 'https://archive.lightspeedsystems.com',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'x-api-key': 'onEkoztnFpTi3VG7XQEq6skQWN3aFm3h'
},
// graphQL vvv
"body": `{"query":"\\nquery getDeviceCategorization($itemA: CustomHostLookupInput!, $itemB: CustomHostLookupInput!){\\n a: custom_HostLookup(item: $itemA) { cat}\\n b: custom_HostLookup(item: $itemB) { cat \\n }\\n}","variables":{"itemA":{"hostname":"${url}"}, "itemB":{"hostname":"${url}"}}}`
}
);
let body= await res.json();
let cat = [body["data"]["a"]["cat"],body["data"]["b"]["cat"]]
return [await lightspeedCategorize(cat[0]),await lightspeedCategorize(cat[1])]
}
// FortiGuard
async function fortiguard(url:string) {
let res = await fetch("https://www.fortiguard.com/learnmore/dns",{
"method":"POST",
"headers": {
'Accept':
'*/*',
'Accept-Language':
'en-US,en;q=0.9',
'Authority':
'www.fortiguard.com',
'Content-Type':
'application/json;charset=UTF-8',
'Cookie':
'cookiesession1=678A3E0F33B3CB9D7BEECD2B8A5DD036; privacy_agreement=true',
'Origin':
'https://www.fortiguard.com',
'Referer':
'https://www.fortiguard.com/services/sdns',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
},
"body": `{"value": "${url}", "version": 9}`
})
let rJson = await res.json();
return rJson["dns"]["categoryname"]
}
// Palo Alto
async function palo(domain: string): Promise<any> {
try {
const res = await fetch(`https://urlfiltering.paloaltonetworks.com/single_cr/?url=${domain}`);
const html = await res.text();
const c = cheerio.load(html);
return [c(`*[for="id_new_category"]`).eq(2).parent().find(".form-text").text().trim(),c(`*[for="id_new_category"]`).eq(1).parent().find(".form-text").text().trim()]
} catch (error) {
console.error('Error fetching or parsing the HTML:', error);
return ''; // Return an empty string in case of error
}
}
export default { palo,fortiguard,lightspeed,lightspeedCategorize }

738
src/modules/lightspeed.json Normal file
View File

@@ -0,0 +1,738 @@
[
{
"CategoryNumber": -1,
"CategoryName": "not reviewed"
},
{
"CategoryNumber": 1,
"CategoryName": "local-allow"
},
{
"CategoryNumber": 2,
"CategoryName": "local-block"
},
{"CategoryNumber": 3,"CategoryName": "ads"},
{
"CategoryNumber": 4,
"CategoryName": "adult"
},
{
"CategoryNumber": 5,
"CategoryName": "audio-video"
},
{
"CategoryNumber": 6,
"CategoryName": "business"
},
{
"CategoryNumber": 7,
"CategoryName": "errors"
},
{
"CategoryNumber": 8,
"CategoryName": "drugs"
},
{
"CategoryNumber": 9,
"CategoryName": "education"
},
{
"CategoryNumber": 10,
"CategoryName": "business.finance"
},
{
"CategoryNumber": 11,
"CategoryName": "forums"
},
{
"CategoryNumber": 12,
"CategoryName": "gambling"
},
{
"CategoryNumber": 13,
"CategoryName": "games"
},
{
"CategoryNumber": 14,
"CategoryName": "general"
},
{
"CategoryNumber": 15,
"CategoryName": "government"
},
{
"CategoryNumber": 16,
"CategoryName": "security.hacking"
},
{
"CategoryNumber": 17,
"CategoryName": "violence.hate"
},
{
"CategoryNumber": 18,
"CategoryName": "business.jobs"
},
{
"CategoryNumber": 19,
"CategoryName": "forums.mail"
},
{
"CategoryNumber": 20,
"CategoryName": "news"
},
{
"CategoryNumber": 21,
"CategoryName": "porn"
},
{
"CategoryNumber": 22,
"CategoryName": "porn.de"
},
{
"CategoryNumber": 23,
"CategoryName": "porn.es"
},
{
"CategoryNumber": 24,
"CategoryName": "porn.fr"
},
{
"CategoryNumber": 25,
"CategoryName": "porn.it"
},
{
"CategoryNumber": 26,
"CategoryName": "porn.jp"
},
{
"CategoryNumber": 27,
"CategoryName": "porn.nl"
},
{
"CategoryNumber": 28,
"CategoryName": "security.proxy"
},
{
"CategoryNumber": 29,
"CategoryName": "shopping"
},
{
"CategoryNumber": 30,
"CategoryName": "sports"
},
{
"CategoryNumber": 31,
"CategoryName": "suspicious"
},
{
"CategoryNumber": 32,
"CategoryName": "violence"
},
{
"CategoryNumber": 33,
"CategoryName": "security.warez"
},
{
"CategoryNumber": 34,
"CategoryName": "directory"
},
{
"CategoryNumber": 35,
"CategoryName": "ads.popup-ads"
},
{
"CategoryNumber": 36,
"CategoryName": "travel"
},
{
"CategoryNumber": 37,
"CategoryName": "automobile"
},
{
"CategoryNumber": 38,
"CategoryName": "forums.newsgroups"
},
{
"CategoryNumber": 39,
"CategoryName": "forums.personals"
},
{
"CategoryNumber": 40,
"CategoryName": "humor"
},
{
"CategoryNumber": 41,
"CategoryName": "education.lifestyles"
},
{
"CategoryNumber": 42,
"CategoryName": "alcohol"
},
{
"CategoryNumber": 43,
"CategoryName": "family.health"
},
{
"CategoryNumber": 44,
"CategoryName": "education.science"
},
{
"CategoryNumber": 45,
"CategoryName": "entertainment"
},
{
"CategoryNumber": 46,
"CategoryName": "kids_and_teens"
},
{
"CategoryNumber": 47,
"CategoryName": "education.arts"
},
{
"CategoryNumber": 48,
"CategoryName": "education.literature"
},
{
"CategoryNumber": 49,
"CategoryName": "music"
},
{
"CategoryNumber": 50,
"CategoryName": "education.music"
},
{
"CategoryNumber": 51,
"CategoryName": "microsoft"
},
{
"CategoryNumber": 52,
"CategoryName": "ads.banner-ads"
},
{
"CategoryNumber": 53,
"CategoryName": "ads.html-ads"
},
{
"CategoryNumber": 54,
"CategoryName": "ads.javascript-ads"
},
{
"CategoryNumber": 55,
"CategoryName": "spam"
},
{
"CategoryNumber": 56,
"CategoryName": "ham"
},
{
"CategoryNumber": 57,
"CategoryName": "computers"
},
{
"CategoryNumber": 58,
"CategoryName": "family.religion"
},
{
"CategoryNumber": 59,
"CategoryName": "world"
},
{
"CategoryNumber": 60,
"CategoryName": "forums.p2p"
},
{
"CategoryNumber": 61,
"CategoryName": "forums.im"
},
{
"CategoryNumber": 62,
"CategoryName": "security.spyware"
},
{
"CategoryNumber": 63,
"CategoryName": "security.virus"
},
{
"CategoryNumber": 64,
"CategoryName": "security.test"
},
{
"CategoryNumber": 65,
"CategoryName": "security.phishing"
},
{
"CategoryNumber": 66,
"CategoryName": "weapons"
},
{
"CategoryNumber": 67,
"CategoryName": "access-denied"
},
{
"CategoryNumber": 68,
"CategoryName": "law"
},
{
"CategoryNumber": 69,
"CategoryName": "kids_and_teens.chat"
},
{
"CategoryNumber": 70,
"CategoryName": "adult.language"
},
{
"CategoryNumber": 71,
"CategoryName": "forums.blogs"
},
{
"CategoryNumber": 72,
"CategoryName": "security"
},
{
"CategoryNumber": 73,
"CategoryName": "business.real_estate"
},
{
"CategoryNumber": 74,
"CategoryName": "education.games"
},
{
"CategoryNumber": 75,
"CategoryName": "education.social_science"
},
{
"CategoryNumber": 76,
"CategoryName": "family.food"
},
{
"CategoryNumber": 77,
"CategoryName": "kids_and_teens.animals"
},
{
"CategoryNumber": 78,
"CategoryName": "shopping.spam"
},
{
"CategoryNumber": 79,
"CategoryName": "society"
},
{
"CategoryNumber": 80,
"CategoryName": "education.sex"
},
{
"CategoryNumber": 81,
"CategoryName": "shopping.auctions"
},
{
"CategoryNumber": 82,
"CategoryName": "sports.fantasy"
},
{
"CategoryNumber": 83,
"CategoryName": "hobby"
},
{
"CategoryNumber": 84,
"CategoryName": "sports.youth"
},
{
"CategoryNumber": 85,
"CategoryName": "search"
},
{
"CategoryNumber": 86,
"CategoryName": "world.de"
},
{
"CategoryNumber": 87,
"CategoryName": "world.es"
},
{
"CategoryNumber": 88,
"CategoryName": "world.fr"
},
{
"CategoryNumber": 89,
"CategoryName": "world.it"
},
{
"CategoryNumber": 90,
"CategoryName": "world.jp"
},
{
"CategoryNumber": 91,
"CategoryName": "world.nl"
},
{
"CategoryNumber": 92,
"CategoryName": "world.pt"
},
{
"CategoryNumber": 93,
"CategoryName": "world.ru"
},
{
"CategoryNumber": 94,
"CategoryName": "porn.illicit"
},
{
"CategoryNumber": 95,
"CategoryName": "family"
},
{
"CategoryNumber": 96,
"CategoryName": "society.politics"
},
{
"CategoryNumber": 97,
"CategoryName": "society.crime"
},
{
"CategoryNumber": 98,
"CategoryName": "sports.martial_arts"
},
{
"CategoryNumber": 99,
"CategoryName": "education.history"
},
{
"CategoryNumber": 100,
"CategoryName": "adult.art"
},
{
"CategoryNumber": 101,
"CategoryName": "adult.bodyart"
},
{
"CategoryNumber": 102,
"CategoryName": "adult.games"
},
{
"CategoryNumber": 103,
"CategoryName": "adult.lifestyles"
},
{
"CategoryNumber": 104,
"CategoryName": "shopping.office_supplies"
},
{
"CategoryNumber": 105,
"CategoryName": "expired"
},
{
"CategoryNumber": 106,
"CategoryName": "world.pl"
},
{
"CategoryNumber": 107,
"CategoryName": "world.cn"
},
{
"CategoryNumber": 108,
"CategoryName": "world.kr"
},
{
"CategoryNumber": 109,
"CategoryName": "porn.pl"
},
{
"CategoryNumber": 110,
"CategoryName": "porn.ru"
},
{
"CategoryNumber": 111,
"CategoryName": "porn.pt"
},
{
"CategoryNumber": 112,
"CategoryName": "plagiarism"
},
{
"CategoryNumber": 113,
"CategoryName": "parked"
},
{
"CategoryNumber": 114,
"CategoryName": "suspicious.script"
},
{
"CategoryNumber": 115,
"CategoryName": "business.construction"
},
{
"CategoryNumber": 116,
"CategoryName": "security.nettools"
},
{
"CategoryNumber": 117,
"CategoryName": "forums.social_networking"
},
{
"CategoryNumber": 118,
"CategoryName": "forums.dating"
},
{
"CategoryNumber": 119,
"CategoryName": "business.manufacturing"
},
{
"CategoryNumber": 120,
"CategoryName": "G-Rated"
},
{
"CategoryNumber": 121,
"CategoryName": "PG-Rated"
},
{
"CategoryNumber": 122,
"CategoryName": "R-Rated"
},
{
"CategoryNumber": 123,
"CategoryName": "X-Rated"
},
{
"CategoryNumber": 124,
"CategoryName": "S-Rated"
},
{
"CategoryNumber": 125,
"CategoryName": "security.potentially_unwanted_applications"
},
{
"CategoryNumber": 126,
"CategoryName": "offensive"
},
{
"CategoryNumber": 127,
"CategoryName": "computers.filehosting"
},
{
"CategoryNumber": 128,
"CategoryName": "computers.consumer_electronics"
},
{
"CategoryNumber": 129,
"CategoryName": "education.media"
},
{
"CategoryNumber": 130,
"CategoryName": "security.virus_ignore"
},
{
"CategoryNumber": 131,
"CategoryName": "entertainment.radio_and_tv"
},
{
"CategoryNumber": 132,
"CategoryName": "photography"
},
{
"CategoryNumber": 133,
"CategoryName": "security.shorteners"
},
{
"CategoryNumber": 134,
"CategoryName": "security.malware"
},
{
"CategoryNumber": 135,
"CategoryName": "security.translators"
},
{
"CategoryNumber": 136,
"CategoryName": "computers.storage"
},
{
"CategoryNumber": 137,
"CategoryName": "violence.extremism"
},
{
"CategoryNumber": 138,
"CategoryName": "computers.analytics"
},
{
"CategoryNumber": 139,
"CategoryName": "esports"
},
{
"CategoryNumber": 140,
"CategoryName": "artificial-intelligence"
},
{
"CategoryNumber": 141,
"CategoryName": "artificial-Intelligence.generative"
},
{
"CategoryNumber": 142,
"CategoryName": "artificial-intelligence.detective"
},
{
"CategoryNumber": 200,
"CategoryName": "facebook"
},
{
"CategoryNumber": 201,
"CategoryName": "twitter"
},
{
"CategoryNumber": 202,
"CategoryName": "instagram"
},
{
"CategoryNumber": 203,
"CategoryName": "pinterest"
},
{
"CategoryNumber": 900,
"CategoryName": "education.videos"
}
]

27
src/modules/whois.ts Normal file
View File

@@ -0,0 +1,27 @@
import ipRangeCheck from 'ip-range-check';
export async function getRDAP(ipv4Address: string): Promise<string | null> {
try {
const response = await fetch('https://data.iana.org/rdap/ipv4.json');
if (!response.ok) {
throw new Error('Failed to fetch RDAP data');
}
const rdapData = await response.json();
const ipv4Services: Array<Array<any>> = rdapData.services;
for (const service of ipv4Services) {
const cidrRanges: Array<string> = service[0] as Array<string>;
const endpoints: Array<string> = service[1] as Array<string>;
if (ipRangeCheck(ipv4Address, cidrRanges)) {
return endpoints[0]; // usually https
}
}
return null;
} catch (error) {
console.error('Error fetching RDAP data:', error);
return null;
}
}

100
src/web/api.ts Normal file
View File

@@ -0,0 +1,100 @@
import Elysia from "elysia";
import filters from "../modules/filters"
import { join } from "path";
import { readFile } from "fs/promises";
const app = new Elysia();
app.get("/", async () => {
const filePath = join(import.meta.dir, "../../index.html");
const fileContent = await readFile(filePath);
return new Response(fileContent, { headers: { "Content-Type": "text/html" } });
});
app.get("/api/",()=>{
return "OK"
})
app.get("/api/ping",()=>{
return "OK"
})
app.get("/api/check/:url/results.txt",async ({ params })=>{
let url = params.url
let results = [await filters.fortiguard(url),await filters.lightspeed(url),await filters.palo(url)]
let formatted = ["FortiGuard:\nCategory: " + results[0] + "\n",`Lightspeed:\nLS Filter: ${results[1][0]}\nLS Rocket: ${results[1][1]}\n`,`Palo Alto:\nRisk: ${results[2][1]}\nCategory: ${results[2][0].trim().replace(/^\s*$(?:\r\n?|\n)/gm,"")}\n`]
return `FilterChecker Report for ${url}:\n\n${formatted.join("\n")}`
})
app.get("/api/check/:url/results.json",async ({ params })=>{
let url = params.url
let results = [await filters.fortiguard(url),await filters.lightspeed(url),await filters.palo(url)]
return {"fortiguard":results[0],"lightspeed":results[1],"paloalto":results[2]}
});
app.post("/check/:url/results.txt",async ({ params,body,set })=>{
let _:any = body
let bj = {"filter": "all"};
try {
bj = JSON.parse(_)
} catch {
set.status = 400;
return "Bad JSON"
}
let url = params.url
if (bj.filter == "all") {
let results = [await filters.fortiguard(url),await filters.lightspeed(url),await filters.palo(url)]
let formatted = ["FortiGuard:\nCategory: " + results[0] + "\n",`Lightspeed:\nLS Filter: ${results[1][0]}\nLS Rocket: ${results[1][1]}\n`,`Palo Alto:\nRisk: ${results[2][1]}\nCategory: ${results[2][0].trim().replace(/^\s*$(?:\r\n?|\n)/gm,"")}\n`]
return `FilterChecker Report for ${url}:\n\n${formatted.join("\n")}`
} else {
let results; let formatted;
switch (bj.filter) {
case ("fortiguard" || "forti"):
results = await filters.fortiguard(url)
formatted = "FortiGuard:\nCategory: " + results[0]
return `FilterChecker Report for ${url}:\n\n${formatted}`
case ("lightspeed" || "ls"):
results = await filters.lightspeed(url)
formatted = `Lightspeed:\nLS Filter: ${results[0]}\nLS Rocket: ${results[1]}\n`
return `FilterChecker Report for ${url}:\n\n${formatted}`
case ("palo" || "paloalto") :
results = await filters.palo(url)
formatted = `Palo Alto:\nRisk: ${results[2][1]}\nCategory: ${results[2][0].trim().replace(/^\s*$(?:\r\n?|\n)/gm,"")}\n`
return `FilterChecker Report for ${url}:\n\n${formatted}`
default:
set.status = 400
return "Unknown filter. Accepted values: fortiguard, forti, lightspeed, ls, palo, paloalto"
}
}
})
app.post("/check/:url/results.json",async ({ params,body,set })=>{
let _:any = body
let bj = {"filter": "all"};
try {
bj = JSON.parse(_)
} catch {
set.status = 400;
return {"error":"Bad JSON"}
}
let url = params.url
if (bj.filter == "all") {
let url = params.url
let results = [await filters.fortiguard(url),await filters.lightspeed(url),await filters.palo(url)]
return {"fortiguard":results[0],"lightspeed":results[1],"paloalto":results[2]}
} else {
switch (bj.filter) {
case ("fortiguard" || "forti"):
return {"fortiguard":await filters.fortiguard(url)}
case ("lightspeed" || "ls"):
return {"lightspeed":await filters.lightspeed(url)}
case ("palo" || "paloalto") :
return {"palo":await filters.palo(url)}
default:
set.status = 400
return {"error":"Unknown filter. Accepted values: fortiguard, forti, lightspeed, ls, palo, paloalto"}
}
}
})
let port = 10000;
if (process.env.PORT) {port = Number(process.env.PORT)}
if (!isNaN(Number(process.argv[process.argv.length - 1]))) {port = Number(process.argv[process.argv.length - 1])}
console.log(`Listening on port: ${port}`)
app.listen(port)