This commit is contained in:
Georg Pfuetzenreuter 2021-06-03 01:46:17 +02:00
parent cc4ef9b16b
commit eda43f1d3c
Signed by: Georg
GPG Key ID: 0EC71AFA80C807E3
5 changed files with 246 additions and 116 deletions

Binary file not shown.

Binary file not shown.

View File

@ -29,6 +29,7 @@
### ###
from supybot import conf, registry from supybot import conf, registry
from supybot.commands import private
try: try:
from supybot.i18n import PluginInternationalization from supybot.i18n import PluginInternationalization
_ = PluginInternationalization('Mailcow') _ = PluginInternationalization('Mailcow')
@ -52,5 +53,40 @@ Mailcow = conf.registerPlugin('Mailcow')
# conf.registerGlobalValue(Mailcow, 'someConfigVariableName', # conf.registerGlobalValue(Mailcow, 'someConfigVariableName',
# registry.Boolean(False, _("""Help for someConfigVariableName."""))) # registry.Boolean(False, _("""Help for someConfigVariableName.""")))
conf.registerGroup(Mailcow, 'api')
conf.registerGlobalValue(Mailcow.api, 'key',
registry.String('',
"""
Your Mailcow API Key
"""
, private=True
))
conf.registerGlobalValue(Mailcow.api, 'server',
registry.String('',
"""
Your Mailcow server \(https://example.com\)
"""
, private=False
))
conf.registerGroup(Mailcow, 'access')
conf.registerGlobalValue(Mailcow.access, 'read',
registry.CommaSeparatedListOfStrings('',
"""
Nicknames to grant Read-Only access
"""
, private=True
))
conf.registerGlobalValue(Mailcow.access, 'write',
registry.CommaSeparatedListOfStrings('',
"""
Nicknames to grant Write access
"""
, private=True
))
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

315
plugin.py
View File

