mirror of
				https://github.com/TitanEmbeds/Titan.git
				synced 2025-11-04 07:47:10 +01:00 
			
		
		
		
	Basic websockets authentication handling
This commit is contained in:
		@@ -23,4 +23,13 @@ class SocketIOInterface:
 | 
			
		||||
                "mentions": get_message_mentions(message.mentions),
 | 
			
		||||
                "attachments": message.attachments,
 | 
			
		||||
            }
 | 
			
		||||
            await self.io.emit('MESSAGE_CREATE', data=msg, room=message.server.id, namespace='/gateway')
 | 
			
		||||
            nickname = None
 | 
			
		||||
            if hasattr(message.author, 'nick') and message.author.nick:
 | 
			
		||||
                nickname = message.author.nick
 | 
			
		||||
            msg["author"]["nickname"] = nickname
 | 
			
		||||
            for mention in msg["mentions"]:
 | 
			
		||||
                mention["nickname"] = None
 | 
			
		||||
                member = message.server.get_member(mention["id"])
 | 
			
		||||
                if member:
 | 
			
		||||
                    mention["nickname"] = member.nick
 | 
			
		||||
            await self.io.emit('MESSAGE_CREATE', data=msg, room=str("CHANNEL_"+message.channel.id), namespace='/gateway')
 | 
			
		||||
@@ -2,11 +2,10 @@ from titanembeds.database import db, Guilds, UnauthenticatedUsers, Unauthenticat
 | 
			
		||||
from titanembeds.decorators import valid_session_required, discord_users_only
 | 
			
		||||
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
 | 
			
		||||
from titanembeds.oauth import user_has_permission, generate_avatar_url, check_user_can_administrate_guild
 | 
			
		||||
from titanembeds.database import get_administrators_list
 | 
			
		||||
from titanembeds.userbookkeeping import user_unauthenticated, checkUserRevoke, checkUserBanned, update_user_status, check_user_in_guild, get_guild_channels
 | 
			
		||||
from flask import Blueprint, abort, jsonify, session, request, url_for
 | 
			
		||||
from sqlalchemy import and_
 | 
			
		||||
import random
 | 
			
		||||
import requests
 | 
			
		||||
import json
 | 
			
		||||
import datetime
 | 
			
		||||
import re
 | 
			
		||||
@@ -14,97 +13,6 @@ from config import config
 | 
			
		||||
 | 
			
		||||
api = Blueprint("api", __name__)
 | 
			
		||||
 | 
			
		||||
def user_unauthenticated():
 | 
			
		||||
    if 'unauthenticated' in session:
 | 
			
		||||
        return session['unauthenticated']
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
def checkUserRevoke(guild_id, user_key=None):
 | 
			
		||||
    revoked = True #guilty until proven not revoked
 | 
			
		||||
    if user_unauthenticated():
 | 
			
		||||
        dbUser = UnauthenticatedUsers.query.filter(and_(UnauthenticatedUsers.guild_id == guild_id, UnauthenticatedUsers.user_key == user_key)).first()
 | 
			
		||||
        revoked = dbUser.isRevoked()
 | 
			
		||||
    else:
 | 
			
		||||
        banned = checkUserBanned(guild_id)
 | 
			
		||||
        if banned:
 | 
			
		||||
            return revoked
 | 
			
		||||
        dbUser = GuildMembers.query.filter(GuildMembers.guild_id == guild_id).filter(GuildMembers.user_id == session["user_id"]).first()
 | 
			
		||||
        revoked = not dbUser or not dbUser.active
 | 
			
		||||
    return revoked
 | 
			
		||||
 | 
			
		||||
def checkUserBanned(guild_id, ip_address=None):
 | 
			
		||||
    banned = True
 | 
			
		||||
    if user_unauthenticated():
 | 
			
		||||
        dbUser = UnauthenticatedBans.query.filter(and_(UnauthenticatedBans.guild_id == guild_id, UnauthenticatedBans.ip_address == ip_address)).all()
 | 
			
		||||
        if not dbUser:
 | 
			
		||||
            banned = False
 | 
			
		||||
        else:
 | 
			
		||||
            for usr in dbUser:
 | 
			
		||||
                if usr.lifter_id is not None:
 | 
			
		||||
                    banned = False
 | 
			
		||||
    else:
 | 
			
		||||
        banned = False
 | 
			
		||||
        dbUser = GuildMembers.query.filter(GuildMembers.guild_id == guild_id).filter(GuildMembers.user_id == session["user_id"]).first()
 | 
			
		||||
        if not dbUser:
 | 
			
		||||
            banned = False
 | 
			
		||||
        else:
 | 
			
		||||
            banned = dbUser.banned
 | 
			
		||||
    return banned
 | 
			
		||||
 | 
			
		||||
