Browse Source

Attempting to create a working docker deploy

master
Drew Short 5 years ago
parent
commit
08ef5005d4
  1. 11
      .dockerignore
  2. 7
      .gitignore
  3. 18
      Dockerfile
  4. 83
      app.py
  5. 6
      db.py
  6. 14
      docker-compose.yml
  7. 7
      example.env
  8. 44
      register_new_matrix_user.py
  9. 3
      templates/base.html

11
.dockerignore

@ -0,0 +1,11 @@
*.env
*.conf
.git
.gitignore
*.db
Dockerfile
docker-compose.yml
tmp

7
.gitignore

@ -1,3 +1,6 @@
.idea
__pycache__
tmp
*.db
.idea
*.db
.env

18
Dockerfile

@ -0,0 +1,18 @@
FROM python:3.7
MAINTAINER Drew Short <warrick@sothr.com>
RUN mkdir /srv/portal /srv/portal/data
ENV APP_DATA_DIRECTORY=/srv/portal/data
VOLUME /srv/portal/data
WORKDIR /srv/portal
CMD ["gunicorn", "-b", "0.0.0.0:8080", "app:app"]
COPY . /srv/portal
RUN cd /srv/portal \
&& pip install -r requirements.txt \
&& pip install gunicorn

83
app.py

@ -1,12 +1,12 @@
import logging
import os
import uuid
from logging.config import dictConfig
from urllib.parse import urlparse, urljoin
import flask
from flask import Flask, redirect, render_template, request, g, flash
from flask_login import LoginManager, login_required, login_user, logout_user, UserMixin, \
current_user
from flask import Flask, redirect, render_template, request, g, flash, url_for
from flask_login import LoginManager, login_required, login_user, logout_user, UserMixin
from flask_wtf import CSRFProtect
from db import get_db, get_registration_codes, add_registration_code, \
@ -14,15 +14,36 @@ from db import get_db, get_registration_codes, add_registration_code, \
add_registered_user
from forms import RegistrationForm, LoginForm, RegistrationCodeForm, \
ExpireRegistrationCodeForm
from register_new_matrix_user import register_new_user
csrf = CSRFProtect()
login_manager = LoginManager()
dictConfig({
'version': 1,
'disable_existing_loggers': False,
'formatters': {'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}},
'handlers': {
'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
}
},
'root': {
'level': 'INFO',
'handlers': ['wsgi']
}
})
log = logging.getLogger(__name__)
def init_db(flask_app):
with flask_app.app_context():
log.info("Initializing DB")
db = get_db()
with flask_app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
@ -34,12 +55,16 @@ def create_app():
flask_app = Flask(__name__)
flask_app.config.update(dict(
APPLICATION_ROOT=os.getenv("APPLICATION_ROOT", "/"),
ADMIN_TOKEN=os.getenv("ADMIN_TOKEN", uuid.uuid4().__str__()),
SECRET_KEY=os.getenv("SECRET_KEY", "changeme"),
WTF_CSRF_SECRET_KEY=os.getenv("CSRF_SECRET_KEY", "csrf_changeme")
WTF_CSRF_SECRET_KEY=os.getenv("CSRF_SECRET_KEY", "csrf_changeme"),
MATRIX_HOMESERVER=os.getenv("MATRIX_HOMESERVER"),
MATRIX_SHARED_SECRET=os.getenv("MATRIX_SHARED_SECRET"),
REGISTRATION_SUCCESS_REDIRECT=os.getenv("REGISTRATION_SUCCESS_REDIRECT")
))
print("Admin Token: %s" % flask_app.config.get("ADMIN_TOKEN"))
log.info("Admin Token: %s" % flask_app.config.get("ADMIN_TOKEN"))
csrf.init_app(flask_app)
@ -48,11 +73,15 @@ def create_app():
init_db(flask_app)
log.info("Application ready")
return flask_app
app = create_app()
log.info("Bound reverse proxy wsgi app")
def flash_form_errors(form):
if hasattr(form, 'errors') and len(form.errors) > 0:
@ -82,6 +111,13 @@ def is_safe_url(target):
return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc
def get_successful_registration_redirect():
target = app.config.get('REGISTRATION_SUCCESS_REDIRECT')
if target is None or not target.startswith('http'):
return url_for('index', _external=True)
return target
@login_manager.user_loader
def load_user(user_id):
if user_id == "admin":
@ -94,15 +130,33 @@ def load_user(user_id):
@app.route('/')
def index():
return redirect('/register')
return redirect(url_for('registration'))
@app.route('/register', methods=('GET', 'POST'))
def registration():
form = RegistrationForm()
if form.validate_on_submit():
add_registered_user(form.registration_code.data, form.username.data)
return redirect('/success')
if app.config.get("MATRIX_HOMESERVER") is None:
flash("Matrix Homeserver Currently Unavailable. Please Try Again Later!")
return render_template('register.html', form=form)
else:
if app.config.get("MATRIX_SHARED_SECRET") is None:
flash("Registration Configuration Is Invalid. Contact Administrator!")
return render_template('register.html', form=form)
else:
successful = register_new_user(
form.username.data,
form.password.data,
app.config.get("MATRIX_HOMESERVER"),
app.config.get("MATRIX_SHARED_SECRET")
)
if successful:
add_registered_user(form.registration_code.data, form.username.data)
return redirect(get_successful_registration_redirect())
else:
flash("Registration Failure. Contact Administrator!")
return render_template('register.html', form=form)
flash_form_errors(form)
@ -131,11 +185,11 @@ def admin_add_registration_code():
expiration_time = form.expiration_time.data
max_usages = form.max_usages.data
add_registration_code(expiration_time, max_usages)
redirect('/admin')
redirect(url_for('admin_index', _external=True))
flash_form_errors(form)
return redirect('/admin')
return redirect(url_for('admin_index', _external=True))
@app.route('/admin/expire_registration_code', methods=['POST'])
@ -147,17 +201,16 @@ def admin_expire_registration_code():
expire_registration_code(form.registration_code.data)
elif form.delete.data:
delete_registration_code(form.registration_code.data)
redirect('/admin')
redirect(url_for('admin_index', _external=True))
flash_form_errors(form)
return redirect('/admin')
return redirect(url_for('admin_index', _external=True))
@app.route('/admin/login', methods=('GET', 'POST'))
def admin_login():
form = LoginForm()
tmp = current_user
if form.validate_on_submit():
user = load_user(form.username.data)
if user is not None:
@ -172,7 +225,7 @@ def admin_login():
if next_loc is not None:
return redirect(next_loc)
else:
return redirect('/admin')
return redirect(url_for('admin_index', _external=True))
flash_form_errors(form)
@ -184,7 +237,7 @@ def admin_login():
def admin_logout():
logout_user()
flask.flash('Logged out successfully.')
return redirect('/')
return redirect(url_for('index', _external=True))
@app.teardown_appcontext

