Browse Source

Initial commit

master
Drew Short 5 years ago
commit
d70c8b30e6
  1. 1
      .gitignore
  2. 111
      app.py
  3. 20
      db.py
  4. 14
      forms.py
  5. 108
      register_new_matrix_user.py
  6. 4
      requirements.txt
  7. 9
      templates/admin.html
  8. 24
      templates/base.html
  9. 14
      templates/login.html
  10. 15
      templates/register.html
  11. 12
      todo.md

1
.gitignore

@ -0,0 +1 @@
.idea

111
app.py

@ -0,0 +1,111 @@
import os
import uuid
from urllib.parse import urlparse, urljoin
import flask
from flask import Flask, redirect, render_template, request
from flask_login import LoginManager, login_required, login_user, logout_user, UserMixin, \
current_user
from flask_wtf import CSRFProtect
from forms import RegistrationForm, LoginForm
app = Flask(__name__)
app.config.update(dict(
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")
))
print("Admin Token: %s" % app.config.get("ADMIN_TOKEN"))
csrf = CSRFProtect(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "admin_login"
class User(UserMixin):
username: str
token: str
authenticated: bool = False
def __init__(self, username: str, token: str):
self.username = username
self.token = token
def is_authenticated(self):
return self.authenticated
def get_id(self):
return self.username
def is_safe_url(target):
ref_url = urlparse(request.host_url)
test_url = urlparse(urljoin(request.host_url, target))
return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc
@login_manager.user_loader
def load_user(user_id):
if user_id == "admin":
return User("admin", app.config.get("ADMIN_TOKEN"))
else:
return None
@app.route('/')
def index():
return 'Hello World!'
@app.route('/register', methods=('GET', 'POST'))
def registration():
form = RegistrationForm()
if form.validate_on_submit():
return redirect('/success')
return render_template('register.html', form=form)
@app.route('/admin')
@login_required
def admin_index():
return render_template('admin.html')
@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:
if form.token.data == user.token:
user.authenticated = True
login_user(user)
flask.flash('Logged in successfully.')
next_loc = flask.request.args.get('next')
if not is_safe_url(next_loc):
return flask.abort(400)
else:
if next_loc is not None:
return redirect(next_loc)
else:
return redirect('/admin')
return render_template('login.html', form=form)
@app.route("/admin/logout")
@login_required
def admin_logout():
logout_user()
flask.flash('Logged out successfully.')
return redirect('/')
if __name__ == '__main__':
app.run()

20
db.py

@ -0,0 +1,20 @@
import os
import sqlite3
from flask import g
DATABASE = os.getenv("DATA_DIRECTORY", ".") + "/data.db"
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(DATABASE)
return db
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()

14
forms.py

@ -0,0 +1,14 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
registration_code = StringField('Registration Code', validators=[DataRequired()])
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
token = PasswordField('Token', validators=[DataRequired()])

108
register_new_matrix_user.py

@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2016 OpenMarket Ltd
# Copyright 2018 New Vector
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This script has been simplified and adapted from
# https://raw.githubusercontent.com/matrix-org/synapse/master/synapse/_scripts/register_new_matrix_user.py
#
# The purpose is to facilitate registration using a shared_secret over the open
# registration that is supported in the matrix spec
#
import hashlib
import hmac
import sys
import requests as _requests
def request_registration(
user,
password,
server_location,
shared_secret,
admin=False,
user_type=None,
requests=_requests,
_print=print,
exit=sys.exit,
):
url = "%s/_matrix/client/r0/admin/register" % (server_location,)
# Get the nonce
r = requests.get(url, verify=False)
if r.status_code is not 200:
_print("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)
nonce = r.json()["nonce"]
mac = hmac.new(key=shared_secret.encode('utf8'), digestmod=hashlib.sha1)
mac.update(nonce.encode('utf8'))
mac.update(b"\x00")
mac.update(user.encode('utf8'))
mac.update(b"\x00")
mac.update(password.encode('utf8'))
mac.update(b"\x00")
mac.update(b"admin" if admin else b"notadmin")
if user_type:
mac.update(b"\x00")
mac.update(user_type.encode('utf8'))
mac = mac.hexdigest()
data = {
"nonce": nonce,
"username": user,
"password": password,
"mac": mac,
"admin": admin,
"user_type": user_type,
}
_print("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))
if 400 <= r.status_code < 500:
try:
_print(r.json()["error"])
except Exception:
pass
return exit(1)
_print("Success!")
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)

4
requirements.txt

@ -0,0 +1,4 @@
flask==1.0.2
flask-wtf==0.14
flask-login==0.4.1
requests==2.21.0

9
templates/admin.html

@ -0,0 +1,9 @@
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Admin{% endblock %}</h1>
{% endblock %}
{% block content %}
<p>ADMIN</p>
{% endblock %}

24
templates/base.html

@ -0,0 +1,24 @@
<!doctype html>
<title>{% block title %}{% endblock %} - Matrix</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
{#<nav>#}
{# <h1>Flaskr</h1>#}
{# <ul>#}
{# {% if g.user %}#}
{# <li><span>{{ g.user['username'] }}</span>#}
{# <li><a href="{{ url_for('auth.logout') }}">Log Out</a>#}
{# {% else %}#}
{# <li><a href="{{ url_for('auth.register') }}">Register</a>#}
{# <li><a href="{{ url_for('auth.login') }}">Log In</a>#}
{# {% endif %}#}
{# </ul>#}
{#</nav>#}
<section class="content">
<header>
{% block header %}{% endblock %}
</header>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% block content %}{% endblock %}
</section>

14
templates/login.html

@ -0,0 +1,14 @@
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Login{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="POST">
{{ form.csrf_token }}
{{ form.username.label }} {{ form.username(size=20) }}
{{ form.token.label }} {{ form.token() }}
<input type="submit" value="Go">
</form>
{% endblock %}

15
templates/register.html

@ -0,0 +1,15 @@
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Register{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="POST">
{{ form.csrf_token }}
{{ form.username.label }} {{ form.username(size=20) }}
{{ form.password.label }} {{ form.password() }}
{{ form.registration_code.label }} {{ form.registration_code() }}
<input type="submit" value="Go">
</form>
{% endblock %}

12
todo.md

@ -0,0 +1,12 @@
# TODO
* Admin endpoint
* List existing registration codes
* Create new registration codes
* Deactivate registration codes
* View registrations
* Registration Form
* Fields:
* Desired username
* Password
* Registration Code
Loading…
Cancel
Save