예제 #1
0
def start_server():
    ''' Main entry point for the application '''
    if options.debug:
        logging.warn("%sDebug mode is enabled; DO NOT USE THIS IN PRODUCTION%s" % (
            bold + R, W
        ))
    if options.autostart_game:
        logging.info("The game is about to begin, good hunting!")
        app.settings['history_callback'].start()
        if options.use_bots:
            app.settings['score_bots_callback'].start()
    # Setup server object
    if options.ssl:
        server = HTTPServer(app,
                            ssl_options={
                                "certfile": options.certfile,
                                "keyfile": options.keyfile,
                            },
                            xheaders=options.x_headers
                            )
    else:
        server = HTTPServer(app, xheaders=options.x_headers)
    sockets = netutil.bind_sockets(options.listen_port, options.listen_interface)
    server.add_sockets(sockets)
    Scoreboard.now(app)
    try:
        io_loop.start()
    except KeyboardInterrupt:
        sys.stdout.write('\r' + WARN + 'Shutdown Everything!\n')
    except:
        logging.exception("Main i/o loop threw exception")
    finally:
        io_loop.stop()
        _exit(0)
예제 #2
0
def start_server():
    """ Main entry point for the application """
    locale.set_default_locale("en_US")
    locale.load_translations("locale")
    if options.autostart_game:
        app.settings["game_started"] = True
        app.settings["history_callback"].start()
        if options.use_bots:
            app.settings["score_bots_callback"].start()
    # Setup server object
    if options.ssl:
        server = HTTPServer(
            app,
            ssl_options={"certfile": options.certfile, "keyfile": options.keyfile},
            xheaders=options.x_headers,
        )
    else:
        server = HTTPServer(app, xheaders=options.x_headers)
    try:
        sockets = netutil.bind_sockets(options.listen_port, options.listen_interface)
    except (OSError, IOError) as err:
        logging.error("Problem binding socket to port %s", str(options.listen_port))
        if err.errno == 13:
            pypath = sys.executable
            if os_path.islink(pypath):
                pypath = os_path.realpath(pypath)
            logging.error(
                "Possible Fix: sudo setcap CAP_NET_BIND_SERVICE=+eip %s", pypath
            )
        elif err.errno == 98:
            logging.error(
                "The port may be in use by an existing service.  RTB already running?"
            )
        else:
            logging.error(err)
        sys.exit()
    server.add_sockets(sockets)
    if options.debug:
        logging.warn(
            "%sDebug mode is enabled; DO NOT USE THIS IN PRODUCTION%s" % (bold + R, W)
        )
    if options.autostart_game:
        logging.info("The game is about to begin, good hunting!")
    try:
        Scoreboard.update_gamestate(app)
    except OperationalError as err:
        if "Table definition has changed" in str(err):
            logging.info("Table definitions have changed -restarting RootTheBox.")
            return "restart"
        else:
            logging.error("There was a problem starting RootTheBox. Error: " + str(err))
    try:
        io_loop.start()
    except KeyboardInterrupt:
        sys.stdout.write("\r" + WARN + "Shutdown Everything!\n")
    except:
        logging.exception("Main i/o loop threw exception")
    finally:
        io_loop.stop()
        _exit(0)
예제 #3
0
def start_server():
    ''' Main entry point for the application '''
    if options.debug:
        logging.warn(
            "%sDebug mode is enabled; DO NOT USE THIS IN PRODUCTION%s" %
            (bold + R, W))
    if options.autostart_game:
        logging.info("The game is about to begin, good hunting!")
        app.settings['history_callback'].start()
        if options.use_bots:
            app.settings['score_bots_callback'].start()
    # Setup server object
    if options.ssl:
        server = HTTPServer(app,
                            ssl_options={
                                "certfile": options.certfile,
                                "keyfile": options.keyfile,
                            },
                            xheaders=options.x_headers)
    else:
        server = HTTPServer(app, xheaders=options.x_headers)
    sockets = netutil.bind_sockets(options.listen_port,
                                   options.listen_interface)
    server.add_sockets(sockets)
    Scoreboard.now(app)
    try:
        io_loop.start()
    except KeyboardInterrupt:
        sys.stdout.write('\r' + WARN + 'Shutdown Everything!\n')
    except:
        logging.exception("Main i/o loop threw exception")
    finally:
        io_loop.stop()
        _exit(0)
