Compare commits

..

No commits in common. "master" and "eda43f1d3cb0ecd5682d5073c547d37228531c32" have entirely different histories.

6 changed files with 188 additions and 379 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
__pycache__/
.idea/

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -68,7 +68,7 @@ registry.String('',
""" """
Your Mailcow server \(https://example.com\) Your Mailcow server \(https://example.com\)
""" """
, private=True , private=False
)) ))
conf.registerGroup(Mailcow, 'access') conf.registerGroup(Mailcow, 'access')
@ -76,7 +76,7 @@ conf.registerGroup(Mailcow, 'access')
conf.registerGlobalValue(Mailcow.access, 'read', conf.registerGlobalValue(Mailcow.access, 'read',
registry.CommaSeparatedListOfStrings('', registry.CommaSeparatedListOfStrings('',
""" """
Hostmasks to grant Read-Only access Nicknames to grant Read-Only access
""" """
, private=True , private=True
)) ))
@ -84,7 +84,7 @@ Hostmasks to grant Read-Only access
conf.registerGlobalValue(Mailcow.access, 'write', conf.registerGlobalValue(Mailcow.access, 'write',
registry.CommaSeparatedListOfStrings('', registry.CommaSeparatedListOfStrings('',
""" """
Hostmasks to grant Write access Nicknames to grant Write access
""" """
, private=True , private=True
)) ))

385
plugin.py
View File