@ -33,6 +33,7 @@ import secrets
import string import string
from supybot import utils, plugins, ircutils, callbacks, ircdb from supybot import utils, plugins, ircutils, callbacks, ircdb
from supybot.commands import * from supybot.commands import *
from supybot.ircmsgs import nick
try: try:
from supybot.i18n import PluginInternationalization from supybot.i18n import PluginInternationalization
_ = PluginInternationalization('Mailcow') _ = PluginInternationalization('Mailcow')
@ -41,149 +42,231 @@ except ImportError:
# without the i18n module # without the i18n module
_ = lambda x: x _ = lambda x: x
server = 'https://zz0.email'
api = '/api/v1' api = '/api/v1'
get = api + '/get' get = api + '/get'
api_key = ""
capability = ircdb.checkCapability(hostmask='cranberry!~u@cranberry.juice', capability='owner', ignoreDefaultAllow=True)
class Mailcow(callbacks.Plugin): class Mailcow(callbacks.Plugin):
"""Mailcow API through IRC""" """Mailcow API through IRC"""
pass pass
def maildomain(self, irc, msg, args, variant, id): def maildomain(self, irc, msg, args, variant, id):
"""<variant> <id> """<option> <id>
i.e. 'get liberta.casa' will print infos about the respective MX zone""" i.e. 'summary liberta.casa' will print infos about the respective zone"""
server = self.registryValue('api.server')
api_key = self.registryValue('api.key')
read = self.registryValue('access.read')
write = self.registryValue('access.write')
nick = msg.nick
hostmask = irc.state.nickToHostmask(msg.nick)
#Read-Functions: Summary
if 'summary' in variant: if 'summary' in variant:
URL = server + get + '/domain/' + id if hostmask in read or write:
response = requests.get( URL = server + get + '/domain/' + id
URL, response = requests.get(
headers = {'accept': 'application/json', 'X-API-Key': api_key}, URL,
) headers = {'accept': 'application/json', 'X-API-Key': api_key},
data = response.json() )
domain = data['domain_name'] data = response.json()
description = data['description'] domain = data['domain_name']
bytes_total = data['bytes_total'] description = data['description']
irc.reply(f"Domain: {domain} | Description: {description} | Bytes Total: {bytes_total} " + str(capability)) bytes_total = data['bytes_total']
irc.reply(f"Domain: {domain} | Description: {description} | Bytes Total: {bytes_total} ")
else:
irc.reply("Thou shall not pass.")
print("Intrusion attempt: " + hostmask)
#Write-Functions: Create/Delete
elif 'create' in variant: elif 'create' in variant:
URL = server + api + '/add/domain' if hostmask in write:
#domain = id['domain'] URL = server + api + '/add/domain'
payload = { #domain = id['domain']
"active": "1", payload = {
"aliases": "20", "active": "1",
"backupmx": "0", "aliases": "20",
"defquota": "1024", "backupmx": "0",
"description": id, "defquota": "1024",
"domain": id, "description": id,
"mailboxes": "10", "domain": id,
"maxquota": "2048", "mailboxes": "10",
"quota": "5120", "maxquota": "2048",
"relay_all_recipients": "0", "quota": "5120",
"rl_frame": "s", "relay_all_recipients": "0",
"rl_value": "10", "rl_frame": "s",
"restart_sogo": "10" "rl_value": "10",
} "restart_sogo": "10"
response = requests.post( }
URL, response = requests.post(
headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'}, URL,
json = payload, headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
) json = payload,
data = response.json() )
print(data) data = response.json()
status = data[0]['type'] print(data)
#object = data[0]['domain'] status = data[0]['type']
#active = data[0]['active'] #object = data[0]['domain']
msg = data[0]['msg'] #active = data[0]['active']
#max_aliases = data['aliases'] msg = data[0]['msg']
#max_mailboxes = data['mailboxes'] #max_aliases = data['aliases']
#default_quota = data['defquota'] #max_mailboxes = data['mailboxes']
#max_mailbox_quota = data['maxquota'] #default_quota = data['defquota']
#max_domain_quota = data['quota'] #max_mailbox_quota = data['maxquota']
irc.reply(f"CREATION: {status} | {msg} | NOTE: SOGo is NOT being restarted automatically.")# Issue 'sogo restart' to make the object visible through Groupware. | Summary of object properties: MaxAliases: {aliases} | MaxMailboxes: {mailboxes} | DefaultQuota: {default_quota} | MaxMailBoxQuota: {max_mailbox_quota} | MaxDomainQuota: {max_domain_quota}") #max_domain_quota = data['quota']
irc.reply(f"CREATION: {status} | {msg} | NOTE: SOGo is NOT being restarted automatically.")# Issue 'sogo restart' to make the object visible through Groupware. | Summary of object properties: MaxAliases: {aliases} | MaxMailboxes: {mailboxes} | DefaultQuota: {default_quota} | MaxMailBoxQuota: {max_mailbox_quota} | MaxDomainQuota: {max_domain_quota}")
else:
irc.reply("Thou shall not create.")
print("Intrusion attempt: " + hostmask)
elif 'delete' in variant: elif 'delete' in variant:
URL = server + api + '/delete/domain' if hostmask in write:
payload = [ URL = server + api + '/delete/domain'
id payload = [
] id
response = requests.post( ]
URL, response = requests.post(
headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'}, URL,
json = payload, headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
) json = payload,
data = response.json() )
status = data[0]['type'] data = response.json()
object = data[0]['msg'] status = data[0]['type']
irc.reply(f"DELETION: {status} - {msg} - Hey, where's that backup again?") object = data[0]['msg']
irc.reply(f"DELETION: {status} - {msg} - Hey, where's that backup again?")
else:
irc.reply("Thou shall not delete.")
print("Intrusion attempt: " + hostmask)
else: else:
irc.reply("Unknown option.") irc.reply("Unknown option.")
maildomain = wrap(maildomain, ['anything', 'anything']) maildomain = wrap(maildomain, ['anything', 'anything'])
####################
#FOR DEBUGGING / REMOVE BEFORE RELEASE
####################
def mcdebug(self, irc, msg, args, variant):
"""Prints values."""
server = self.registryValue('api.server')
api_key = self.registryValue('api.key')
read = self.registryValue('access.read')
write = self.registryValue('access.write')
nick = msg.nick
hostmask = irc.state.nickToHostmask(msg.nick)
if hostmask in read or hostmask in write:
if 'key' in variant:
irc.reply('> ' + api_key + ' <')
elif 'server' in variant:
irc.reply('> ' + server + ' <')
elif 'user' in variant:
u = ircdb.users.getUser(msg.prefix)
nick = msg.nick
hm = irc.state.nickToHostmask(nick)
print(hm)
irc.reply('> ' + u.name + ' ' + hm + ' <')
elif 'read' in variant:
irc.reply('> ' + str(read) + ' <')
elif 'write' in variant:
irc.reply('> ' + str(write) + ' <')
else:
irc.reply('What?')
else:
irc.reply('Go home')
mcdebug = wrap(mcdebug, ['anything'])
####################
def mailbox(self, irc, msg, args, variant, id): def mailbox(self, irc, msg, args, variant, id):
"""<variant> <id> """<option> <id>
Modifies Mailboxes.""" i.e. 'summary cranberrry@liberta.casa' will print some details about his mailbox"""
server = self.registryValue('api.server')
api_key = self.registryValue('api.key')
read = self.registryValue('access.read')
write = self.registryValue('access.write')
nick = msg.nick
hostmask = irc.state.nickToHostmask(msg.nick)
#Read-Functions: Summary
if 'summary' in variant: if 'summary' in variant:
URL = server + get + '/mailbox/' + id if hostmask in read or write:
response = requests.get( URL = server + get + '/mailbox/' + id
URL, response = requests.get(
params={'q': 'requests'}, URL,
headers={'accept': 'application/json', 'X-API-Key': api_key}, params={'q': 'requests'},
) headers={'accept': 'application/json', 'X-API-Key': api_key},
data = response.json() )
#return(print(data)) data = response.json()
irc.reply('Username: ' + data['username'] + ' | Quota: ' + str(data['quota']) + ' | Messages: ' + str(data['messages']) + ' | Mail Active: ' + str(data['active']) + ' | XMPP Active: ' + str(data['domain_xmpp'])) #return(print(data))
irc.reply('Username: ' + data['username'] + ' | Quota: ' + str(data['quota']) + ' | Messages: ' + str(data['messages']) + ' | Mail Active: ' + str(data['active']) + ' | XMPP Active: ' + str(data['domain_xmpp']))
else:
irc.reply("Thou shall not pass.")
print("Intrusion attempt: " + hostmask)
#Write-Functions: Create/Delete
elif 'create' in variant: elif 'create' in variant:
URL = server + api + '/add/mailbox/' + id if hostmask in write:
user = id.split('@')[0] URL = server + api + '/add/mailbox/' + id
domain = id.split('@')[1] user = id.split('@')[0]
random = secrets.token_urlsafe(64) domain = id.split('@')[1]
payload = { random = secrets.token_urlsafe(64)
"active": "1", payload = {
"domain": domain, "active": "1",
"local_part": user, "domain": domain,
"name": user + '@' + domain, "local_part": user,
"password": random, "name": user + '@' + domain,
"password2": random, "password": random,
"quota": "512", "password2": random,
"force_pw_update": "1", "quota": "512",
"tls_enforce_in": "1", "force_pw_update": "1",
"tls_enforce_out": "1" "tls_enforce_in": "1",
} "tls_enforce_out": "1"
response = requests.post( }
URL, response = requests.post(
headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'}, URL,
json = payload, headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
) json = payload,
data = response.json() )
status = data[0]['type'] data = response.json()
msg = data[0]['msg'] status = data[0]['type']
msg = data[0]['msg']
irc.reply(f"CREATION: {status} | {msg} | " + str(random) + server) irc.reply(f"CREATION: {status} | {msg} | " + str(random) + server)
else:
irc.reply("Thou shall not create.")
print("Intrusion attempt: " + hostmask)
elif 'delete' in variant: elif 'delete' in variant:
URL = server + api + '/delete/mailbox/' + id if hostmask in write:
payload = [ URL = server + api + '/delete/mailbox/' + id
id payload = [
] id
response = requests.post( ]
URL, response = requests.post(
headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'}, URL,
json = payload, headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
) json = payload,
data = response.json() )
status = data[0]['type'] data = response.json()
object = data[0]['msg'] status = data[0]['type']
object = data[0]['msg']
irc.reply(f"DELETION: {status} - {msg}")
irc.reply(f"DELETION: {status} - {msg}")
else:
irc.reply("Thou shall not delete.")
print("Intrusion attempt: " + hostmask)
else: else:
irc.reply('Unknown function.') irc.reply('Unknown function.')
mailbox = wrap(mailbox, ['anything', 'anything']) mailbox = wrap(mailbox, ['anything', 'anything'])

View File

@ -31,3 +31,14 @@ INFO Shutdown initiated.
INFO Killing Driver objects. INFO Killing Driver objects.
INFO Killing Irc objects. INFO Killing Irc objects.
INFO Shutdown complete. INFO Shutdown complete.
ERROR Invalid user dictionary file, resetting to empty.
ERROR Exact error: FileNotFoundError: [Errno 2] No such file or directory: '/home/georg/limnoria/Mailcow/test-conf/users.conf'
ERROR Invalid channel database, resetting to empty.
ERROR Exact error: FileNotFoundError: [Errno 2] No such file or directory: '/home/georg/limnoria/Mailcow/test-conf/channels.conf'
ERROR Invalid network database, resetting to empty.
ERROR Exact error: FileNotFoundError: [Errno 2] No such file or directory: '/home/georg/limnoria/Mailcow/test-conf/networks.conf'
WARNING Couldn't open ignore database: [Errno 2] No such file or directory: '/home/georg/limnoria/Mailcow/test-conf/ignores.conf'
INFO Shutdown initiated.
INFO Killing Driver objects.
INFO Killing Irc objects.
INFO Shutdown complete.