diff --git a/app/controllers/admin.py b/app/controllers/admin.py index 2143e6c..e2ebe2a 100644 --- a/app/controllers/admin.py +++ b/app/controllers/admin.py @@ -5,13 +5,12 @@ from flask_login import login_required import psutil -import settings from app.util import admin_required from app import db from app.forms import UserAdminForm, DeployCustomServerForm, NoticeForm, SuperuserPasswordForm -from app.forms import SendChannelMessageForm, CreateTokenForm, CleanupExpiredServersForm, get_all_hosts -from app.forms import CreateHostForm, HostAdminForm, CreatePackageForm, get_active_hosts_by_type, build_packages_list -from app.models import Server, User, Notice, Rating, Token, Host, Package +from app.forms import SendChannelMessageForm, CreateTokenForm, CleanupExpiredServersForm +from app.forms import CreateHostForm, HostAdminForm, CreatePackageForm, CreateBanForm, get_active_hosts_by_type, build_packages_list +from app.models import Server, User, Notice, Rating, Token, Host, Package, Ban import app.murmur as murmur ITEMS_PER_PAGE = 50 @@ -517,7 +516,7 @@ def get(self, id): order=package.order, active=package.active ) - return render_template('admin/package.html', package=package, form=form, title="Pacakge: %s" % package.name) + return render_template('admin/package.html', package=package, form=form, title="Package: %s" % package.name) @login_required @admin_required @@ -535,4 +534,47 @@ def update(self, id): package.active = form.active.data db.session.commit() return redirect('/admin/packages/%s' % package.id) - return render_template('admin/package.html', package=package, form=form, title="Package: %s" % package.name) \ No newline at end of file + return render_template('admin/package.html', package=package, form=form, title="Package: %s" % package.name) + +class AdminBansView(FlaskView): + @login_required + @admin_required + def index(self): + page = int(request.args.get('page', 1)) + banned = Ban.query.order_by(Ban.last_accessed.desc()).paginate(page, ITEMS_PER_PAGE, False) + form = CreateBanForm(request.form) + return render_template('admin/bans.html', banned=banned, form=form, title="Bans") + + @login_required + @admin_required + def post(self): + page = int(request.args.get('page', 1)) + form = CreateBanForm() + banned = Ban.query.order_by(Ban.last_accessed.desc()).paginate(page, ITEMS_PER_PAGE, False) + if form.validate_on_submit(): + try: + # Create database entry + b = Ban() + b.ip = form.ip.data or None + b.reason = form.reason.data or None + b.note = form.note.data or None + + db.session.add(b) + db.session.commit() + return redirect('/admin/bans/') + + except: + import traceback + db.session.rollback() + traceback.print_exc() + return redirect('/admin/bans/') + + return render_template('admin/bans.html', form=form, banned=banned) + + @login_required + @admin_required + def delete(self, id): + ban = Ban.query.filter_by(id=id).first_or_404() + db.session.delete(ban) + db.session.commit() + return jsonify({ id: id }) \ No newline at end of file diff --git a/app/controllers/home.py b/app/controllers/home.py index 8bdbfee..10fe23e 100644 --- a/app/controllers/home.py +++ b/app/controllers/home.py @@ -1,4 +1,5 @@ import uuid +from datetime import datetime from flask import render_template, redirect, url_for, g, flash, request, make_response from flask_classy import FlaskView, route @@ -8,7 +9,7 @@ from app import db, cache, tasks, mail from app.forms import DeployServerForm, ContactForm from app.forms import duration_choices, get_active_hosts_by_type -from app.models import Server, Package +from app.models import Server, Package, Ban from app import murmur @@ -23,6 +24,20 @@ def index(self): return render_template('index.html', form=form) def post(self): + # Set admin's IP. + x_forwarded_for = request.headers.getlist('X-Forwarded-For'); + ip = x_forwarded_for[0] if x_forwarded_for else request.remote_addr + ip = ip.split(',')[0] + + # Flash message if user is on banlist. + banned = Ban.query.filter_by(ip=ip).first() + if banned: + banned.last_accessed = datetime.utcnow() + db.session.add(banned) + db.session.commit() + flash("User banned! Reason: %s" % banned.reason) + return redirect('/') + form = DeployServerForm() form.duration.choices = duration_choices() form.region.choices = get_active_hosts_by_type('free') @@ -32,10 +47,6 @@ def post(self): # Generate UUID gen_uuid = str(uuid.uuid4()) - # Set admin's IP - x_forwarded_for = request.headers.getlist('X-Forwarded-For'); - ip = x_forwarded_for[0] if x_forwarded_for else request.remote_addr - # Create database entry s = Server() s.duration = form.duration.data diff --git a/app/forms.py b/app/forms.py index eb1bdd2..f7ca928 100644 --- a/app/forms.py +++ b/app/forms.py @@ -129,6 +129,11 @@ class CreatePackageForm(FlaskForm): active = BooleanField('active', default=False) order = IntegerField('duration', default=0) +class CreateBanForm(FlaskForm): + ip = TextField('ip') + reason = TextField('reason') + note = TextField('note') + class LoginForm(FlaskForm): openid = TextField('openid', validators=[Required()]) remember_me = BooleanField('remember_me', default=False) diff --git a/app/models.py b/app/models.py index 208caee..c356b4b 100644 --- a/app/models.py +++ b/app/models.py @@ -187,4 +187,12 @@ class Package(db.Model): slots = db.Column(db.Integer) duration = db.Column(db.Integer) active = db.Column(db.Boolean, default=False) - order = db.Column(db.Integer, default=0) \ No newline at end of file + order = db.Column(db.Integer, default=0) + + +class Ban(db.Model): + id = db.Column(db.Integer, primary_key=True) + ip = db.Column(db.String(64)) + reason = db.Column(db.String) + note = db.Column(db.String) + last_accessed = db.Column(db.DateTime, default=datetime.datetime.utcnow) \ No newline at end of file diff --git a/app/static/css/style.css b/app/static/css/style.css index 6064c99..e862be9 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -215,7 +215,7 @@ a:hover { .password-generator { font-size: 14px; margin-top: -10px; - width: 61.5%; + width: 66.5%; } .description { diff --git a/app/static/img/favicon.ico b/app/static/img/favicon.ico deleted file mode 100644 index a23e3af..0000000 Binary files a/app/static/img/favicon.ico and /dev/null differ diff --git a/app/static/img/favicon.png b/app/static/img/favicon.png new file mode 100644 index 0000000..96a329d Binary files /dev/null and b/app/static/img/favicon.png differ diff --git a/app/static/img/guildbit_ico.png b/app/static/img/guildbit_ico.png index 58fc5f6..c39971c 100644 Binary files a/app/static/img/guildbit_ico.png and b/app/static/img/guildbit_ico.png differ diff --git a/app/static/img/screenshot_home.png b/app/static/img/screenshot_home.png index c989074..c6c7d34 100644 Binary files a/app/static/img/screenshot_home.png and b/app/static/img/screenshot_home.png differ diff --git a/app/static/js/main.js b/app/static/js/main.js index 62944ab..e5e1f98 100755 --- a/app/static/js/main.js +++ b/app/static/js/main.js @@ -43,19 +43,19 @@ $(document).ready(function() { else if (os.indexOf("Win") !== -1) { $('#os-download #os-text').text(_WindowsDownload); $('#os-download #download-link i').addClass('fa-windows'); - $('#os-download #download-link').attr('href', 'https://github.com/mumble-voip/mumble/releases/download/1.3.3/mumble-1.3.3.msi'); + $('#os-download #download-link').attr('href', 'https://github.com/mumble-voip/mumble/releases/download/1.3.4/mumble-1.3.4.msi'); } else if (os.indexOf("MacOS") !== -1 || os.indexOf("MacIntel") !== -1) { $('#os-download #os-text').text(_OSXDownload); $('#os-download #download-link i').removeClass('fa-windows'); $('#os-download #download-link i').addClass('fa-apple'); - $('#os-download #download-link').attr('href', 'https://github.com/mumble-voip/mumble/releases/download/1.3.3/Mumble-1.3.3.dmg'); + $('#os-download #download-link').attr('href', 'https://github.com/mumble-voip/mumble/releases/download/1.3.4/Mumble-1.3.4.dmg'); } else if (ua.indexOf("android") > -1) { $('#os-download #os-text').text(_AndroidDownload); $('#os-download #download-link i').removeClass('fa-windows'); $('#os-download #download-link i').addClass('fa-android'); - $('#os-download #download-link').attr('href', 'https://play.google.com/store/apps/details?id=com.morlunk.mumbleclient'); + $('#os-download #download-link').attr('href', 'https://play.google.com/store/apps/details?id=se.lublin.mumla'); } else if (os === 'iPad' || os == 'iPhone' || os === 'iPod') { $('#os-download #os-text').text(_iOSDownload); diff --git a/app/templates/admin/bans.html b/app/templates/admin/bans.html new file mode 100644 index 0000000..9ac3fd5 --- /dev/null +++ b/app/templates/admin/bans.html @@ -0,0 +1,123 @@ +{% extends"layout/admin_base.html" %} + +{% block title %}Banned IPs{% endblock %} + +{% block body %} +
+ Add Ban +
+ + + + + + + + + + + + + {% for i in banned.items %} + + + + + + + + {% endfor %} + {% if banned == [] %} + + {% endif %} + + +
IPLast AccessedReasonNoteAction
{{ i.ip }}{{ i.last_accessed }}{{ i.reason }}{{ i.note }} + +
No Banned Users
+ +

({{ banned.total }} total)

+ + + +{% endblock %} + +{% block scripts %} + + + +{% endblock %} \ No newline at end of file diff --git a/app/templates/admin/server.html b/app/templates/admin/server.html index 5de925b..0cae285 100644 --- a/app/templates/admin/server.html +++ b/app/templates/admin/server.html @@ -25,13 +25,17 @@ UUID {{ server.uuid }} + + IP + {{ server.ip }} + Type {{ server.type }} Created - {{ server.created_date }} + {{ server.created_date }} Duration Hours @@ -148,6 +152,7 @@ var base_url = '/server/{{ server.uuid }}' var base_url_id = '/admin/servers/{{ server.uuid }}' var expire_date = '{{ server.expiration }}'; + $("#created-date").text(moment.utc(expire_date).local().format("ddd, MMM Do, h:mm:ss a")); $("#expires-date").text(moment.utc(expire_date).local().format("ddd, MMM Do, h:mm:ss a")); $("#expires").text(moment.utc(expire_date).fromNow()); $("#kill-server").on('submit', function() { diff --git a/app/templates/admin/servers.html b/app/templates/admin/servers.html index 35dfa43..955c764 100644 --- a/app/templates/admin/servers.html +++ b/app/templates/admin/servers.html @@ -24,6 +24,7 @@ ID UUID Created Date + IP Duration Password Status @@ -39,6 +40,7 @@ {{ s.id }} {{ s.uuid }} {{ s.created_date }} + {{ s.ip }} {% if s.extensions > 0 %} {{ s.duration - s.extensions }} +{{ s.extensions }} {% else %} @@ -51,7 +53,7 @@ {{ s.mumble_instance }} {% else %} - No Servers + No Servers {% endfor %} diff --git a/app/templates/index.html b/app/templates/index.html index 7c6573d..0bec228 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -20,6 +20,16 @@

{{ _('Deploy a Mumble server for your group. It's f Generate Password + {% with messages = get_flashed_messages() %} + {% if messages %} + + {% endif %} + {% endwith %} + {% if form.errors %}