예제 #4
0
    def create_team(self):
        """ Admins can create teams manually """
        try:
            name = self.get_argument("team_name", "")
            if Team.by_name(name) is not None:
                raise ValidationError("Team already exists")
            team = Team()
            team.name = self.get_argument("team_name", "")
            team.motto = self.get_argument("motto", "")
            if not self.config.banking:
                team.money = 0
            level_0 = GameLevel.by_number(0)
            if not level_0:
                level_0 = GameLevel.all()[0]
            team.game_levels.append(level_0)
            self.dbsession.add(team)
            self.dbsession.commit()

            # Avatar
            avatar_select = self.get_argument("team_avatar_select", "")
            if avatar_select and len(avatar_select) > 0:
                team._avatar = avatar_select
            elif hasattr(self.request, "files") and "avatar" in self.request.files:
                team.avatar = self.request.files["avatar"][0]["body"]
            self.dbsession.add(team)
            self.dbsession.commit()
            Scoreboard.update_gamestate(self)
            self.redirect("/admin/users")
        except ValidationError as error:
            self.render("admin/create/team.html", errors=[str(error)])
예제 #5
0
 def on_message(self, message):
     """ We ignore messages if there are more than 1 every 3 seconds """
     if self.application.settings["freeze_scoreboard"]:
         self.write_message("pause")
     elif datetime.now() - self.last_message > timedelta(seconds=3):
         self.last_message = datetime.now()
         Scoreboard.update_gamestate(self)
         self.write_message(Scoreboard.now(self))
예제 #6
0
 def get(self, *args, **kargs):
     user = self.get_current_user()
     if scoreboard_visible(user):
         Scoreboard.update_gamestate(self)
         self.render("scoreboard/summary.html", timer=self.timer())
     elif not user:
         self.redirect("/login")
     else:
         self.render("public/404.html")
예제 #7
0
def start_server():
    """ Main entry point for the application """
    if options.debug:
        logging.warn(
            "%sDebug mode is enabled; DO NOT USE THIS IN PRODUCTION%s" %
            (bold + R, W))
    if options.autostart_game:
        logging.info("The game is about to begin, good hunting!")
        app.settings["history_callback"].start()
        if options.use_bots:
            app.settings["score_bots_callback"].start()
    # Setup server object
    if options.ssl:
        server = HTTPServer(
            app,
            ssl_options={
                "certfile": options.certfile,
                "keyfile": options.keyfile
            },
            xheaders=options.x_headers,
        )
    else:
        server = HTTPServer(app, xheaders=options.x_headers)
    try:
        sockets = netutil.bind_sockets(options.listen_port,
                                       options.listen_interface)
    except (OSError, IOError) as err:
        if err.errno == 13:
            pypath = sys.executable
            if os_path.islink(pypath):
                pypath = os_path.realpath(pypath)
            logging.error("Problem binding to port %s",
                          str(options.listen_port))
            logging.error(
                "Possible Fix: sudo setcap CAP_NET_BIND_SERVICE=+eip %s",
                pypath)
            sys.exit()
    server.add_sockets(sockets)
    Scoreboard.now(app)
    try:
        io_loop.start()
    except KeyboardInterrupt:
        sys.stdout.write("\r" + WARN + "Shutdown Everything!\n")
    except:
        logging.exception("Main i/o loop threw exception")
    finally:
        io_loop.stop()
        _exit(0)
예제 #8
0
 def on_message(self, message):
     ''' We ignore messages if there are more than 1 every 3 seconds '''
     if self.application.settings['freeze_scoreboard']:
         self.write_message("pause")
     elif datetime.now() - self.last_message > timedelta(seconds=3):
         self.last_message = datetime.now()
         self.write_message(Scoreboard.now())
