Compare commits

..

5 Commits

Author SHA1 Message Date
7cad4e42ee
Removing legacy xmpp_domain output
Signed-off-by: Georg <georg@lysergic.dev>
2021-12-18 01:14:18 +01:00
c122dfcf92
Removing __pycache__
Signed-off-by: Georg <georg@lysergic.dev>
2021-09-23 13:18:49 +02:00
8bbea1e042
Adding .gitignore
Signed-off-by: Georg <georg@lysergic.dev>
2021-09-23 13:17:35 +02:00
248d81ab86
Mailbox polishments. First Alias attempts.
Signed-off-by: Georg <georg@lysergic.dev>
2021-06-29 17:02:41 +02:00
491452f326
Version 1
- Added basic error handling
- Decided to keep Debug block:
	- moved it to the bottom
	- hardcoded my hostmask
- Changed server config variable to Private
- Changed access config variable's help text
2021-06-03 05:42:21 +02:00
6 changed files with 379 additions and 188 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
__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=False , private=True
)) ))
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('',
""" """
Nicknames to grant Read-Only access Hostmasks to grant Read-Only access
""" """
, private=True , private=True
)) ))
@ -84,7 +84,7 @@ Nicknames to grant Read-Only access
conf.registerGlobalValue(Mailcow.access, 'write', conf.registerGlobalValue(Mailcow.access, 'write',
registry.CommaSeparatedListOfStrings('', registry.CommaSeparatedListOfStrings('',
""" """
Nicknames to grant Write access Hostmasks 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 from supybot import utils, plugins, ircutils, callbacks, ircdb, ircmsgs
from supybot.commands import * from supybot.commands import *
from supybot.ircmsgs import nick from supybot.ircmsgs import nick
try: try:
@ -60,10 +60,11 @@ 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 write: if hostmask in read or hostmask in 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},
@ -72,16 +73,20 @@ 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 shall not pass.") irc.reply("Thou shalt 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",
@ -132,7 +137,18 @@ 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']
irc.reply(f"DELETION: {status} - {msg} - Hey, where's that backup again?") if 'success' in status:
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)
@ -140,14 +156,247 @@ 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):
#FOR DEBUGGING / REMOVE BEFORE RELEASE """<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
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.""" """Prints values. If you were supposed to use this, you would know how."""
server = self.registryValue('api.server') server = self.registryValue('api.server')
api_key = self.registryValue('api.key') api_key = self.registryValue('api.key')
@ -158,7 +407,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 + ' <')
@ -178,97 +427,37 @@ 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('What?') irc.reply('program me better', requester)
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('Go home') irc.reply('program me better', receiver)
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