def update_user_status(guild_id, username, user_key=None):
 | 
			
		||||
    if user_unauthenticated():
 | 
			
		||||
        ip_address = get_client_ipaddr()
 | 
			
		||||
        status = {
 | 
			
		||||
            'authenticated': False,
 | 
			
		||||
            'avatar': None,
 | 
			
		||||
            'manage_embed': False,
 | 
			
		||||
            'ip_address': ip_address,
 | 
			
		||||
            'username': username,
 | 
			
		||||
            'nickname': None,
 | 
			
		||||
            'user_key': user_key,
 | 
			
		||||
            'guild_id': guild_id,
 | 
			
		||||
            'user_id': session['user_id'],
 | 
			
		||||
            'banned': checkUserBanned(guild_id, ip_address),
 | 
			
		||||
            'revoked': checkUserRevoke(guild_id, user_key),
 | 
			
		||||
        }
 | 
			
		||||
        if status['banned'] or status['revoked']:
 | 
			
		||||
            session['user_keys'].pop(guild_id, None)
 | 
			
		||||
            return status
 | 
			
		||||
        dbUser = UnauthenticatedUsers.query.filter(and_(UnauthenticatedUsers.guild_id == guild_id, UnauthenticatedUsers.user_key == user_key)).first()
 | 
			
		||||
        dbUser.bumpTimestamp()
 | 
			
		||||
        if dbUser.username != username or dbUser.ip_address != ip_address:
 | 
			
		||||
            dbUser.username = username
 | 
			
		||||
            dbUser.ip_address = ip_address
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
    else:
 | 
			
		||||
        status = {
 | 
			
		||||
            'authenticated': True,
 | 
			
		||||
            'avatar': session["avatar"],
 | 
			
		||||
            'manage_embed': check_user_can_administrate_guild(guild_id),
 | 
			
		||||
            'username': username,
 | 
			
		||||
            'nickname': None,
 | 
			
		||||
            'discriminator': session['discriminator'],
 | 
			
		||||
            'guild_id': guild_id,
 | 
			
		||||
            'user_id': session['user_id'],
 | 
			
		||||
            'banned': checkUserBanned(guild_id),
 | 
			
		||||
            'revoked': checkUserRevoke(guild_id)
 | 
			
		||||
        }
 | 
			
		||||
        if status['banned'] or status['revoked']:
 | 
			
		||||
            return status
 | 
			
		||||
        dbMember = get_guild_member(guild_id, status["user_id"])
 | 
			
		||||
        if dbMember:
 | 
			
		||||
            status["nickname"] = dbMember.nickname
 | 
			
		||||
        dbUser = db.session.query(AuthenticatedUsers).filter(and_(AuthenticatedUsers.guild_id == guild_id, AuthenticatedUsers.client_id == status['user_id'])).first()
 | 
			
		||||
        dbUser.bumpTimestamp()
 | 
			
		||||
    return status
 | 
			
		||||
 | 
			
		||||
def check_user_in_guild(guild_id):
 | 
			
		||||
    if user_unauthenticated():
 | 
			
		||||
        return guild_id in session['user_keys']
 | 
			
		||||
    else:
 | 
			
		||||
        dbUser = db.session.query(AuthenticatedUsers).filter(and_(AuthenticatedUsers.guild_id == guild_id, AuthenticatedUsers.client_id == session['user_id'])).first()
 | 
			
		||||
        return dbUser is not None and not checkUserRevoke(guild_id)
 | 
			
		||||
 | 
			
		||||
def parse_emoji(textToParse, guild_id):
 | 
			
		||||
    guild_emojis = get_guild_emojis(guild_id)
 | 
			
		||||
    for gemoji in guild_emojis:
 | 
			
		||||
@@ -160,92 +68,6 @@ def format_everyone_mention(channel, content):
 | 
			
		||||
            content = content.replace("@here", u"@\u200Bhere")
 | 
			
		||||
    return content
 | 
			
		||||
 | 
			
		||||
def get_member_roles(guild_id, user_id):
 | 
			
		||||
    q = db.session.query(GuildMembers).filter(GuildMembers.guild_id == guild_id).filter(GuildMembers.user_id == user_id).first()
 | 
			
		||||
    return json.loads(q.roles)
 | 
			
		||||
 | 
			
		||||