예제 #9
0
 def open(self):
     """ When we receive a new websocket connect """
     self.connections.add(self)
     if self.application.settings["freeze_scoreboard"]:
         self.write_message("pause")
     else:
         self.write_message(Scoreboard.now(self))
예제 #10
0
 def open(self):
     ''' When we receive a new websocket connect '''
     self.connections.add(self)
     if self.application.settings['freeze_scoreboard']:
         self.write_message("pause")
     else:
         self.write_message(Scoreboard.now())
예제 #11
0
    def create_user(self):
        """ Add user to the database """
        if User.by_handle(self.get_argument("handle", "")) is not None:
            raise ValidationError("This handle is already registered")
        if self.get_argument("pass1", "") != self.get_argument("pass2", ""):
            raise ValidationError("Passwords do not match")
        user = User()
        user.handle = self.get_argument("handle", "")
        user.password = self.get_argument("pass1", "")
        user.bank_password = self.get_argument("bpass", "")
        user.name = self.get_argument("playername", "")
        user.email = self.get_argument("email", "")
        team = self.get_team()
        self.dbsession.add(user)
        self.dbsession.add(team)
        self.dbsession.commit()

        # Avatar
        avatar_select = self.get_argument("user_avatar_select", "")
        if avatar_select and len(avatar_select) > 0:
            user._avatar = avatar_select
        elif hasattr(self.request, "files") and "avatar" in self.request.files:
            user.avatar = self.request.files["avatar"][0]["body"]
        team.members.append(user)
        if not options.teams:
            if avatar_select and len(avatar_select) > 0:
                team._avatar = avatar_select
            elif hasattr(self.request, "files") and "avatar" in self.request.files:
                team.avatar = self.request.files["avatar"][0]["body"]
        self.dbsession.add(user)
        self.dbsession.add(team)
        self.dbsession.commit()
        Scoreboard.update_gamestate(self)
        self.event_manager.user_joined_team(user)

        # Chat
        if self.chatsession:
            self.chatsession.create_user(user, self.get_argument("pass1", ""))

        return user
예제 #12
0
 def get(self, *args, **kargs):
     user = self.get_current_user()
     try:
         page = int(self.get_argument("page", 1))
         display = int(self.get_argument("count", 50))
     except ValueError:
         page = 1
         display = 50
     if scoreboard_visible(user):
         teamcount = Scoreboard.update_gamestate(self)
         self.render(
             "scoreboard/summary.html",
             timer=self.timer(),
             hide_scoreboard=self.application.settings["hide_scoreboard"],
             page=page,
             display=display,
             teamcount=teamcount,
         )
     elif not user:
         self.redirect("/login")
     else:
         self.render("public/404.html")