6
db.py

@ -1,3 +1,4 @@
import logging
import os
import sqlite3
import uuid
@ -8,7 +9,7 @@ from flask import g
from models import RegistrationCode, RegisteredUser
DATABASE = os.getenv("DATA_DIRECTORY", ".") + "/data.db"
DATABASE = os.getenv("APP_DATA_DIRECTORY", ".") + "/data.db"
REGISTRATION_CODE_INSERT_SQL = """INSERT INTO
@ -24,10 +25,13 @@ registered_users(registrationCode, username, registeredTime)
VALUES(?, ?, ?)
"""
log = logging.getLogger(__name__)
def get_db():
db = getattr(g, '_database', None)
if db is None:
log.info("Using database at: %s" % DATABASE)
db = g._database = sqlite3.connect(DATABASE)
return db

14
docker-compose.yml

@ -0,0 +1,14 @@
version: "2"
services:
portal:
build: .
environment:
- ADMIN_TOKEN
- SECRET_KEY
- WTF_CSRF_SECRET_KEY
- MATRIX_HOMESERVER
- MATRIX_SHARED_SECRET
- DATA_DIRECTORY=/srv/portal/data
volumes:
- ${DATA_DIR}:/srv/portal/data:Z

7
example.env

@ -0,0 +1,7 @@
ADMIN_TOKEN=changeme
SECRET_KEY=changeme_too
WTF_CSRF_SECRET_KEY=csrf_changeme_also
MATRIX_HOMESERVER=your_matrix_homeserver
MATRIX_SHARED_SECRET=the_shared_registration_secret
DATA_DIRECTORY=/srv/portal/data
REGISTRATION_SUCCESS_REDIRECT=/success

44
register_new_matrix_user.py

@ -24,11 +24,14 @@
import hashlib
import hmac
import sys
import logging
import requests as _requests
log = logging.getLogger(__name__)
def request_registration(
user,
password,
@ -36,9 +39,7 @@ def request_registration(
shared_secret,
admin=False,
user_type=None,
requests=_requests,
_print=print,
exit=sys.exit,
requests=_requests
):
url = "%s/_matrix/client/r0/admin/register" % (server_location,)
@ -47,13 +48,13 @@ def request_registration(
r = requests.get(url, verify=False)
if r.status_code is not 200:
_print("ERROR! Received %d %s" % (r.status_code, r.reason))
log.error("ERROR! Received %d %s" % (r.status_code, r.reason))
if 400 <= r.status_code < 500:
try:
_print(r.json()["error"])
except Exception:
pass
return exit(1)
log.error(r.json()["error"])
except Exception as e:
log.error(e)
return False
nonce = r.json()["nonce"]
@ -81,28 +82,19 @@ def request_registration(
"user_type": user_type,
}
_print("Sending registration request...")
log.debug("Sending registration request...")
r = requests.post(url, json=data, verify=False)
if r.status_code is not 200:
_print("ERROR! Received %d %s" % (r.status_code, r.reason))
log.error("ERROR! Received %d %s" % (r.status_code, r.reason))
if 400 <= r.status_code < 500:
try:
_print(r.json()["error"])
except Exception:
pass
return exit(1)
_print("Success!")
log.error(r.json()["error"])
except Exception as e:
log.error(e)
return False
return True
def register_new_user(user, password, server_location, shared_secret):
if not user:
print("Invalid user name")
sys.exit(1)
if not password:
print("Invalid user name")
sys.exit(1)
request_registration(user, password, server_location, shared_secret, False, None)
return request_registration(user, password, server_location, shared_secret, False, None)

3
templates/base.html

@ -6,8 +6,9 @@
<ul>
{% if g.user %}
<li><span>{{ g.user['username'] }}</span>
<li><a href="{{ url_for('admin_index') }}">Admin Panel</a>
<li><a href="{{ url_for('admin_logout') }}">Log Out</a>
{% else %}
{% else %}
<li><a href="{{ url_for('registration') }}">Register</a>
<li><a href="{{ url_for('admin_login') }}">Log In</a>
{% endif %}

Loading…
Cancel
Save