Beispiel #1
0
    def perform(self, paste, analyzer_name=None):
        """Send a message via a Telegram bot to a specified user, without checking for errors"""
        r = Request()
        text = TemplatingEngine.fill_template(paste,
                                              analyzer_name,
                                              template_string=self.template)

        api_url = "https://api.telegram.org/bot{0}/sendMessage?chat_id={1}&text={2}".format(
            self.token, self.receiver, text)
        r.get(api_url)
Beispiel #2
0
    def perform(self, paste, analyzer_name=None):
        """Send a message via a Telegram bot to a specified user, without checking for errors"""
        r = Request()
        if self.template is None:
            text = "New paste matched by analyzer '{0}' - Link: {1}".format(
                analyzer_name, paste.full_url)
        else:
            paste_dict = paste.to_dict()
            paste_dict["analyzer_name"] = analyzer_name
            text = self.template.safe_substitute(DictWrapper(paste_dict))

        api_url = "https://api.telegram.org/bot{0}/sendMessage?chat_id={1}&text={2}".format(
            self.token, self.receiver, text)
        r.get(api_url)
Beispiel #3
0
    def _get_recent(self, limit=100):
        """Downloads a list of the most recent pastes - the amount is limited by the <limit> parameter"""
        r = Request()
        endpoint = "api_scraping.php"
        api_url = "{0}/{1}?limit={2}".format(self.api_base_url, endpoint, limit)

        try:
            response_data = r.get(api_url)

            self._check_error(response_data)

            pastes_dict = json.loads(response_data)
            pastes = []

            # Loop through the response and create objects by the data
            for paste in pastes_dict:
                paste_obj = Paste(key=paste.get("key"),
                                  title=paste.get("title"),
                                  user=paste.get("user"),
                                  size=paste.get("size"),
                                  date=paste.get("date"),
                                  expire=paste.get("expire"),
                                  syntax=paste.get("syntax"),
                                  scrape_url=paste.get("scrape_url"),
                                  full_url=paste.get("full_url"))
                pastes.append(paste_obj)

            return pastes
        except Exception as e:
            self.logger.error(e)
            return None
Beispiel #4
0
    def _get_paste_content(self, key):
        """Downloads the content of a certain paste"""
        r = Request()
        endpoint = "api_scrape_item.php"
        api_url = "{0}/{1}?i={2}".format(self.api_base_url, endpoint, key)

        self.logger.debug("Downloading paste {0}".format(key))
        try:
            response_data = r.get(api_url)
        except Exception as e:
            self.logger.error(e)
            raise e

        self._check_error(response_data, key)

        return response_data
Beispiel #5
0
    def initialize_gateway(self):
        """Initialize the bot token so Discord identifies it properly."""
        if self.webhook is not None:
            raise NotImplementedError(
                'Gateway initialization is only necessary for bot accounts.')

        # Call Get Gateway Bot to get the websocket URL
        r = Request()
        r.headers = {'Authorization': 'Bot {}'.format(self.token)}
        res = json.loads(r.get('https://discordapp.com/api/gateway/bot'))
        ws_url = res.get('url')

        # Start websocket client
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self._identify(ws_url))
        self.identified = True
