malias/malias.py
2023-04-12 11:57:35 +02:00

288 lines
8.3 KiB
Python

#!/usr/bin/python3
import sqlite3
from pathlib import Path
from sqlite3 import Error
import urllib.request
import json
import logging
import argparse
import requests
import os
import time
import sys
from types import SimpleNamespace
from datetime import datetime
from string import ascii_letters, digits
from rich import print
from argparse import RawTextHelpFormatter
#from urllib import Request, urlopen
from urllib.request import urlopen
# Info pages for dev
# https://mailcow.docs.apiary.io/#reference/aliases/get-aliases/get-aliases
# https://demo.mailcow.email/api/#/Aliases
homefilepath = Path.home()
filepath = homefilepath.joinpath('.config/malias')
database = filepath.joinpath('malias.db')
logfile = filepath.joinpath('malias.log')
Path(filepath).mkdir(parents=True, exist_ok=True)
logging.basicConfig(filename=logfile,level=logging.INFO,format='%(message)s')
app_version = '0.1'
def connect_database():
Path(filepath).mkdir(parents=True, exist_ok=True)
conn = None
try:
conn = sqlite3.connect(database)
except Error as e:
logging.error(time.strftime("%Y-%m-%d %H:%M") + ' - Error : ' + str(e))
print(e)
finally:
if conn:
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS apikey
(id integer NOT NULL PRIMARY KEY,
api text NOT NULL)''')
c.execute('''CREATE TABLE IF NOT EXISTS settings (
id INTEGER NOT NULL PRIMARY KEY,
first_run INTEGER DEFAULT 0,
server TEXT DEFAULT "TEST"
)''')
c.execute('''CREATE TABLE IF NOT EXISTS aliases
(id integer NOT NULL PRIMARY KEY,
alias text NOT NULL,
goto text NOT NULL,
created text NOT NULL)''')
conn.commit()
first_run(conn)
return conn
def first_run(conn):
now = datetime.now().strftime("%m-%d-%Y %H:%M")
cursor = conn.cursor()
cursor.execute('SELECT count(*) FROM settings')
count = cursor.fetchone()[0]
if count == 0:
logging.error(now + ' - First run!')
cursor.execute('INSERT INTO settings values(?,?,?)', (1, 1, 'dummy.server'))
cursor.execute('INSERT INTO apikey values(?,?)', (1, 'DUMMY_KEY'))
conn.commit()
return None
def get_settings(kind):
cursor = conn.cursor()
cursor.execute('SELECT * FROM settings')
data = cursor.fetchall()
first_run_status = data[0][1]
mail_server = data[0][2]
if kind == 'mail_server':
if mail_server == 'dummy.server':
print('Error: No MailCow server active. Please add one with [b]malias -m [i]your.server[/i][/b]')
exit(0)
else:
return mail_server
if kind == 'first_run_status':
return first_run_status
def get_api():
cursor = conn.cursor()
cursor.execute('SELECT api FROM apikey')
apikey = cursor.fetchone()[0]
if apikey == 'DUMMY_KEY':
print('Missing API key. Please add with [b]malias -k [i]YOUR-API-KEY[/i][/b]')
exit(0)
else:
return apikey
def set_mailserver(server):
now = datetime.now().strftime("%m-%d-%Y %H:%M")
cursor = conn.cursor()
cursor.execute('UPDATE settings SET server = ? WHERE id = 1',(server,))
logging.info(now + ' - Info : MailCow server updated')
print('Your mail server has been updated.')
conn.commit()
def apikey(key):
now = datetime.now().strftime("%m-%d-%Y %H:%M")
cursor = conn.cursor()
cursor.execute('UPDATE apikey SET api = ? WHERE id = 1',(key,))
logging.info(now + ' - Info : API key updated')
print('Your API key has been updated.')
conn.commit()
def create(alias,to_address):
now = datetime.now().strftime("%m-%d-%Y %H:%M")
server = get_settings('mail_server')
apikey = get_api()
if checklist(alias) == True:
logging.error(now + ' - Error : alias %s exists on the MailCow instance %s ' %(alias,server))
print('\n[b]Error[/b] : alias %s exists on the MailCow instance %s \n' %(alias,server))
exit(0)
else:
data = {'address': alias,'goto': to_address,'active': "1"}
headers = {'X-API-Key': apikey, "Content-Type": "application/json"}
response = requests.post('https://'+server+'/api/v1/add/alias',
data=json.dumps(data), headers=headers)
mail_id = alias_id(alias)
if mail_id == None:
logging.error(now + ' - Error : alias %s not created on the MailCow instance %s ' %(alias,server))
print('\n[b]Error[/b] : alias %s exists on the MailCow instance %s \n' %(alias,server))
else:
cursor = conn.cursor()
cursor.execute('INSERT INTO aliases values(?,?,?,?)', (mail_id, alias,to_address,now))
conn.commit()
def delete(alias):
print('Delete : ' + alias)
def checklist(alias):
apikey = get_api()
mail_server = get_settings('mail_server')
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all')
req.add_header('Content-Type', 'application/json')
req.add_header('X-API-Key', apikey)
current = urllib.request.urlopen(req)
remote = current.read().decode('utf-8')
remoteData = json.loads(remote)
i = 0
for search in remoteData:
if alias in remoteData[i]['address']:
return True
i=i+1
return None
def list_alias():
apikey = get_api()
mail_server = get_settings('mail_server')
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all')
req.add_header('Content-Type', 'application/json')
req.add_header('X-API-Key', apikey)
current = urllib.request.urlopen(req)
remote = current.read().decode('utf-8')
remoteData = json.loads(remote)
i = 0
for search in remoteData:
print(remoteData[i]['address'])
i=i+1
def alias_id(alias):
apikey = get_api()
mail_server = get_settings('mail_server')
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all')
req.add_header('Content-Type', 'application/json')
req.add_header('X-API-Key', apikey)
current = urllib.request.urlopen(req)
remote = current.read().decode('utf-8')
remoteData = json.loads(remote)
i = 0
for search in remoteData:
if remoteData[i]['address'] == alias:
return remoteData[i]['id']
i=i+1
return None
def number_of_aliases_in_db():
cursor = conn.cursor()
cursor.execute('SELECT count(*) FROM aliases')
count = cursor.fetchone()[0]
return count
def search(alias):
results = checklist(alias)
mail_server = get_settings('mail_server')
if results == True:
print('\n\nThe mail address %s exists. Using the MailCow instance : %s\n\n'%(alias,mail_server))
else:
print('\n\nThe mail address %s [b]does not[/b] exists. Using the MailCow instance : %s\n\n'%(alias,mail_server))
def show_current_info():
API = get_api()
mail_server = get_settings('mail_server')
if API == 'DUMMY_KEY':
API = 'Missing API Key!'
if mail_server == 'dummy.server':
mail_server = 'Missing address to MailCow instance!'
aliases_server = number_of_aliases_on_server()
alias_db = number_of_aliases_in_db()
print('\n[b]malias[/b] - Manage aliases on MailCow Instance.')
print('===================================================')
print('API key : [b]%s[/b]' % (API))
print('MailCow Instance : [b]%s[/b]' % (mail_server))
print('Logfile : [b]%s[/b]' % (logfile))
print('Aliases on server : [b]%s[/b]' % (aliases_server))
print('Aliases in DB : [b]%s[/b]' % (alias_db))
print('')
print('App version : [b]%s[/b] (https://gitlab.pm/rune/malias)' % (app_version))
print('')
conn = connect_database()
parser = argparse.ArgumentParser(prog='malias',
description='Application description',
formatter_class=RawTextHelpFormatter,
epilog='Making MailCow easier...')
parser.add_argument('-k', '--api', help='Add/Change API key.\n\n',
nargs=1, metavar=('APIkey'), required=False, action="append")
parser.add_argument('-s', '--search', help='Search for alias.\n\n',
nargs=1, metavar=('alias@domain.com'), required=False, action="append")
parser.add_argument('-m', '--server', help='Add/Uppdate MailCow instance.\n\n',
nargs=1, metavar=('alias@domain.com'), required=False, action="append")
parser.add_argument('-a', '--add', help='Add new alias.\n\n',
nargs=2, metavar=('alias@domain.com', 'to@domain.com'), required=False, action="append")
parser.add_argument('-v', '--version', help='Show current version and config info\n\n',
required=False, action='store_true')
args = vars(parser.parse_args())
if args['api']:
apikey(args['api'][0][0])
elif args['search']:
search(args['search'][0][0])
elif args['server']:
set_mailserver(args['server'][0][0])
elif args['add']:
create(args['add'][0][0],args['add'][0][1])
elif args['version']:
show_current_info()
else:
# get_settings(first_run_status)
get_api()
list_alias()
print('\n\nError use [b]malias -h[/b] to see the help screen!\n\n\n')