예제 #13
0
class EventManager(object):
    '''
    All event callbacks go here!
    This class holds refs to all open web sockets
    '''
    def __init__(self):
        self.notify_connections = {}
        self.scoreboard_connections = []
        self.history_connections = []
        self.scoreboard = Scoreboard()

    @property
    def users_online(self):
        ''' Number of currently open notify sockets '''
        sumation = 0
        for team_id in self.notify_connections:
            sumation += len(self.notify_connections[team_id])
        return sumation

    def is_online(self, user):
        ''' 
        Returns bool if the given user has an open notify socket
        '''
        if user.team.id in self.notify_connections:
            if user.id in self.notify_connections[user.team.id]:
                return 0 < len(self.notify_connections[user.team.id][user.id])
        return False

    # [ Connection Methods ] -----------------------------------------------
    def add_connection(self, wsocket):
        ''' Add a connection '''
        if not wsocket.team_id in self.notify_connections:
            self.notify_connections[wsocket.team_id] = {}
        if wsocket.user_id in self.notify_connections[wsocket.team_id]:
            self.notify_connections[wsocket.team_id][wsocket.user_id].append(
                wsocket)
        else:
            self.notify_connections[wsocket.team_id][wsocket.user_id] = [
                wsocket
            ]

    def remove_connection(self, wsocket):
        ''' Remove connection '''
        self.notify_connections[wsocket.team_id][wsocket.user_id].remove(
            wsocket)
        if len(self.notify_connections[wsocket.team_id][wsocket.user_id]) == 0:
            del self.notify_connections[wsocket.team_id][wsocket.user_id]

    def deauth(self, user):
        if user.team.id in self.notify_connections:
            if user.id in self.notify_connections[user.team.id]:
                wsocks = self.notify_connections[user.team.id][user.id]
                for wsock in wsocks:
                    wsock.write_message(
                        {'warn': "You have been deauthenticated"})
                    wsock.close()

    # [ Push Updates ] -----------------------------------------------------
    def refresh_scoreboard(self):
        ''' Push to everyone '''
        update = self.scoreboard.now()
        for wsocket in self.scoreboard_connections:
            wsocket.write_message(update)

    def push_history(self, snapshot):
        ''' Push latest snapshot to everyone '''
        for wsocket in self.history_connections:
            wsocket.write_message({'update': snapshot})

    def push_broadcast_notification(self, event_uuid):
        ''' Push to everyone '''
        json = Notification.by_event_uuid(event_uuid).to_json()
        for team_id in self.notify_connections:
            for user_id in self.notify_connections[team_id]:
                for wsocket in self.notify_connections[team_id][user_id]:
                    wsocket.write_message(json)
                    # Only mark delivered for non-public users
                    if wsocket.user_id != '$public_user':
                        Notification.delivered(user_id, event_uuid)

    def push_team_notification(self, event_uuid, team_id):
        ''' Push to one team '''
        if team_id in self.notify_connections:
            json = Notification.by_event_uuid(event_uuid).to_json()
            for user_id in self.notify_connections[team_id]:
                for wsocket in self.notify_connections[team_id][user_id]:
                    wsocket.write_message(json)
                    Notification.delivered(wsocket.user_id, event_uuid)

    def push_user_notification(self, event_uuid, team_id, user_id):
        ''' Push to one user '''
        if team_id in self.notify_connections and user_id in self.notify_connections[
                team_id]:
            json = Notification.by_event_uuid(event_uuid).to_json()
            for wsocket in self.notify_connections[team_id][user_id]:
                wsocket.write_message(json)
                Notification.delivered(wsocket.user_id, event_uuid)

    # [ Broadcast Events ] -------------------------------------------------
    def create_flag_capture_event(self, user, flag):
        ''' Callback for when a flag is captured '''
        self.refresh_scoreboard()
        evt_id = Notifier.broadcast_success(
            "Flag Capture", "%s has captured '%s'." % (
                user.team.name,
                flag.name,
            ))
        return (self.push_broadcast_notification, {'event_uuid': evt_id})

    def create_unlocked_level_event(self, user, level):
        ''' Callback for when a team unlocks a new level '''
        self.refresh_scoreboard()
        message = "%s unlocked level #%d." % (
            user.team.name,
            level.number,
        )
        evt_id = Notifier.broadcast_success("Level Unlocked", message)
        return (self.push_broadcast_notification, {'event_uuid': evt_id})

    def create_purchased_item_event(self, user, item):
        ''' Callback when a team purchases an item '''
        self.refresh_scoreboard()
        message = "%s purchased %s from the black market." % (
            user.handle,
            item.name,
        )
        evt_id = Notifier.team_success(user.team, "Upgrade Purchased", message)
        self.push_broadcast_notification(evt_id)
        message2 = "%s unlocked %s." % (
            user.team.name,
            item.name,
        )
        evt_id2 = Notifier.broadcast_warning("Team Upgrade", message2)
        return (self.push_broadcast_notification, {'event_uuid': evt_id2})

    def create_swat_player_event(self, user, target):
        message("%s called the SWAT team on %s." % (
            user.handle,
            target.handle,
        ))
        evt_id = Notifier.broadcast_warning("Player Arrested!", message)
        return (self.push_broadcast_notification, {'event_uuid': evt_id})

    # [ Team Events ] ------------------------------------------------------
    def create_joined_team_event(self, user):
        ''' Callback when a user joins a team'''
        message = "%s has joined your team." % user.handle
        evt_id = Notifier.team_success(user.team, "New Team Member", message)
        return (self.push_team_notification, {
            'event_uuid': evt_id,
            'team_id': user.team.id
        })

    def create_team_file_share_event(self, user, file_upload):
        ''' Callback when a team file share is created '''
        message = "%s has shared a file called '%s'" % (
            user.handle,
            file_upload.file_name,
        )
        evt_id = Notifier.team_success(user.team, "File Share", message)
        return (self.push_team_notification, {
            'event_uuid': evt_id,
            'team_id': user.team.id
        })

    def create_paste_bin_event(self, user, paste):
        ''' Callback when a pastebin is created '''
        message = "%s posted to the team paste-bin" % user.handle
        evt_id = Notifier.team_success(user.team, "Text Share", message)
        return (self.push_team_notification, {
            'event_uuid': evt_id,
            'team_id': user.team.id
        })

    # [ Misc Events ] ------------------------------------------------------
    def create_cracked_password_events(self, cracker, victim, password, value):
        user_msg = "Your password '%s' was cracked by %s." % (
            password,
            cracker.handle,
        )
        evt_id = Notifier.user_warning(victim, "Security Breach", user_msg)
        event1 = (self.push_user_notification, {
            'event_uuid': evt_id,
            'team_id': victim.team.id,
            'user_id': victim.id
        })
        message = "%s hacked %s's bank account and stole $%d" % (
            cracker.handle,
            victim.team.name,
            value,
        )
        evt_id = Notifier.broadcast_custom("Password Cracked", message,
                                           cracker.avatar)
        event2 = (self.push_broadcast_notification, {'event_uuid': evt_id})
        return event1, event2
예제 #14
0
 def __init__(self):
     self.notify_connections = {}
     self.scoreboard_connections = []
     self.history_connections = []
     self.scoreboard = Scoreboard()
예제 #15
0
 def __init__(self):
     self.notify_connections = {}
     self.scoreboard_connections = []
     self.history_connections = []
     self.scoreboard = Scoreboard()
예제 #16
0
class EventManager(object):
    '''
    All event callbacks go here!
    This class holds refs to all open web sockets
    '''

    def __init__(self):
        self.notify_connections = {}
        self.scoreboard_connections = []
        self.history_connections = []
        self.scoreboard = Scoreboard()

    @property
    def users_online(self):
        ''' Number of currently open notify sockets '''
        sumation = 0
        for team_id in self.notify_connections:
            sumation += len(self.notify_connections[team_id])
        return sumation

    def is_online(self, user):
        ''' 
        Returns bool if the given user has an open notify socket
        '''
        if user.team.id in self.notify_connections:
            if user.id in self.notify_connections[user.team.id]:
                return 0 < len(self.notify_connections[user.team.id][user.id])
        return False

    # [ Connection Methods ] -----------------------------------------------
    def add_connection(self, wsocket):
        ''' Add a connection '''
        if not wsocket.team_id in self.notify_connections:
            self.notify_connections[wsocket.team_id] = {}
        if wsocket.user_id in self.notify_connections[wsocket.team_id]:
            self.notify_connections[wsocket.team_id][wsocket.user_id].append(wsocket)
        else:
            self.notify_connections[wsocket.team_id][wsocket.user_id] = [wsocket]

    def remove_connection(self, wsocket):
        ''' Remove connection '''
        self.notify_connections[wsocket.team_id][wsocket.user_id].remove(wsocket)
        if len(self.notify_connections[wsocket.team_id][wsocket.user_id]) == 0:
            del self.notify_connections[wsocket.team_id][wsocket.user_id]

    def deauth(self, user):
        if user.team.id in self.notify_connections:
            if user.id in self.notify_connections[user.team.id]:
                wsocks = self.notify_connections[user.team.id][user.id]
                for wsock in wsocks:
                    wsock.write_message({
                        'warn': "You have been deauthenticated"
                    })
                    wsock.close()

    # [ Push Updates ] -----------------------------------------------------
    def refresh_scoreboard(self):
        ''' Push to everyone '''
        update = self.scoreboard.now()
        for wsocket in self.scoreboard_connections:
            wsocket.write_message(update)

    def push_history(self, snapshot):
        ''' Push latest snapshot to everyone '''
        for wsocket in self.history_connections:
            wsocket.write_message({'update': snapshot})

    def push_broadcast_notification(self, event_uuid):
        ''' Push to everyone '''
        json = Notification.by_event_uuid(event_uuid).to_json()
        for team_id in self.notify_connections:
            for user_id in self.notify_connections[team_id]:
                for wsocket in self.notify_connections[team_id][user_id]:
                    wsocket.write_message(json)
                    # Only mark delivered for non-public users
                    if wsocket.user_id != '$public_user':
                        Notification.delivered(user_id, event_uuid)

    def push_team_notification(self, event_uuid, team_id):
        ''' Push to one team '''
        if team_id in self.notify_connections:
            json = Notification.by_event_uuid(event_uuid).to_json()
            for user_id in self.notify_connections[team_id]:
                for wsocket in self.notify_connections[team_id][user_id]:
                    wsocket.write_message(json)
                    Notification.delivered(wsocket.user_id, event_uuid)

    def push_user_notification(self, event_uuid, team_id, user_id):
        ''' Push to one user '''
        if team_id in self.notify_connections and user_id in self.notify_connections[team_id]:
            json = Notification.by_event_uuid(event_uuid).to_json()
            for wsocket in self.notify_connections[team_id][user_id]:
                wsocket.write_message(json)
                Notification.delivered(wsocket.user_id, event_uuid)

    # [ Broadcast Events ] -------------------------------------------------
    def flag_capture(self, user, flag):
        ''' Callback for when a flag is captured '''
        self.refresh_scoreboard()
        evt_id = Notifier.broadcast_success("Flag Capture", 
            "%s has captured '%s'." % (user.team.name, flag.name,)
        )
        self.push_broadcast_notification(evt_id)

    def unlocked_level(self, user, level):
        ''' Callback for when a team unlocks a new level '''
        self.refresh_scoreboard()
        message = "%s unlocked level #%d." % (user.team.name, level.number,)
        evt_id = Notifier.broadcast_success("Level Unlocked", message)
        self.push_broadcast_notification(evt_id)

    def purchased_item(self, user, item):
        ''' Callback when a team purchases an item '''
        self.refresh_scoreboard()
        message = "%s purchased %s from the black market." % (
            user.handle, item.name,
        )
        evt_id = Notifier.team_success(user.team, "Upgrade Purchased", message)
        self.push_broadcast_notification(evt_id)
        message2 = "%s unlocked %s." % (user.team.name, item.name,)
        evt_id2 = Notifier.broadcast_warning("Team Upgrade", message2)
        self.push_broadcast_notification(evt_id2)

    def swat_player(self, user, target):
        message("%s called the SWAT team on %s." % (user.handle, target.handle,))
        evt_id = Notifier.broadcast_warning("Player Arrested!", message)
        self.push_broadcast_notification(evt_id)

    # [ Team Events ] ------------------------------------------------------
    def joined_team(self, user):
        ''' Callback when a user joins a team'''
        message = "%s has joined your team." % user.handle
        evt_id = Notifier.team_success(user.team, "New Team Member", message)
        self.push_team_notification(evt_id, user.team.id)

    def team_file_share(self, user, file_upload):
        ''' Callback when a team file share is created '''
        message = "%s has shared a file called '%s'" % (
            user.handle, file_upload.file_name,
        )
        evt_id = Notifier.team_success(user.team, "File Share", message)
        self.push_team_notification(evt_id, user.team.id)

    def paste_bin(self, user, paste):
        ''' Callback when a pastebin is created '''
        message = "%s posted to the team paste-bin" % user.handle
        evt_id = Notifier.team_success(user.team, "Text Share", message)
        self.push_team_notification(evt_id, user.team.id)

    # [ Misc Events ] ------------------------------------------------------
    def cracked_password(self, cracker, victim, password, value):
        user_msg = "Your password '%s' was cracked by %s." % (
            password, cracker.handle,
        )
        evt_id = Notifier.user_warning(victim, "Security Breach", user_msg)
        self.push_user_notification(evt_id, victim.team.id, victim.id)
        message = "%s hacked %s's bank account and stole $%d" % (
            cracker.handle, victim.team.name, value,
        )
        evt_id = Notifier.broadcast_custom("Password Cracked",
            message, cracker.avatar
        )
        self.push_broadcast_notification(evt_id)
 def on_message(self, message):
     ''' We ignore messages if there are more than 1 every 5 seconds '''
     if self.last_message - datetime.now() > timedelta(seconds=5):
         self.last_message = datetime.now()
         self.write_message(Scoreboard.now())
 def open(self):
     ''' When we receive a new websocket connect '''
     self.connections.add(self)
     self.write_message(Scoreboard.now())
예제 #19
0
class EventManager(object):
    '''
    All event callbacks go here!
    This class holds refs to all open web sockets
    '''

    def __init__(self):
        self.botnets = {}
        self.notify_connections = {}
        self.scoreboard_connections = []
        self.history_connections = []
        self.scoreboard = Scoreboard()

    # [ Connection Methods ] -----------------------------------------------

    @debug
    def add_connection(self, wsocket):
        ''' Add a connection '''
        if not wsocket.team_id in self.notify_connections:
            self.notify_connections[wsocket.team_id] = {}
        if wsocket.user_id in self.notify_connections[wsocket.team_id]:
            self.notify_connections[wsocket.team_id][wsocket.user_id].append(wsocket)
        else:
            self.notify_connections[wsocket.team_id][wsocket.user_id] = [wsocket]

    @debug
    def remove_connection(self, wsocket):
        ''' Remove connection '''
        self.notify_connections[wsocket.team_id][wsocket.user_id].remove(wsocket)
        if len(self.notify_connections[wsocket.team_id][wsocket.user_id]) == 0:
            del self.notify_connections[wsocket.team_id][wsocket.user_id]

    @debug
    def add_bot(self, bot_socket):
        ''' Add a bot to a team's botnet '''
        if not bot_socket.team.id in self.botnets:
            self.botnets[bot_socket.team.id] = {}
        if bot_socket.box.id in self.botnets[bot_socket.team.id]:
            self.botnets[bot_socket.team.id][bot_socket.box.id].close()
            del self.botnets[bot_socket.team.id][bot_socket.box.id]
        self.botnets[bot_socket.team.id][bot_socket.box.id] = bot_socket

    @debug
    def remove_bot(self, bot_socket):
        ''' Remove ref to bot connection '''
        del self.botnets[bot_socket.team.id][bot_socket.box.id]

    @debug
    def bot_count(self, team):
        ''' Get number of current bots owned by a given team '''
        if team.id in self.botnets:
            return len(self.botnets[team.id].keys())
        else:
            return 0

    @debug
    def deauth(self, user):
        pass  # Remove all socket objects for user

    # [ Push Updates ] -----------------------------------------------------

    @debug
    def refresh_scoreboard(self):
        ''' Push to everyone '''
        update = self.scoreboard.now()
        for wsocket in self.scoreboard_connections:
            wsocket.write_message(update)

    @debug
    def push_history(self, snapshot):
        ''' Push latest snapshot to everyone '''
        for wsocket in self.history_connections:
            wsocket.write_message({'update': snapshot})

    @debug
    def push_broadcast_notification(self, event_uuid):
        ''' Push to everyone '''
        json = Notification.by_event_uuid(event_uuid).to_json()
        for team_id in self.notify_connections.keys():
            for user_id in self.notify_connections[team_id].keys():
                for wsocket in self.notify_connections[team_id][user_id]:
                    wsocket.write_message(json)
                    if wsocket.user_id != '$public_user':
                        Notification.delivered(user_id, event_uuid)

    @debug
    def push_team_notification(self, event_uuid, team_id):
        ''' Push to one team '''
        json = Notification.by_event_uuid(event_uuid).to_json()
        if team_id in self.notify_connections:
            for user_id in self.notify_connections[team_id].keys():
                for wsocket in self.notify_connections[team_id][user_id]:
                    wsocket.write_message(json)
                    Notification.delivered(wsocket.user_id, event_uuid)

    @debug
    def push_user_notification(self, event_uuid, team_id, user_id):
        ''' Push to one user '''
        json = Notification.by_event_uuid(event_uuid).to_json()
        if team_id in self.notify_connections and user_id in self.notify_connections[team_id]:
            for wsocket in self.notify_connections[team_id][user_id]:
                wsocket.write_message(json)
                Notification.delivered(wsocket.user_id, event_uuid)

    # [ Broadcast Events ] -------------------------------------------------

    @debug
    def flag_capture(self, user, flag):
        ''' Callback for when a flag is captured '''
        self.refresh_scoreboard()
        evt_id = Notifier.broadcast_success("Flag Capture", 
            "%s has captured '%s'." % (user.team.name, flag.name,)
        )
        self.push_broadcast_notification(evt_id)

    @debug
    def unlocked_level(self, user, level):
        ''' Callback for when a team unlocks a new level '''
        self.refresh_scoreboard()
        message = "%s unlocked level #%d." % (user.team.name, level.number,)
        evt_id = Notifier.broadcast_success("Level Unlocked", message)
        self.push_broadcast_notification(evt_id)

    @debug
    def purchased_item(self, user, item):
        ''' Callback when a team purchases an item '''
        self.refresh_scoreboard()
        message = "%s purchased %s from the black market." % (
            user.handle, item.name,
        )
        evt_id = Notifier.team_success(user.team, "Upgrade Purchased", message)
        self.push_broadcast_notification(evt_id)
        message2 = "%s unlocked %s." % (user.team.name, item.name,)
        evt_id2 = Notifier.broadcast_warning("Team Upgrade", message2)
        self.push_broadcast_notification(evt_id2)

    @debug
    def swat_player(self, user, target):
        message("%s called the SWAT team on %s." % (user.handle, target.handle,))
        evt_id = Notifier.broadcast_warning("Player Arrested!", message)
        self.push_broadcast_notification(evt_id)

    # [ Team Events ] ------------------------------------------------------

    @debug
    def joined_team(self, user):
        ''' Callback when a user joins a team'''
        message = "%s has joined your team." % user.handle
        evt_id = Notifier.team_success(user.team, "New Team Member", message)
        self.push_team_notification(evt_id, user.team.id)

    @debug
    def team_file_share(self, user, file_upload):
        ''' Callback when a team file share is created '''
        message = "%s has shared a file called '%s'" % (
            user.handle, file_upload.file_name,
        )
        evt_id = Notifier.team_success(user.team, "File Share", message)
        self.push_team_notification(evt_id, user.team.id)

    @debug
    def paste_bin(self, user, paste):
        ''' Callback when a pastebin is created '''
        message = "%s posted to the team paste-bin" % user.handle
        evt_id = Notifier.team_success(user.team, "Text Share", message)
        self.push_team_notification(evt_id, user.team.id)

    @debug
    def new_bot(self, bot):
        message = "New bot connected to botnet from %s " % (bot.box.name,)
        evt_id = Notifier.team_success(bot.team, "Botnet", message)
        self.push_team_notification(evt_id)

    @debug
    def lost_bot(self, bot):
        message = "Lost communication with bot on %s" % (bot.box.name,)
        evt_id = Notifier.team_warning(bot.team, "Botnet", message)
        self.push_team_notification(evt_id)

    # [ Misc Events ] ------------------------------------------------------

    @debug
    def cracked_password(self, cracker, victim, password, value):
        user_msg = "Your password '%s' was cracked by %s." % (
            password, cracker.handle,
        )
        evt_id = Notifier.user_warning(victim, "Security Breach", user_msg)
        self.push_user_notification(evt_id, victim.team.id, victim.id)
        message = "%s hacked %s's bank account and stole $%d" % (
            cracker.handle, victim.team.name, value,
        )
        evt_id = Notifier.broadcast_custom("Password Cracked",
            message, cracker.avatar
        )
        self.push_broadcast_notification(evt_id)