11 Commits
0.2.1 ... 0.3.1

Author SHA1 Message Date
e8d45fc477 Code cleanup, changed version check and updated search function 2023-10-03 10:15:50 +02:00
8000779fe8 Added app version checks. 2023-09-06 12:29:32 +02:00
8814127cf8 Added some functionality 2023-09-05 11:36:39 +02:00
f653a20d35 Added function updating local DB from aliases on Mailcow instance 2023-09-04 15:12:57 +02:00
7f12bd3743 Added function for listing mail domains 2023-09-01 11:22:54 +02:00
8a6eceb9a5 Added some small fixes and some pepper 2023-08-20 15:53:43 +02:00
2bd8ddeb04 Update README.md 2023-08-13 18:32:35 +02:00
f3ba4f7d67 Update README.md 2023-08-13 18:31:49 +02:00
37d670b54e Added screenshot 2023-08-13 18:30:16 +02:00
12215074d6 Changes in list function 2023-04-19 08:49:22 +02:00
15e8f8ac90 Changes in list function 2023-04-19 08:04:44 +02:00
4 changed files with 170 additions and 24 deletions

View File

@@ -4,7 +4,7 @@ _malias_ is a helper for mailcow instances. You can create, delete, search and l
## Installation ## Installation
Download the latest relase from https://gitlab.pm/rune/malias/releases. Unzip and move to a folder in you path (ease of use). You can also rename the file ```malias.py``` to just ```malias``` and make the file executable with ```chmod +x malias```. To install required python modules run ```pip3 install -r requirements.txt``` Download the latest release from https://gitlab.pm/rune/malias/releases. Unzip and move to a folder in you path (ease of use). I also recommend rename the file ```malias.py``` to just ```malias``` and make the file executable with ```chmod +x malias```. To install required python modules run ```pip3 install -r requirements.txt```
## Usage ## Usage
@@ -14,6 +14,10 @@ For instructions run
malias -h malias -h
``` ```
## Screenshot
![Screenshot of malias](https://gitlab.pm/rune/malias/raw/branch/main/malias.png)
## Contributing ## Contributing
Pull requests are welcome. For major changes, please open an issue first Pull requests are welcome. For major changes, please open an issue first

BIN
malias.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 KiB

183
malias.py Normal file → Executable file
View File

@@ -10,12 +10,12 @@ import requests
import os import os
import time import time
import sys import sys
import git
from types import SimpleNamespace from types import SimpleNamespace
from datetime import datetime from datetime import datetime
from string import ascii_letters, digits from string import ascii_letters, digits
from rich import print from rich import print
from argparse import RawTextHelpFormatter from argparse import RawTextHelpFormatter
#from urllib import Request, urlopen
from urllib.request import urlopen from urllib.request import urlopen
# Info pages for dev # Info pages for dev
@@ -29,9 +29,26 @@ database = filepath.joinpath('malias.db')
logfile = filepath.joinpath('malias.log') logfile = filepath.joinpath('malias.log')
Path(filepath).mkdir(parents=True, exist_ok=True) Path(filepath).mkdir(parents=True, exist_ok=True)
logging.basicConfig(filename=logfile,level=logging.INFO,format='%(message)s') logging.basicConfig(filename=logfile,level=logging.INFO,format='%(message)s')
app_version = '0.2.1' app_version = '0.3.1'
def get_latest_release():
req = urllib.request.Request('https://gitlab.pm/api/v1/repos/rune/malias/releases/latest')
req.add_header('Content-Type', 'application/json')
current = urllib.request.urlopen(req)
remote = current.read().decode('utf-8')
remoteData = json.loads(remote)
return remoteData['tag_name']
def release_check():
latest_release = get_latest_release()
if app_version != latest_release:
print('[b]New version available @ [i]https://iurl.no/malias[/b][/i]')
else:
print ('You have the the latest version. Version: %s' %(app_version))
def connect_database(): def connect_database():
Path(filepath).mkdir(parents=True, exist_ok=True) Path(filepath).mkdir(parents=True, exist_ok=True)
conn = None conn = None
@@ -99,6 +116,7 @@ def get_settings(kind):
def get_api(): def get_api():
latest_release = get_latest_release()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute('SELECT api FROM apikey') cursor.execute('SELECT api FROM apikey')
apikey = cursor.fetchone()[0] apikey = cursor.fetchone()[0]
@@ -117,7 +135,6 @@ def set_mailserver(server):
print('Your mail server has been updated.') print('Your mail server has been updated.')
conn.commit() conn.commit()
def apikey(key): def apikey(key):
now = datetime.now().strftime("%m-%d-%Y %H:%M") now = datetime.now().strftime("%m-%d-%Y %H:%M")
@@ -126,7 +143,34 @@ def apikey(key):
logging.info(now + ' - Info : API key updated') logging.info(now + ' - Info : API key updated')
print('Your API key has been updated.') print('Your API key has been updated.')
conn.commit() conn.commit()
def get_mail_domains(info):
apikey = get_api()
cursor = conn.cursor()
mail_server = get_settings('mail_server')
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/domain/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)
if info:
total_aliases = 0
i=0
print('\n[b]malias[/b] - All email domains on %s' %(mail_server))
print('==================================================================')
for domains in remoteData:
cursor.execute('SELECT count(*) FROM aliases where alias like ? or goto like ?', ('%'+remoteData[i]['domain_name']+'%','%'+remoteData[i]['domain_name']+'%',))
count = cursor.fetchone()[0]
total_aliases += count
print('%s \t\twith %s aliases' %(remoteData[i]['domain_name'],count))
i+=1
print('\n\nThere is a total of %s domains with %s aliases.' %(str(i),str(total_aliases)))
else:
return(remoteData)
def create(alias,to_address): def create(alias,to_address):
now = datetime.now().strftime("%m-%d-%Y %H:%M") now = datetime.now().strftime("%m-%d-%Y %H:%M")
@@ -151,7 +195,7 @@ def create(alias,to_address):
conn.commit() conn.commit()
logging.info(now + ' - Info : alias %s created for %s on the mailcow instance %s ' %(alias,to_address,server)) logging.info(now + ' - Info : alias %s created for %s on the mailcow instance %s ' %(alias,to_address,server))
print('\n[b]Info[/b] : alias %s created for %s on the mailcow instance %s \n' %(alias,to_address,server)) print('\n[b]Info[/b] : alias %s created for %s on the mailcow instance %s \n' %(alias,to_address,server))
def delete_alias(alias): def delete_alias(alias):
@@ -184,6 +228,7 @@ def delete_alias(alias):
def copy_data(): def copy_data():
apikey = get_api() apikey = get_api()
mail_server = get_settings('mail_server') mail_server = get_settings('mail_server')
@@ -206,8 +251,41 @@ def copy_data():
logging.info(now + ' - Info : aliases imported from the mailcow instance %s to local DB' %(mail_server)) logging.info(now + ' - Info : aliases imported from the mailcow instance %s to local DB' %(mail_server))
print('\n[b]Info[/b] : aliases imported from the mailcow instance %s to local DB\n' %(mail_server)) print('\n[b]Info[/b] : aliases imported from the mailcow instance %s to local DB\n' %(mail_server))
else: else:
print('\n[b]Info[/b] : aliases alreday imported from the mailcow instance %s to local DB\n' %(mail_server)) print('\n[b]Info[/b] : aliases alreday imported from the mailcow instance %s to local DB\n\n[i]Updating with any missing aliases![/i]' %(mail_server))
update_data()
def update_data():
apikey = get_api()
mail_server = get_settings('mail_server')
if get_settings('copy_status') == 1:
now = datetime.now().strftime("%m-%d-%Y %H:%M")
cursor = conn.cursor()
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
count_alias = 0
cursor = conn.cursor()
for data in remoteData:
cursor.execute('SELECT count(*) FROM aliases where alias like ? and goto like ?', (remoteData[i]['address'],remoteData[i]['goto'],))
count = cursor.fetchone()[0]
if count >= 1 :
i+=1
else:
cursor.execute('INSERT INTO aliases values(?,?,?,?)', (remoteData[i]['id'], remoteData[i]['address'],remoteData[i]['goto'],now))
count_alias+=1
i+=1
conn.commit()
if count_alias > 0:
logging.info(now + ' - Info : Local DB updated with %s new aliases from %s ' %(str(count_alias),mail_server))
print('\n[b]Info[/b] : Local DB update with %s new aliases from %s \n' %(str(count_alias),mail_server))
else:
print('\n[b]Info[/b] : No missing aliases from local DB \n')
def checklist(alias): def checklist(alias):
alias_exist = None alias_exist = None
@@ -235,6 +313,7 @@ def checklist(alias):
def list_alias(): def list_alias():
apikey = get_api() apikey = get_api()
cursor = conn.cursor()
mail_server = get_settings('mail_server') mail_server = get_settings('mail_server')
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all') req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all')
req.add_header('Content-Type', 'application/json') req.add_header('Content-Type', 'application/json')
@@ -243,13 +322,21 @@ def list_alias():
remote = current.read().decode('utf-8') remote = current.read().decode('utf-8')
remoteData = json.loads(remote) remoteData = json.loads(remote)
i = 0 i = 0
print('\n[b]malias[/b] - All aliases on %s' %(mail_server)) l = 0
print('===================================================') print('\n[b]malias[/b] - All aliases on %s ([b]*[/b] also in local db)' %(mail_server))
print('==================================================================')
for search in remoteData: for search in remoteData:
the_alias = remoteData[i]['address'].ljust(20,' ') the_alias = remoteData[i]['address'].ljust(20,' ')
print(the_alias + '\tgoes to\t\t' + remoteData[i]['goto']) the_goto = remoteData[i]['goto'].ljust(20,' ')
cursor.execute('SELECT count(*) FROM aliases where alias like ? or goto like ?', (remoteData[i]['address'],remoteData[i]['address'],))
count = cursor.fetchone()[0]
if count >= 1:
print(the_alias + '\tgoes to\t\t' + the_goto + '\t[b]*[/b]')
l=l+1
else:
print(the_alias + '\tgoes to\t\t' + the_goto)
i=i+1 i=i+1
print('\n\nTotal number of aliases %s on instance [b]%s[/b] and %s on [b]local DB[/b].' %(str(i),mail_server,str(l)))
def alias_id(alias): def alias_id(alias):
@@ -297,10 +384,11 @@ def check_local_db(alias_id):
def search(alias): def search(alias):
apikey = get_api() apikey = get_api()
mail_server = get_settings('mail_server') mail_server = get_settings('mail_server')
alias_server = number_of_aliases_on_server()
alias_db = number_of_aliases_in_db()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute('SELECT data_copy FROM settings where id = 1') cursor.execute('SELECT data_copy FROM settings where id = 1')
result = cursor.fetchone()[0] result = cursor.fetchone()[0]
@@ -309,13 +397,14 @@ def search(alias):
cursor.execute('SELECT * from aliases where alias like ? or goto like ?',(search_term,search_term,)) cursor.execute('SELECT * from aliases where alias like ? or goto like ?',(search_term,search_term,))
remoteData = cursor.fetchall() remoteData = cursor.fetchall()
i = 0 i = 0
print('\nAliases on %s that contains %s' %(mail_server,alias)) print('\nAliases on %s that contains [b]%s[/b]' %(mail_server,alias))
print('=================================================================') print('=================================================================')
for search in remoteData: for search in remoteData:
the_alias = remoteData[i][1].ljust(20,' ') the_alias = remoteData[i][1].ljust(20,' ')
print(the_alias + '\tgoes to\t\t' + remoteData[i][2]) print(the_alias + '\tgoes to\t\t' + remoteData[i][2])
i=i+1 i=i+1
print('\n\nData from local DB') print('\n\nData from local DB')
else: else:
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all') req = urllib.request.Request('https://'+mail_server+'/api/v1/get/alias/all')
req.add_header('Content-Type', 'application/json') req.add_header('Content-Type', 'application/json')
@@ -324,20 +413,44 @@ def search(alias):
remote = current.read().decode('utf-8') remote = current.read().decode('utf-8')
remoteData = json.loads(remote) remoteData = json.loads(remote)
i = 0 i = 0
print('\nAliases on %s that contains %s' %(mail_server,alias)) print('\nAliases on %s that contains [b]%s[/b]' %(mail_server,alias))
print('=================================================') print('=================================================')
for search in remoteData: for search in remoteData:
if alias in remoteData[i]['address'] or alias in remoteData[i]['goto']: if alias in remoteData[i]['address'] or alias in remoteData[i]['goto']:
print(remoteData[i]['address'] + '\tgoes to\t\t' + remoteData[i]['goto']) print(remoteData[i]['address'] + '\tgoes to\t\t' + remoteData[i]['goto'])
i=i+1 i=i+1
print('\n\nData from server') print('\n\nData from server')
if alias_server != alias_db:
print('\n\nThere are %s aliases on the server and %s aliases in local DB' %(str(alias_server),str(alias_db)))
print('Run [i]malias -c[/i] to update local DB')
def get_mailcow_version():
apikey = get_api()
mail_server = get_settings('mail_server')
req = urllib.request.Request('https://'+mail_server+'/api/v1/get/status/version')
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)
remote_heads = git.cmd.Git().ls_remote('https://github.com/mailcow/mailcow-dockerized', tags=True)
tags = remote_heads.splitlines()
for x in tags:
string = x.rsplit('/',2)
if remoteData['version'] != string[2]:
versionInfo = 'Your Mailcow version is %s and the latest is %s' %(remoteData['version'], string[2])
else:
versionInfo = 'You have the latest Mailcow version %s' %remoteData['version']
return (versionInfo)
def show_current_info(): def show_current_info():
API = get_api() API = get_api()
mail_server = get_settings('mail_server') mail_server = get_settings('mail_server')
latest_release = get_latest_release()
if API == 'DUMMY_KEY': if API == 'DUMMY_KEY':
API = 'Missing API Key!' API = 'Missing API Key!'
@@ -346,16 +459,31 @@ def show_current_info():
aliases_server = number_of_aliases_on_server() aliases_server = number_of_aliases_on_server()
alias_db = number_of_aliases_in_db() alias_db = number_of_aliases_in_db()
mailcow_version = get_mailcow_version()
mail_domains = get_mail_domains(False)
domain = ""
i=0
for domains in mail_domains:
if i!=0:
domain = domain + ', ' + str(mail_domains[i]['domain_name'])
else:
domain = domain + str(mail_domains[i]['domain_name'])
i+=1
print('\n[b]malias[/b] - Manage aliases on mailcow Instance.') print('\n[b]malias[/b] - Manage aliases on mailcow Instance.')
print('===================================================') print('===================================================')
print('API key : [b]%s[/b]' % (API)) print('API key : [b]%s[/b]' % (API))
print('mailcow Instance : [b]%s[/b]' % (mail_server)) print('Mailcow Instance : [b]%s[/b]' % (mail_server))
print('Active domains : [b]%s[/b]' % (domain))
print('Mailcow version : [b]%s[/b]' % (mailcow_version))
print('Logfile : [b]%s[/b]' % (logfile)) print('Logfile : [b]%s[/b]' % (logfile))
print('Databse : [b]%s[b]' % (database))
print('Aliases on server : [b]%s[/b]' % (aliases_server)) print('Aliases on server : [b]%s[/b]' % (aliases_server))
print('Aliases in DB : [b]%s[/b]' % (alias_db)) print('Aliases in DB : [b]%s[/b]' % (alias_db))
print('') print('')
print('App version : [b]%s[/b] (https://gitlab.pm/rune/malias)' % (app_version)) if app_version != latest_release:
print('App version : [b]%s[/b] a new version (%s) is available @ https://iurl.no/malias' % (app_version,latest_release))
else:
print('App version : [b]%s[/b]' % (app_version))
print('') print('')
@@ -384,7 +512,10 @@ parser.add_argument('-d', '--delete', help='Delete alias.\n\n',
nargs=1, metavar=('alias@domain.com'), required=False, action="append") nargs=1, metavar=('alias@domain.com'), required=False, action="append")
parser.add_argument('-v', '--version', help='Show current version and config info\n\n', parser.add_argument('-i', '--info', help='Show current config and appliacation info\n\n',
required=False, action='store_true')
parser.add_argument('-v', '--version', help='Show current version\n\n',
required=False, action='store_true') required=False, action='store_true')
parser.add_argument('-c', '--copy', help='Copy alias data from mailcow server to local DB.\n\n', parser.add_argument('-c', '--copy', help='Copy alias data from mailcow server to local DB.\n\n',
@@ -393,6 +524,9 @@ parser.add_argument('-c', '--copy', help='Copy alias data from mailcow server to
parser.add_argument('-l', '--list', help='List all aliases on the Mailcow instance.\n\n', parser.add_argument('-l', '--list', help='List all aliases on the Mailcow instance.\n\n',
required=False, action='store_true') required=False, action='store_true')
parser.add_argument('-o', '--domains', help='List all mail domains on the Mailcow instance.\n\n',
required=False, action='store_true')
args = vars(parser.parse_args()) args = vars(parser.parse_args())
@@ -406,13 +540,18 @@ elif args['add']:
create(args['add'][0][0],args['add'][0][1]) create(args['add'][0][0],args['add'][0][1])
elif args['delete']: elif args['delete']:
delete_alias(args['delete'][0][0]) delete_alias(args['delete'][0][0])
elif args['version']: elif args['info']:
show_current_info() show_current_info()
elif args['version']:
release_check()
elif args['copy']: elif args['copy']:
copy_data() copy_data()
elif args['list']: elif args['list']:
list_alias() list_alias()
elif args['domains']:
get_mail_domains(True)
else: else:
# get_api()
print('\n\nEh, sorry! I need something more to help you! If you write [b]malias -h[/b] I\'ll show a help screen to get you going!!!\n\n\n') print('\n\nEh, sorry! I need something more to help you! If you write [b]malias -h[/b] I\'ll show a help screen to get you going!!!\n\n\n')

View File

@@ -11,7 +11,9 @@ click==8.1.3
docopt==0.6.2 docopt==0.6.2
docutils==0.19 docutils==0.19
frozenlist==1.3.3 frozenlist==1.3.3
gpg==1.19.0 gitdb==4.0.10
GitPython==3.1.32
gpg==1.21.0
idna==3.4 idna==3.4
importlib-metadata==6.1.0 importlib-metadata==6.1.0
jaraco.classes==3.2.3 jaraco.classes==3.2.3
@@ -36,6 +38,7 @@ requests-toolbelt==0.10.1
rfc3986==2.0.0 rfc3986==2.0.0
rich==13.3.1 rich==13.3.1
six==1.16.0 six==1.16.0
smmap==5.0.0
tqdm==4.65.0 tqdm==4.65.0
twine==4.0.2 twine==4.0.2
urllib3==1.26.14 urllib3==1.26.14