Beispiel #6
0
class PastePwn(object):
    """Represents an instance of the pastepwn core module"""
    def __init__(self, database=None, proxies=None, store_all_pastes=True):
        """
        Basic PastePwn object handling the connection to pastebin and all the analyzers and actions
        :param database: Database object extending AbstractDB
        :param proxies: Dict of proxies as defined in the requests documentation
        :param store_all_pastes: Bool to decide if all pastes should be stored into the db
        """
        self.logger = logging.getLogger(__name__)
        self.is_idle = False
        self.database = database
        self.paste_queue = Queue()
        self.action_queue = Queue()
        self.error_handlers = list()
        self.onstart_handlers = list()
        self.__exception_event = Event()
        self.__request = Request(proxies)  # initialize singleton

        # Usage of ipify to get the IP - Uses the X-Forwarded-For Header which might
        # lead to issues with proxies
        try:
            ip = self.__request.get("https://api.ipify.org")
            self.logger.info("Your public IP is {0}".format(ip))
        except Exception as e:
            self.logger.warning(
                "Could not fetch public IP via ipify: {0}".format(e))

        self.scraping_handler = ScrapingHandler(
            paste_queue=self.paste_queue,
            exception_event=self.__exception_event)
        self.paste_dispatcher = PasteDispatcher(
            paste_queue=self.paste_queue,
            action_queue=self.action_queue,
            exception_event=self.__exception_event)
        self.action_handler = ActionHandler(
            action_queue=self.action_queue,
            exception_event=self.__exception_event)

        if self.database is not None and store_all_pastes:
            # Save every paste to the database with the AlwaysTrueAnalyzer
            self.logger.info("Database provided! Storing pastes in there.")
            database_action = DatabaseAction(self.database)
            always_true = AlwaysTrueAnalyzer(database_action)
            self.add_analyzer(always_true)
        elif store_all_pastes:
            self.logger.info("No database provided!")
        else:
            self.logger.info("Not storing all pastes!")

    def add_scraper(self, scraper, restart_scraping=False):
        """
        Adds a scraper to the list of scrapers. Scraping handler must be restarted for this to take effect.
        :param scraper: Instance of a BasicScraper
        :param restart_scraping: Indicates if the scraping handler should be restarted. Not setting this option results in your scraper not being started.
        :return: None
         """
        scraper.init_exception_event(self.__exception_event)
        self.scraping_handler.add_scraper(scraper, restart_scraping)

    def add_analyzer(self, analyzer):
        """
        Adds a new analyzer to the list of analyzers
        :param analyzer: Instance of a BasicAnalyzer
        :return: None
        """

        self.paste_dispatcher.add_analyzer(analyzer)

    def add_error_handler(self, error_handler):
        """
        Adds an error handler which will be called when an error happens
        :param error_handler: Callable to be called when an error happens
        :return: None
        """
        if not callable(error_handler):
            self.logger.error(
                "The error handler you passed is not a function!")
            return

        self.error_handlers.append(error_handler)

    def add_onstart_handler(self, onstart_handler):
        """Add a function as onstart_handler"""
        if not callable(onstart_handler):
            self.logger.error(
                "The onstart handler you passed is not a function!")
            return

        self.onstart_handlers.append(onstart_handler)

    def start(self):
        """Starts the pastepwn instance"""
        if self.__exception_event.is_set():
            self.logger.error(
                "An exception occured. Aborting the start of PastePwn!")
            exit(1)
        if len(self.scraping_handler.scrapers) == 0:
            from pastepwn.scraping.pastebin import PastebinScraper
            pastebinscraper = PastebinScraper()
            self.add_scraper(pastebinscraper, True)
        self.scraping_handler.start()
        self.paste_dispatcher.start()
        self.action_handler.start()

        for onstart_handler in self.onstart_handlers:
            try:
                onstart_handler()
            except Exception as e:
                self.logger.error(
                    "Onstart handler %s failed with error: %s. Pastepwn is still running."
                    % (onstart_handler.__name__, e))

    def stop(self):
        """Stops the pastepwn instance"""
        self.scraping_handler.stop()
        self.paste_dispatcher.stop()
        self.action_handler.stop()
        self.is_idle = False

    def signal_handler(self, signum, frame):
        """Handler method to handle signals"""
        self.is_idle = False
        self.logger.info("Received signal {}, stopping...".format(signum))
        self.stop()

    def idle(self, stop_signals=(SIGINT, SIGTERM, SIGABRT)):
        """
        Blocks until one of the signals are received and stops the updater.
        Thanks to the python-telegram-bot developers - https://github.com/python-telegram-bot/python-telegram-bot/blob/2cde878d1e5e0bb552aaf41d5ab5df695ec4addb/telegram/ext/updater.py#L514-L529
        :param stop_signals: The signals to which the code reacts to
        """
        self.is_idle = True
        self.logger.info("In Idle!")

        for sig in stop_signals:
            signal(sig, self.signal_handler)

        while self.is_idle:
            if self.__exception_event.is_set():
                self.logger.warning(
                    "An exception occurred. Calling exception handlers and going down!"
                )
                for handler in self.error_handlers:
                    # call the error handlers in case of an exception
                    handler()
                self.is_idle = False
                self.stop()
                return

            sleep(1)