@ -31,7 +31,7 @@
import requests import requests
import secrets import secrets
import string import string
from supybot import utils, plugins, ircutils, callbacks, ircdb, ircmsgs from supybot import utils, plugins, ircutils, callbacks, ircdb
from supybot.commands import * from supybot.commands import *
from supybot.ircmsgs import nick from supybot.ircmsgs import nick
try: try:
@ -60,11 +60,10 @@ class Mailcow(callbacks.Plugin):
hostmask = irc.state.nickToHostmask(msg.nick) hostmask = irc.state.nickToHostmask(msg.nick)
#Read-Functions: Summary #Read-Functions: Summary
try:
if 'summary' in variant: if 'summary' in variant:
if hostmask in read or hostmask in write: if hostmask in read or write:
URL = server + get + '/domain/' + id URL = server + get + '/domain/' + id
try:
response = requests.get( response = requests.get(
URL, URL,
headers = {'accept': 'application/json', 'X-API-Key': api_key}, headers = {'accept': 'application/json', 'X-API-Key': api_key},
@ -73,20 +72,16 @@ class Mailcow(callbacks.Plugin):
domain = data['domain_name'] domain = data['domain_name']
description = data['description'] description = data['description']
bytes_total = data['bytes_total'] bytes_total = data['bytes_total']
#response.raise_for_status()
irc.reply(f"Domain: {domain} | Description: {description} | Bytes Total: {bytes_total} ") irc.reply(f"Domain: {domain} | Description: {description} | Bytes Total: {bytes_total} ")
except requests.exceptions.ConnectionError as err:
irc.error("Connection failed.")
except requests.exceptions.HTTPError as err:
irc.error(err)
else: else:
irc.reply("Thou shalt not pass.") irc.reply("Thou shall not pass.")
print("Intrusion attempt: " + hostmask) print("Intrusion attempt: " + hostmask)
#Write-Functions: Create/Delete #Write-Functions: Create/Delete
elif 'create' in variant: elif 'create' in variant:
if hostmask in write: if hostmask in write:
URL = server + api + '/add/domain' URL = server + api + '/add/domain'
#domain = id['domain']
payload = { payload = {
"active": "1", "active": "1",
"aliases": "20", "aliases": "20",
@ -137,18 +132,7 @@ class Mailcow(callbacks.Plugin):
data = response.json() data = response.json()
status = data[0]['type'] status = data[0]['type']
object = data[0]['msg'] object = data[0]['msg']
if 'success' in status: irc.reply(f"DELETION: {status} - {msg} - Hey, where's that backup again?")
if 'domain_removed' in object:
usefulstatus = status.replace("success", "Attempted Removal - please manually confirm")
usefulobject = object
else:
usefulstatus = status.replace("success", "Transmitted")
usefulobject = object
else:
usefulstatus = status
usefulobject = object
irc.reply(f"DELETION: {usefulstatus} - {usefulobject} - Hey, where's that backup again?")
else: else:
irc.reply("Thou shall not delete.") irc.reply("Thou shall not delete.")
print("Intrusion attempt: " + hostmask) print("Intrusion attempt: " + hostmask)
@ -156,247 +140,14 @@ class Mailcow(callbacks.Plugin):
else: else:
irc.reply("Unknown option.") irc.reply("Unknown option.")
except KeyError as err:
key = err.args[0]
if key == 'domain_name':
irc.error("Invalid domain.")
else:
irc.error("Unhandled " + str(err))
maildomain = wrap(maildomain, ['anything', 'anything']) maildomain = wrap(maildomain, ['anything', 'anything'])
def mailbox(self, irc, msg, args, variant, id): ####################
"""<option> <id> #FOR DEBUGGING / REMOVE BEFORE RELEASE
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
try:
if 'summary' in variant:
if hostmask in read or hostmask in write:
URL = server + get + '/mailbox/' + id
try:
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']))
except requests.exceptions.ConnectionError as err:
irc.error("Connection failed.")
except requests.exceptions.HTTPError as err:
irc.error(err)
else:
irc.reply("Thou shall not pass.")
print("Intrusion attempt: " + hostmask)
#Write-Functions: Create/Delete
elif 'create' in variant:
if hostmask in write:
URL = server + api + '/add/mailbox/' + id
user = id.split('@')[0]
domain = id.split('@')[1]
alphabet = string.ascii_letters + string.digits
random = ''.join(secrets.choice(alphabet) for i in range(64))
pw = random
payload = {
"active": "1",
"domain": domain,
"local_part": user,
"name": user + '@' + domain,
"password": pw,
"password2": pw,
"quota": "512",
"force_pw_update": "0",
"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']
if 'success' in status:
irc.queueMsg(msg=ircmsgs.IrcMsg(command='PRIVMSG', args=(nick, f'{pw}')))
irc.reply(f"CREATION OK: {status} | {msg}")
else:
irc.reply(f"CREATION: {status} | {msg}")
else:
irc.reply("Thou shall not create.")
print("Intrusion attempt: " + hostmask)
elif 'delete' in variant:
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']
if 'danger' in status:
if 'access_denied' in object:
usefulstatus = status.replace("danger", "Error:")
usefulobject = object.replace("access_denied", "Access denied or Mailbox does not exist")
else:
usefulstatus = status.replace("danger", "Error:")
usefulobject = object
elif 'success' in status:
usefulstatus = status.replace("success", "Success:")
usefulobject = object
else:
usefulstatus = status
usefulobject = object
irc.reply(f"DELETION: {usefulstatus} {usefulobject}")
else:
irc.reply("Thou shall not delete.")
print("Intrusion attempt: " + hostmask)
else:
irc.reply('Unknown function.')
except KeyError as err:
key = err.args[0]
if key == 'username':
irc.error("Invalid mailbox.")
else:
irc.error("Unhandled " + str(err))
mailbox = wrap(mailbox, ['anything', 'anything'])
def mailalias(self, irc, msg, args, variant, id, id2):
"""<option> <id> [<id2>]
i.e. 'summary cranberrry@lib.casa' will print some details about this alias"""
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
try:
if 'summary' in variant:
if hostmask in read or hostmask in write:
URL = server + get + '/alias/' + id
try:
response = requests.get(
URL,
params={'q': 'requests'},
headers={'accept': 'application/json', 'X-API-Key': api_key},
)
data = response.json()
print(response.json())
if 'address' not in data:
irc.error('Alias not found or error not handled.')
else:
irc.reply('From: ' + data['address'] + ' | To: ' + str(data['goto']) + ' | ID: ' + str(data['id']) + ' | Catch-All: ' + str(data['is_catch_all']) + ' | Comment: ' + str(data['public_comment']) + ' | Active: ' + str(data['active']))
except requests.exceptions.ConnectionError as err:
irc.error("Connection failed.")
except requests.exceptions.HTTPError as err:
irc.error(err)
else:
irc.reply("Thou shall not pass.")
print("Intrusion attempt: " + hostmask)
#Write-Functions: Create/Delete
elif 'create' in variant: #IN PROGRESS
if hostmask in write:
URL = server + api + '/add/alias'
fromaddress = id
toaddress = id2
payload = {
"active": "1",
"address": fromaddress,
"goto": toaddress,
}
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"Alias Creation: {status} | {msg}")
else:
irc.reply("Thou shall not create.")
print("Intrusion attempt: " + hostmask)
elif 'delete' in variant: #EXAMPLE EXAMPLE EXAMPLE
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']
if 'danger' in status:
if 'access_denied' in object:
usefulstatus = status.replace("danger", "Error:")
usefulobject = object.replace("access_denied", "Access denied or Mailbox does not exist")
else:
usefulstatus = status.replace("danger", "Error:")
usefulobject = object
elif 'success' in status:
usefulstatus = status.replace("success", "Success:")
usefulobject = object
else:
usefulstatus = status
usefulobject = object
irc.reply(f"DELETION: {usefulstatus} {usefulobject}")
else:
irc.reply("Thou shall not delete.")
print("Intrusion attempt: " + hostmask)
else:
irc.reply('Unknown function.')
except KeyError as err:
key = err.args[0]
if key == 'username':
irc.error("Invalid alias.")
else:
irc.error("Unhandled " + str(err))
mailalias = wrap(mailalias, ['anything', 'anything', optional('anything')])
############################################################
#FOR DEBUGGING / REMOVE BEFORE RELEASE (or don't, developers hostmask is hardcoded)
############################################################
def mcdebug(self, irc, msg, args, variant): def mcdebug(self, irc, msg, args, variant):
"""Prints values. If you were supposed to use this, you would know how.""" """Prints values."""
server = self.registryValue('api.server') server = self.registryValue('api.server')
api_key = self.registryValue('api.key') api_key = self.registryValue('api.key')
@ -407,7 +158,7 @@ class Mailcow(callbacks.Plugin):
if hostmask in read or hostmask in write: if hostmask in read or hostmask in write:
if hostmask == 'cranberry!~u@cranberry.juice':
if 'key' in variant: if 'key' in variant:
irc.reply('> ' + api_key + ' <') irc.reply('> ' + api_key + ' <')
@ -427,37 +178,97 @@ class Mailcow(callbacks.Plugin):
elif 'write' in variant: elif 'write' in variant:
irc.reply('> ' + str(write) + ' <') irc.reply('> ' + str(write) + ' <')
elif 'whois' in variant:
user = 'foo.bar'
# this does not work. i tried to do some cool logic that figures out if the user you request a box for exists in order to send them their password directly
# i suck
# help me??
requester = ircmsgs.IrcMsg(command='WHO', args=(nick, 'n'))
receiver = ircmsgs.IrcMsg(command='WHO', args=(user, 'n'))
print('DEBUG WHO', requester, receiver)
if 'nick' in requester:
irc.reply('found requester.', requester)
elif not 'nick' in requester:
irc.reply('did not find requester. what the fuck.', requester)
else: else:
irc.reply('program me better', requester) irc.reply('What?')
if 'user' in receiver:
irc.reply('found receiver.', receiver)
elif not 'user' in receiver:
irc.reply('did not find receiver.', receiver)
else: else:
irc.reply('program me better', receiver) irc.reply('Go home')
irc.reply('see console')
else:
irc.reply("What?")
else:
irc.error("You're not a dev. Firstly, install Arch Linux.")
else:
irc.reply("Go home")
mcdebug = wrap(mcdebug, ['anything']) mcdebug = wrap(mcdebug, ['anything'])
############################################################ ####################
def mailbox(self, irc, msg, args, variant, id):
"""<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:
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:
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:
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.')
mailbox = wrap(mailbox, ['anything', 'anything'])
Class = Mailcow Class = Mailcow