This commit is contained in:
Adrian Amaglio 2020-05-01 15:38:00 +02:00
parent be9839936f
commit 2610c48a79

146
main.py
View File

@ -32,66 +32,48 @@ class StripPathMiddleware(object):
return self.a(e, h) return self.a(e, h)
app = application = bottle.Bottle() app = application = bottle.Bottle(catchall=False)
##################################################### Configuration ############################################$ ##################################################### Configuration ############################################$
def get_env(var, default=None):
if var in os.environ:
return os.environ[var]
elif default is not None:
return default
else:
raise MissingParameterException("Environment variable {} is missing".format(var))
# Token generation
token_chars = string.ascii_lowercase+string.ascii_uppercase+string.digits
token_len = 50
# form template regex
form_regex = '\{\{(\w+)(\|\w+)?\}\}'
# Load file from .env file. # Load file from .env file.
load_dotenv(os.path.dirname(__file__) + '.env') load_dotenv(os.path.dirname(__file__) + '.env')
token_chars = string.ascii_lowercase+string.ascii_uppercase+string.digits
token_len = 50
# Get address and port from env # Get address and port from env
listen_address = os.environ['LISTEN_ADDRESS'] if 'LISTEN_ADDRESS' in os.environ else '0.0.0.0' listen_address = get_env('LISTEN_ADDRESS', '0.0.0.0')
listen_port = os.environ['LISTEN_PORT'] if 'LISTEN_PORT' in os.environ else 8080 listen_port = get_env('LISTEN_PORT', 8080)
# Get mail related informations from env
mail_default_subject = os.environ['MAIL_DEFAULT_SUBJECT'] if 'MAIL_DEFAULT_SUBJECT' in os.environ else 'Nouveau message'
mail_subject_prefix = os.environ['MAIL_SUBJECT_PREFIX'] if 'MAIL_SUBJECT_PREFIX' in os.environ else '[Contact]'
# Redirect info
success_redirect_default = os.environ['SUCCESS_REDIRECT_DEFAULT'] if 'SUCCESS_REDIRECT_DEFAULT' in os.environ else '/success'
failure_redirect_default = os.environ['FAILURE_REDIRECT_DEFAULT'] if 'FAILURE_REDIRECT_DEFAULT' in os.environ else '/fail'
# Get SMTP infos from env # Get SMTP infos from env
if 'SMTP_SERVER_ADDRESS' in os.environ: smtp_server_address = get_env('SMTP_SERVER_ADDRESS')
smtp_server_address = os.environ['SMTP_SERVER_ADDRESS'] smtp_server_port = get_env('SMTP_SERVER_PORT')
else: smtp_server_username = get_env('SMTP_SERVER_USERNAME')
raise MissingParameterException("Environment variable SMTP_SERVER_ADDRESS is missing") smtp_server_password = get_env('SMTP_SERVER_PASSWORD')
smtp_server_sender = get_env('SMTP_SERVER_SENDER')
if 'SMTP_SERVER_PORT' in os.environ:
smtp_server_port = os.environ['SMTP_SERVER_PORT']
else:
raise MissingParameterException("Environment variable SMTP_SERVER_PORT is missing")
if 'SMTP_SERVER_USERNAME' in os.environ:
smtp_server_username = os.environ['SMTP_SERVER_USERNAME']
else:
raise MissingParameterException("Environment variable SMTP_SERVER_USERNAME is missing")
if 'SMTP_SERVER_PASSWORD' in os.environ:
smtp_server_password = os.environ['SMTP_SERVER_PASSWORD']
else:
raise MissingParameterException("return Environment variable SMTP_SERVER_PASSWORD is missing")
if 'SMTP_SERVER_SENDER' in os.environ:
smtp_server_sender = os.environ['SMTP_SERVER_SENDER']
else:
raise MissingParameterException("Environment variable SMTP_SERVER_SENDER is missing")
# Get mongodb connection # Get mongodb connection
if 'MONGODB_HOST' in os.environ: mongodb_host = get_env('MONGODB_HOST')
mongodb_host = os.environ['MONGODB_HOST'] mongodb_port = get_env('MONGODB_PORT', '27017')
else: mongodb_dbname = get_env('MONGODB_DBNAME', 'contact_mailer')
raise MissingParameterException("Environment variable MONGODB_HOST is missing")
mongodb_port = os.environ['MONGODB_PORT'] if 'MONGODB_PORT' in os.environ else '27017'
mongodb_dbname = os.environ['MONGODB_DBNAME'] if 'MONGODB_DBNAME' in os.environ else 'contact_mailer'
# Security # Security
admin_password = get_env('ADMIN_PASSWORD')
if 'SMTP_SSL' in os.environ and os.environ['SMTP_SSL'] == 'true': if 'SMTP_SSL' in os.environ and os.environ['SMTP_SSL'] == 'true':
security = 'ssl' security = 'ssl'
elif 'SMTP_STARTTLS' in os.environ and os.onviron['SMTP_STARTTLS'] == 'true': elif 'SMTP_STARTTLS' in os.environ and os.onviron['SMTP_STARTTLS'] == 'true':
@ -99,25 +81,12 @@ elif 'SMTP_STARTTLS' in os.environ and os.onviron['SMTP_STARTTLS'] == 'true':
else: else:
raise MissingParameterException('No security env var (SMTP_SSL or SMTP_STARTTLS) have been defined. (Expected true or false)') raise MissingParameterException('No security env var (SMTP_SSL or SMTP_STARTTLS) have been defined. (Expected true or false)')
if 'ADMIN_PASSWORD' in os.environ:
admin_password = os.environ['ADMIN_PASSWORD']
else:
raise MissingParameterException("Environment variable ADMIN_PASSWORD is missing")
# mongodb initialization # mongodb initialization
mongodb_client = pymongo.MongoClient("mongodb://{}:{}/".format(mongodb_host, mongodb_port)) mongodb_client = pymongo.MongoClient("mongodb://{}:{}/".format(mongodb_host, mongodb_port), connect=False, serverSelectionTimeoutMS=10000, connectTimeoutMS=10000)
mongodb_database = mongodb_client[mongodb_dbname] mongodb_database = mongodb_client[mongodb_dbname]
# form template regex
form_regex = '\{\{(\w+)(\|\w+)?\}\}'
##################################################### main route: mail submission ############################################$
@app.post('/fail')
def fail ():
a = 2/0
print('lol, failed', file=sys.stderr)
return 'failed'
@app.post('/submit') @app.post('/submit')
def submission (): def submission ():
@ -140,6 +109,9 @@ def submission ():
except IndexError as e: except IndexError as e:
response.status = 400 response.status = 400
return 'Le formulaire est introuvable' return 'Le formulaire est introuvable'
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
try: try:
subject_fields = fill_fields(request, get_fields(form['subject'])) subject_fields = fill_fields(request, get_fields(form['subject']))
@ -151,9 +123,13 @@ def submission ():
subject = re.sub(form_regex, r'{\1}', form['subject']).format(**subject_fields) subject = re.sub(form_regex, r'{\1}', form['subject']).format(**subject_fields)
content = re.sub(form_regex, r'{\1}', form['content']).format(**content_fields) content = re.sub(form_regex, r'{\1}', form['content']).format(**content_fields)
try:
if not send_mail(from_address, form['mail'], subject, content): if not send_mail(from_address, form['mail'], subject, content):
response.status = 500 response.status = 500
return 'Le mail na pas pu être envoyé.' return 'Le mail na pas pu être envoyé.'
except SMTPDataError as e:
response.status = 500
return 'Le mail a été refusé.'
# Redirection # Redirection
#redirect(success_redirect_default) #redirect(success_redirect_default)
@ -220,6 +196,9 @@ def login(request):
return user return user
except IndexError as e: except IndexError as e:
pass pass
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
return {'_privilege': 1000} # anonymous return {'_privilege': 1000} # anonymous
@ -258,6 +237,7 @@ def create_form ():
# TODO limit the insertion rate # TODO limit the insertion rate
token = ''.join(random.sample(token_chars, token_len)) token = ''.join(random.sample(token_chars, token_len))
try:
inserted = mongodb_database['forms'].insert_one({ inserted = mongodb_database['forms'].insert_one({
'mail': mail, 'mail': mail,
'content': content, 'content': content,
@ -265,11 +245,15 @@ def create_form ():
'user_id': user['_id'], 'user_id': user['_id'],
'token': token, 'token': token,
}) })
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
return 'Créé : ' + token return 'Créé : ' + token
@app.post('/form/list') @app.post('/form/list')
def list_forms (): def list_forms ():
try:
user = login(request) user = login(request)
if user['_privilege'] == 0: if user['_privilege'] == 0:
filt = {} filt = {}
@ -278,7 +262,12 @@ def list_forms ():
else: else:
response.status = 400 response.status = 400
return 'Privilèges insufisants' return 'Privilèges insufisants'
return bottle.template("list.tpl", data=mongodb_database['forms'].find(filt)) data = mongodb_database['forms'].find(filt)
return bottle.template("list.tpl", data=data)
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
@app.delete('/form/<token>') @app.delete('/form/<token>')
@ -295,11 +284,18 @@ def delete_form(token):
except IndexError as e: except IndexError as e:
response.status = 400 response.status = 400
return 'Le token nest pas valide' return 'Le token nest pas valide'
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
if user['_privilege'] == 0 or (form['user_id'] == user['_id']): if user['_privilege'] == 0 or (form['user_id'] == user['_id']):
try:
mongodb_database['forms'].delete_one({ mongodb_database['forms'].delete_one({
'token': token, 'token': token,
}) })
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
return 'Supprimé ' + token return 'Supprimé ' + token
response.status = 400 response.status = 400
return 'Privilèges insufisants' return 'Privilèges insufisants'
@ -313,7 +309,13 @@ def list_users ():
if user['_privilege'] > 0: if user['_privilege'] > 0:
response.status = 400 response.status = 400
return 'Privilèges insufisants' return 'Privilèges insufisants'
return bottle.template("list.tpl", data=mongodb_database['users'].find()) try:
data = mongodb_database['users'].find()
return bottle.template("list.tpl", data=data)
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
@app.put('/user/<username>') @app.put('/user/<username>')
def create_user (username): def create_user (username):
@ -325,11 +327,18 @@ def create_user (username):
mongodb_database['users'].find({'username': username})[0] mongodb_database['users'].find({'username': username})[0]
return 'Lutilisateur existe déjà' return 'Lutilisateur existe déjà'
except IndexError as e: except IndexError as e:
try:
inserted = mongodb_database['users'].insert_one({ inserted = mongodb_database['users'].insert_one({
'username': username, 'username': username,
'token': ''.join(random.sample(token_chars, token_len)) 'token': ''.join(random.sample(token_chars, token_len))
}) })
return 'Créé : ' + username return 'Créé : ' + username
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
@app.delete('/user/<username>') @app.delete('/user/<username>')
@ -340,15 +349,20 @@ def delete_user (username):
return 'Privilèges insufisants' return 'Privilèges insufisants'
try: try:
mongodb_database['users'].find({'username': username})[0] mongodb_database['users'].find({'username': username})[0]
except IndexError as e:
response.status = 400
return 'Lutilisateur nexiste pas'
mongodb_database['users'].delete_one({ mongodb_database['users'].delete_one({
'username': username, 'username': username,
}) })
return 'Supprimé ' + username return 'Supprimé ' + username
except IndexError as e:
response.status = 400
return 'Lutilisateur nexiste pas'
except pymongo.errors.ServerSelectionTimeoutError as e:
response.status = 500
return 'La base de donnée nest pas accessible'
##################################################### app startup ############################################$
if __name__ == '__main__': if __name__ == '__main__':
bottle.run(app=StripPathMiddleware(app), host=listen_address, port=listen_port, debug=True) bottle.run(app=StripPathMiddleware(app), host=listen_address, port=listen_port, debug=True)
else: else: