From bf47f9457c6143512aa0b9c994325d8203812071 Mon Sep 17 00:00:00 2001 From: Jeremy Zhang Date: Fri, 5 Jan 2018 08:52:22 +0000 Subject: [PATCH] Administrator can now disable misbehaving servers --- ...146d173e028_added_disabled_guilds_table.py | 32 ++++++++++ webapp/titanembeds/blueprints/admin/admin.py | 29 +++++++++- webapp/titanembeds/blueprints/api/api.py | 10 +++- webapp/titanembeds/blueprints/embed/embed.py | 3 +- webapp/titanembeds/blueprints/user/user.py | 12 +++- webapp/titanembeds/database/__init__.py | 1 + .../titanembeds/database/disabled_guilds.py | 16 +++++ webapp/titanembeds/decorators.py | 14 ++++- .../static/js/admin_disabled_guilds.js | 57 ++++++++++++++++++ webapp/titanembeds/static/js/embed.js | 6 ++ .../templates/admin_disabled_guilds.html.j2 | 58 +++++++++++++++++++ .../titanembeds/templates/admin_index.html.j2 | 7 +++ .../templates/administrate_guild.html.j2 | 13 +++++ webapp/titanembeds/templates/embed.html.j2 | 1 + 14 files changed, 253 insertions(+), 6 deletions(-) create mode 100644 webapp/alembic/versions/f146d173e028_added_disabled_guilds_table.py create mode 100644 webapp/titanembeds/database/disabled_guilds.py create mode 100644 webapp/titanembeds/static/js/admin_disabled_guilds.js create mode 100644 webapp/titanembeds/templates/admin_disabled_guilds.html.j2 diff --git a/webapp/alembic/versions/f146d173e028_added_disabled_guilds_table.py b/webapp/alembic/versions/f146d173e028_added_disabled_guilds_table.py new file mode 100644 index 0000000..f3fd813 --- /dev/null +++ b/webapp/alembic/versions/f146d173e028_added_disabled_guilds_table.py @@ -0,0 +1,32 @@ +"""Added disabled guilds table + +Revision ID: f146d173e028 +Revises: d5dcee6894fa +Create Date: 2018-01-05 07:36:58.561149 + +""" + +# revision identifiers, used by Alembic. +revision = 'f146d173e028' +down_revision = 'd5dcee6894fa' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('disabled_guilds', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('guild_id', sa.String(length=255), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('disabled_guilds') + # ### end Alembic commands ### diff --git a/webapp/titanembeds/blueprints/admin/admin.py b/webapp/titanembeds/blueprints/admin/admin.py index f2d7c45..63a16ff 100644 --- a/webapp/titanembeds/blueprints/admin/admin.py +++ b/webapp/titanembeds/blueprints/admin/admin.py @@ -1,7 +1,7 @@ from flask import Blueprint, url_for, redirect, session, render_template, abort, request, jsonify from flask_socketio import emit from functools import wraps -from titanembeds.database import db, get_administrators_list, Cosmetics, Guilds, UnauthenticatedUsers, UnauthenticatedBans, TitanTokens, TokenTransactions, get_titan_token, set_titan_token +from titanembeds.database import db, get_administrators_list, Cosmetics, Guilds, UnauthenticatedUsers, UnauthenticatedBans, TitanTokens, TokenTransactions, get_titan_token, set_titan_token, list_disabled_guilds, DisabledGuilds from titanembeds.oauth import generate_guild_icon_url import datetime import json @@ -266,4 +266,31 @@ def patch_titan_tokens(): if get_titan_token(user_id) == -1: abort(409) set_titan_token(user_id, amount, "MODIFY VIA ADMIN [{}]".format(str(reason))) + return ('', 204) + +@admin.route("/disabled_guilds", methods=["GET"]) +@is_admin +def get_disabled_guilds(): + return render_template("admin_disabled_guilds.html.j2", guilds=list_disabled_guilds()) + +@admin.route("/disabled_guilds", methods=["POST"]) +@is_admin +def post_disabled_guilds(): + guild_id = request.form.get("guild_id", None) + if guild_id in list_disabled_guilds(): + abort(409) + guild = DisabledGuilds(guild_id) + db.session.add(guild) + db.session.commit() + return ('', 204) + +@admin.route("/disabled_guilds", methods=["DELETE"]) +@is_admin +def delete_disabled_guilds(): + guild_id = request.form.get("guild_id", None) + if guild_id not in list_disabled_guilds(): + abort(409) + guild = db.session.query(DisabledGuilds).filter(DisabledGuilds.guild_id == guild_id).first() + db.session.delete(guild) + db.session.commit() return ('', 204) \ No newline at end of file diff --git a/webapp/titanembeds/blueprints/api/api.py b/webapp/titanembeds/blueprints/api/api.py index c6afe4e..23fbca1 100644 --- a/webapp/titanembeds/blueprints/api/api.py +++ b/webapp/titanembeds/blueprints/api/api.py @@ -1,5 +1,5 @@ from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, AuthenticatedUsers, GuildMembers, Messages, get_channel_messages, list_all_guild_members, get_guild_member, get_administrators_list, get_badges -from titanembeds.decorators import valid_session_required, discord_users_only +from titanembeds.decorators import valid_session_required, discord_users_only, abort_if_guild_disabled from titanembeds.utils import check_guild_existance, guild_accepts_visitors, guild_query_unauth_users_bool, get_client_ipaddr, discord_api, rate_limiter, channel_ratelimit_key, guild_ratelimit_key, user_unauthenticated, checkUserRevoke, checkUserBanned, update_user_status, check_user_in_guild, get_guild_channels, guild_webhooks_enabled, guild_unauthcaptcha_enabled, get_member_roles from titanembeds.oauth import user_has_permission, generate_avatar_url, check_user_can_administrate_guild from flask import Blueprint, abort, jsonify, session, request, url_for @@ -163,6 +163,7 @@ def get_channel_webhook_url(guild_id, channel_id): @api.route("/fetch", methods=["GET"]) @valid_session_required(api=True) +@abort_if_guild_disabled() @rate_limiter.limit("2 per 2 second", key_func = channel_ratelimit_key) def fetch(): guild_id = request.args.get("guild_id") @@ -193,6 +194,7 @@ def fetch(): return response @api.route("/fetch_visitor", methods=["GET"]) +@abort_if_guild_disabled() @rate_limiter.limit("2 per 2 second", key_func = channel_ratelimit_key) def fetch_visitor(): guild_id = request.args.get("guild_id") @@ -215,6 +217,7 @@ def fetch_visitor(): @api.route("/post", methods=["POST"]) @valid_session_required(api=True) +@abort_if_guild_disabled() @rate_limiter.limit("1 per 5 second", key_func = channel_ratelimit_key) def post(): guild_id = request.form.get("guild_id") @@ -285,6 +288,7 @@ def verify_captcha_request(captcha_response, ip_address): @api.route("/create_unauthenticated_user", methods=["POST"]) @rate_limiter.limit("3 per 30 minute", key_func=guild_ratelimit_key) +@abort_if_guild_disabled() def create_unauthenticated_user(): session['unauthenticated'] = True username = request.form['username'] @@ -326,6 +330,7 @@ def create_unauthenticated_user(): @api.route("/change_unauthenticated_username", methods=["POST"]) @rate_limiter.limit("1 per 10 minute", key_func=guild_ratelimit_key) +@abort_if_guild_disabled() def change_unauthenticated_username(): username = request.form['username'] guild_id = request.form['guild_id'] @@ -381,6 +386,7 @@ def process_query_guild(guild_id, visitor=False): @api.route("/query_guild", methods=["GET"]) @valid_session_required(api=True) +@abort_if_guild_disabled() def query_guild(): guild_id = request.args.get('guild_id') if check_guild_existance(guild_id): @@ -390,6 +396,7 @@ def query_guild(): abort(404) @api.route("/query_guild_visitor", methods=["GET"]) +@abort_if_guild_disabled() def query_guild_visitor(): guild_id = request.args.get('guild_id') if check_guild_existance(guild_id): @@ -400,6 +407,7 @@ def query_guild_visitor(): @api.route("/create_authenticated_user", methods=["POST"]) @discord_users_only(api=True) +@abort_if_guild_disabled() def create_authenticated_user(): guild_id = request.form.get('guild_id') if session['unauthenticated']: diff --git a/webapp/titanembeds/blueprints/embed/embed.py b/webapp/titanembeds/blueprints/embed/embed.py index b828dde..8d1bc93 100644 --- a/webapp/titanembeds/blueprints/embed/embed.py +++ b/webapp/titanembeds/blueprints/embed/embed.py @@ -2,7 +2,7 @@ from flask import Blueprint, render_template, abort, redirect, url_for, session, from flask_babel import gettext from titanembeds.utils import check_guild_existance, guild_query_unauth_users_bool, guild_accepts_visitors, guild_unauthcaptcha_enabled from titanembeds.oauth import generate_guild_icon_url, generate_avatar_url -from titanembeds.database import db, Guilds, UserCSS +from titanembeds.database import db, Guilds, UserCSS, list_disabled_guilds from config import config import random import json @@ -65,6 +65,7 @@ def guild_embed(guild_id): } customcss = get_custom_css() return render_template("embed.html.j2", + disabled=guild_id in list_disabled_guilds(), login_greeting=get_logingreeting(), guild_id=guild_id, guild=guild_dict, diff --git a/webapp/titanembeds/blueprints/user/user.py b/webapp/titanembeds/blueprints/user/user.py index 63816eb..d84b092 100644 --- a/webapp/titanembeds/blueprints/user/user.py +++ b/webapp/titanembeds/blueprints/user/user.py @@ -3,7 +3,7 @@ from flask import current_app as app from flask_socketio import emit from config import config from titanembeds.decorators import discord_users_only -from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, Cosmetics, UserCSS, Patreon, set_titan_token, get_titan_token, add_badge +from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, Cosmetics, UserCSS, Patreon, set_titan_token, get_titan_token, add_badge, list_disabled_guilds from titanembeds.oauth import authorize_url, token_url, make_authenticated_session, get_current_authenticated_user, get_user_managed_servers, check_user_can_administrate_guild, check_user_permission, generate_avatar_url, generate_guild_icon_url, generate_bot_invite_url import time import datetime @@ -218,11 +218,13 @@ def administrate_guild(guild_id): "discordio": db_guild.discordio if db_guild.discordio != None else "", "guest_icon": db_guild.guest_icon if db_guild.guest_icon != None else "", } - return render_template("administrate_guild.html.j2", guild=dbguild_dict, members=users, permissions=permissions, cosmetics=cosmetics) + return render_template("administrate_guild.html.j2", guild=dbguild_dict, members=users, permissions=permissions, cosmetics=cosmetics, disabled=(guild_id in list_disabled_guilds())) @user.route("/administrate_guild/", methods=["POST"]) @discord_users_only() def update_administrate_guild(guild_id): + if guild_id in list_disabled_guilds(): + return ('', 423) if not check_user_can_administrate_guild(guild_id): abort(403) db_guild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first() @@ -316,6 +318,8 @@ def ban_unauthenticated_user(): guild_id = request.form.get("guild_id", None) user_id = request.form.get("user_id", None) reason = request.form.get("reason", None) + if guild_id in list_disabled_guilds(): + return ('', 423) if reason is not None: reason = reason.strip() if reason == "": @@ -342,6 +346,8 @@ def ban_unauthenticated_user(): def unban_unauthenticated_user(): guild_id = request.args.get("guild_id", None) user_id = request.args.get("user_id", None) + if guild_id in list_disabled_guilds(): + return ('', 423) if not guild_id or not user_id: abort(400) if not check_user_permission(guild_id, 2): @@ -362,6 +368,8 @@ def unban_unauthenticated_user(): def revoke_unauthenticated_user(): guild_id = request.form.get("guild_id", None) user_id = request.form.get("user_id", None) + if guild_id in list_disabled_guilds(): + return ('', 423) if not guild_id or not user_id: abort(400) if not check_user_permission(guild_id, 1): diff --git a/webapp/titanembeds/database/__init__.py b/webapp/titanembeds/database/__init__.py index 221a24d..7f751bd 100644 --- a/webapp/titanembeds/database/__init__.py +++ b/webapp/titanembeds/database/__init__.py @@ -14,6 +14,7 @@ from .administrators import Administrators, get_administrators_list from .titan_tokens import TitanTokens, get_titan_token from .token_transactions import TokenTransactions from .patreon import Patreon +from .disabled_guilds import DisabledGuilds, list_disabled_guilds def set_titan_token(user_id, amt_change, action): token_count = get_titan_token(user_id) diff --git a/webapp/titanembeds/database/disabled_guilds.py b/webapp/titanembeds/database/disabled_guilds.py new file mode 100644 index 0000000..18e5caf --- /dev/null +++ b/webapp/titanembeds/database/disabled_guilds.py @@ -0,0 +1,16 @@ +from titanembeds.database import db + +class DisabledGuilds(db.Model): + __tablename__ = "disabled_guilds" + id = db.Column(db.Integer, primary_key=True) # Auto increment id + guild_id = db.Column(db.String(255), nullable=False) # Server id that is disabled + + def __init__(self, guild_id): + self.guild_id = guild_id + +def list_disabled_guilds(): + q = db.session.query(DisabledGuilds).all() + their_ids = [] + for guild in q: + their_ids.append(guild.guild_id) + return their_ids \ No newline at end of file diff --git a/webapp/titanembeds/decorators.py b/webapp/titanembeds/decorators.py index b2908e9..a6ad5f0 100644 --- a/webapp/titanembeds/decorators.py +++ b/webapp/titanembeds/decorators.py @@ -1,5 +1,6 @@ from functools import wraps -from flask import url_for, redirect, session, jsonify, abort +from flask import url_for, redirect, session, jsonify, abort, request +from titanembeds.database import list_disabled_guilds def valid_session_required(api=False): def decorator(f): @@ -26,3 +27,14 @@ def discord_users_only(api=False): return f(*args, **kwargs) return decorated_function return decorator + +def abort_if_guild_disabled(): + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + guild_id = request.args.get("guild_id", None) + if guild_id in list_disabled_guilds(): + return ('', 423) + return f(*args, **kwargs) + return decorated_function + return decorator \ No newline at end of file diff --git a/webapp/titanembeds/static/js/admin_disabled_guilds.js b/webapp/titanembeds/static/js/admin_disabled_guilds.js new file mode 100644 index 0000000..8ee89fa --- /dev/null +++ b/webapp/titanembeds/static/js/admin_disabled_guilds.js @@ -0,0 +1,57 @@ +/* global $, Materialize, location */ + +function postForm(guild_id) { + var funct = $.ajax({ + dataType: "json", + method: "POST", + data: {"guild_id": guild_id} + }); + return funct.promise(); +} + +function deleteForm(guild_id) { + var funct = $.ajax({ + dataType: "json", + method: "DELETE", + data: {"guild_id": guild_id} + }); + return funct.promise(); +} + +$(function() { + $("#new_submit").click(function () { + var guild_id = $("#new_guild_id").val(); + if (guild_id.length < 1) { + Materialize.toast("The server ID field can't be blank!", 2000); + return; + } + var formPost = postForm(guild_id); + formPost.done(function (data) { + location.reload(); + }); + formPost.fail(function (data) { + if (data.status == 409) { + Materialize.toast('This server id already exists!', 10000); + } else { + Materialize.toast('Oh no! Something has failed submitting a new entry!', 10000); + } + }); + }); +}); + +function delete_guild(guild_id) { + var confirmation = confirm("Are you sure that you want to reenable server?"); + if (confirmation) { + var formDelete = deleteForm(guild_id); + formDelete.done(function (data) { + location.reload(); + }); + formDelete.fail(function (data) { + if (data.status == 409) { + Materialize.toast('This server id does not exists!', 10000); + } else { + Materialize.toast('Oh no! Something has failed deleting this server entry!', 10000); + } + }); + } +} \ No newline at end of file diff --git a/webapp/titanembeds/static/js/embed.js b/webapp/titanembeds/static/js/embed.js index 6346457..48c2211 100644 --- a/webapp/titanembeds/static/js/embed.js +++ b/webapp/titanembeds/static/js/embed.js @@ -16,6 +16,7 @@ /* global linkify */ /* global unauth_captcha_enabled */ /* global soundManager */ +/* global disabled */ (function () { const theme_options = ["DiscordDark", "BetterTitan"]; // All the avaliable theming names @@ -290,6 +291,11 @@ } }); + if (disabled) { + Materialize.toast('This server is currently disabled. If you are an administrator of this server, please get in touch with a TitanEmbeds team member to lift the ban.', 100000); + return; + } + primeEmbed(); setInterval(send_socket_heartbeat, 5000); if (getParameterByName("username")) { diff --git a/webapp/titanembeds/templates/admin_disabled_guilds.html.j2 b/webapp/titanembeds/templates/admin_disabled_guilds.html.j2 new file mode 100644 index 0000000..25740b0 --- /dev/null +++ b/webapp/titanembeds/templates/admin_disabled_guilds.html.j2 @@ -0,0 +1,58 @@ +{% extends 'site_layout.html.j2' %} +{% set title="Editing Disabled Servers" %} + +{% block content %} +

Administrating Disabled Servers

+ +
+
+
+

Add an entry

+ + + + + + + + + + + + + +
Server IDSubmit
+
+ +
+
+ Submit +
+
+
+ +
+
+ + + + + + + + + {% for guild in guilds %} + + + + + {% endfor %} + +
RemoveServer ID
Remove{{ guild }}
+
+
+
+{% endblock %} +{% block script %} + +{% endblock %} diff --git a/webapp/titanembeds/templates/admin_index.html.j2 b/webapp/titanembeds/templates/admin_index.html.j2 index 310fbb6..45e03d8 100644 --- a/webapp/titanembeds/templates/admin_index.html.j2 +++ b/webapp/titanembeds/templates/admin_index.html.j2 @@ -27,5 +27,12 @@ Manage +
+
+

Disabled Servers

+

Block or reinstate servers from using Titan Embeds.

+ Manage +
+
{% endblock %} \ No newline at end of file diff --git a/webapp/titanembeds/templates/administrate_guild.html.j2 b/webapp/titanembeds/templates/administrate_guild.html.j2 index b00d04b..81feb26 100644 --- a/webapp/titanembeds/templates/administrate_guild.html.j2 +++ b/webapp/titanembeds/templates/administrate_guild.html.j2 @@ -17,6 +17,19 @@ .

+ + {% if disabled %} +
+
+
+
+ This server is currently disabled on the platform. +

You will not be able to embed the server for the time being. To have this action lifted, please see an administrator.

+
+
+
+
+ {% endif %}

Embed URLs

diff --git a/webapp/titanembeds/templates/embed.html.j2 b/webapp/titanembeds/templates/embed.html.j2 index f688042..314cf33 100644 --- a/webapp/titanembeds/templates/embed.html.j2 +++ b/webapp/titanembeds/templates/embed.html.j2 @@ -371,6 +371,7 @@ {% endraw %}