[DockerAPI] WIP: change of structure, add some more commands to control mail queue

master
André 2018-10-23 21:12:37 +02:00
parent 5347009fbb
commit fbf1c7b7c1
1 changed files with 209 additions and 106 deletions

View File

@ -1,6 +1,7 @@
from flask import Flask from flask import Flask
from flask_restful import Resource, Api from flask_restful import Resource, Api
from flask import jsonify from flask import jsonify
from flask import Response
from flask import request from flask import request
from threading import Thread from threading import Thread
from OpenSSL import crypto from OpenSSL import crypto
@ -71,7 +72,93 @@ class container_post(Resource):
if not request.json or not 'cmd' in request.json: if not request.json or not 'cmd' in request.json:
return jsonify(type='danger', msg='cmd is missing') return jsonify(type='danger', msg='cmd is missing')
if request.json['cmd'] == 'df' and request.json['dir']: if request.json['cmd'] == 'mailq':
if 'items' in request.json:
# Check if queue id is valid
r = re.compile("^[0-9a-fA-F]+$")
filtered_qids = filter(r.match, request.json['items'])
if filtered_qids:
if request.json['task'] == 'delete':
flagged_qids = ['-d %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids));
try:
for container in docker_client.containers.list(filters={"id": container_id}):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
if postsuper_r.exit_code == 0:
return jsonify(type='success', msg='command completed successfully')
else:
return jsonify(type='danger', msg=str(postsuper_r.output))
except Exception as e:
return jsonify(type='danger', msg=str(e))
if request.json['task'] == 'hold':
flagged_qids = ['-h %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids));
try:
for container in docker_client.containers.list(filters={"id": container_id}):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
if postsuper_r.exit_code == 0:
return jsonify(type='success', msg='command completed successfully')
else:
return jsonify(type='danger', msg=str(postsuper_r.output))
except Exception as e:
return jsonify(type='danger', msg=str(e))
if request.json['task'] == 'unhold':
flagged_qids = ['-H %s' % i for i in filtered_qids]
sanitized_string = str(' '.join(flagged_qids));
try:
for container in docker_client.containers.list(filters={"id": container_id}):
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
if postsuper_r.exit_code == 0:
return jsonify(type='success', msg='command completed successfully')
else:
return jsonify(type='danger', msg=str(postsuper_r.output))
except Exception as e:
return jsonify(type='danger', msg=str(e))
if request.json['task'] == 'deliver':
flagged_qids = ['-i %s' % i for i in filtered_qids]
try:
for container in docker_client.containers.list(filters={"id": container_id}):
for i in flagged_qids:
postqueue_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postqueue " + i], user='postfix')
# todo: check each exit code
return jsonify(type='success', msg=str("Scheduled immediate delivery"))
except Exception as e:
return jsonify(type='danger', msg=str(e))
elif request.json['task'] == 'list':
try:
for container in docker_client.containers.list(filters={"id": container_id}):
mailq_return = container.exec_run(["/usr/sbin/postqueue", "-j"], user='postfix')
if mailq_return.exit_code == 0:
# We want plain text content from Postfix
r = Response(response=mailq_return.output, status=200, mimetype="text/plain")
r.headers["Content-Type"] = "text/plain; charset=utf-8"
return r
except Exception as e:
return jsonify(type='danger', msg=str(e))
elif request.json['task'] == 'flush':
try:
for container in docker_client.containers.list(filters={"id": container_id}):
postqueue_r = container.exec_run(["/usr/sbin/postqueue", "-f"], user='postfix')
if postqueue_r.exit_code == 0:
return jsonify(type='success', msg='command completed successfully')
else:
return jsonify(type='danger', msg=str(postqueue_r.output))
except Exception as e:
return jsonify(type='danger', msg=str(e))
elif request.json['task'] == 'super_delete':
try:
for container in docker_client.containers.list(filters={"id": container_id}):
postsuper_r = container.exec_run(["/usr/sbin/postsuper", "-d", "ALL"])
if postsuper_r.exit_code == 0:
return jsonify(type='success', msg='command completed successfully')
else:
return jsonify(type='danger', msg=str(postsuper_r.output))
except Exception as e:
return jsonify(type='danger', msg=str(e))
elif request.json['cmd'] == 'system':
if request.json['task'] == 'df':
if 'dir' in request.json:
try: try:
for container in docker_client.containers.list(filters={"id": container_id}): for container in docker_client.containers.list(filters={"id": container_id}):
# Should be changed to be able to validate a path # Should be changed to be able to validate a path
@ -83,52 +170,63 @@ class container_post(Resource):
return "0,0,0,0,0,0" return "0,0,0,0,0,0"
except Exception as e: except Exception as e:
return jsonify(type='danger', msg=str(e)) return jsonify(type='danger', msg=str(e))
elif request.json['cmd'] == 'sieve_list' and request.json['username']:
elif request.json['cmd'] == 'sieve':
if request.json['task'] == 'list':
if 'username' in request.json:
try: try:
for container in docker_client.containers.list(filters={"id": container_id}): for container in docker_client.containers.list(filters={"id": container_id}):
sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/local/bin/doveadm sieve list -u '" + request.json['username'].replace("'", "'\\''") + "'"]) sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/local/bin/doveadm sieve list -u '" + request.json['username'].replace("'", "'\\''") + "'"])
return sieve_return.output r = Response(response=sieve_return.output, status=200, mimetype="text/plain")
r.headers["Content-Type"] = "text/plain; charset=utf-8"
return r
except Exception as e: except Exception as e:
return jsonify(type='danger', msg=str(e)) return jsonify(type='danger', msg=str(e))
elif request.json['cmd'] == 'sieve_print' and request.json['script_name'] and request.json['username']: elif request.json['task'] == 'print':
if 'username' in request.json and 'script_name' in request.json:
try: try:
for container in docker_client.containers.list(filters={"id": container_id}): for container in docker_client.containers.list(filters={"id": container_id}):
sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/local/bin/doveadm sieve get -u '" + request.json['username'].replace("'", "'\\''") + "' '" + request.json['script_name'].replace("'", "'\\''") + "'"]) sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/local/bin/doveadm sieve get -u '" + request.json['username'].replace("'", "'\\''") + "' '" + request.json['script_name'].replace("'", "'\\''") + "'"])
return sieve_return.output r = Response(response=sieve_return.output, status=200, mimetype="text/plain")
r.headers["Content-Type"] = "text/plain; charset=utf-8"
return r
except Exception as e: except Exception as e:
return jsonify(type='danger', msg=str(e)) return jsonify(type='danger', msg=str(e))
# not in use...
elif request.json['cmd'] == 'mail_crypt_generate' and request.json['username'] and request.json['old_password'] and request.json['new_password']: # elif request.json['cmd'] == 'mail_crypt_generate' and request.json['username'] and request.json['old_password'] and request.json['new_password']:
try: # try:
for container in docker_client.containers.list(filters={"id": container_id}): # for container in docker_client.containers.list(filters={"id": container_id}):
# create if missing # # create if missing
crypto_generate = container.exec_run(["/bin/bash", "-c", "/usr/local/bin/doveadm mailbox cryptokey generate -u '" + request.json['username'].replace("'", "'\\''") + "' -URf"], user='vmail') # crypto_generate = container.exec_run(["/bin/bash", "-c", "/usr/local/bin/doveadm mailbox cryptokey generate -u '" + request.json['username'].replace("'", "'\\''") + "' -URf"], user='vmail')
if crypto_generate.exit_code == 0: # if crypto_generate.exit_code == 0:
# open a shell, bind stdin and return socket # # open a shell, bind stdin and return socket
cryptokey_shell = container.exec_run(["/bin/bash"], stdin=True, socket=True, user='vmail') # cryptokey_shell = container.exec_run(["/bin/bash"], stdin=True, socket=True, user='vmail')
# command to be piped to shell # # command to be piped to shell
cryptokey_cmd = "/usr/local/bin/doveadm mailbox cryptokey password -u '" + request.json['username'].replace("'", "'\\''") + "' -n '" + request.json['new_password'].replace("'", "'\\''") + "' -o '" + request.json['old_password'].replace("'", "'\\''") + "'\n" # cryptokey_cmd = "/usr/local/bin/doveadm mailbox cryptokey password -u '" + request.json['username'].replace("'", "'\\''") + "' -n '" + request.json['new_password'].replace("'", "'\\''") + "' -o '" + request.json['old_password'].replace("'", "'\\''") + "'\n"
# socket is .output # # socket is .output
cryptokey_socket = cryptokey_shell.output; # cryptokey_socket = cryptokey_shell.output;
try : # try :
# send command utf-8 encoded # # send command utf-8 encoded
cryptokey_socket.sendall(cryptokey_cmd.encode('utf-8')) # cryptokey_socket.sendall(cryptokey_cmd.encode('utf-8'))
# we won't send more data than this # # we won't send more data than this
cryptokey_socket.shutdown(socket.SHUT_WR) # cryptokey_socket.shutdown(socket.SHUT_WR)
except socket.error: # except socket.error:
# exit on socket error # # exit on socket error
return jsonify(type='danger', msg=str('socket error')) # return jsonify(type='danger', msg=str('socket error'))
# read response # # read response
cryptokey_response = recv_socket_data(cryptokey_socket) # cryptokey_response = recv_socket_data(cryptokey_socket)
crypto_error = re.search('dcrypt_key_load_private.+failed.+error', cryptokey_response) # crypto_error = re.search('dcrypt_key_load_private.+failed.+error', cryptokey_response)
if crypto_error is not None: # if crypto_error is not None:
return jsonify(type='danger', msg=str("dcrypt_key_load_private error")) # return jsonify(type='danger', msg=str("dcrypt_key_load_private error"))
return jsonify(type='success', msg=str("key pair generated")) # return jsonify(type='success', msg=str("key pair generated"))
else: # else:
return jsonify(type='danger', msg=str(crypto_generate.output)) # return jsonify(type='danger', msg=str(crypto_generate.output))
except Exception as e: # except Exception as e:
return jsonify(type='danger', msg=str(e)) # return jsonify(type='danger', msg=str(e))
elif request.json['cmd'] == 'maildir_cleanup' and request.json['maildir']:
elif request.json['cmd'] == 'maildir':
if request.json['task'] == 'cleanup':
if 'maildir' in request.json:
try: try:
for container in docker_client.containers.list(filters={"id": container_id}): for container in docker_client.containers.list(filters={"id": container_id}):
sane_name = re.sub(r'\W+', '', request.json['maildir']) sane_name = re.sub(r'\W+', '', request.json['maildir'])
@ -139,7 +237,10 @@ class container_post(Resource):
return jsonify(type='danger', msg=str(maildir_cleanup.output)) return jsonify(type='danger', msg=str(maildir_cleanup.output))
except Exception as e: except Exception as e:
return jsonify(type='danger', msg=str(e)) return jsonify(type='danger', msg=str(e))
elif request.json['cmd'] == 'worker_password' and request.json['raw']:
elif request.json['cmd'] == 'rspamd':
if request.json['task'] == 'worker_password':
if 'raw' in request.json:
try: try:
for container in docker_client.containers.list(filters={"id": container_id}): for container in docker_client.containers.list(filters={"id": container_id}):
worker_shell = container.exec_run(["/bin/bash"], stdin=True, socket=True, user='_rspamd') worker_shell = container.exec_run(["/bin/bash"], stdin=True, socket=True, user='_rspamd')
@ -167,16 +268,18 @@ class container_post(Resource):
return jsonify(type='danger', msg='command did not complete') return jsonify(type='danger', msg='command did not complete')
except Exception as e: except Exception as e:
return jsonify(type='danger', msg=str(e)) return jsonify(type='danger', msg=str(e))
elif request.json['cmd'] == 'mailman_password' and request.json['email'] and request.json['passwd']: # elif request.json['cmd'] == 'mailman':
try: # if request.json['task'] == 'password':
for container in docker_client.containers.list(filters={"id": container_id}): # if request.json['email'] and request.json['passwd']:
add_su = container.exec_run(["/bin/bash", "-c", "/opt/mm_web/add_su.py '" + request.json['passwd'].replace("'", "'\\''") + "' '" + request.json['email'].replace("'", "'\\''") + "'"], user='mailman') # try:
if add_su.exit_code == 0: # for container in docker_client.containers.list(filters={"id": container_id}):
return jsonify(type='success', msg='command completed successfully') # add_su = container.exec_run(["/bin/bash", "-c", "/opt/mm_web/add_su.py '" + request.json['passwd'].replace("'", "'\\''") + "' '" + request.json['email'].replace("'", "'\\''") + "'"], user='mailman')
else: # if add_su.exit_code == 0:
return jsonify(type='danger', msg='command did not complete, exit code was ' + int(add_su.exit_code)) # return jsonify(type='success', msg='command completed successfully')
except Exception as e: # else:
return jsonify(type='danger', msg=str(e)) # return jsonify(type='danger', msg='command did not complete, exit code was ' + int(add_su.exit_code))
# except Exception as e:
# return jsonify(type='danger', msg=str(e))
else: else:
return jsonify(type='danger', msg='Unknown command') return jsonify(type='danger', msg='Unknown command')