Compare commits
10 Commits
f6db2d5d7a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f72b04d49b | |||
| 8157ca00a8 | |||
| 5c5e2ee5ba | |||
| cc4abb3385 | |||
| 299530b0dd | |||
| b8db58a71a | |||
| 8dce37fe08 | |||
| 593083d994 | |||
| d816568522 | |||
| 1361fab0ad |
27
package.json
27
package.json
@@ -32,29 +32,30 @@
|
|||||||
"@grammyjs/i18n": "1.1.2",
|
"@grammyjs/i18n": "1.1.2",
|
||||||
"@grammyjs/parse-mode": "1.11.1",
|
"@grammyjs/parse-mode": "1.11.1",
|
||||||
"@grammyjs/runner": "2.0.3",
|
"@grammyjs/runner": "2.0.3",
|
||||||
"@grammyjs/types": "3.22.2",
|
"@grammyjs/types": "3.23.0",
|
||||||
"@hono/node-server": "1.19.4",
|
"@hono/node-server": "1.19.9",
|
||||||
"@urql/core": "^6.0.1",
|
"@urql/core": "^6.0.1",
|
||||||
|
"axios": "^1.13.3",
|
||||||
"callback-data": "1.1.1",
|
"callback-data": "1.1.1",
|
||||||
"grammy": "1.38.2",
|
"grammy": "1.39.3",
|
||||||
"hono": "4.9.9",
|
"hono": "4.11.6",
|
||||||
"iso-639-1": "3.1.5",
|
"iso-639-1": "3.1.5",
|
||||||
"pino": "9.12.0",
|
"pino": "10.3.0",
|
||||||
"pino-pretty": "13.1.1",
|
"pino-pretty": "13.1.3",
|
||||||
"tsx": "4.20.6",
|
"tsx": "4.21.0",
|
||||||
"valibot": "1.1.0"
|
"valibot": "1.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "5.4.1",
|
"@antfu/eslint-config": "7.2.0",
|
||||||
"@eslint/js": "^9.39.2",
|
"@eslint/js": "^9.39.2",
|
||||||
"@types/node": "^24.5.2",
|
"@types/node": "^25.0.10",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^9.39.2",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"lint-staged": "^16.2.3",
|
"lint-staged": "^16.2.7",
|
||||||
"prettier": "3.7.4",
|
"prettier": "3.8.1",
|
||||||
"tsc-watch": "^7.2.0",
|
"tsc-watch": "^7.2.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-eslint": "^8.51.0"
|
"typescript-eslint": "^8.54.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.ts": "eslint"
|
"*.ts": "eslint"
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ const composer = new Composer<Context>();
|
|||||||
|
|
||||||
const feature = composer.chatType(["private", "group", "supergroup"]);
|
const feature = composer.chatType(["private", "group", "supergroup"]);
|
||||||
|
|
||||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What triggers this feature and adds to the log when it has been triggered.
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
* The trigger is the command "/botInfo"
|
* The trigger is the command "/botInfo"
|
||||||
@@ -18,6 +16,8 @@ feature.hears(
|
|||||||
/^\/botInfo/,
|
/^\/botInfo/,
|
||||||
logHandle("bot-info-command"),
|
logHandle("bot-info-command"),
|
||||||
async (ctx: Context) => {
|
async (ctx: Context) => {
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
|
||||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
|
||||||
// Checks if the context includes a message property.
|
// Checks if the context includes a message property.
|
||||||
@@ -45,21 +45,21 @@ feature.hears(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
await ctx.reply(
|
await ctx.reply(
|
||||||
`[Lucid](https://werewolfkid.monster) made this bot as a protest against the enshittification of Twitter and Nazi\\-fication of it\\ ever since Elon Must did a Nazi salute at a Trump Rally celebrating Trump\\'s second inauguration\\.`,
|
`[Lucid](https://werewolfkid.monster) made this bot as a protest against the enshittification and Nazi\\-fication of Twitter\\ ever since Elon Musk took it over. The final straw aws when he did a Nazi salute at a Trump Rally celebrating Trump\\'s second inauguration\\.`,
|
||||||
{
|
{
|
||||||
parse_mode: "MarkdownV2",
|
parse_mode: "MarkdownV2",
|
||||||
reply_parameters: { message_id: ctx.msg.message_id }
|
reply_parameters: { message_id: ctx.msg.message_id }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
await ctx.reply(
|
await ctx.reply(
|
||||||
`Recently there have been reports of extremist right\\-wing individuals doxxing and harassing anyone left of center\\. The victims have come out to state that they\\'ve had several accounts hacked into\\, including onces with unique passwords\\. It is clear that these assholes are using some kind of script kiddie malware to capture\\/steal credentials and possibly even stored passwords\\.`,
|
`There have been reports of extremist right\\-wing individuals doxxing and harassing anyone left of center\\. The victims have come out to state that they\\'ve had several accounts hacked into\\, including onces with unique passwords\\. It is clear that these assholes are using some kind of script kiddie malware to capture\\/steal credentials and possibly even stored passwords\\.`,
|
||||||
{
|
{
|
||||||
parse_mode: "MarkdownV2",
|
parse_mode: "MarkdownV2",
|
||||||
reply_parameters: { message_id: ctx.msg.message_id }
|
reply_parameters: { message_id: ctx.msg.message_id }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return await ctx.reply(
|
return await ctx.reply(
|
||||||
`Lucid decided it was time to make a statement\\. Twitter\\/X is not safe anymore\\. The fandom doesn\\'t need it\\. It should be boycotted and not allowed anymore\\. Thus decided to try making this bot public\\-use to test it's viability\\. Feel free to add this bot into your own group\\. All it needs is an admin role with the permission to delete messages\\.`,
|
`Lucid decided it was time to make a statement\\. Twitter\\/X is not safe anymore\\. The fandom doesn\\'t need it\\. It should be boycotted and not allowed anymore\\. Thus they decided to try making this bot public\\-use to test it's viability\\. Feel free to add this bot into your own group\\. All it needs is an admin role with the permission to delete messages\\.`,
|
||||||
{
|
{
|
||||||
parse_mode: "MarkdownV2",
|
parse_mode: "MarkdownV2",
|
||||||
reply_parameters: { message_id: ctx.msg.message_id }
|
reply_parameters: { message_id: ctx.msg.message_id }
|
||||||
|
|||||||
@@ -7,18 +7,19 @@ import { urql } from "#root/main.js";
|
|||||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||||
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
|
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
|
||||||
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
|
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
|
||||||
|
import tiktokLinkCheck from "#root/lib/tiktokLinkCheck.js";
|
||||||
|
|
||||||
const composer = new Composer<Context>();
|
const composer = new Composer<Context>();
|
||||||
|
|
||||||
const feature = composer.chatType(["group", "supergroup"]);
|
const feature = composer.chatType(["group", "supergroup"]);
|
||||||
|
|
||||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What triggers this feature and adds to the log when it has been triggered.
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
* The trigger is anytime an embedded url is detected.
|
* The trigger is anytime an embedded url is detected.
|
||||||
*/
|
*/
|
||||||
feature.on("message::url", logHandle("embed-check"), async (ctx: Context) => {
|
feature.on("message::url", logHandle("embed-check"), async (ctx: Context) => {
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
|
||||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
|
||||||
if (ctx.chat && ctx.msg) {
|
if (ctx.chat && ctx.msg) {
|
||||||
@@ -32,144 +33,37 @@ feature.on("message::url", logHandle("embed-check"), async (ctx: Context) => {
|
|||||||
// Filters every message/caption entity that is a url into a new array.
|
// Filters every message/caption entity that is a url into a new array.
|
||||||
const embeds = ctx.msg.entities
|
const embeds = ctx.msg.entities
|
||||||
? ctx.msg.entities.filter(e => e.type === "text_link")
|
? ctx.msg.entities.filter(e => e.type === "text_link")
|
||||||
: null;
|
: [];
|
||||||
const captionEmbeds = ctx.msg.caption_entities
|
const captionEmbeds = ctx.msg.caption_entities
|
||||||
? ctx.msg.caption_entities.filter(e => e.type === "text_link")
|
? ctx.msg.caption_entities.filter(e => e.type === "text_link")
|
||||||
: null;
|
: [];
|
||||||
|
const allEmbeds = embeds.concat(captionEmbeds);
|
||||||
|
|
||||||
// If the caption embeds array isn't empty filter through them to check if any is a Twitter/X or Meta url.
|
// If the caption embeds array isn't empty filter through them to check if any is a Twitter/X or Meta url.
|
||||||
if (captionEmbeds !== null && captionEmbeds.length) {
|
if (allEmbeds.length) {
|
||||||
const metaLinks = captionEmbeds.filter(({ url }) => metaLinkCheck(url));
|
const metaLinks = allEmbeds.filter(({ url }) => metaLinkCheck(url));
|
||||||
const twitterLinks = captionEmbeds.filter(({ url }) =>
|
const twitterLinks = allEmbeds.filter(({ url }) => twitterLinkCheck(url));
|
||||||
twitterLinkCheck(url)
|
const tiktokLinks = allEmbeds.filter(({ url }) => tiktokLinkCheck(url));
|
||||||
);
|
|
||||||
|
|
||||||
// Handle action and response if both meta and Twitter/X links are detected.
|
// Handles Meta & Facebook Links
|
||||||
if (metaLinks.length && twitterLinks.length) {
|
|
||||||
// Deletes the offending message.
|
|
||||||
ctx.msg.delete();
|
|
||||||
deletedLinks++;
|
|
||||||
|
|
||||||
await urql
|
|
||||||
.mutation(increment, { link: true, mutationKey })
|
|
||||||
.toPromise()
|
|
||||||
.then(async () => {
|
|
||||||
if (ctx.msg) {
|
|
||||||
// Replies to the user informing them of the action.
|
|
||||||
await ctx.reply(
|
|
||||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Also Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.\n\nIf this was forwarded from a channel consider forwarding without the caption so the media isn't deleted\\.`,
|
|
||||||
{ parse_mode: "MarkdownV2" }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle action and response if only meta links are detected.
|
|
||||||
if (metaLinks.length) {
|
if (metaLinks.length) {
|
||||||
// Deletes the offending message.
|
deletedLinks += metaLinks.length;
|
||||||
ctx.msg.delete();
|
|
||||||
deletedLinks++;
|
|
||||||
|
|
||||||
await urql
|
|
||||||
.mutation(increment, { link: true, mutationKey })
|
|
||||||
.toPromise()
|
|
||||||
.then(async () => {
|
|
||||||
if (ctx.msg) {
|
|
||||||
// Replies to the user informing them of the action.
|
|
||||||
await ctx.reply(
|
|
||||||
`@${username} Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\\n\nIf this was forwarded from a channel consider forwarding without the caption so the media isn't deleted\\.`,
|
|
||||||
{ parse_mode: "MarkdownV2" }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle action and response if only Twitter/X links are detected.
|
// Handles Twitter/X links.
|
||||||
if (twitterLinks.length) {
|
if (twitterLinks.length) {
|
||||||
// Deletes the offending message.
|
deletedLinks += twitterLinks.length;
|
||||||
ctx.msg.delete();
|
|
||||||
deletedLinks++;
|
|
||||||
|
|
||||||
await urql
|
|
||||||
.mutation(increment, { link: true, mutationKey })
|
|
||||||
.toPromise()
|
|
||||||
.then(async () => {
|
|
||||||
if (ctx.msg) {
|
|
||||||
// Replies to the user informing them of the action.
|
|
||||||
await ctx.reply(
|
|
||||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.\n\nIf this was forwarded from a channel consider forwarding without the caption so the media isn't deleted\\.`,
|
|
||||||
{ parse_mode: "MarkdownV2" }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the embeds array isn't empty filter through them to check if any is a Twitter/X or Meta url.
|
|
||||||
if (embeds !== null && embeds.length) {
|
|
||||||
const metaLinks = embeds.filter(({ url }) => metaLinkCheck(url));
|
|
||||||
const twitterLinks = embeds.filter(({ url }) => twitterLinkCheck(url));
|
|
||||||
|
|
||||||
// Handle action and response if both meta and Twitter/X links are detected.
|
|
||||||
if (metaLinks.length && twitterLinks.length) {
|
|
||||||
// Deletes the offending message.
|
|
||||||
ctx.msg.delete();
|
|
||||||
deletedLinks++;
|
|
||||||
|
|
||||||
await urql
|
|
||||||
.mutation(increment, { link: true, mutationKey })
|
|
||||||
.toPromise()
|
|
||||||
.then(async () => {
|
|
||||||
if (ctx.msg) {
|
|
||||||
// Replies to the user informing them of the action.
|
|
||||||
await ctx.reply(
|
|
||||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Also Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
|
||||||
{ parse_mode: "MarkdownV2" }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle action and response if only meta links are detected.
|
// Handles TikTok links.
|
||||||
if (metaLinks.length) {
|
if (tiktokLinks.length) {
|
||||||
// Deletes the offending message.
|
deletedLinks += tiktokLinks.length;
|
||||||
ctx.msg.delete();
|
|
||||||
deletedLinks++;
|
|
||||||
|
|
||||||
await urql
|
|
||||||
.mutation(increment, { link: true, mutationKey })
|
|
||||||
.toPromise()
|
|
||||||
.then(async () => {
|
|
||||||
if (ctx.msg) {
|
|
||||||
// Replies to the user informing them of the action.
|
|
||||||
await ctx.reply(
|
|
||||||
`@${username} Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
|
||||||
{ parse_mode: "MarkdownV2" }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle action and response if only Twitter/X links are detected.
|
|
||||||
if (twitterLinks.length) {
|
|
||||||
// Deletes the offending message.
|
|
||||||
ctx.msg.delete();
|
|
||||||
deletedLinks++;
|
|
||||||
|
|
||||||
await urql
|
|
||||||
.mutation(increment, { link: true, mutationKey })
|
|
||||||
.toPromise()
|
|
||||||
.then(async () => {
|
|
||||||
if (ctx.msg) {
|
|
||||||
// Replies to the user informing them of the action.
|
|
||||||
await ctx.reply(
|
|
||||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
|
||||||
{ parse_mode: "MarkdownV2" }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deletedLinks) {
|
if (deletedLinks) {
|
||||||
|
ctx.msg.delete();
|
||||||
|
|
||||||
return await urql
|
return await urql
|
||||||
.mutation(addGroup, {
|
.mutation(addGroup, {
|
||||||
groupID,
|
groupID,
|
||||||
@@ -179,13 +73,28 @@ feature.on("message::url", logHandle("embed-check"), async (ctx: Context) => {
|
|||||||
})
|
})
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(() =>
|
.then(() =>
|
||||||
urql.mutation(incrementGroup, {
|
urql
|
||||||
|
.mutation(incrementGroup, {
|
||||||
groupID,
|
groupID,
|
||||||
linksDeleted: deletedLinks,
|
linksDeleted: deletedLinks,
|
||||||
mutationKey
|
mutationKey
|
||||||
})
|
})
|
||||||
|
.then(
|
||||||
|
async () =>
|
||||||
|
await urql
|
||||||
|
.mutation(increment, { link: deletedLinks, mutationKey })
|
||||||
|
.toPromise()
|
||||||
|
.then(async () => {
|
||||||
|
if (ctx.msg) {
|
||||||
|
// Replies to the user informing them of the action.
|
||||||
|
await ctx.reply(
|
||||||
|
`@${username} One or more links in your last message were on the banlist\\. Remember TikTok, Meta & Facebook, and Twitter\\/X links along with any reformatting services for them are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\.\n\nNo administration action was taken against you other than the message being deleted\\.\n\nIf this was forwarded from a channel consider forwarding without the caption so the media isn't deleted\\.`,
|
||||||
|
{ parse_mode: "MarkdownV2" }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ const composer = new Composer<Context>();
|
|||||||
|
|
||||||
const feature = composer.chatType(["group", "supergroup"]);
|
const feature = composer.chatType(["group", "supergroup"]);
|
||||||
|
|
||||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What triggers this feature and adds to the log when it has been triggered.
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
* The trigger is the command "/groupStats"
|
* The trigger is the command "/groupStats"
|
||||||
@@ -19,6 +17,8 @@ feature.hears(
|
|||||||
/^\/groupStats/,
|
/^\/groupStats/,
|
||||||
logHandle("groups-stats-command"),
|
logHandle("groups-stats-command"),
|
||||||
async (ctx: Context) => {
|
async (ctx: Context) => {
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
|
||||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
|
||||||
// Checks if the context includes a message property.
|
// Checks if the context includes a message property.
|
||||||
|
|||||||
@@ -3,19 +3,23 @@ import type { Context } from "#root/bot/context.js";
|
|||||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||||
import { urql } from "#root/main.js";
|
import { urql } from "#root/main.js";
|
||||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||||
|
import getCommandsList, { Commands } from "#root/lib/getCommandsList.js";
|
||||||
|
|
||||||
const composer = new Composer<Context>();
|
const composer = new Composer<Context>();
|
||||||
|
|
||||||
const feature = composer.chatType(["group", "supergroup", "private"]);
|
const feature = composer.chatType(["group", "supergroup", "private"]);
|
||||||
|
|
||||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What triggers this feature and adds to the log when it has been triggered.
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
* The trigger is the command "/help"
|
* The trigger is the command "/help"
|
||||||
*/
|
*/
|
||||||
feature.hears(/^\/help/, logHandle("help"), async (ctx: Context) => {
|
feature.hears(/^\/help/, logHandle("help"), async (ctx: Context) => {
|
||||||
|
const apiKey = process.env.GRAPHQL_API_TOKEN || "";
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
const statsSite = process.env.STATS_SITE || "";
|
||||||
|
|
||||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
const commandsListArr = await getCommandsList(`${statsSite}api/bot`, apiKey);
|
||||||
|
|
||||||
// const GROUP_IDS = process.env.GROUP_IDS
|
// const GROUP_IDS = process.env.GROUP_IDS
|
||||||
// ? process.env.GROUP_IDS.split(",")
|
// ? process.env.GROUP_IDS.split(",")
|
||||||
@@ -32,7 +36,7 @@ feature.hears(/^\/help/, logHandle("help"), async (ctx: Context) => {
|
|||||||
if (ctx.chat.type === "private") {
|
if (ctx.chat.type === "private") {
|
||||||
// Responds with message.
|
// Responds with message.
|
||||||
await ctx.reply(
|
await ctx.reply(
|
||||||
`Currently I have no commands for the public beta\\. I require no configuration\\. Simply add me to a group and make me an admin with the permission to delete messages\\. From there I will start deleting any Twitter\\/X and Meta links I detect\\. I also check embeds and forwards\\. Use /\\botInfo to learn more about my mission and why I was created\\.`,
|
`I require no configuration\\. Simply add me to a group and make me an admin with the permission to delete messages\\. From there I will start deleting any Twitter\\/X and Meta links I detect\\. I also check embeds and forwards\\.`,
|
||||||
{
|
{
|
||||||
parse_mode: "MarkdownV2",
|
parse_mode: "MarkdownV2",
|
||||||
reply_parameters: { message_id: ctx.msg.message_id }
|
reply_parameters: { message_id: ctx.msg.message_id }
|
||||||
@@ -48,7 +52,7 @@ feature.hears(/^\/help/, logHandle("help"), async (ctx: Context) => {
|
|||||||
if (["creator", "administrator"].includes(chatMember.status)) {
|
if (["creator", "administrator"].includes(chatMember.status)) {
|
||||||
// Respond with message.
|
// Respond with message.
|
||||||
await ctx.reply(
|
await ctx.reply(
|
||||||
`Currently I have no commands for the public beta\\. I require no configuration\\. If I am not working\\, make sure I have an admin role with the permission to delete messages\\. I should already be deleting any Twitter\\/X and Meta links I detect\\. I also check embeds and forwards\\. Use /\\botInfo to learn more about my mission and why I was created\\.`,
|
`I require no configuration\\. If I am not working\\, make sure I have an admin role with the permission to delete messages\\. I should already be deleting any Twitter\\/X and Meta links I detect\\. I also check embeds and forwards\\.`,
|
||||||
{
|
{
|
||||||
parse_mode: "MarkdownV2",
|
parse_mode: "MarkdownV2",
|
||||||
reply_parameters: { message_id: ctx.msg.message_id }
|
reply_parameters: { message_id: ctx.msg.message_id }
|
||||||
@@ -63,6 +67,17 @@ feature.hears(/^\/help/, logHandle("help"), async (ctx: Context) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const commandsListStr = commandsListArr.reduce((prev, curr) => {
|
||||||
|
const { command, description, groups } = curr;
|
||||||
|
|
||||||
|
return (prev += `**Command**: ${command} \\- ${description}\\.\nGroups: ${groups ? "✔️" : "❌"} \\| Private: ${curr.private ? "✔️" : "❌"}\n\n`);
|
||||||
|
}, "Here are a list of my commands:\n\n");
|
||||||
|
|
||||||
|
await ctx.reply(commandsListStr, {
|
||||||
|
parse_mode: "MarkdownV2",
|
||||||
|
reply_parameters: { message_id: ctx.msg.message_id }
|
||||||
|
});
|
||||||
|
|
||||||
await ctx.reply(
|
await ctx.reply(
|
||||||
`In the future a public GitHub repo will be set up with a mirror of the private git that the bot code is stored on\\. That repo will be used to handle bug reports and feature requests\\. Including requests to check for more domains\\.`,
|
`In the future a public GitHub repo will be set up with a mirror of the private git that the bot code is stored on\\. That repo will be used to handle bug reports and feature requests\\. Including requests to check for more domains\\.`,
|
||||||
{
|
{
|
||||||
@@ -71,13 +86,13 @@ feature.hears(/^\/help/, logHandle("help"), async (ctx: Context) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return await ctx.reply(
|
// return await ctx.reply(
|
||||||
`Down with fascism\\! Fuck MAGA\\! Fuck Trump\\! Fuck Nazis\\! Trans rights are human rights\\! Trans women are women\\! Trans men are men\\! Never let them take away your happiness\\!`,
|
// `Down with fascism\\! Fuck MAGA\\! Fuck Trump\\! Fuck Nazis\\! Trans rights are human rights\\! Trans women are women\\! Trans men are men\\! Never let them take away your happiness\\!`,
|
||||||
{
|
// {
|
||||||
parse_mode: "MarkdownV2",
|
// parse_mode: "MarkdownV2",
|
||||||
reply_parameters: { message_id: ctx.msg.message_id }
|
// reply_parameters: { message_id: ctx.msg.message_id }
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,16 +11,16 @@ const composer = new Composer<Context>();
|
|||||||
|
|
||||||
const feature = composer.chatType(["group", "supergroup"]);
|
const feature = composer.chatType(["group", "supergroup"]);
|
||||||
|
|
||||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What triggers this feature and adds to the log when it has been triggered.
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
* The trigger uses the global Twitter regex to detect Twitter and X links within messages.
|
* The trigger uses the global Twitter regex to detect Twitter and X links within messages.
|
||||||
*/
|
*/
|
||||||
feature.hears(
|
feature.hears(
|
||||||
metaRegex,
|
metaRegex,
|
||||||
logHandle("blacklist-detection-meta"),
|
logHandle("banlist-detection-meta"),
|
||||||
async (ctx: Context) => {
|
async (ctx: Context) => {
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
|
||||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
|
||||||
if (ctx.chat && ctx.msg) {
|
if (ctx.chat && ctx.msg) {
|
||||||
@@ -29,7 +29,7 @@ feature.hears(
|
|||||||
ctx.msg.delete();
|
ctx.msg.delete();
|
||||||
|
|
||||||
return await urql
|
return await urql
|
||||||
.mutation(increment, { link: true, mutationKey })
|
.mutation(increment, { link: 1, mutationKey })
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
if (ctx.msg && ctx.chat) {
|
if (ctx.msg && ctx.chat) {
|
||||||
@@ -64,4 +64,4 @@ feature.hears(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export { composer as metaBlacklist };
|
export { composer as metaBanlist };
|
||||||
@@ -9,8 +9,6 @@ const composer = new Composer<Context>();
|
|||||||
|
|
||||||
const feature = composer.chatType(["group", "supergroup"]);
|
const feature = composer.chatType(["group", "supergroup"]);
|
||||||
|
|
||||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What triggers this feature and adds to the log when it has been triggered.
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
* The trigger is the command "/registerGroup"
|
* The trigger is the command "/registerGroup"
|
||||||
@@ -19,6 +17,8 @@ feature.hears(
|
|||||||
/^\/registerGroup/,
|
/^\/registerGroup/,
|
||||||
logHandle("register-group-command"),
|
logHandle("register-group-command"),
|
||||||
async (ctx: Context) => {
|
async (ctx: Context) => {
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
|
||||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
|
||||||
// Checks if the context includes a message property.
|
// Checks if the context includes a message property.
|
||||||
67
src/bot/features/tiktokBanlist.ts
Normal file
67
src/bot/features/tiktokBanlist.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { Composer } from "grammy";
|
||||||
|
import type { Context } from "#root/bot/context.js";
|
||||||
|
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||||
|
import { urql } from "#root/main.js";
|
||||||
|
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||||
|
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
|
||||||
|
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
|
||||||
|
import { tiktokRegex } from "#root/lib/tiktokLinkCheck.js";
|
||||||
|
|
||||||
|
const composer = new Composer<Context>();
|
||||||
|
|
||||||
|
const feature = composer.chatType(["group", "supergroup"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
|
* The trigger uses the global Twitter regex to detect TikTok links within messages.
|
||||||
|
*/
|
||||||
|
feature.hears(
|
||||||
|
tiktokRegex,
|
||||||
|
logHandle("banlist-detection-tiktok"),
|
||||||
|
async (ctx: Context) => {
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
|
||||||
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
|
||||||
|
if (ctx.chat && ctx.msg) {
|
||||||
|
const username = ctx.msg.from?.username;
|
||||||
|
// Deletes the offending message.
|
||||||
|
ctx.msg.delete();
|
||||||
|
|
||||||
|
return await urql
|
||||||
|
.mutation(increment, { link: 1, mutationKey })
|
||||||
|
.toPromise()
|
||||||
|
.then(async () => {
|
||||||
|
if (ctx.msg && ctx.chat) {
|
||||||
|
// Replies to the user informing them of the action.
|
||||||
|
await ctx.reply(
|
||||||
|
`@${username} TikTok links are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||||
|
{ parse_mode: "MarkdownV2" }
|
||||||
|
);
|
||||||
|
|
||||||
|
const groupName = ctx.chat?.title || "";
|
||||||
|
const groupID = ctx.chat?.id.toString() || "";
|
||||||
|
const groupUsername = ctx.chat?.username || "";
|
||||||
|
|
||||||
|
return await urql
|
||||||
|
.mutation(addGroup, {
|
||||||
|
groupID,
|
||||||
|
groupName,
|
||||||
|
groupUsername,
|
||||||
|
mutationKey
|
||||||
|
})
|
||||||
|
.toPromise()
|
||||||
|
.then(() =>
|
||||||
|
urql.mutation(incrementGroup, {
|
||||||
|
groupID,
|
||||||
|
linksDeleted: 1,
|
||||||
|
mutationKey
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export { composer as tiktokBanlist };
|
||||||
@@ -11,16 +11,16 @@ const composer = new Composer<Context>();
|
|||||||
|
|
||||||
const feature = composer.chatType(["group", "supergroup"]);
|
const feature = composer.chatType(["group", "supergroup"]);
|
||||||
|
|
||||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What triggers this feature and adds to the log when it has been triggered.
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
* The trigger uses the global Twitter regex to detect Twitter and X links within messages.
|
* The trigger uses the global Twitter regex to detect Twitter and X links within messages.
|
||||||
*/
|
*/
|
||||||
feature.hears(
|
feature.hears(
|
||||||
twitterRegex,
|
twitterRegex,
|
||||||
logHandle("blacklist-detection-twitter"),
|
logHandle("banlist-detection-twitter"),
|
||||||
async (ctx: Context) => {
|
async (ctx: Context) => {
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
|
||||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
|
||||||
if (ctx.chat && ctx.msg) {
|
if (ctx.chat && ctx.msg) {
|
||||||
@@ -29,7 +29,7 @@ feature.hears(
|
|||||||
ctx.msg.delete();
|
ctx.msg.delete();
|
||||||
|
|
||||||
return await urql
|
return await urql
|
||||||
.mutation(increment, { link: true, mutationKey })
|
.mutation(increment, { link: 1, mutationKey })
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
if (ctx.msg && ctx.chat) {
|
if (ctx.msg && ctx.chat) {
|
||||||
@@ -64,4 +64,4 @@ feature.hears(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export { composer as twitterBlacklist };
|
export { composer as twitterBanlist };
|
||||||
@@ -8,13 +8,13 @@ const composer = new Composer<Context>();
|
|||||||
|
|
||||||
const feature = composer.chatType("private");
|
const feature = composer.chatType("private");
|
||||||
|
|
||||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What triggers this feature and adds to the log when it has been triggered.
|
* What triggers this feature and adds to the log when it has been triggered.
|
||||||
* The trigger is the command "/start" or "start"
|
* The trigger is the command "/start" or "start"
|
||||||
*/
|
*/
|
||||||
feature.command("start", logHandle("command-start"), async ctx => {
|
feature.command("start", logHandle("command-start"), async ctx => {
|
||||||
|
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||||
|
|
||||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||||
|
|
||||||
await urql
|
await urql
|
||||||
|
|||||||
@@ -13,14 +13,15 @@ import { hydrate } from "@grammyjs/hydrate";
|
|||||||
import { hydrateReply, parseMode } from "@grammyjs/parse-mode";
|
import { hydrateReply, parseMode } from "@grammyjs/parse-mode";
|
||||||
import { sequentialize } from "@grammyjs/runner";
|
import { sequentialize } from "@grammyjs/runner";
|
||||||
import { MemorySessionStorage, Bot as TelegramBot } from "grammy";
|
import { MemorySessionStorage, Bot as TelegramBot } from "grammy";
|
||||||
import { twitterBlacklist } from "./features/twitterBlacklist.js";
|
import { twitterBanlist } from "./features/twitterBanlist.js";
|
||||||
import { metaBlacklist } from "./features/metaBlacklist.js";
|
import { metaBanlist } from "./features/metaBanlist.js";
|
||||||
|
import { tiktokBanlist } from "./features/tiktokBanlist.js";
|
||||||
import { botInfoCommand } from "./features/botInfoCommand.js";
|
import { botInfoCommand } from "./features/botInfoCommand.js";
|
||||||
import { helpCommand } from "./features/helpCommand.js";
|
import { helpCommand } from "./features/helpCommand.js";
|
||||||
import { embedCheck } from "./features/embedCheck.js";
|
import { embedCheck } from "./features/embedCheck.js";
|
||||||
import { registerGroup } from "./features/registerBotCommand.js";
|
import { registerGroup } from "./features/registerGroupCommand.js";
|
||||||
import { getGroupStats } from "./features/getGroupStatsCommand.js";
|
import { getGroupStats } from "./features/getGroupStatsCommand.js";
|
||||||
import { statsSiteCommand } from "./features/statsSiteCommand.js";
|
import { statsSiteCommand } from "./features/botStatsSiteCommand.js";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
config: Config;
|
config: Config;
|
||||||
@@ -77,9 +78,10 @@ export function createBot(
|
|||||||
protectedBot.use(getGroupStats);
|
protectedBot.use(getGroupStats);
|
||||||
protectedBot.use(statsSiteCommand);
|
protectedBot.use(statsSiteCommand);
|
||||||
|
|
||||||
// Blacklist Feature
|
// banlist Feature
|
||||||
protectedBot.use(twitterBlacklist);
|
protectedBot.use(twitterBanlist);
|
||||||
protectedBot.use(metaBlacklist);
|
protectedBot.use(metaBanlist);
|
||||||
|
protectedBot.use(tiktokBanlist);
|
||||||
protectedBot.use(embedCheck);
|
protectedBot.use(embedCheck);
|
||||||
|
|
||||||
// must be the last handler
|
// must be the last handler
|
||||||
|
|||||||
30
src/lib/getCommandsList.ts
Normal file
30
src/lib/getCommandsList.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export interface Commands {
|
||||||
|
command: String;
|
||||||
|
description: String;
|
||||||
|
groups: boolean;
|
||||||
|
private: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchCommandsList = async (
|
||||||
|
url: string,
|
||||||
|
apiKey: string
|
||||||
|
): Promise<Commands[]> => {
|
||||||
|
let commandsList = [] as Commands[];
|
||||||
|
|
||||||
|
await axios
|
||||||
|
.get(url, {
|
||||||
|
headers: { "x-api-key": apiKey }
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
commandsList = res.data;
|
||||||
|
})
|
||||||
|
.catch(res => {
|
||||||
|
console.error(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
return commandsList;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default fetchCommandsList;
|
||||||
@@ -3,7 +3,7 @@ import { gql } from "@urql/core";
|
|||||||
const increment = gql`
|
const increment = gql`
|
||||||
mutation increment(
|
mutation increment(
|
||||||
$command: Boolean
|
$command: Boolean
|
||||||
$link: Boolean
|
$link: Int
|
||||||
$trigger: Boolean
|
$trigger: Boolean
|
||||||
$mutationKey: String
|
$mutationKey: String
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const metaRegex =
|
|||||||
/**
|
/**
|
||||||
* This function will check if a url matches Meta services links using regex.
|
* This function will check if a url matches Meta services links using regex.
|
||||||
*
|
*
|
||||||
* @param linkUrl representing a suspected blacklisted url
|
* @param linkUrl representing a suspected url on the banlist
|
||||||
* @returns flag
|
* @returns flag
|
||||||
*/
|
*/
|
||||||
const metaLinkCheck = (linkUrl: string): boolean => {
|
const metaLinkCheck = (linkUrl: string): boolean => {
|
||||||
|
|||||||
21
src/lib/tiktokLinkCheck.ts
Normal file
21
src/lib/tiktokLinkCheck.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// Global regex used to detect TikTok links.
|
||||||
|
const tiktokRegex = /(tiktok\.com)/gi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will check if a url matches TikTok services links using regex.
|
||||||
|
*
|
||||||
|
* @param linkUrl representing a suspected url on the banlist
|
||||||
|
* @return flag
|
||||||
|
*/
|
||||||
|
const tiktokLinkCheck = (linkUrl: string): boolean => {
|
||||||
|
let flag = false;
|
||||||
|
|
||||||
|
if (linkUrl.match(tiktokRegex)) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { tiktokRegex };
|
||||||
|
export default tiktokLinkCheck;
|
||||||
@@ -4,7 +4,7 @@ const twitterRegex = /(x\.com|twitter\.com)/gi;
|
|||||||
/**
|
/**
|
||||||
* This function will check if a url matches Twitter/X services links using regex.
|
* This function will check if a url matches Twitter/X services links using regex.
|
||||||
*
|
*
|
||||||
* @param linkUrl representing a suspected blacklisted url
|
* @param linkUrl representing a suspected url on the banlist
|
||||||
* @return flag
|
* @return flag
|
||||||
*/
|
*/
|
||||||
const twitterLinkCheck = (linkUrl: string): boolean => {
|
const twitterLinkCheck = (linkUrl: string): boolean => {
|
||||||
|
|||||||
Reference in New Issue
Block a user