summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg2021-06-03 01:46:17 +0200
committerGeorg2021-06-03 01:46:17 +0200
commiteda43f1d3cb0ecd5682d5073c547d37228531c32 (patch)
tree24baddbbdff93c5c62eab28300dfd72b9d223ae7
parentcc4ef9b16bcc694bdf536adae00169f7dfb9507a (diff)
downloadmailcow-eda43f1d3cb0ecd5682d5073c547d37228531c32.tar.gz
mailcow-eda43f1d3cb0ecd5682d5073c547d37228531c32.tar.bz2
mailcow-eda43f1d3cb0ecd5682d5073c547d37228531c32.zip
Init
-rw-r--r--__pycache__/config.cpython-38.pycbin689 -> 1196 bytes
-rw-r--r--__pycache__/plugin.cpython-38.pycbin3738 -> 4995 bytes
-rw-r--r--config.py36
-rw-r--r--plugin.py317
-rw-r--r--test-logs/messages.log11
5 files changed, 247 insertions, 117 deletions
diff --git a/__pycache__/config.cpython-38.pyc b/__pycache__/config.cpython-38.pyc
index 1c327bc..dcb98bc 100644
--- a/__pycache__/config.cpython-38.pyc
+++ b/__pycache__/config.cpython-38.pyc
Binary files differ
diff --git a/__pycache__/plugin.cpython-38.pyc b/__pycache__/plugin.cpython-38.pyc
index 3d3c663..139a39b 100644
--- a/__pycache__/plugin.cpython-38.pyc
+++ b/__pycache__/plugin.cpython-38.pyc
Binary files differ
diff --git a/config.py b/config.py
index 0d04725..ed3fbc3 100644
--- a/config.py
+++ b/config.py
@@ -29,6 +29,7 @@
###
from supybot import conf, registry
+from supybot.commands import private
try:
from supybot.i18n import PluginInternationalization
_ = PluginInternationalization('Mailcow')
@@ -52,5 +53,40 @@ Mailcow = conf.registerPlugin('Mailcow')
# conf.registerGlobalValue(Mailcow, '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:
diff --git a/plugin.py b/plugin.py
index 9f855c3..0f5dc26 100644
--- a/plugin.py
+++ b/plugin.py
@@ -33,6 +33,7 @@ import secrets
import string
from supybot import utils, plugins, ircutils, callbacks, ircdb
from supybot.commands import *
+from supybot.ircmsgs import nick
try:
from supybot.i18n import PluginInternationalization
_ = PluginInternationalization('Mailcow')
@@ -41,149 +42,231 @@ except ImportError:
# without the i18n module
_ = lambda x: x
-server = 'https://zz0.email'
api = '/api/v1'
get = api + '/get'
-api_key = ""
-
-capability = ircdb.checkCapability(hostmask='cranberry!~u@cranberry.juice', capability='owner', ignoreDefaultAllow=True)
-
class Mailcow(callbacks.Plugin):
"""Mailcow API through IRC"""
pass
-
+
def maildomain(self, irc, msg, args, variant, id):
- """<variant> <id>
- i.e. 'get liberta.casa' will print infos about the respective MX zone"""
+ """<option> <id>
+ 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:
- URL = server + get + '/domain/' + id
- response = requests.get(
- URL,
- headers = {'accept': 'application/json', 'X-API-Key': api_key},
- )
- data = response.json()
- domain = data['domain_name']
- description = data['description']
- bytes_total = data['bytes_total']
- irc.reply(f"Domain: {domain} | Description: {description} | Bytes Total: {bytes_total} " + str(capability))
+ if hostmask in read or write:
+ URL = server + get + '/domain/' + id
+ response = requests.get(
+ URL,
+ headers = {'accept': 'application/json', 'X-API-Key': api_key},
+ )
+ data = response.json()
+ domain = data['domain_name']
+ description = data['description']
+ 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:
- URL = server + api + '/add/domain'
- #domain = id['domain']
- payload = {
- "active": "1",
- "aliases": "20",
- "backupmx": "0",
- "defquota": "1024",
- "description": id,
- "domain": id,
- "mailboxes": "10",
- "maxquota": "2048",
- "quota": "5120",
- "relay_all_recipients": "0",
- "rl_frame": "s",
- "rl_value": "10",
- "restart_sogo": "10"
- }
- response = requests.post(
- URL,
- headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
- json = payload,
- )
- data = response.json()
- print(data)
- status = data[0]['type']
- #object = data[0]['domain']
- #active = data[0]['active']
- msg = data[0]['msg']
- #max_aliases = data['aliases']
- #max_mailboxes = data['mailboxes']
- #default_quota = data['defquota']
- #max_mailbox_quota = data['maxquota']
- #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}")
+ if hostmask in write:
+ URL = server + api + '/add/domain'
+ #domain = id['domain']
+ payload = {
+ "active": "1",
+ "aliases": "20",
+ "backupmx": "0",
+ "defquota": "1024",
+ "description": id,
+ "domain": id,
+ "mailboxes": "10",
+ "maxquota": "2048",
+ "quota": "5120",
+ "relay_all_recipients": "0",
+ "rl_frame": "s",
+ "rl_value": "10",
+ "restart_sogo": "10"
+ }
+ response = requests.post(
+ URL,
+ headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
+ json = payload,
+ )
+ data = response.json()
+ print(data)
+ status = data[0]['type']
+ #object = data[0]['domain']
+ #active = data[0]['active']
+ msg = data[0]['msg']
+ #max_aliases = data['aliases']
+ #max_mailboxes = data['mailboxes']
+ #default_quota = data['defquota']
+ #max_mailbox_quota = data['maxquota']
+ #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:
- URL = server + api + '/delete/domain'
- payload = [
- id
- ]
- response = requests.post(
- URL,
- headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
- json = payload,
- )
- data = response.json()
- status = data[0]['type']
- object = data[0]['msg']
- irc.reply(f"DELETION: {status} - {msg} - Hey, where's that backup again?")
+ if hostmask in write:
+ URL = server + api + '/delete/domain'
+ payload = [
+ id
+ ]
+ response = requests.post(
+ URL,
+ headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
+ json = payload,
+ )
+ data = response.json()
+ status = data[0]['type']
+ 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:
irc.reply("Unknown option.")
+
+
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):
- """<variant> <id>
- Modifies Mailboxes."""
+ """<option> <id>
+ 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:
- URL = server + get + '/mailbox/' + id
- response = requests.get(
- URL,
- params={'q': 'requests'},
- headers={'accept': 'application/json', 'X-API-Key': api_key},
- )
- data = response.json()
- #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']))
+ if hostmask in read or write:
+ URL = server + get + '/mailbox/' + id
+ response = requests.get(
+ URL,
+ params={'q': 'requests'},
+ headers={'accept': 'application/json', 'X-API-Key': api_key},
+ )
+ data = response.json()
+ #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:
- URL = server + api + '/add/mailbox/' + id
- user = id.split('@')[0]
- domain = id.split('@')[1]
- random = secrets.token_urlsafe(64)
- payload = {
- "active": "1",
- "domain": domain,
- "local_part": user,
- "name": user + '@' + domain,
- "password": random,
- "password2": random,
- "quota": "512",
- "force_pw_update": "1",
- "tls_enforce_in": "1",
- "tls_enforce_out": "1"
- }
- response = requests.post(
- URL,
- headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
- json = payload,
- )
- data = response.json()
- status = data[0]['type']
- msg = data[0]['msg']
-
- irc.reply(f"CREATION: {status} | {msg} | " + str(random) + server)
+ if hostmask in write:
+ URL = server + api + '/add/mailbox/' + id
+ user = id.split('@')[0]
+ domain = id.split('@')[1]
+ random = secrets.token_urlsafe(64)
+ payload = {
+ "active": "1",
+ "domain": domain,
+ "local_part": user,
+ "name": user + '@' + domain,
+ "password": random,
+ "password2": random,
+ "quota": "512",
+ "force_pw_update": "1",
+ "tls_enforce_in": "1",
+ "tls_enforce_out": "1"
+ }
+ response = requests.post(
+ URL,
+ headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
+ json = payload,
+ )
+ data = response.json()
+ status = data[0]['type']
+ msg = data[0]['msg']
+
+ irc.reply(f"CREATION: {status} | {msg} | " + str(random) + server)
+ else:
+ irc.reply("Thou shall not create.")
+ print("Intrusion attempt: " + hostmask)
elif 'delete' in variant:
- URL = server + api + '/delete/mailbox/' + id
- payload = [
- id
- ]
- response = requests.post(
- URL,
- headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
- json = payload,
- )
- data = response.json()
- status = data[0]['type']
- object = data[0]['msg']
-
- irc.reply(f"DELETION: {status} - {msg}")
+ if hostmask in write:
+ URL = server + api + '/delete/mailbox/' + id
+ payload = [
+ id
+ ]
+ response = requests.post(
+ URL,
+ headers = {'accept': 'application/json', 'X-API-Key': api_key, 'Content-Type': 'application/json'},
+ json = payload,
+ )
+ data = response.json()
+ status = data[0]['type']
+ object = data[0]['msg']
+ irc.reply(f"DELETION: {status} - {msg}")
+ else:
+ irc.reply("Thou shall not delete.")
+ print("Intrusion attempt: " + hostmask)
else:
- irc.reply('Unknown function.')
+ irc.reply('Unknown function.')
mailbox = wrap(mailbox, ['anything', 'anything'])
diff --git a/test-logs/messages.log b/test-logs/messages.log
index 30010f8..7a41f73 100644
--- a/test-logs/messages.log
+++ b/test-logs/messages.log
@@ -31,3 +31,14 @@ INFO Shutdown initiated.
INFO Killing Driver objects.
INFO Killing Irc objects.
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.