From 7218b22b2bc396dc2d5b5926edcdf0f7828c4636 Mon Sep 17 00:00:00 2001 From: Ashley Graves Date: Tue, 15 Oct 2024 09:30:27 +0200 Subject: [PATCH] woah is that a refactor??? --- commands/catgpt.js | 41 ----------- commands/eval.js | 25 ------- commands/help.js | 55 -------------- commands/info.js | 16 ----- commands/join.js | 13 ---- commands/restart.js | 13 ---- commands/toggle.js | 47 ------------ modules/fedimbed.js | 81 --------------------- modules/meow.js | 49 ------------- package.json | 4 +- auth-fetch.js => src/auth-fetch.js | 0 src/commands/catgpt.js | 45 ++++++++++++ src/commands/eval.js | 29 ++++++++ src/commands/help.js | 62 ++++++++++++++++ src/commands/info.js | 20 ++++++ src/commands/join.js | 16 +++++ src/commands/restart.js | 16 +++++ src/commands/toggle.js | 50 +++++++++++++ index.js => src/index.js | 111 +++++++++++++++++++---------- src/lib/base/command.js | 19 +++++ src/lib/base/event.js | 7 ++ src/lib/base/module.js | 15 ++++ {lib => src/lib}/ext.js | 0 {lib => src/lib}/fedimbed.js | 0 login.js => src/login.js | 0 src/modules/fedimbed.js | 79 ++++++++++++++++++++ src/modules/meow.js | 48 +++++++++++++ 27 files changed, 482 insertions(+), 379 deletions(-) delete mode 100644 commands/catgpt.js delete mode 100644 commands/eval.js delete mode 100644 commands/help.js delete mode 100644 commands/info.js delete mode 100644 commands/join.js delete mode 100644 commands/restart.js delete mode 100644 commands/toggle.js delete mode 100644 modules/fedimbed.js delete mode 100644 modules/meow.js rename auth-fetch.js => src/auth-fetch.js (100%) create mode 100644 src/commands/catgpt.js create mode 100644 src/commands/eval.js create mode 100644 src/commands/help.js create mode 100644 src/commands/info.js create mode 100644 src/commands/join.js create mode 100644 src/commands/restart.js create mode 100644 src/commands/toggle.js rename index.js => src/index.js (60%) create mode 100644 src/lib/base/command.js create mode 100644 src/lib/base/event.js create mode 100644 src/lib/base/module.js rename {lib => src/lib}/ext.js (100%) rename {lib => src/lib}/fedimbed.js (100%) rename login.js => src/login.js (100%) create mode 100644 src/modules/fedimbed.js create mode 100644 src/modules/meow.js diff --git a/commands/catgpt.js b/commands/catgpt.js deleted file mode 100644 index b8f27e1..0000000 --- a/commands/catgpt.js +++ /dev/null @@ -1,41 +0,0 @@ -var meows = [ - "mreow", - "miau", - "mewo", - "maow", - "mrow", - "mrao", - "meow", - "mew", - "nya", -]; - -var emoticons = [ - ":3", - "^w^", - "=^w^=", - "-w-", - ":333" -]; - -async function execute(client, event) { - var reply = ""; - for(let i = 0;i < Math.random() * 15; i++) - reply += " " + meows.random(); - - reply += "!".repeat(Math.random() * 5); - - if(Math.random() > 0.5) { - reply += " " + emoticons.random(); - } - - await client.reply(event, reply); -} - -export default { - command: "catgpt", - name: "catgpt", - usage: "[prompt]", - desc: "advanced NAI-based language meowdel", - execute -} diff --git a/commands/eval.js b/commands/eval.js deleted file mode 100644 index d2b99af..0000000 --- a/commands/eval.js +++ /dev/null @@ -1,25 +0,0 @@ -import { xxh64 } from "@node-rs/xxhash"; -import { encode } from "html-entities"; -import { JSDOM } from "jsdom"; -import util from "util"; -import fs from "fs"; - -function execute(client, event, args) { - var c = ""; - try { - var result = eval(args); - c = util.format(result).replaceAll(process.env.ACCESS_TOKEN, "*".repeat(process.env.ACCESS_TOKEN.length)); - } catch(err) { - c = util.format(err); - } - client.reply(event, c, `
${encode(c)}
`); -} - -export default { - command: "eval", - name: "eval", - usage: "", - owner: true, - desc: "run JS code and reply with the result", - execute -} diff --git a/commands/help.js b/commands/help.js deleted file mode 100644 index 5dc7ee7..0000000 --- a/commands/help.js +++ /dev/null @@ -1,55 +0,0 @@ -import { encode } from "html-entities"; - -function execute(client, event, args) { - var name = args.toLowerCase(); - - var command = client.commands.filter(c=>(c.name.toLowerCase()==name || c.command.toLowerCase()==name))[0]; - var module = client.modules.filter(m=>m.name.toLowerCase()==name)[0]; - var specific = command ?? module ?? false; - - if(args != "") { - if(!command && !module) { - client.reply(event, `section "${args}" not found.\nrun "${process.env.PREFIX}help" for a list of commands and modules.`); - return; - } - - if(module) { - var reply = module.name + "\n"; - reply += module.desc; - - var replyHTML = `${encode(module.name)}
` + - `${encode(module.desc)}`; - - client.reply(event, reply, replyHTML); - return; - } - - var reply = command.name + "\n" + - command.desc + "\n\n" + - command.usage; - - var replyHTML = `${encode(command.name)}
` + - `${encode(command.desc)}` + - `
${encode(command.usage)}`; - - client.reply(event, reply, replyHTML); - return; - } - - var reply = `commands: ${client.commands.map(m => m.name).join(", ")}\n` + - `modules: ${client.modules.map(m => m.name).join(", ")}\n` + - `run ${process.env.PREFIX}help for more information.`; - - var replyHTML = `commands: ${client.commands.map(m => encode(m.name)).join(", ")}
` + - `modules: ${client.modules.map(m => encode(m.name)).join(", ")}
` + - encode(`run ${process.env.PREFIX}help for more information.`); - - client.reply(event, reply, replyHTML); -} - -export default { - command: "help", - name: "help", - desc: "show list of commands and modules", - execute -} diff --git a/commands/info.js b/commands/info.js deleted file mode 100644 index 8caed69..0000000 --- a/commands/info.js +++ /dev/null @@ -1,16 +0,0 @@ -function execute(client, event, args) { - var info = `source code: https://git.lgbt/root/possumbot\n`; - info += `commands: ${client.commands.length}\n`; - info += `modules: ${client.modules.length}\n`; - info += `prefix: ${process.env.PREFIX} (you can also mention the bot!)\n`; - info += `owner: ${process.env.OWNER_ID}`; - - client.reply(event, info); -} - -export default { - command: "info", - name: "info", - desc: "show general info about the bot", - execute -} diff --git a/commands/join.js b/commands/join.js deleted file mode 100644 index beec0e8..0000000 --- a/commands/join.js +++ /dev/null @@ -1,13 +0,0 @@ -import { exec } from "node:child_process"; - -function execute(client, event, args) { - client.joinRoom(args); -} - -export default { - command: "join", - name: "join", - owner: true, - desc: "join a room", - execute -} diff --git a/commands/restart.js b/commands/restart.js deleted file mode 100644 index 491d7f3..0000000 --- a/commands/restart.js +++ /dev/null @@ -1,13 +0,0 @@ -import { exec } from "node:child_process"; - -function execute(client, event, args) { - process.exit(255); -} - -export default { - command: "restart", - name: "restart", - owner: true, - desc: "restarts the bot", - execute -} diff --git a/commands/toggle.js b/commands/toggle.js deleted file mode 100644 index 05b79a5..0000000 --- a/commands/toggle.js +++ /dev/null @@ -1,47 +0,0 @@ -import { encode } from "html-entities"; - -function execute(client, event, args) { - var name = args.toLowerCase(); - - var command = client.commands.filter(c=>(c.name.toLowerCase()==name || c.command.toLowerCase()==name))[0]; - var module = client.modules.filter(m=>m.name.toLowerCase()==name)[0]; - var specific = command ?? module ?? false; - - var config = client.config.get(event.sender.roomId); - - if(args != "") { - if(!module) { - client.reply(event, `Module "${args}" not found.\nRun "${process.env.PREFIX}help" for a list of commands and modules.`); - return; - } - - config.set(module.name, !(config.get(module.name) ?? true)); - var state = (config.get(module.name) ? "En" : "Dis") + "abled"; - - var reply = state + " " + module.name; - var replyHTML = `${state} ${encode(module.name)}`; - - client.reply(event, reply, replyHTML); - return; - } - - var modules = client.modules.map(m=>m.name); - var enabled = modules.filter(m=>config.get(m)!==false); - - var reply = `enabled modules:\n${enabled.join(", ")}`; - var replyHTML = `enabled modules:
${enabled.join(", ")}`; - - reply += `\navailable modules:\n${modules.join(", ")}`; - replyHTML += `
available modules:
${modules.join(", ")}`; - - client.reply(event, reply, replyHTML); -} - -export default { - command: "toggle", - name: "toggle", - usage: "", - minPwr: 50, - desc: "toggle a module on or off in current channel", - execute -} diff --git a/modules/fedimbed.js b/modules/fedimbed.js deleted file mode 100644 index 13dc91c..0000000 --- a/modules/fedimbed.js +++ /dev/null @@ -1,81 +0,0 @@ -import fedimbed from "../lib/fedimbed.js"; -import { encode } from "html-entities"; -import { JSDOM } from "jsdom"; -import util from "util"; - -async function onMessage(client, event) { - const embed = await fedimbed(event.getContent().body); - if(!embed) return; - const dom = new JSDOM(""); - const document = dom.window.document; - var quote = document.createElement("blockquote"); - if(!embed.embeds) { - var c = util.format(embed); - client.reply(event, c, `
${encode(c)}
`); - return; - } - - for(const emb of embed.embeds) { - var link = document.createElement("a"); - link.href = emb.url; - - if(emb.thumbnail && emb.thumbnail.url) { - var avatar = document.createElement("img"); - avatar.src = await client.uploadMedia(emb.thumbnail.url); - avatar.height = "16"; - link.appendChild(avatar); - } - - var linkText = document.createElement("span"); - linkText.innerHTML = ((emb.thumbnail?.url) ? " " : "") + emb.title; - link.appendChild(linkText); - - quote.appendChild(link); - - var text = document.createElement("p"); - text.innerHTML = emb.description; - - for(const emote of embed.emotes) { - console.log(text.innerHTML); - var img = document.createElement("img"); - img.src = await client.uploadMedia(emote.url); - img.height = "16"; - img.alt = emote.name; - text.innerHTML = text.innerHTML.replaceAll(emote.name, img.outerHTML); - } - - quote.appendChild(text); - } - for(const file of embed.files) { - var media; - switch(file.type.split("/")[0]) { - case "audio": - media = document.createElement("audio"); - break; - case "video": - media = document.createElement("video"); - break; - case "image": - media = document.createElement("img"); - break; - } - media.src = await client.uploadMedia(file.url); - media.alt = media.title = file.desc ?? ""; - quote.appendChild(media); - } - document.body.appendChild(quote); - - let x = document.createElement("small"); - x.innerHTML = "Powered by HF Fedimbed"; - document.body.appendChild(x); - - client.reply(event, "This message uses HTML, which your client does not support.", document.body.outerHTML); -} - -export default { - name: "fedimbed", - desc: "embed fediverse post contents", - hooks: { - message: onMessage - } -} diff --git a/modules/meow.js b/modules/meow.js deleted file mode 100644 index f16439f..0000000 --- a/modules/meow.js +++ /dev/null @@ -1,49 +0,0 @@ -var meows = [ - "mreow", - "miau", - "mewo", - "maow", - "mrow", - "mrao", - "meow", - "mew", - "nya", -]; - -var re = new RegExp("\\b(n+y+a+n*?|m+[re]*([yiaou]+[wu]+|w+))(ing|er|s)?\\b", "gi"); - -var emoticons = [ - ":3", - "^w^", - "=^w^=", - "-w-", - ":333" -]; - -async function onMessage(client, event) { - var content = event.getContent(); - - if(content["m.new_content"] != null) return; - - for(const meow of meows) { - if(re.test(content.body.toLowerCase())) { - var reply = meows.random(); - reply += "!".repeat(Math.random()*5) - - if(Math.random() > 0.5) { - reply += " " + emoticons.random(); - } - - client.reply(event, reply); - break; - } - } -} - -export default { - name: "meow", - desc: ":33", - hooks: { - message: onMessage - } -} diff --git a/package.json b/package.json index 3160e8d..426a0c2 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,11 @@ "type": "module", "version": "0.0.0", "description": "General purpose Matrix bot", - "main": "index.js", + "main": "src/index.js", "author": "Ashley Graves", "license": "GPL-v3", "scripts": { - "login": "node login.js" + "login": "node src/login.js" }, "dependencies": { "@matrix-org/olm": "^3.2.15", diff --git a/auth-fetch.js b/src/auth-fetch.js similarity index 100% rename from auth-fetch.js rename to src/auth-fetch.js diff --git a/src/commands/catgpt.js b/src/commands/catgpt.js new file mode 100644 index 0000000..fd82da9 --- /dev/null +++ b/src/commands/catgpt.js @@ -0,0 +1,45 @@ +import BaseCommand from "../lib/base/command.js"; + +var meows = [ + "mreow", + "miau", + "mewo", + "maow", + "mrow", + "mrao", + "meow", + "mew", + "nya", +]; + +var emoticons = [ + ":3", + "^w^", + "=^w^=", + "-w-", + ":333" +]; + +class CatGPTCommand extends BaseCommand { + command = "catgpt"; + name = "catgpt"; + usage = "[prompt]"; + description = "advanced NAI-based language meowdel"; + + /** @type {BaseCommand['execute']} */ + async execute(client, event) { + var reply = ""; + for (let i = 0; i < Math.random() * 15; i++) + reply += " " + meows.random(); + + reply += "!".repeat(Math.random() * 5); + + if (Math.random() > 0.5) { + reply += " " + emoticons.random(); + } + + await client.reply(event, reply); + } +} + +export default new CatGPTCommand(); \ No newline at end of file diff --git a/src/commands/eval.js b/src/commands/eval.js new file mode 100644 index 0000000..7d33cb9 --- /dev/null +++ b/src/commands/eval.js @@ -0,0 +1,29 @@ +import BaseCommand from "../lib/base/command.js"; +import { xxh64 } from "@node-rs/xxhash"; +import { encode } from "html-entities"; +import { JSDOM } from "jsdom"; +import util from "util"; +import fs from "fs"; + +class EvalCommand extends BaseCommand { + name = "eval"; + command = "eval"; + usage = ""; + ownerOnly = true; + description = "run JS code and reply with the result"; + + /** @type {BaseCommand['execute']} */ + async execute(client, event, args) { + var c = ""; + try { + var result = eval(args); + c = util.format(result).replaceAll(process.env.ACCESS_TOKEN, "*".repeat(process.env.ACCESS_TOKEN.length)); + } catch (err) { + c = util.format(err); + } + + await client.reply(event, c, `
${encode(c)}
`); + } +} + +export default new EvalCommand(); \ No newline at end of file diff --git a/src/commands/help.js b/src/commands/help.js new file mode 100644 index 0000000..a8e8ff1 --- /dev/null +++ b/src/commands/help.js @@ -0,0 +1,62 @@ +import { encode } from "html-entities"; +import BaseCommand from "../lib/base/command.js"; + +class HelpCommand extends BaseCommand { + command = "help"; + name = "help"; + desc = "show list of commands and modules"; + + /** @type {BaseCommand['execute']} */ + async execute(client, event, args) { + var name = args.toLowerCase(); + + var command = client.commands.filter(c => (c.name.toLowerCase() == name || c.command.toLowerCase() == name))[0]; + var module = client.modules.filter(m => m.name.toLowerCase() == name)[0]; + + if (args != "") { + if (!command && !module) { + client.reply(event, `section "${args}" not found.\nrun "${process.env.PREFIX}help" for a list of commands and modules.`); + return; + } + + if (module) { + module.desc = module.desc ?? module.description; + + var reply = module.name + "\n"; + reply += module.desc; + + var replyHTML = `${encode(module.name)}
` + + `${encode(module.desc)}`; + + client.reply(event, reply, replyHTML); + return; + } + + command.desc = command.desc ?? command.description; + + var reply = command.name + "\n" + + command.desc + "\n\n" + + command.usage; + + var replyHTML = `${encode(command.name)}
` + + `${encode(command.desc)}` + + `
${encode(command.usage)}`; + + client.reply(event, reply, replyHTML); + + return; + } + + var reply = `commands: ${client.commands.map(m => m.name).join(", ")}\n` + + `modules: ${client.modules.map(m => m.name).join(", ")}\n` + + `run ${process.env.PREFIX}help for more information.`; + + var replyHTML = `commands: ${client.commands.map(m => encode(m.name)).join(", ")}
` + + `modules: ${client.modules.map(m => encode(m.name)).join(", ")}
` + + encode(`run ${process.env.PREFIX}help for more information.`); + + client.reply(event, reply, replyHTML); + } +} + +export default new HelpCommand(); \ No newline at end of file diff --git a/src/commands/info.js b/src/commands/info.js new file mode 100644 index 0000000..4c6a178 --- /dev/null +++ b/src/commands/info.js @@ -0,0 +1,20 @@ +import BaseCommand from "../lib/base/command.js"; + +class InfoCommand extends BaseCommand { + command = "info"; + name = "info"; + desc = "show general info about the bot"; + + /** @type {BaseCommand['execute']} */ + async execute(client, event, args) { + var info = `source code: https://git.lgbt/root/possumbot\n`; + info += `commands: ${client.commands.length}\n`; + info += `modules: ${client.modules.length}\n`; + info += `prefix: ${process.env.PREFIX} (you can also mention the bot!)\n`; + info += `owner: ${process.env.OWNER_ID}`; + + await client.reply(event, info); + } +} + +export default new InfoCommand(); \ No newline at end of file diff --git a/src/commands/join.js b/src/commands/join.js new file mode 100644 index 0000000..c60dc84 --- /dev/null +++ b/src/commands/join.js @@ -0,0 +1,16 @@ +import { exec } from "node:child_process"; +import BaseCommand from "../lib/base/command.js"; + +class JoinCommand extends BaseCommand { + command = "join"; + name = "join"; + ownerOnly = true; + description = "join a room"; + + /** @type {BaseCommand['execute']} */ + async execute(client, event, args) { + client.joinRoom(args); + } +} + +export default new JoinCommand(); \ No newline at end of file diff --git a/src/commands/restart.js b/src/commands/restart.js new file mode 100644 index 0000000..bcac3dc --- /dev/null +++ b/src/commands/restart.js @@ -0,0 +1,16 @@ +import BaseCommand from "../lib/base/command.js"; + +class RestartCommand extends BaseCommand { + name = "restart"; + command = "restart"; + description = "restarts the bot"; + ownerOnly = true; + + /** @type {BaseCommand['execute']} */ + async execute(client, event, args) { + await client.reply(event, "Restarting, please wait..."); + process.exit(255); + } +} + +export default new RestartCommand(); \ No newline at end of file diff --git a/src/commands/toggle.js b/src/commands/toggle.js new file mode 100644 index 0000000..966e2d2 --- /dev/null +++ b/src/commands/toggle.js @@ -0,0 +1,50 @@ +import { encode } from "html-entities"; +import BaseCommand from "../lib/base/command.js"; + +class ToggleCommand extends BaseCommand { + command = "toggle"; + name = "toggle"; + usage = ""; + minPowerLevel = 50; + description = "toggle a module on or off in current channel"; + + /** @type {BaseCommand['execute']} */ + async execute(client, event, args) { + var name = args.toLowerCase(); + + var command = client.commands.filter(c => (c.name.toLowerCase() == name || c.command.toLowerCase() == name))[0]; + var module = client.modules.filter(m => m.name.toLowerCase() == name)[0]; + var specific = command ?? module ?? false; + + var config = client.config.get(event.sender.roomId); + + if (args != "") { + if (!module) { + client.reply(event, `Module "${args}" not found.\nRun "${process.env.PREFIX}help" for a list of commands and modules.`); + return; + } + + config.set(module.name, !(config.get(module.name) ?? true)); + var state = (config.get(module.name) ? "En" : "Dis") + "abled"; + + var reply = state + " " + module.name; + var replyHTML = `${state} ${encode(module.name)}`; + + client.reply(event, reply, replyHTML); + return; + } + + var modules = client.modules.map(m => m.name); + var enabled = modules.filter(m => config.get(m) !== false); + + var reply = `enabled modules:\n${enabled.join(", ")}`; + var replyHTML = `enabled modules:
${enabled.join(", ")}`; + + reply += `\navailable modules:\n${modules.join(", ")}`; + replyHTML += `
available modules:
${modules.join(", ")}`; + + client.reply(event, reply, replyHTML); + } +} + +export default new ToggleCommand(); \ No newline at end of file diff --git a/index.js b/src/index.js similarity index 60% rename from index.js rename to src/index.js index c181b3b..cae8913 100644 --- a/index.js +++ b/src/index.js @@ -6,6 +6,9 @@ import sdkExt from "./lib/ext.js"; import { resolve } from "node:path"; import fs from "node:fs"; import { LocalStorage } from 'node-localstorage'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +global.__dirname = dirname(fileURLToPath(import.meta.url)); import fetch from "node-fetch"; global.fetch = fetch; @@ -14,6 +17,8 @@ import Olm from "@matrix-org/olm"; global.Olm = Olm; import env from "dotenv"; +import BaseCommand from "./lib/base/command.js"; +import { format } from "node:util"; env.config(); const localStorage = new LocalStorage("./data/localstorage"); @@ -49,10 +54,11 @@ client.initialized = false; client.modules = []; client.commands = []; -for (const file of fs.readdirSync(resolve("modules"))) { +var modulesDir = resolve(__dirname, "modules"); +for (const file of fs.readdirSync(modulesDir)) { try { if (file.startsWith(".")) continue; - var module = (await import(resolve("modules", file))).default; + var module = (await import(resolve(modulesDir, file))).default; client.modules.push(module); client.log("[load:modules]", `loaded ${module.name}`); } catch (err) { @@ -60,10 +66,11 @@ for (const file of fs.readdirSync(resolve("modules"))) { } } -for (const file of fs.readdirSync(resolve("commands"))) { +var commandsDir = resolve(__dirname, "commands"); +for (const file of fs.readdirSync(commandsDir)) { try { if (file.startsWith(".")) continue; - var command = (await import(resolve("commands", file))).default; + var command = (await import(resolve(commandsDir, file))).default; command.usage = process.env.PREFIX + command.command + (command.usage ? " " + command.usage : ''); client.commands.push(command); client.log("[load:commands]", `loaded ${command.name}`); @@ -74,27 +81,36 @@ for (const file of fs.readdirSync(resolve("commands"))) { function doModule(client, event) { client.modules.forEach(m => { - if (!m) return; + if (!m.onMessage) return; var config = client.config.get(event.sender.roomId); if (config.get(m.name) === false) return; try { - m.hooks?.message(client, event); + m.onMessage(client, event); } catch (err) { client.log("[hook]", err); } }); } +/** + * @param {MatrixClient} client + * @param {MatrixEvent} event + * @param {string} cmd + * @param {string} args + * @returns {Boolean} Success? + */ function doCommand(client, event, cmd, args) { - var command; - command = client.commands.filter(c => c.command == cmd)[0]; + /** + * @type {BaseCommand} + */ + var command = client.commands.filter(c => c.command == cmd)[0]; if (!command) return false; - if ((command.owner && event.sender.userId != process.env.OWNER_ID) || (command.minPwr && event.sender.powerLevel < command.minPwr && event.sender.userId != process.env.OWNER_ID)) { - var addl = command.minPwr ? `this command requires a power level of ${command.minPwr}\nyour power level is ${event.sender.powerLevel}` : "this command is owner-only."; + if ((command.ownerOnly && event.sender.userId != process.env.OWNER_ID) || (command.minPowerLevel > 0 && event.sender.powerLevel < command.minPowerLevel && event.sender.userId != process.env.OWNER_ID)) { + var addl = command.minPowerLevel ? `this command requires a power level of ${command.minPowerLevel}\nyour power level is ${event.sender.powerLevel}` : "this command is owner-only."; client.reply(event, addl, 'nuh uh
' + addl.replaceAll("\n", "
")); return true; } @@ -107,35 +123,57 @@ function doCommand(client, event, cmd, args) { return true; } -async function verifyCallback(request) { +/** @param {import("matrix-js-sdk/lib/crypto-api.js").VerificationRequest} request */ +client.verifyCallback = async function (request) { console.log("### VERIFICATION ### Starting for " + request.otherUserId); + if (!request.initiatedByMe) { await request.accept(); - var verifier = await request.startVerification(VerificationMethod.Sas); - verifier.on(VerifierEvent.ShowSas, async function () { - console.log("### VERIFICATION ### Confirming"); - await verifier.getShowSasCallbacks().confirm(); - }); + try { + var verifier = await request.startVerification(VerificationMethod.Sas); + verifier.on(VerifierEvent.ShowSas, async function () { + console.log("### VERIFICATION ### Confirming"); + await verifier.getShowSasCallbacks().confirm(); + }); + verifier.on(VerifierEvent.Cancel, async function (e) { + console.log("### VERIFICATION ### ", e); + await client.sendMessage(request.roomId, { + body: format(e), + msgtype: sdk.MsgType.Text + }) + }); + } catch (err) { + client.sendMessage(request.roomId, { + body: err, + msgtype: sdk.MsgType.Notice + }) + } } request.on(VerificationRequestEvent.Change, async function () { - switch (request.phase) { - case 3: - break; - case 4: - var verifier = await request.startVerification(VerificationMethod.Sas); - verifier.on(VerifierEvent.ShowSas, async function () { - console.log("### VERIFICATION ### Confirming"); - await verifier.getShowSasCallbacks().confirm(); - }); - case 5: - console.log("### VERIFICATION ### Cancelled!"); - case 6: - console.log("### VERIFICATION ### Done!"); - break; - default: - console.log("### VERIFICATION ### " + request.phase); - break; + try { + switch (request.phase) { + case 3: + case 4: + var verifier = await request.startVerification(VerificationMethod.Sas); + verifier.on(VerifierEvent.ShowSas, async function () { + console.log("### VERIFICATION ### Confirming"); + await verifier.getShowSasCallbacks().confirm(); + }); + case 5: + console.log("### VERIFICATION ### Cancelled!"); + case 6: + console.log("### VERIFICATION ### Done!"); + break; + default: + console.log("### VERIFICATION ### " + request.phase); + break; + } + } catch (err) { + client.sendMessage(request.roomId, { + body: err, + msgtype: sdk.MsgType.Notice + }) } }); } @@ -149,15 +187,14 @@ client.once("sync", async function (state, prevState, data) { prefixes.push(client.name + " "); client.initialized = true; - while (!await client.getCrypto().isCrossSigningReady()) { } var status = await client.getCrypto().getDeviceVerificationStatus(client.getUserId(), client.getDeviceId()); if (!status || Object.keys(status).map(v => status[v]).includes(false)) { const request = await client.getCrypto().requestOwnUserVerification(); - verifyCallback(request); + client.verifyCallback(request); } }); -client.on(sdk.CryptoEvent.VerificationRequestReceived, verifyCallback); +client.on(sdk.CryptoEvent.VerificationRequestReceived, client.verifyCallback); client.on(sdk.RoomEvent.Timeline, async function (event, room, toStartOfTimeline) { await client.decryptEventIfNeeded(event); @@ -184,7 +221,7 @@ client.on(sdk.RoomEvent.Timeline, async function (event, room, toStartOfTimeline } if (!isCommand) { - doModule(client, event); + doModule(client, event) } else { var args = content.split(/\s/g); var cmd = args.shift(); diff --git a/src/lib/base/command.js b/src/lib/base/command.js new file mode 100644 index 0000000..4a8f675 --- /dev/null +++ b/src/lib/base/command.js @@ -0,0 +1,19 @@ +import { MatrixClient, MatrixEvent } from "matrix-js-sdk"; +import BaseEvent from "./event.js"; + +export default class BaseCommand extends BaseEvent { + command = ""; + usage = ""; + minPowerLevel = 0; + ownerOnly = false; + + /** + * @param {MatrixClient} client + * @param {MatrixEvent} event + * @param {string} args + * @returns {Boolean} Success? + */ + async execute(client, event, args) { + throw new Error("Not implemented."); + } +} \ No newline at end of file diff --git a/src/lib/base/event.js b/src/lib/base/event.js new file mode 100644 index 0000000..e80fde5 --- /dev/null +++ b/src/lib/base/event.js @@ -0,0 +1,7 @@ +import { MatrixClient, MatrixEvent } from "matrix-js-sdk"; + +export default class BaseEvent { + name = ""; + description = ""; + hooks = {}; +} \ No newline at end of file diff --git a/src/lib/base/module.js b/src/lib/base/module.js new file mode 100644 index 0000000..bf1abd9 --- /dev/null +++ b/src/lib/base/module.js @@ -0,0 +1,15 @@ +import BaseEvent from "./event.js"; + +export default class BaseModule extends BaseEvent { + name = ""; + description = ""; + + /** + * @param {MatrixClient} client + * @param {MatrixEvent} event + * @returns {Boolean} Success? + */ + async onMessage(client, event) { + + } +} \ No newline at end of file diff --git a/lib/ext.js b/src/lib/ext.js similarity index 100% rename from lib/ext.js rename to src/lib/ext.js diff --git a/lib/fedimbed.js b/src/lib/fedimbed.js similarity index 100% rename from lib/fedimbed.js rename to src/lib/fedimbed.js diff --git a/login.js b/src/login.js similarity index 100% rename from login.js rename to src/login.js diff --git a/src/modules/fedimbed.js b/src/modules/fedimbed.js new file mode 100644 index 0000000..0e9e99f --- /dev/null +++ b/src/modules/fedimbed.js @@ -0,0 +1,79 @@ +import fedimbed from "../lib/fedimbed.js"; +import { encode } from "html-entities"; +import { JSDOM } from "jsdom"; +import util from "util"; +import BaseModule from "../lib/base/module.js"; + +export default class FedimbedModule extends BaseModule { + name = "fedimbed"; + description = "embed fediverse post contents"; + + async onMessage(client, event) { + const embed = await fedimbed(event.getContent().body); + if (!embed) return; + const dom = new JSDOM(""); + const document = dom.window.document; + var quote = document.createElement("blockquote"); + if (!embed.embeds) { + var c = util.format(embed); + client.reply(event, c, `
${encode(c)}
`); + return; + } + + for (const emb of embed.embeds) { + var link = document.createElement("a"); + link.href = emb.url; + + if (emb.thumbnail && emb.thumbnail.url) { + var avatar = document.createElement("img"); + avatar.src = await client.uploadMedia(emb.thumbnail.url); + avatar.height = "16"; + link.appendChild(avatar); + } + + var linkText = document.createElement("span"); + linkText.innerHTML = ((emb.thumbnail?.url) ? " " : "") + emb.title; + link.appendChild(linkText); + + quote.appendChild(link); + + var text = document.createElement("p"); + text.innerHTML = emb.description; + + for (const emote of embed.emotes) { + console.log(text.innerHTML); + var img = document.createElement("img"); + img.src = await client.uploadMedia(emote.url); + img.height = "16"; + img.alt = emote.name; + text.innerHTML = text.innerHTML.replaceAll(emote.name, img.outerHTML); + } + + quote.appendChild(text); + } + for (const file of embed.files) { + var media; + switch (file.type.split("/")[0]) { + case "audio": + media = document.createElement("audio"); + break; + case "video": + media = document.createElement("video"); + break; + case "image": + media = document.createElement("img"); + break; + } + media.src = await client.uploadMedia(file.url); + media.alt = media.title = file.desc ?? ""; + quote.appendChild(media); + } + document.body.appendChild(quote); + + let x = document.createElement("small"); + x.innerHTML = "Powered by HF Fedimbed"; + document.body.appendChild(x); + + client.reply(event, "This message uses HTML, which your client does not support.", document.body.outerHTML); + } +} \ No newline at end of file diff --git a/src/modules/meow.js b/src/modules/meow.js new file mode 100644 index 0000000..aa06962 --- /dev/null +++ b/src/modules/meow.js @@ -0,0 +1,48 @@ +import BaseModule from "../lib/base/module.js"; + +var meows = [ + "mreow", + "miau", + "mewo", + "maow", + "mrow", + "mrao", + "meow", + "mew", + "nya", +]; + +var re = new RegExp("\\b(n+y+a+n*?|m+[re]*([yiaou]+[wu]+|w+))(ing|er|s)?\\b", "gi"); + +var emoticons = [ + ":3", + "^w^", + "=^w^=", + "-w-", + ":333" +]; + +export default class MeowModule extends BaseModule { + name = "meow"; + description = ":33"; + + async onMessage(client, event) { + var content = event.getContent(); + + if (content["m.new_content"] != null) return; + + for (const meow of meows) { + if (re.test(content.body.toLowerCase())) { + var reply = meows.random(); + reply += "!".repeat(Math.random() * 5) + + if (Math.random() > 0.5) { + reply += " " + emoticons.random(); + } + + client.reply(event, reply); + break; + } + } + } +} \ No newline at end of file