mirror of
https://gitlab.com/octospacc/WinDog.git
synced 2025-06-05 22:09:20 +02:00
Start Matrix support, more refactoring, cleaner /help and /translate
This commit is contained in:
@@ -1 +1,7 @@
|
||||
import base64
|
||||
|
||||
#RegisterModule(name="Codings", group="Geek", endpoints={
|
||||
# "Encode": CreateEndpoint(["encode"], summary="", handler=cEncode),
|
||||
# "Decode": CreateEndpoint(["decode"], summary="", handler=cDecode),
|
||||
#})
|
||||
|
||||
|
@@ -1,3 +1,8 @@
|
||||
# ================================== #
|
||||
# WinDog multi-purpose chatbot #
|
||||
# Licensed under AGPLv3 by OctoSpacc #
|
||||
# ================================== #
|
||||
|
||||
import hashlib
|
||||
|
||||
def cHash(context, data) -> None:
|
||||
|
@@ -1,7 +1,11 @@
|
||||
# TODO: implement /help <commandname> feature
|
||||
# ================================== #
|
||||
# WinDog multi-purpose chatbot #
|
||||
# Licensed under AGPLv3 by OctoSpacc #
|
||||
# ================================== #
|
||||
|
||||
# TODO: implement /help <commandname> feature
|
||||
def cHelp(context, data=None) -> None:
|
||||
moduleList, commands = '', ''
|
||||
moduleList = ''
|
||||
for module in Modules:
|
||||
summary = Modules[module]["summary"]
|
||||
endpoints = Modules[module]["endpoints"]
|
||||
@@ -9,9 +13,7 @@ def cHelp(context, data=None) -> None:
|
||||
for endpoint in endpoints:
|
||||
summary = endpoints[endpoint]["summary"]
|
||||
moduleList += (f"\n* /{', /'.join(endpoints[endpoint]['names'])}" + (f": {summary}" if summary else ''))
|
||||
for cmd in Endpoints.keys():
|
||||
commands += f'* /{cmd}\n'
|
||||
SendMsg(context, {"Text": f"[ Available Modules ]{moduleList}\n\nFull Endpoints List:\n{commands}"})
|
||||
SendMsg(context, {"Text": f"[ Available Modules ]{moduleList}"})
|
||||
|
||||
RegisterModule(name="Help", group="Basic", endpoints={
|
||||
"Help": CreateEndpoint(["help"], summary="Provides help for the bot. For now, it just lists the commands.", handler=cHelp),
|
||||
|
@@ -1,3 +1,8 @@
|
||||
# ================================== #
|
||||
# WinDog multi-purpose chatbot #
|
||||
# Licensed under AGPLv3 by OctoSpacc #
|
||||
# ================================== #
|
||||
|
||||
from urlextract import URLExtract
|
||||
from urllib import parse as UrlParse
|
||||
from urllib.request import urlopen, Request
|
||||
@@ -63,14 +68,20 @@ def cWeb(context, data) -> None:
|
||||
else:
|
||||
pass
|
||||
|
||||
def cImages(context, data) -> None:
|
||||
pass
|
||||
|
||||
def cNews(context, data) -> None:
|
||||
pass
|
||||
|
||||
def cTranslate(context, data) -> None:
|
||||
if len(data.Tokens) < 3:
|
||||
return
|
||||
try:
|
||||
Lang = data.Tokens[1]
|
||||
toLang = data.Tokens[1]
|
||||
# TODO: Use many different public Lingva instances in rotation to avoid overloading a specific one
|
||||
Result = json.loads(HttpGet(f'https://lingva.ml/api/v1/auto/{Lang}/{UrlParse.quote(Lang.join(data.Body.split(Lang)[1:]))}').read())["translation"]
|
||||
SendMsg(context, {"TextPlain": Result})
|
||||
result = json.loads(HttpGet(f'https://lingva.ml/api/v1/auto/{toLang}/{UrlParse.quote(toLang.join(data.Body.split(toLang)[1:]))}').read())
|
||||
SendMsg(context, {"TextPlain": f"[{result['info']['detectedSource']} (auto) -> {toLang}]\n\n{result['translation']}"})
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
@@ -119,7 +130,7 @@ def cSafebooru(context, data) -> None:
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
RegisterModule(name="Internet", group="Internet", summary="Tools and toys related to the Internet.", endpoints={
|
||||
RegisterModule(name="Internet", summary="Tools and toys related to the Internet.", endpoints={
|
||||
"Embedded": CreateEndpoint(["embedded"], summary="Rewrites a link, trying to bypass embed view protection.", handler=cEmbedded),
|
||||
"Web": CreateEndpoint(["web"], summary="Provides results of a DuckDuckGo search.", handler=cWeb),
|
||||
"Translate": CreateEndpoint(["translate"], summary="Returns the received message after translating it in another language.", handler=cTranslate),
|
||||
|
@@ -3,21 +3,19 @@
|
||||
# Licensed under AGPLv3 by OctoSpacc #
|
||||
# ==================================== #
|
||||
|
||||
# Module: Percenter
|
||||
# Provides fun trough percentage-based toys.
|
||||
def percenter(context, data) -> None:
|
||||
import re, subprocess
|
||||
|
||||
def mPercenter(context, data) -> None:
|
||||
SendMsg(context, {"Text": choice(Locale.__(f'{data.Name}.{"done" if data.Body else "empty"}')).format(
|
||||
Cmd=data.Tokens[0], Percent=RandPercent(), Thing=data.Body)})
|
||||
|
||||
# Module: Multifun
|
||||
# Provides fun trough preprogrammed-text-based toys.
|
||||
def multifun(context, data) -> None:
|
||||
def mMultifun(context, data) -> None:
|
||||
cmdkey = data.Name
|
||||
replyToId = None
|
||||
if data.Quoted:
|
||||
replyFromUid = data.Quoted.User.Id
|
||||
# TODO work on all platforms for the bot id
|
||||
if int(replyFromUid.split('@')[0]) == int(TelegramId) and 'bot' in Locale.__(cmdkey):
|
||||
if replyFromUid.split('@')[0] == TelegramToken.split(':')[0] and 'bot' in Locale.__(cmdkey):
|
||||
Text = choice(Locale.__(f'{cmdkey}.bot'))
|
||||
elif replyFromUid == data.User.Id and 'self' in Locale.__(cmdkey):
|
||||
Text = choice(Locale.__(f'{cmdkey}.self')).format(data.User.Name)
|
||||
@@ -30,13 +28,9 @@ def multifun(context, data) -> None:
|
||||
Text = choice(Locale.__(f'{cmdkey}.empty'))
|
||||
SendMsg(context, {"Text": Text, "ReplyTo": replyToId})
|
||||
|
||||
# Module: Start
|
||||
# Salutes the user, hinting that the bot is working and providing basic quick help.
|
||||
def cStart(context, data) -> None:
|
||||
SendMsg(context, {"Text": choice(Locale.__('start')).format(data.User.Name)})
|
||||
|
||||
# Module: Source
|
||||
# Provides a copy of the bot source codes and/or instructions on how to get it.
|
||||
def cSource(context, data=None) -> None:
|
||||
SendMsg(context, {"TextPlain": ("""\
|
||||
* Original Code: {https://gitlab.com/octospacc/WinDog}
|
||||
@@ -52,13 +46,9 @@ def cSource(context, data=None) -> None:
|
||||
# # ... language: en, it, ...
|
||||
# # ... userdata: import, export, delete
|
||||
|
||||
# Module: Ping
|
||||
# Responds pong, useful for testing messaging latency.
|
||||
def cPing(context, data=None) -> None:
|
||||
SendMsg(context, {"Text": "*Pong!*"})
|
||||
|
||||
# Module: Echo
|
||||
# Responds back with the original text of the received message.
|
||||
def cEcho(context, data) -> None:
|
||||
if data.Body:
|
||||
prefix = "🗣️ "
|
||||
@@ -75,8 +65,6 @@ def cEcho(context, data) -> None:
|
||||
else:
|
||||
SendMsg(context, {"Text": choice(Locale.__('echo.empty'))})
|
||||
|
||||
# Module: Broadcast
|
||||
# Sends an admin message over to another destination
|
||||
def cBroadcast(context, data) -> None:
|
||||
if data.User.Id not in AdminIds:
|
||||
return SendMsg(context, {"Text": choice(Locale.__('eval'))})
|
||||
@@ -92,13 +80,9 @@ def cBroadcast(context, data) -> None:
|
||||
# CharEscape(choice(Locale.__('time')).format(time.ctime().replace(' ', ' ')), 'MARKDOWN_SPEECH'),
|
||||
# reply_to_message_id=update.message.message_id)
|
||||
|
||||
# Module: Eval
|
||||
# Execute a Python command (or safe literal operation) in the current context. Currently not implemented.
|
||||
def cEval(context, data=None) -> None:
|
||||
SendMsg(context, {"Text": choice(Locale.__('eval'))})
|
||||
|
||||
# Module: Exec
|
||||
# Execute a system command from the allowed ones and return stdout/stderr.
|
||||
def cExec(context, data) -> None:
|
||||
if len(data.Tokens) >= 2 and data.Tokens[1].lower() in ExecAllowed:
|
||||
cmd = data.Tokens[1].lower()
|
||||
@@ -113,13 +97,18 @@ def cExec(context, data) -> None:
|
||||
else:
|
||||
SendMsg(context, {"Text": choice(Locale.__('eval'))})
|
||||
|
||||
# Module: Format
|
||||
# Reformat text using an handful of rules. Currently not implemented.
|
||||
def cFormat(context, data=None) -> None:
|
||||
pass
|
||||
|
||||
# Module: Frame
|
||||
# Frame someone's message into a platform-styled image. Currently not implemented.
|
||||
def cFrame(context, data=None) -> None:
|
||||
pass
|
||||
RegisterModule(name="Misc", endpoints={
|
||||
"Percenter": CreateEndpoint(["wish", "level"], summary="Provides fun trough percentage-based toys.", handler=mPercenter),
|
||||
"Multifun": CreateEndpoint(["hug", "pat", "poke", "cuddle", "hands", "floor", "sessocto"], summary="Provides fun trough preprogrammed-text-based toys.", handler=mMultifun),
|
||||
"Start": CreateEndpoint(["start"], summary="Salutes the user, hinting that the bot is working and providing basic quick help.", handler=cStart),
|
||||
"Source": CreateEndpoint(["source"], summary="Provides a copy of the bot source codes and/or instructions on how to get it.", handler=cSource),
|
||||
"Ping": CreateEndpoint(["ping"], summary="Responds pong, useful for testing messaging latency.", handler=cPing),
|
||||
"Echo": CreateEndpoint(["echo"], summary="Responds back with the original text of the received message.", handler=cEcho),
|
||||
"Broadcast": CreateEndpoint(["broadcast"], summary="Sends an admin message over to any chat destination.", handler=cBroadcast),
|
||||
"Eval": CreateEndpoint(["eval"], summary="Execute a Python command (or safe literal operation) in the current context. Currently not implemented.", handler=cEval),
|
||||
"Exec": CreateEndpoint(["exec"], summary="Execute a system command from the allowed ones and return stdout+stderr.", handler=cExec),
|
||||
#"Format": CreateEndpoint(["format"], summary="Reformat text using an handful of rules. Not yet implemented.", handler=cFormat),
|
||||
#"Frame": CreateEndpoint(["frame"], summary="Frame someone's message into a platform-styled image. Not yet implemented.", handler=cFrame),
|
||||
#"Repeat": CreateEndpoint(["repeat"], summary="I had this planned but I don't remember what this should have done. Not yet implemented.", handler=cRepeat),
|
||||
})
|
||||
|
@@ -1,24 +1,18 @@
|
||||
# ================================== #
|
||||
# WinDog multi-purpose chatbot #
|
||||
# Licensed under AGPLv3 by OctoSpacc #
|
||||
# ================================== #
|
||||
|
||||
luaCycleLimit = 10000
|
||||
luaMemoryLimit = (512 * 1024) # 512 KB
|
||||
luaCrashMessage = f"Lua Error: Script has been forcefully terminated due to having exceeded the max cycle count limit ({luaCycleLimit})."
|
||||
luaCrashMessage = f"Script has been forcefully terminated due to having exceeded the max cycle count limit ({luaCycleLimit})."
|
||||
|
||||
from lupa import LuaRuntime as NewLuaRuntime, LuaError, LuaSyntaxError
|
||||
# Use specific Lua version; always using the latest is risky due to possible new APIs and using JIT is vulnerable
|
||||
from lupa.lua54 import LuaRuntime as NewLuaRuntime, LuaError, LuaSyntaxError
|
||||
|
||||
def luaAttributeFilter(obj, attr_name, is_setting):
|
||||
raise AttributeError("Access Denied.")
|
||||
|
||||
#LuaRuntime = NewLuaRuntime(max_memory=(16 * 1024**2), register_eval=False, register_builtins=False, attribute_filter=luaAttributeFilter)
|
||||
#for key in LuaRuntime.globals():
|
||||
# if key not in ("error", "assert", "math", "type"):
|
||||
# del LuaRuntime.globals()[key]
|
||||
#luaGlobalsCopy = dict(LuaRuntime.globals()) # should this manually handle nested stuff?
|
||||
# this way to prevent overwriting of global fields is flawed since this doesn't protect concurrent scripts
|
||||
# better to use the currently active solution of a dedicated instance for each new script running
|
||||
#def luaFunctionRunner(userFunction:callable):
|
||||
# for key in luaGlobalsCopy:
|
||||
# LuaRuntime.globals()[key] = luaGlobalsCopy[key]
|
||||
# return userFunction()
|
||||
|
||||
# TODO make print behave the same as normal Lua, and expose a function for printing without newlines
|
||||
def cLua(context, data=None) -> None:
|
||||
scriptText = (data.Body or (data.Quoted and data.Quoted.Body))
|
||||
@@ -27,12 +21,12 @@ def cLua(context, data=None) -> None:
|
||||
luaRuntime = NewLuaRuntime(max_memory=luaMemoryLimit, register_eval=False, register_builtins=False, attribute_filter=luaAttributeFilter)
|
||||
luaRuntime.eval(f"""(function()
|
||||
_windog = {{ stdout = "" }}
|
||||
function print (text, endl) _windog.stdout = _windog.stdout .. text .. (endl ~= false and "\\n" or "") end
|
||||
function print (text, endl) _windog.stdout = _windog.stdout .. tostring(text) .. (endl ~= false and "\\n" or "") end
|
||||
function luaCrashHandler () return error("{luaCrashMessage}") end
|
||||
debug.sethook(luaCrashHandler, "", {luaCycleLimit})
|
||||
end)()""")
|
||||
for key in luaRuntime.globals():
|
||||
if key not in ("error", "assert", "math", "string", "print", "_windog"):
|
||||
if key not in ["error", "assert", "math", "string", "tostring", "print", "_windog"]:
|
||||
del luaRuntime.globals()[key]
|
||||
try:
|
||||
textOutput = ("[ʟᴜᴀ ꜱᴛᴅᴏᴜᴛ]\n\n" + luaRuntime.eval(f"""(function()
|
||||
@@ -40,7 +34,7 @@ _windog.scriptout = (function()\n{scriptText}\nend)()
|
||||
return _windog.stdout .. (_windog.scriptout or '')
|
||||
end)()"""))
|
||||
except (LuaError, LuaSyntaxError) as error:
|
||||
Log(textOutput := str("Lua Error: " + error))
|
||||
Log(textOutput := ("Lua Error: " + str(error)))
|
||||
SendMsg(context, {"TextPlain": textOutput})
|
||||
|
||||
RegisterModule(name="Scripting", group="Geek", summary="Tools for programming the bot and expanding its features.", endpoints={
|
||||
|
Reference in New Issue
Block a user