def run(self): log.info("Starting server thread...") self.running = True self.load_config() self.slack_wrapper = SlackWrapper(self.get_config_option("api_key")) self.start_services() while self.running: try: if self.slack_wrapper.connected: log.info("Connection successful...") self.load_bot_data() read_websocket_delay = 1 # 1 second delay between reading from firehose # Might even pass the bot server for handlers? log.info("Initializing handlers...") handler_factory.initialize(self.slack_wrapper, self) # Main loop log.info("Bot is running...") while self.running: message = self.slack_wrapper.read() if message: reaction, channel, ts, reaction_user = self.parse_slack_reaction( message) if reaction: log.debug("Received reaction : {} ({})".format( reaction, channel)) handler_factory.process_reaction( self.slack_wrapper, reaction, ts, channel, reaction_user) command, channel, user = self.parse_slack_message( message) if command: log.debug( "Received bot command : {} ({})".format( command, channel)) handler_factory.process( self.slack_wrapper, command, channel, user) time.sleep(read_websocket_delay) else: log.error( "Connection failed. Invalid slack token or bot id?") self.running = False except websocket._exceptions.WebSocketConnectionClosedException: log.exception("Web socket error. Executing reconnect...") except SlackConnectionError: # Try to reconnect if slackclient auto_reconnect didn't work out. Keep an eye on the logfiles, # and remove the superfluous exception handling if auto_reconnect works. log.exception( "Slack connection error. Trying manual reconnect in 5 seconds..." ) time.sleep(5) self.stop_services() log.info("Shutdown complete...")
def execute(cls, slack_wrapper, args, timestamp, channel_id, user_id, user_is_admin): old_name = args[0].lower() new_name = args[1].lower() # Validate that the user is in a CTF channel ctf = get_ctf_by_channel_id(ChallengeHandler.DB, channel_id) if not ctf: raise InvalidCommand( "Rename challenge failed: You are not in a CTF channel.") if len(new_name) > (MAX_CHANNEL_NAME_LENGTH - len(ctf.name) - 1): raise InvalidCommand( "Rename challenge failed: Challenge name must be <= {} characters." .format(MAX_CHANNEL_NAME_LENGTH - len(ctf.name) - 1)) # Check for invalid characters if not is_valid_name(new_name): raise InvalidCommand( "Command failed: Invalid characters for challenge name found.") old_channel_name = "{}-{}".format(ctf.name, old_name) new_channel_name = "{}-{}".format(ctf.name, new_name) # Get the channel id for the channel to rename challenge = get_challenge_by_name(ChallengeHandler.DB, old_name, ctf.channel_id) if not challenge: raise InvalidCommand( "Rename challenge failed: Challenge '{}' not found.".format( old_name)) log.debug("Renaming channel %s to %s", channel_id, new_name) response = slack_wrapper.rename_channel(challenge.channel_id, new_channel_name, is_private=True) if not response['ok']: raise InvalidCommand( "\"{}\" channel rename failed:\nError: {}".format( old_channel_name, response['error'])) # Update channel purpose slack_wrapper.update_channel_purpose_name(challenge.channel_id, new_name, is_private=True) # Update database update_challenge_name(ChallengeHandler.DB, challenge.channel_id, new_name) text = "Challenge `{}` renamed to `{}` (#{})".format( old_name, new_name, new_channel_name) slack_wrapper.post_message(channel_id, text)
def __init__(self): log.debug("Parse config file and initialize threading...") threading.Thread.__init__(self) self.running = False self.config = {} self.bot_name = "" self.bot_id = "" self.bot_at = "" self.slack_wrapper = None self.read_websocket_delay = 1
def load_bot_data(self): """ Fetches the bot user information such as bot_name, bot_id and bot_at. """ log.debug("Resolving bot user in slack") self.bot_name = self.slack_wrapper.username self.bot_id = self.slack_wrapper.user_id self.bot_at = "<@{}>".format(self.bot_id) log.debug("Found bot user {} ({})".format(self.bot_name, self.bot_id)) self.running = True
def init_bot_data(self): """ Fetches the bot user information such as bot_name, bot_id and bot_at. """ log.debug("Resolving bot user in slack") self.bot_name = self.slack_wrapper.username self.bot_id = self.slack_wrapper.user_id self.bot_at = "<@{}>".format(self.bot_id) log.debug("Found bot user %s (%s)", self.bot_name, self.bot_id) self.running = True # Might even pass the bot server for handlers? log.info("Initializing handlers...") handler_factory.initialize(self.slack_wrapper, self)
def handle_message(self, message): reaction, channel, time_stamp, reaction_user = self.parse_slack_reaction( message) if reaction and not self.bot_id == reaction_user: log.debug("Received reaction : %s (%s)", reaction, channel) handler_factory.process_reaction(self.slack_wrapper, reaction, time_stamp, channel, reaction_user) command, channel, time_stamp, user = self.parse_slack_message(message) if command and not self.bot_id == user: log.debug("Received bot command : %s (%s)", command, channel) handler_factory.process(self.slack_wrapper, self, command, time_stamp, channel, user)
def process_reaction(slack_wrapper, reaction, timestamp, channel_id, user_id): try: log.debug("Processing reaction: %s from %s (%s)", reaction, channel_id, timestamp) admin_users = botserver.get_config_option("admin_users") user_is_admin = admin_users and user_id in admin_users for handler_name, handler in handlers.items(): if handler.can_handle_reaction(reaction): handler.process_reaction(slack_wrapper, reaction, channel_id, timestamp, user_id, user_is_admin) except InvalidCommand as e: slack_wrapper.post_message(channel_id, e, timestamp) except Exception: log.exception("An error has occured while processing a command")
def process(slack_wrapper, botserver, message, timestamp, channel_id, user_id): log.debug("Processing message: %s from %s (%s)", message, channel_id, user_id) try: # Parse command and check for malformed input command_line = unidecode(message) lexer = shlex.shlex(command_line, posix=True) lexer.quotes = '"' lexer.whitespace_split = True args = list(lexer) except: message = "Command failed : Malformed input." slack_wrapper.post_message(channel_id, message, timestamp) return process_command(slack_wrapper, message, args, timestamp, channel_id, user_id)