def get_dbguild_channels(guild_id):
 | 
			
		||||
    q = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first()
 | 
			
		||||
    return json.loads(q.channels)
 | 
			
		||||
 | 
			
		||||
def get_guild_channels(guild_id, force_everyone=False):
 | 
			
		||||
    if user_unauthenticated() or force_everyone:
 | 
			
		||||
        member_roles = [guild_id] #equivilant to @everyone role
 | 
			
		||||
    else:
 | 
			
		||||
        member_roles = get_member_roles(guild_id, session['user_id'])
 | 
			
		||||
        if guild_id not in member_roles:
 | 
			
		||||
            member_roles.append(guild_id)
 | 
			
		||||
    dbguild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first()
 | 
			
		||||
    guild_channels = json.loads(dbguild.channels)
 | 
			
		||||
    guild_roles = json.loads(dbguild.roles)
 | 
			
		||||
    guild_owner = str(dbguild.owner_id)
 | 
			
		||||
    result_channels = []
 | 
			
		||||
    for channel in guild_channels:
 | 
			
		||||
        if channel['type'] == "text":
 | 
			
		||||
            result = {"channel": channel, "read": False, "write": False, "mention_everyone": False}
 | 
			
		||||
            if guild_owner == session.get("user_id"):
 | 
			
		||||
                result["read"] = True
 | 
			
		||||
                result["write"] = True
 | 
			
		||||
                result["mention_everyone"] = True
 | 
			
		||||
                result_channels.append(result)
 | 
			
		||||
                continue
 | 
			
		||||
            channel_perm = 0
 | 
			
		||||
 | 
			
		||||
            # @everyone
 | 
			
		||||
            for role in guild_roles:
 | 
			
		||||
                if role["id"] == guild_id:
 | 
			
		||||
                    channel_perm |= role["permissions"]
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
            # User Guild Roles
 | 
			
		||||
            for m_role in member_roles:
 | 
			
		||||
                for g_role in guild_roles:
 | 
			
		||||
                    if g_role["id"] == m_role:
 | 
			
		||||
                        channel_perm |= g_role["permissions"]
 | 
			
		||||
                        continue
 | 
			
		||||
 | 
			
		||||
            # If has server administrator permission
 | 
			
		||||
            if user_has_permission(channel_perm, 3):
 | 
			
		||||
                result["read"] = True
 | 
			
		||||
                result["write"] = True
 | 
			
		||||
                result["mention_everyone"] = True
 | 
			
		||||
                result_channels.append(result)
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            denies = 0
 | 
			
		||||
            allows = 0
 | 
			
		||||
 | 
			
		||||
            # channel specific
 | 
			
		||||
            for overwrite in channel["permission_overwrites"]:
 | 
			
		||||
                if overwrite["type"] == "role" and overwrite["id"] in member_roles:
 | 
			
		||||
                    denies |= overwrite["deny"]
 | 
			
		||||
                    allows |= overwrite["allow"]
 | 
			
		||||
 | 
			
		||||
            channel_perm = (channel_perm & ~denies) | allows
 | 
			
		||||
 | 
			
		||||
            # member specific
 | 
			
		||||
            for overwrite in channel["permission_overwrites"]:
 | 
			
		||||
                if overwrite["type"] == "member" and overwrite["id"] == session.get("user_id"):
 | 
			
		||||
                    channel_perm = (channel_perm & ~overwrite['deny']) | overwrite['allow']
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
            result["read"] = user_has_permission(channel_perm, 10)
 | 
			
		||||
            result["write"] = user_has_permission(channel_perm, 11)
 | 
			
		||||
            result["mention_everyone"] = user_has_permission(channel_perm, 17)
 | 
			
		||||
 | 
			
		||||
            # If default channel, you can read
 | 
			
		||||
            if channel["id"] == guild_id:
 | 
			
		||||
                result["read"] = True
 | 
			
		||||
 | 
			
		||||
            # If you cant read channel, you cant write in it
 | 
			
		||||
            if not user_has_permission(channel_perm, 10):
 | 
			
		||||
                result["read"] = False
 | 
			
		||||
                result["write"] = False
 | 
			
		||||
                result["mention_everyone"] = False
 | 
			
		||||
 | 
			
		||||
            result_channels.append(result)
 | 
			
		||||
    return sorted(result_channels, key=lambda k: k['channel']['position'])
 | 
			
		||||
 | 
			
		||||
def filter_guild_channel(guild_id, channel_id, force_everyone=False):
 | 
			
		||||
    channels = get_guild_channels(guild_id, force_everyone)
 | 
			
		||||
    for chan in channels:
 | 
			
		||||
