mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-07-07 11:07:19 +00:00
feat: replace Phisherman with FishFish
This commit is contained in:
parent
bf08cade15
commit
8c2058821f
13 changed files with 202 additions and 475 deletions
|
@ -1,11 +1,10 @@
|
|||
import { escapeInlineCode } from "discord.js";
|
||||
import z from "zod/v4";
|
||||
import { allowTimeout } from "../../../RegExpRunner.js";
|
||||
import { phishermanDomainIsSafe } from "../../../data/Phisherman.js";
|
||||
import { getFishFishDomain } from "../../../data/FishFish.js";
|
||||
import { getUrlsInString, zRegex } from "../../../utils.js";
|
||||
import { mergeRegexes } from "../../../utils/mergeRegexes.js";
|
||||
import { mergeWordsIntoRegex } from "../../../utils/mergeWordsIntoRegex.js";
|
||||
import { PhishermanPlugin } from "../../Phisherman/PhishermanPlugin.js";
|
||||
import { getTextMatchPartialSummary } from "../functions/getTextMatchPartialSummary.js";
|
||||
import { MatchableTextType, matchMultipleTextTypesOnMessage } from "../functions/matchMultipleTextTypesOnMessage.js";
|
||||
import { automodTrigger } from "../helpers.js";
|
||||
|
@ -40,6 +39,7 @@ const configSchema = z.strictObject({
|
|||
include_verified: z.boolean().optional(),
|
||||
})
|
||||
.optional(),
|
||||
include_malicious: z.boolean().default(false),
|
||||
only_real_links: z.boolean().default(true),
|
||||
match_messages: z.boolean().default(true),
|
||||
match_embeds: z.boolean().default(true),
|
||||
|
@ -155,22 +155,18 @@ export const MatchLinksTrigger = automodTrigger<MatchResultType>()({
|
|||
}
|
||||
}
|
||||
|
||||
if (trigger.phisherman) {
|
||||
const phishermanResult = await pluginData.getPlugin(PhishermanPlugin).getDomainInfo(normalizedHostname);
|
||||
if (phishermanResult != null && !phishermanDomainIsSafe(phishermanResult)) {
|
||||
if (
|
||||
(trigger.phisherman.include_suspected && !phishermanResult.verifiedPhish) ||
|
||||
(trigger.phisherman.include_verified && phishermanResult.verifiedPhish)
|
||||
) {
|
||||
const suspectedVerified = phishermanResult.verifiedPhish ? "verified" : "suspected";
|
||||
return {
|
||||
extra: {
|
||||
type,
|
||||
link: link.input,
|
||||
details: `using Phisherman (${suspectedVerified})`,
|
||||
},
|
||||
};
|
||||
}
|
||||
const includeMalicious =
|
||||
trigger.include_malicious || trigger.phisherman?.include_suspected || trigger.phisherman?.include_verified;
|
||||
if (includeMalicious) {
|
||||
const domainInfo = getFishFishDomain(normalizedHostname);
|
||||
if (domainInfo && domainInfo.category !== "safe") {
|
||||
return {
|
||||
extra: {
|
||||
type,
|
||||
link: link.input,
|
||||
details: `(known ${domainInfo.category} domain)`,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +1,7 @@
|
|||
import { PluginOptions, guildPlugin } from "knub";
|
||||
import { hasPhishermanMasterAPIKey, phishermanApiKeyIsValid } from "../../data/Phisherman.js";
|
||||
import { makePublicFn } from "../../pluginUtils.js";
|
||||
import { getDomainInfo } from "./functions/getDomainInfo.js";
|
||||
import { guildPlugin } from "knub";
|
||||
import { PhishermanPluginType, zPhishermanConfig } from "./types.js";
|
||||
|
||||
export const PhishermanPlugin = guildPlugin<PhishermanPluginType>()({
|
||||
name: "phisherman",
|
||||
|
||||
configSchema: zPhishermanConfig,
|
||||
|
||||
public(pluginData) {
|
||||
return {
|
||||
getDomainInfo: makePublicFn(pluginData, getDomainInfo),
|
||||
};
|
||||
},
|
||||
|
||||
async beforeLoad(pluginData) {
|
||||
const { state } = pluginData;
|
||||
|
||||
pluginData.state.validApiKey = null;
|
||||
|
||||
if (!hasPhishermanMasterAPIKey()) {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.warn("[PHISHERMAN] Could not load Phisherman plugin: master API key is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
const apiKey = pluginData.config.get().api_key;
|
||||
if (apiKey) {
|
||||
const isValid = await phishermanApiKeyIsValid(apiKey).catch((err) => {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.warn(`[PHISHERMAN] Error checking user API key validity:\n${err.toString()}`);
|
||||
return false;
|
||||
});
|
||||
if (isValid) {
|
||||
state.validApiKey = apiKey;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -4,41 +4,12 @@ import { zPhishermanConfig } from "./types.js";
|
|||
|
||||
export const phishermanPluginDocs: ZeppelinPluginDocs = {
|
||||
prettyName: "Phisherman",
|
||||
type: "stable",
|
||||
type: "legacy",
|
||||
description: trimPluginDescription(`
|
||||
Match scam/phishing links using the Phisherman API. See https://phisherman.gg/ for more details!
|
||||
Match malicious links using Phisherman
|
||||
`),
|
||||
configurationGuide: trimPluginDescription(`
|
||||
### Getting started
|
||||
To get started, request an API key for Phisherman following the instructions at https://docs.phisherman.gg/guide/getting-started.html#requesting-api-access
|
||||
Then, add the api key to the plugin's config:
|
||||
|
||||
~~~yml
|
||||
phisherman:
|
||||
config:
|
||||
api_key: "your key here"
|
||||
~~~
|
||||
|
||||
### Note
|
||||
When using Phisherman features in Zeppelin, Zeppelin reports statistics about checked links back to Phisherman. This only includes the domain (e.g. zeppelin.gg), not the full link.
|
||||
|
||||
### Usage with Automod
|
||||
Once you have configured the Phisherman plugin, you are ready to use it with automod. Currently, Phisherman is available as an option in the \`match_links\` plugin:
|
||||
|
||||
~~~yml
|
||||
automod:
|
||||
config:
|
||||
rules:
|
||||
# Clean any scam links detected by Phisherman
|
||||
filter_scam_links:
|
||||
triggers:
|
||||
- match_links:
|
||||
phisherman:
|
||||
include_suspected: true # It's recommended to keep this enabled to catch new scam domains quickly
|
||||
include_verified: true
|
||||
actions:
|
||||
clean: true
|
||||
~~~
|
||||
This plugin has been deprecated. Please use the \`include_malicious\` option for automod \`match_links\` trigger instead.
|
||||
`),
|
||||
configSchema: zPhishermanConfig,
|
||||
};
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import { GuildPluginData } from "knub";
|
||||
import {
|
||||
getPhishermanDomainInfo,
|
||||
phishermanDomainIsSafe,
|
||||
trackPhishermanCaughtDomain,
|
||||
} from "../../../data/Phisherman.js";
|
||||
import { PhishermanDomainInfo } from "../../../data/types/phisherman.js";
|
||||
import { PhishermanPluginType } from "../types.js";
|
||||
|
||||
export async function getDomainInfo(
|
||||
pluginData: GuildPluginData<PhishermanPluginType>,
|
||||
domain: string,
|
||||
): Promise<PhishermanDomainInfo | null> {
|
||||
if (!pluginData.state.validApiKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const info = await getPhishermanDomainInfo(domain).catch((err) => {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.warn(`[PHISHERMAN] Error in getDomainInfo() for server ${pluginData.guild.id}: ${err.message}`);
|
||||
if (err.message === "missing permissions") {
|
||||
pluginData.state.validApiKey = null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
if (info != null && !phishermanDomainIsSafe(info)) {
|
||||
trackPhishermanCaughtDomain(pluginData.state.validApiKey, domain);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
|
@ -7,7 +7,5 @@ export const zPhishermanConfig = z.strictObject({
|
|||
|
||||
export interface PhishermanPluginType extends BasePluginType {
|
||||
configSchema: typeof zPhishermanConfig;
|
||||
state: {
|
||||
validApiKey: string | null;
|
||||
};
|
||||
state: {};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue