A self-service web application for Mail-in-a-box (https://mailinabox.email/).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

342 lines
14 KiB

# imports
import requests
from configparser import ConfigParser
from bottle import route, run, template, error, get, \
post, request, response, redirect, \
static_file
# config
configfile = "app.conf"
config = ConfigParser()
config.read(configfile)
if config['DEFAULT']['miab_admin']:
miab_admin = config['DEFAULT']['miab_admin']
else:
miab_admin = "norealadmin@domain.ltd"
if config['DEFAULT']['miab_passwd']:
miab_passwd = config['DEFAULT']['miab_passwd']
else:
miab_passwd = "norealpassword"
if config['DEFAULT']['miab_url']:
miab_url = config['DEFAULT']['miab_url']
else:
miab_url = "https://norealmiab.domain.tld"
if config['DEFAULT']['app_name']:
app_name = config['DEFAULT']['app_name']
else:
app_name = "Accounts"
if config['DEFAULT']['static_files']:
static_files = config['DEFAULT']['static_files']
else:
static_files = "static"
if config['DEFAULT']['cookie_secret']:
cookie_secret = config['DEFAULT']['cookie_secret']
else:
cookie_secret = "norealsecretDTR46SNI2390LGFsnDTRLASED2309h"
if config['DEFAULT']['cookie_max_age']:
cookie_max_age = int(config['DEFAULT']['cookie_max_age'])
else:
cookie_max_age=1800
if config['DEFAULT']['cookie_name']:
cookie_name = config['DEFAULT']['cookie_name']
else:
cookie_name = "accounts"
if config['DEFAULT']['max_aliases']:
max_aliases = int(config['DEFAULT']['max_aliases'])
else:
max_aliases=5
# functions
# verify session
# if valid we return the username
def logged_in():
#read remote cookie
username = request.get_cookie(cookie_name, secret=cookie_secret)
if username:
return username
else:
return False
# do actual authentication against miab
def miab_auth(username, password):
#authenticate against miab api
a = requests.get(miab_url + "/mail/users", auth=(username, password))
# if valid set cookie and return True
if a.text == 'You are not an administrator.\n' or a.status_code == 200:
response.set_cookie(cookie_name, username, secret=cookie_secret, max_age=cookie_max_age)
return True
else:
#or False
return False
# get all aliases for a username
def get_aliases(username):
a = requests.get(miab_url + "/mail/aliases?format=json", auth=(miab_admin, miab_passwd))
data = a.json()
return [alias['address'] for user in data[1:] for alias in user['aliases'] if alias['forwards_to'] and alias['forwards_to'][0] == username]
# get all addresses available on miab
def get_addresses():
# get alias data
a = requests.get(miab_url + "/mail/aliases?format=json", auth=(miab_admin, miab_passwd))
aliases = a.json()
# get user data
u = requests.get(miab_url + "/mail/users?format=json", auth=(miab_admin, miab_passwd))
users = u.json()
# generate list of all addresses on the box
addresses = [alias['address'] for user in aliases for alias in user['aliases']]
addresses.extend([ user['email'] for domains in users for user in domains['users']])
return addresses
# get all valid domains from miab
def get_domains():
u = requests.get(miab_url + "/mail/users?format=json", auth=(miab_admin, miab_passwd))
users = u.json()
return [ user['domain'] for user in users ]
# get forwarding alias for user
def get_forwards(username):
a = requests.get(miab_url + "/mail/aliases?format=json", auth=(miab_admin, miab_passwd))
aliases = a.json()
return [ alias['forwards_to'][0] for domains in aliases for alias in domains['aliases'] if alias['address'] == username ]
# routing
# render main page
@get('/')
def home():
username = logged_in()
message = request.get_cookie(cookie_name + "_message", secret=cookie_secret)
if username:
aliases = get_aliases(username)
forward = get_forwards(username)
# render homepage
return template('default', username=username, app_name=app_name, message=message, aliases=aliases, max_aliases=max_aliases, forward=forward)
else:
# render login
message = request.get_cookie(cookie_name + "_message", secret=cookie_secret)
return template('login', app_name=app_name, cookie_max_age=cookie_max_age, message=message)
# get login credentials
@post('/login')
def post_login():
username = request.forms.get('username')
password = request.forms.get('password')
if miab_auth(username, password):
message = { "message": "You have logged in successfully", "alert": "success" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5)
redirect('/')
else:
message = { "message": "Email address or password wrong", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5)
redirect('/')
# delete cookie
@get('/logout')
@get('/logout/')
def logout():
if logged_in():
response.delete_cookie(cookie_name)
message = { "message": "You have logged out successfully", "alert": "success" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5)
redirect('/')
else:
redirect('/')
# serve static files
@get('/static/<filename:path>')
def send_static(filename):
return static_file(filename, root=static_files)
# change account password
@post('/password')
def post_password():
username = logged_in()
if username:
oldpassword = request.forms.get('oldpassword')
newpassword = request.forms.get('newpassword')
if miab_auth(username, oldpassword):
data = { "email": username, }
r = requests.post(miab_url + "/mail/users/remove", data=data, auth=(miab_admin, miab_passwd))
data = { "email": username, "password": newpassword }
a = requests.post(miab_url + "/mail/users/add", data=data, auth=(miab_admin, miab_passwd))
if r.status_code == 200 and a.status_code == 200:
message = { "message": "Your password has been changed successfully", "alert": "success" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5)
redirect('/')
else:
message = { "message": "Something went wrong while changing your password", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5)
redirect('/')
else:
message = { "message": "Your supplied password is wrong", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5)
redirect('/')
else:
redirect('/')
# create an email alias
@post('/alias/add')
def add_alias():
username = logged_in()
if username:
add = request.forms.get('add')
aliases = get_aliases(username)
#it must be below max_aliases
if len(aliases) < max_aliases:
#it must be in domains
domains = get_domains()
addresses = get_addresses()
for domain in domains:
if domain == add[(add.find("@")+1):]:
#it must not be in addresses
for address in addresses:
if address == add:
#match found. break
message = { "message": str(add) + " does already exist", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
#create the alias
data = { "address": add, "forwards_to": username }
r = requests.post(miab_url + "/mail/aliases/add", data=data, auth=(miab_admin, miab_passwd))
if r.status_code == 200:
message = { "message": str(add) + " has been created successfully", "alert": "success" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
message = { "message": "Something went wrong while creating " + str(add), "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
message = { "message": str(add[(add.find("@")+1):]) + " is not a valid domain", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
message = { "message": "You have reached the alias limit", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
redirect("/")
# delete an email alias
@post('/alias/delete')
def delete_alias():
username = logged_in()
if username:
delete = request.forms.get('delete')
aliases = get_aliases(username)
for alias in aliases:
if alias == delete:
#remove the alias
data = { "address": delete, }
r = requests.post(miab_url + "/mail/aliases/remove", data=data, auth=(miab_admin, miab_passwd))
if r.status_code == 200:
message = { "message": "The alias " + str(delete) + " has been removed successfully", "alert": "success" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
message = { "message": "Something went wrong while removing an alias", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
message = { "message": "You're trying to do something filthy", "alert": "danger"}
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
redirect('/')
# configure email forwarding
@post('/forward/add')
def add_forward():
username = logged_in()
forward = request.forms.get('forward')
if username:
if get_forwards(username):
message = { "message": "Email forwarding is already configured", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
data = { "address": username, "forwards_to": forward }
c = requests.post(miab_url + "/mail/aliases/add", data=data, auth=(miab_admin, miab_passwd))
if c.status_code == 200:
message = { "message": "Email forwarding to " + str(forward) + " has been configured successfully", "alert": "success" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
message = { "message": "Something went wrong while configuring email forwarding", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
redirect('/')
# deconfigure email forwarding
@post('/forward/delete')
def delete_forward():
username = logged_in()
forward = request.forms.get('forward')
if username:
if forward == get_forwards(username)[0]:
data = { "address": username, }
d = requests.post(miab_url + "/mail/aliases/remove", data=data, auth=(miab_admin, miab_passwd))
if d.status_code == 200:
message = { "message": "Email forwarding has been deconfigured successfully", "alert": "success" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
message = { "message": "Something went wrong while deconfiguring email forwarding", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
message = { "message": "Your delete request does not match the configured forwarding", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
redirect('/')
@post('/delete')
def delete_account():
username = logged_in()
password = request.forms.get('password')
if username:
if miab_auth(username, password):
data = { "email": username, }
d = requests.post(miab_url + "/mail/users/remove", data=data, auth=(miab_admin, miab_passwd))
if d.status_code == 200:
message = { "message": "Your account has been deleted successfully", "alert": "success" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
response.delete_cookie(cookie_name)
redirect('/')
else:
message = { "message": "Something went wrong deleting your account", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
message = { "message": "Your supplied password is wrong", "alert": "danger" }
response.set_cookie(cookie_name + "_message", message, secret=cookie_secret, max_age=5, path="/")
redirect('/')
else:
redirect('/')
# run development webserver
#run(host='localhost', port=8000, debug=True, reloader=True)
# run prod server
run(host='0.0.0.0', port=8000, debug=True)