@@ -341,6 +163,7 @@ def fetch():
 | 
			
		||||
        status_code = 403
 | 
			
		||||
        if user_unauthenticated():
 | 
			
		||||
            session['user_keys'].pop(guild_id, None)
 | 
			
		||||
            session.modified = True
 | 
			
		||||
    else:
 | 
			
		||||
        chan = filter_guild_channel(guild_id, channel_id)
 | 
			
		||||
        if not chan:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,43 @@
 | 
			
		||||
from titanembeds.utils import socketio
 | 
			
		||||
from titanembeds.utils import socketio, guild_accepts_visitors, get_client_ipaddr
 | 
			
		||||
from titanembeds.userbookkeeping import check_user_in_guild, get_guild_channels, update_user_status
 | 
			
		||||
from flask_socketio import Namespace, emit, disconnect, join_room
 | 
			
		||||
import functools
 | 
			
		||||
from flask import request, session
 | 
			
		||||
 | 
			
		||||
def authenticated_only(f):
 | 
			
		||||
    @functools.wraps(f)
 | 
			
		||||
    def wrapped(*args, **kwargs):
 | 
			
		||||
        if False:
 | 
			
		||||
            pass
 | 
			
		||||
            #disconnect()
 | 
			
		||||
        else:
 | 
			
		||||
            return f(*args, **kwargs)
 | 
			
		||||
    return wrapped
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
class Gateway(Namespace):
 | 
			
		||||
    def on_connect(self):
 | 
			
		||||
        emit('hello')
 | 
			
		||||
    
 | 
			
		||||
    def on_identify(self, data):
 | 
			
		||||
        room = data["guild_id"]
 | 
			
		||||
        join_room(room)
 | 
			
		||||
        guild_id = data["guild_id"]
 | 
			
		||||
        if not guild_accepts_visitors(guild_id) and not check_user_in_guild(guild_id):
 | 
			
		||||
            disconnect()
 | 
			
		||||
            return
 | 
			
		||||
        channels = []
 | 
			
		||||
        if guild_accepts_visitors(guild_id) and not check_user_in_guild(guild_id):
 | 
			
		||||
            channels = get_guild_channels(guild_id, force_everyone=True)
 | 
			
		||||
        else:
 | 
			
		||||
            channels = get_guild_channels(guild_id)
 | 
			
		||||
        join_room("GUILD_"+guild_id)
 | 
			
		||||
        for chan in channels:
 | 
			
		||||
            if chan["read"]:
 | 
			
		||||
                join_room("CHANNEL_"+chan["channel"]["id"])
 | 
			
		||||
        if session.get("unauthenticated", True) and guild_id in session.get("user_keys", {}):
 | 
			
		||||
            join_room("IP_"+get_client_ipaddr())
 | 
			
		||||
        elif not session.get("unauthenticated", True):
 | 
			
		||||
            join_room("USER_"+session["user_id"])
 | 
			
		||||
        emit("identified")
 | 
			
		||||
    
 | 
			
		||||
    def on_heartbeat(self, data):
 | 
			
		||||
        guild_id = data["guild_id"]
 | 
			
		||||
        visitor_mode = data["visitor_mode"]
 | 
			
		||||
        if not visitor_mode:
 | 
			
		||||
            status = update_user_status(guild_id, session["username"], session["user_keys"][guild_id])
 | 
			
		||||
            if status["revoked"] or status["banned"]:
 | 
			
		||||
                emit("revoke")
 | 
			
		||||
                time.sleep(1000)
 | 
			
		||||
                disconnect()
 | 
			
		||||
        else:
 | 
			
		||||
            if not guild_accepts_visitors(guild_id):
 | 
			
		||||
                disconnect()
 | 
			
		||||
@@ -17,17 +17,13 @@
 | 
			
		||||
    var has_already_been_focused = false; // keep track of if the embed has initially been focused.
 | 
			
		||||
    var has_already_been_initially_resized = false; // keep track if the embed initially been resized
 | 
			
		||||
    var logintimer; // timer to keep track of user inactivity after hitting login
 | 
			
		||||
    var fetchtimeout; // fetch routine timer
 | 
			
		||||
    var currently_fetching; // fetch lock- if true, do not fetch
 | 
			
		||||
    var last_message_id; // last message tracked
 | 
			
		||||
    var selected_channel = null; // user selected channel
 | 
			
		||||
    var guild_channels = {}; // all server channels used to highlight channels in messages
 | 
			
		||||
    var emoji_store = {}; // all server emojis
 | 
			
		||||
    var times_fetched = 0; // kept track of how many times that it has fetched
 | 
			
		||||
    var fetch_error_count = 0; // Number of errors fetch has encountered
 | 
			
		||||
    var priority_query_guild = false; // So you have selected a channel? Let's populate it.
 | 
			
		||||
    var current_username_discrim; // Current username/discrim pair, eg EndenDraogn#4151
 | 
			
		||||
    var visitor_mode = false; // Keep track of if using the visitor mode or authenticate mode
 | 
			
		||||
    var socket = null; // Socket.io object
 | 
			
		||||
 | 
			
		||||
    function element_in_view(element, fullyInView) {
 | 
			
		||||
        var pageTop = $(window).scrollTop();
 | 
			
		||||
@@ -249,6 +245,8 @@
 | 
			
		||||
        } else {
 | 
			
		||||
            primeEmbed();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        setInterval(send_socket_heartbeat, 5000);
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    function changeTheme(theme=null, keep_custom_css=true) {
 | 
			
		||||
@@ -339,6 +337,9 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function initialize_embed(guildobj) {
 | 
			
		||||
        if (socket) {
 | 
			
		||||
            socket.disconnect();
 | 
			
		||||
        }
 | 
			
		||||
        if (guildobj === undefined) {
 | 
			
		||||
            var guild = query_guild();
 | 
			
		||||
            guild.done(function(data) {
 | 
			
		||||
@@ -379,6 +380,7 @@
 | 
			
		||||
        fill_unauthenticated_users(guildobj.embedmembers.unauthenticated);
 | 
			
		||||
        $("#instant-inv").attr("href", guildobj.instant_invite);
 | 
			
		||||
        run_fetch_routine();
 | 
			
		||||
        initiate_websockets();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function fill_channels(channels) {
 | 
			
		||||
@@ -559,8 +561,6 @@
 | 
			
		||||
            last_message_id = null;
 | 
			
		||||
            $("#channels-list > li.active").removeClass("active");
 | 
			
		||||
            $("#channel-"+selected_channel).parent().addClass("active");
 | 
			
		||||
            priority_query_guild = true;
 | 
			
		||||
            clearTimeout(fetchtimeout);
 | 
			
		||||
            run_fetch_routine();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -718,11 +718,6 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function run_fetch_routine() {
 | 
			
		||||
        if (currently_fetching) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        currently_fetching = true;
 | 
			
		||||
        times_fetched += 1;
 | 
			
		||||
        var channel_id = selected_channel;
 | 
			
		||||
        var fet;
 | 
			
		||||
        var jumpscroll;
 | 
			
		||||
@@ -752,13 +747,11 @@
 | 
			
		||||
            }
 | 
			
		||||
            var guild = query_guild();
 | 
			
		||||
            guild.done(function(guildobj) {
 | 
			
		||||
                priority_query_guild = false;
 | 
			
		||||
                fill_channels(guildobj.channels);
 | 
			
		||||
                fill_discord_members(guildobj.discordmembers);
 | 
			
		||||
                fill_authenticated_users(guildobj.embedmembers.authenticated);
 | 
			
		||||
                fill_unauthenticated_users(guildobj.embedmembers.unauthenticated);
 | 
			
		||||
                $("#instant-inv").attr("href", guildobj.instant_invite);
 | 
			
		||||
                initiate_websockets();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        fet.fail(function(data) {
 | 
			
		||||
@@ -769,25 +762,9 @@
 | 
			
		||||
                $('#loginmodal').modal('open');
 | 
			
		||||
                Materialize.toast('Session expired! You have been logged out.', 10000);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (data.status != 429) {
 | 
			
		||||
                setVisitorMode(true);
 | 
			
		||||
                if (visitor_mode) {
 | 
			
		||||
                    fetchtimeout = setTimeout(run_fetch_routine, 5000);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        fet.catch(function(data) {
 | 
			
		||||
          if (500 <= data.status && data.status < 600) {
 | 
			
		||||
              if (fetch_error_count % 5 == 0) {
 | 
			
		||||
                  Materialize.toast('Fetching messages error! EndenDragon probably broke something. Sorry =(', 10000);
 | 
			
		||||
              }
 | 
			
		||||
              fetch_error_count += 1;
 | 
			
		||||
              fetchtimeout = setTimeout(run_fetch_routine, 10000);
 | 
			
		||||
          }
 | 
			
		||||
            setVisitorMode(true);
 | 
			
		||||
        });
 | 
			
		||||
        fet.always(function() {
 | 
			
		||||
            currently_fetching = false;
 | 
			
		||||
            $("#fetching-indicator").fadeOut(800);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
@@ -870,8 +847,6 @@
 | 
			
		||||
                var usr = change_unauthenticated_username($(this).val());
 | 
			
		||||
                usr.done(function(data) {
 | 
			
		||||
                    Materialize.toast('Username changed successfully!', 10000);
 | 
			
		||||
                    priority_query_guild = true;
 | 
			
		||||
                    clearTimeout(fetchtimeout);
 | 
			
		||||
                    run_fetch_routine();
 | 
			
		||||
                });
 | 
			
		||||
                usr.fail(function(data) {
 | 
			
		||||
@@ -900,8 +875,6 @@
 | 
			
		||||
            var funct = post(selected_channel, $(this).val());
 | 
			
		||||
            funct.done(function(data) {
 | 
			
		||||
                $("#messagebox").val("");
 | 
			
		||||
                clearTimeout(fetchtimeout);
 | 
			
		||||
                run_fetch_routine();
 | 
			
		||||
            });
 | 
			
		||||
            funct.fail(function(data) {
 | 
			
		||||
                Materialize.toast('Failed to send message.', 10000);
 | 
			
		||||
@@ -945,13 +918,40 @@
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    function initiate_websockets() {
 | 
			
		||||
        var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + "/gateway", {path: '/gateway', transports: ['websocket']});
 | 
			
		||||
        socket.on('connect', function() {
 | 
			
		||||
        if (socket) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + "/gateway", {path: '/gateway', transports: ['websocket']});
 | 
			
		||||
        socket.on('connect', function () {
 | 
			
		||||
            socket.emit('identify', {"guild_id": guild_id});
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        socket.on('MESSAGE_CREATE', function(msg) {
 | 
			
		||||
            console.log(msg);
 | 
			
		||||
        socket.on("disconnect", function () {
 | 
			
		||||
            socket = null;
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        socket.on("revoke", function () {
 | 
			
		||||
            $('#loginmodal').modal('open');
 | 
			
		||||
            setVisitorMode(true);
 | 
			
		||||
            primeEmbed();
 | 
			
		||||
            Materialize.toast('Authentication error! You have been disconnected by the server.', 10000);
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        socket.on("MESSAGE_CREATE", function (msg) {
 | 
			
		||||
            var thismsgchan = msg.channel_id;
 | 
			
		||||
            if (selected_channel != thismsgchan) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            var jumpscroll = element_in_view($('#discordmessage_'+last_message_id), true);
 | 
			
		||||
            last_message_id = fill_discord_messages([msg], jumpscroll);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    function send_socket_heartbeat() {
 | 
			
		||||
        if (!socket) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        socket.emit("heartbeat", {"guild_id": guild_id, "visitor_mode": visitor_mode});
 | 
			
		||||
    }
 | 
			
		||||
})();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										179
									
								
								webapp/titanembeds/userbookkeeping.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								webapp/titanembeds/userbookkeeping.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
			
		||||
from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, AuthenticatedUsers, GuildMembers, get_guild_member
 | 
			
		||||
from titanembeds.utils import guild_accepts_visitors, guild_query_unauth_users_bool, get_client_ipaddr
 | 
			
		||||
from titanembeds.oauth import check_user_can_administrate_guild, user_has_permission
 | 
			
		||||
from flask import session
 | 
			
		||||
from sqlalchemy import and_
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
def user_unauthenticated():
 | 
			
		||||
    if 'unauthenticated' in session:
 | 
			
		||||
        return session['unauthenticated']
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
def checkUserRevoke(guild_id, user_key=None):
 | 
			
		||||
    revoked = True #guilty until proven not revoked
 | 
			
		||||
    if user_unauthenticated():
 | 
			
		||||
        dbUser = db.session.query(UnauthenticatedUsers).filter(UnauthenticatedUsers.guild_id == guild_id, UnauthenticatedUsers.user_key == user_key).first()
 | 
			
		||||
        revoked = dbUser.isRevoked()
 | 
			
		||||
    else:
 | 
			
		||||
        banned = checkUserBanned(guild_id)
 | 
			
		||||
        if banned:
 | 
			
		||||
            return revoked
 | 
			
		||||
        dbUser = GuildMembers.query.filter(GuildMembers.guild_id == guild_id).filter(GuildMembers.user_id == session["user_id"]).first()
 | 
			
		||||
        revoked = not dbUser or not dbUser.active
 | 
			
		||||
    return revoked
 | 
			
		||||
 | 
			
		||||
def checkUserBanned(guild_id, ip_address=None):
 | 
			
		||||
    banned = True
 | 
			
		||||
    if user_unauthenticated():
 | 
			
		||||
        dbUser = UnauthenticatedBans.query.filter(and_(UnauthenticatedBans.guild_id == guild_id, UnauthenticatedBans.ip_address == ip_address)).all()
 | 
			
		||||
        if not dbUser:
 | 
			
		||||
            banned = False
 | 
			
		||||
        else:
 | 
			
		||||
            for usr in dbUser:
 | 
			
		||||
                if usr.lifter_id is not None:
 | 
			
		||||
                    banned = False
 | 
			
		||||
    else:
 | 
			
		||||
        banned = False
 | 
			
		||||
        dbUser = GuildMembers.query.filter(GuildMembers.guild_id == guild_id).filter(GuildMembers.user_id == session["user_id"]).first()
 | 
			
		||||
        if not dbUser:
 | 
			
		||||
            banned = False
 | 
			
		||||
        else:
 | 
			
		||||
            banned = dbUser.banned
 | 
			
		||||
    return banned
 | 
			
		||||
 | 
			
		||||
def update_user_status(guild_id, username, user_key=None):
 | 
			
		||||
    if user_unauthenticated():
 | 
			
		||||
        ip_address = get_client_ipaddr()
 | 
			
		||||
        status = {
 | 
			
		||||
            'authenticated': False,
 | 
			
		||||
            'avatar': None,
 | 
			
		||||
            'manage_embed': False,
 | 
			
		||||
            'ip_address': ip_address,
 | 
			
		||||
            'username': username,
 | 
			
		||||
            'nickname': None,
 | 
			
		||||
            'user_key': user_key,
 | 
			
		||||
            'guild_id': guild_id,
 | 
			
		||||
            'user_id': session['user_id'],
 | 
			
		||||
            'banned': checkUserBanned(guild_id, ip_address),
 | 
			
		||||
            'revoked': checkUserRevoke(guild_id, user_key),
 | 
			
		||||
        }
 | 
			
		||||
        if status['banned'] or status['revoked']:
 | 
			
		||||
            session['user_keys'].pop(guild_id, None)
 | 
			
		||||
            return status
 | 
			
		||||
        dbUser = UnauthenticatedUsers.query.filter(and_(UnauthenticatedUsers.guild_id == guild_id, UnauthenticatedUsers.user_key == user_key)).first()
 | 
			
		||||
        dbUser.bumpTimestamp()
 | 
			
		||||
        if dbUser.username != username or dbUser.ip_address != ip_address:
 | 
			
		||||
            dbUser.username = username
 | 
			
		||||
            dbUser.ip_address = ip_address
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
    else:
 | 
			
		||||
        status = {
 | 
			
		||||
            'authenticated': True,
 | 
			
		||||
            'avatar': session["avatar"],
 | 
			
		||||
            'manage_embed': check_user_can_administrate_guild(guild_id),
 | 
			
		||||
            'username': username,
 | 
			
		||||
            'nickname': None,
 | 
			
		||||
            'discriminator': session['discriminator'],
 | 
			
		||||
            'guild_id': guild_id,
 | 
			
		||||
            'user_id': session['user_id'],
 | 
			
		||||
            'banned': checkUserBanned(guild_id),
 | 
			
		||||
            'revoked': checkUserRevoke(guild_id)
 | 
			
		||||
        }
 | 
			
		||||
        if status['banned'] or status['revoked']:
 | 
			
		||||
            return status
 | 
			
		||||
        dbMember = get_guild_member(guild_id, status["user_id"])
 | 
			
		||||
        if dbMember:
 | 
			
		||||
            status["nickname"] = dbMember.nickname
 | 
			
		||||
        dbUser = db.session.query(AuthenticatedUsers).filter(and_(AuthenticatedUsers.guild_id == guild_id, AuthenticatedUsers.client_id == status['user_id'])).first()
 | 
			
		||||
        dbUser.bumpTimestamp()
 | 
			
		||||
    return status
 | 
			
		||||
 | 
			
		||||
def check_user_in_guild(guild_id):
 | 
			
		||||
    if user_unauthenticated():
 | 
			
		||||
        return guild_id in session.get("user_keys", {})
 | 
			
		||||
    else:
 | 
			
		||||
        dbUser = db.session.query(AuthenticatedUsers).filter(and_(AuthenticatedUsers.guild_id == guild_id, AuthenticatedUsers.client_id == session['user_id'])).first()
 | 
			
		||||
        return dbUser is not None and not checkUserRevoke(guild_id)
 | 
			
		||||
 | 
			
		||||
def get_member_roles(guild_id, user_id):
 | 
			
		||||
    q = db.session.query(GuildMembers).filter(GuildMembers.guild_id == guild_id).filter(GuildMembers.user_id == user_id).first()
 | 
			
		||||
    return json.loads(q.roles)
 | 
			
		||||
 | 
			
		||||
def get_guild_channels(guild_id, force_everyone=False):
 | 
			
		||||
    if user_unauthenticated() or force_everyone:
 | 
			
		||||
        member_roles = [guild_id] #equivilant to @everyone role
 | 
			
		||||
    else:
 | 
			
		||||
        member_roles = get_member_roles(guild_id, session['user_id'])
 | 
			
		||||
        if guild_id not in member_roles:
 | 
			
		||||
            member_roles.append(guild_id)
 | 
			
		||||
    dbguild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first()
 | 
			
		||||
    guild_channels = json.loads(dbguild.channels)
 | 
			
		||||
    guild_roles = json.loads(dbguild.roles)
 | 
			
		||||
    guild_owner = str(dbguild.owner_id)
 | 
			
		||||
    result_channels = []
 | 
			
		||||
    for channel in guild_channels:
 | 
			
		||||
        if channel['type'] == "text":
 | 
			
		||||
            result = {"channel": channel, "read": False, "write": False, "mention_everyone": False}
 | 
			
		||||
            if guild_owner == session.get("user_id"):
 | 
			
		||||
                result["read"] = True
 | 
			
		||||
                result["write"] = True
 | 
			
		||||
                result["mention_everyone"] = True
 | 
			
		||||
                result_channels.append(result)
 | 
			
		||||
                continue
 | 
			
		||||
            channel_perm = 0
 | 
			
		||||
 | 
			
		||||
            # @everyone
 | 
			
		||||
            for role in guild_roles:
 | 
			
		||||
                if role["id"] == guild_id:
 | 
			
		||||
                    channel_perm |= role["permissions"]
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
            # User Guild Roles
 | 
			
		||||
            for m_role in member_roles:
 | 
			
		||||
                for g_role in guild_roles:
 | 
			
		||||
                    if g_role["id"] == m_role:
 | 
			
		||||
                        channel_perm |= g_role["permissions"]
 | 
			
		||||
                        continue
 | 
			
		||||
 | 
			
		||||
            # If has server administrator permission
 | 
			
		||||
            if user_has_permission(channel_perm, 3):
 | 
			
		||||
                result["read"] = True
 | 
			
		||||
                result["write"] = True
 | 
			
		||||
                result["mention_everyone"] = True
 | 
			
		||||
                result_channels.append(result)
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            denies = 0
 | 
			
		||||
            allows = 0
 | 
			
		||||
 | 
			
		||||
            # channel specific
 | 
			
		||||
            for overwrite in channel["permission_overwrites"]:
 | 
			
		||||
                if overwrite["type"] == "role" and overwrite["id"] in member_roles:
 | 
			
		||||
                    denies |= overwrite["deny"]
 | 
			
		||||
                    allows |= overwrite["allow"]
 | 
			
		||||
 | 
			
		||||
            channel_perm = (channel_perm & ~denies) | allows
 | 
			
		||||
 | 
			
		||||
            # member specific
 | 
			
		||||
            for overwrite in channel["permission_overwrites"]:
 | 
			
		||||
                if overwrite["type"] == "member" and overwrite["id"] == session.get("user_id"):
 | 
			
		||||
                    channel_perm = (channel_perm & ~overwrite['deny']) | overwrite['allow']
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
            result["read"] = user_has_permission(channel_perm, 10)
 | 
			
		||||
            result["write"] = user_has_permission(channel_perm, 11)
 | 
			
		||||
            result["mention_everyone"] = user_has_permission(channel_perm, 17)
 | 
			
		||||
 | 
			
		||||
            # If default channel, you can read
 | 
			
		||||
            if channel["id"] == guild_id:
 | 
			
		||||
                result["read"] = True
 | 
			
		||||
 | 
			
		||||
            # If you cant read channel, you cant write in it
 | 
			
		||||
            if not user_has_permission(channel_perm, 10):
 | 
			
		||||
                result["read"] = False
 | 
			
		||||
                result["write"] = False
 | 
			
		||||
                result["mention_everyone"] = False
 | 
			
		||||
 | 
			
		||||
            result_channels.append(result)
 | 
			
		||||
    return sorted(result_channels, key=lambda k: k['channel']['position'])
 | 
			
		||||
		Reference in New Issue
	
	Block a user