Esempio n. 1
0
def on_internet_available(ui, config, log):
    if config['twitter']['enabled'] and log.is_new() and log.handshakes > 0:
        try:
            import tweepy
        except ImportError:
            logging.error("Couldn't import tweepy")
            return

        logging.info("detected a new session and internet connectivity!")

        picture = '/dev/shm/pwnagotchi.png'

        ui.on_manual_mode(log)
        ui.update(force=True)
        ui.image().save(picture, 'png')
        ui.set('status', 'Tweeting...')
        ui.update(force=True)

        try:
            auth = tweepy.OAuthHandler(config['twitter']['consumer_key'], config['twitter']['consumer_secret'])
            auth.set_access_token(config['twitter']['access_token_key'], config['twitter']['access_token_secret'])
            api = tweepy.API(auth)

            tweet = Voice(lang=config['main']['lang']).on_log_tweet(log)
            api.update_with_media(filename=picture, status=tweet)
            log.save_session_id()

            logging.info("tweeted: %s" % tweet)
        except Exception as e:
            logging.exception("error while tweeting")
Esempio n. 2
0
def on_internet_available(agent):
    config = agent.config()
    display = agent.view()
    last_session = agent.last_session

    if last_session.is_new() and last_session.handshakes > 0:
        try:
            import tweepy
        except ImportError:
            logging.error("Couldn't import tweepy")
            return

        logging.info("detected a new session and internet connectivity!")

        picture = '/dev/shm/pwnagotchi.png'

        display.on_manual_mode(last_session)
        display.update(force=True)
        display.image().save(picture, 'png')
        display.set('status', 'Tweeting...')
        display.update(force=True)

        try:
            auth = tweepy.OAuthHandler(OPTIONS['consumer_key'], OPTIONS['consumer_secret'])
            auth.set_access_token(OPTIONS['access_token_key'], OPTIONS['access_token_secret'])
            api = tweepy.API(auth)

            tweet = Voice(lang=config['main']['lang']).on_last_session_tweet(last_session)
            api.update_with_media(filename=picture, status=tweet)
            last_session.save_session_id()

            logging.info("tweeted: %s" % tweet)
        except Exception as e:
            logging.exception("error while tweeting")
    def on_internet_available(self, agent):
        config = agent.config()
        display = agent.view()
        last_session = agent.last_session

        if last_session.is_new() and last_session.handshakes > 0:
            try:
                import tweepy
            except ImportError:
                logging.error("[twitter] Couldn't import tweepy.")
                return

            logging.info("[twitter] Detected a new session and internet connectivity!")

            picture = '/var/tmp/pwnagotchi/pwnagotchi.png' if os.path.exists("/var/tmp/pwnagotchi/pwnagotchi.png") else '/root/pwnagotchi.png'

            display.on_manual_mode(last_session)
            display.update(force=True)
            display.image().save(picture, 'png')
            display.set('status', 'Tweeting...')
            display.update(force=True)

            try:
                auth = tweepy.OAuthHandler(self.options['consumer_key'], self.options['consumer_secret'])
                auth.set_access_token(self.options['access_token_key'], self.options['access_token_secret'])
                api = tweepy.API(auth)

                tweet = Voice(lang=config['main']['lang']).on_last_session_tweet(last_session)
                api.update_with_media(filename=picture, status=tweet)
                last_session.save_session_id()

                logging.info(f"[twitter] Tweeted: {tweet}")
            except Exception as e:
                logging.exception(f"[twitter] Error while tweeting: {e}")
Esempio n. 4
0
    def on_internet_available(self, agent):
        if not self.ready:
            return

        config = agent.config()
        display = agent.view()
        last_session = agent.last_session

        if last_session.is_new() and last_session.handshakes > 0:
            try:
                import telegram
            except ImportError as e:
                logging.error("[telegram] Couldn't import python library.")
                logging.debug(e)
                return

            logging.info(
                "[telegram] Detected new activity and internet, time to send a message!"
            )

            picture = '/var/tmp/pwnagotchi/pwnagotchi.png' if os.path.exists(
                "/var/tmp/pwnagotchi/pwnagotchi.png"
            ) else '/root/pwnagotchi.png'
            display.on_manual_mode(last_session)
            display.image().save(picture, 'png')
            display.update(force=True)

            try:
                logging.info("[telegram] Connecting to Telegram...")

                message = Voice(lang=config['main']
                                ['lang']).on_last_session_tweet(last_session)
                bot = telegram.Bot(self.options['bot_token'])

                if self.options['send_picture'] is True:
                    logging.info("[telegram] Sending picture...")
                    bot.sendPhoto(chat_id=self.options['chat_id'],
                                  photo=open(picture, 'rb'))
                    logging.info("[telegram] Picture sent.")

                if self.options['send_message'] is True:
                    logging.info("[telegram] Sending message...")
                    bot.sendMessage(chat_id=self.options['chat_id'],
                                    text=message,
                                    disable_web_page_preview=True)
                    logging.info(f"[telegram] Message sent: {message}")

                last_session.save_session_id()
                display.set('status', 'Telegram notification sent!')
                display.update(force=True)
            except Exception as e:
                logging.exception(
                    f"[telegram] An error occurred in the Telegram plugin: {e}"
                )
                display.set('face', faces.BROKEN)
                display.set('status',
                            'An error occured in the Telegram plugin.')
                display.update(force=True)
Esempio n. 5
0
 def __init__(self, config):
     self.config = config
     self.voice = Voice(lang=config['main']['lang'])
     self.path = config['main']['log']['path']
     self.last_session = []
     self.last_session_id = ''
     self.last_saved_session_id = ''
     self.duration = ''
     self.duration_human = ''
     self.deauthed = 0
     self.associated = 0
     self.handshakes = 0
     self.epochs = 0
     self.train_epochs = 0
     self.min_reward = 1000
     self.max_reward = -1000
     self.avg_reward = 0
     self.parsed = False
    def on_internet_available(self, agent):
        config = agent.config()
        display = agent.view()
        last_session = agent.last_session
        api_base_url = self.options['instance_url']
        email = self.options['email']
        password = self.options['password']
        visibility = self.options['visibility']
        client_cred = '/root/.mastodon.client.secret'
        user_cred = '/root/.mastodon.user.secret'

        if last_session.is_new() and last_session.handshakes > 0:
            logging.info('[mastodon] Detected internet and new activity: time to post!')

            if not os.path.isfile(user_cred) or not os.path.isfile(client_cred):
                # Runs only if there are any missing credential files
                Mastodon.create_app(
                    config['main']['name'],
                    api_base_url=api_base_url,
                    to_file=client_cred
                )
            picture = '/root/pwnagotchi.png'
            display.on_manual_mode(last_session)
            display.image().save(picture, 'png')
            display.update(force=True)

            try:
                logging.info('[mastodon] Connecting to Mastodon API')
                mastodon = Mastodon(
                    client_id=client_cred,
                    api_base_url=api_base_url
                )
                mastodon.log_in(
                    email,
                    password,
                    to_file=user_cred
                )
                mastodon = Mastodon(
                    access_token=user_cred,
                    api_base_url=api_base_url
                )
                message = Voice(lang=config['main']['lang']).on_last_session_tweet(last_session)
                mastodon.status_post(
                    message,
                    media_ids=mastodon.media_post(picture),
                    visibility=visibility
                )

                last_session.save_session_id()
                logging.info('[mastodon] posted: %s', message)
                display.set('status', 'Posted!')
                display.update(force=True)
            except Exception as ex:
                logging.exception('[mastodon] error while posting: %s', ex)
Esempio n. 7
0
 def __init__(self, config):
     self.config = config
     self.voice = Voice(lang=config['main']['lang'])
     self.path = config['main']['log']
     self.last_session = []
     self.last_session_id = ''
     self.last_saved_session_id = ''
     self.duration = ''
     self.duration_human = ''
     self.deauthed = 0
     self.associated = 0
     self.handshakes = 0
     self.peers = 0
     self.last_peer = None
     self.epochs = 0
     self.train_epochs = 0
     self.min_reward = 1000
     self.max_reward = -1000
     self.avg_reward = 0
     self._peer_parser = re.compile(
         'detected unit (.+)@(.+) \(v.+\) on channel \d+ \(([\d\-]+) dBm\) \[sid:(.+) pwnd_tot:(\d+) uptime:(\d+)\]')
     self.parsed = False
Esempio n. 8
0
    def on_internet_available(self, agent):
        if not self.ready:
            return

        config = agent.config()
        display = agent.view()
        last_session = agent.last_session

        if last_session.is_new() and last_session.handshakes > 0:
            try:
                from discord import Webhook, RequestsWebhookAdapter, File
            except ImportError as e:
                logging.error("Discord: couldn't import discord.py")
                logging.debug(e)
                return

            logging.info(
                "Discord: detected new activity and internet, time to send a message!"
            )

            picture = '/var/tmp/pwnagotchi/pwnagotchi.png' if os.path.exists(
                "/var/tmp/pwnagotchi/pwnagotchi.png"
            ) else '/root/pwnagotchi.png'
            display.on_manual_mode(last_session)
            display.image().save(picture, 'png')
            display.update(force=True)

            try:
                logging.info("Discord: sending message...")

                message = Voice(lang=config['main']
                                ['lang']).on_last_session_tweet(last_session)
                url = self.options['webhook_url']
                username = self.options['username']

                webhook = Webhook.from_url(url,
                                           adapter=RequestsWebhookAdapter())
                webhook.send(message, username=username, file=File(picture))
                logging.info("Discord: message sent: %s" % message)

                last_session.save_session_id()
                display.set('status', 'Discord notification sent!')
                display.update(force=True)
            except Exception as e:
                logging.exception("Discord: error while sending message")
                logging.debug(e)
Esempio n. 9
0
    def on_internet_available(self, agent):
        config = agent.config()
        display = agent.view()
        last_session = agent.last_session

        if last_session.is_new() and last_session.handshakes > 0:

            try:
                import telegram
            except ImportError:
                logging.error('[telegram] Couldn\'t import telegram')
                return

            logging.info(
                '[telegram] Detected new activity and internet, time to send a message!'
            )

            picture = '/root/pwnagotchi.png'
            display.on_manual_mode(last_session)
            display.image().save(picture, 'png')
            display.update(force=True)

            try:
                logging.info('[telegram] Connecting to Telegram...')

                message = Voice(lang=config['main']
                                ['lang']).on_last_session_tweet(last_session)

                bot = telegram.Bot(self.options['bot_token'])
                if self.options['send_picture'] is True:
                    bot.sendPhoto(chat_id=self.options['chat_id'],
                                  photo=open(picture, 'rb'))
                    logging.info('[telegram] picture sent')
                if self.options['send_message'] is True:
                    bot.sendMessage(chat_id=self.options['chat_id'],
                                    text=message,
                                    disable_web_page_preview=True)
                    logging.info('[telegram] message sent: %s', message)

                last_session.save_session_id()
                display.set('status', 'Telegram notification sent!')
                display.update(force=True)
            except Exception as ex:
                logging.exception(
                    '[telegram] Error while sending on Telegram: %s', ex)
Esempio n. 10
0
    def __init__(self, config):
        self.config = config
        self.voice = Voice(lang=config['main']['lang'])
        self.path = config['main']['log']
        self.last_session = None
        self.last_session_id = ''
        self.last_saved_session_id = ''
        self.duration = ''
        self.duration_human = ''
        self.deauthed = 0
        self.associated = 0
        self.handshakes = 0
        self.peers = 0
        self.last_peer = None
        self._peer_parser = re.compile(
            'detected unit (.+)@(.+) \(v.+\) on channel \d+ \(([\d\-]+) dBm\) \[sid:(.+) pwnd_tot:(\d+) uptime:(\d+)\]'
        )

        lines = []

        if os.path.exists(self.path):
            with FileReadBackwards(self.path, encoding="utf-8") as fp:
                for line in fp:
                    line = line.strip()
                    if line != "" and line[0] != '[':
                        continue
                    lines.append(line)
                    if SessionParser.START_TOKEN in line:
                        break
            lines.reverse()

        if len(lines) == 0:
            lines.append("Initial Session")

        self.last_session = lines
        self.last_session_id = hashlib.md5(lines[0].encode()).hexdigest()
        self.last_saved_session_id = self._get_last_saved_session_id()

        self._parse_stats()
    def on_internet_available(self, agent):
        config = agent.config()
        display = agent.view()
        last_session = agent.last_session

        if last_session.is_new() and last_session.handshakes > 0:
            try:
                import tweepy
            except ImportError as ie:
                logging.error('[twitter] Couldn\'t import tweepy (%s)', ie)
                return

            logging.info(
                '[twitter] detected a new session and internet connectivity!')

            picture = '/root/pwnagotchi.png'

            display.on_manual_mode(last_session)
            with display.block_update(force=True):
                display.image().save(picture, 'png')
            display.set('status', 'Tweeting...')
            display.update(force=True)

            try:
                auth = tweepy.OAuthHandler(self.options['consumer_key'],
                                           self.options['consumer_secret'])
                auth.set_access_token(self.options['access_token_key'],
                                      self.options['access_token_secret'])
                api = tweepy.API(auth)

                tweet = Voice(lang=config['main']
                              ['lang']).on_last_session_tweet(last_session)
                api.update_with_media(filename=picture, status=tweet)
                last_session.save_session_id()

                logging.info('[twitter] tweeted: %s', tweet)
            except Exception as e:
                logging.exception('[twitter] error while tweeting (%s)', e)
Esempio n. 12
0
    def __init__(self, config, impl, state=None):
        global ROOT

        # setup faces from the configuration in case the user customized them
        faces.load_from_config(config['ui']['faces'])

        self._agent = None
        self._render_cbs = []
        self._config = config
        self._canvas = None
        self._frozen = False
        self._lock = Lock()
        self._voice = Voice(lang=config['main']['lang'])
        self._implementation = impl
        self._layout = impl.layout()
        self._width = self._layout['width']
        self._height = self._layout['height']
        self._state = State(state={
            'channel': LabeledValue(color=BLACK, label='CH', value='00', position=self._layout['channel'],
                                    label_font=fonts.Bold,
                                    text_font=fonts.Medium),
            'aps': LabeledValue(color=BLACK, label='APS', value='0 (00)', position=self._layout['aps'],
                                label_font=fonts.Bold,
                                text_font=fonts.Medium),

            'uptime': LabeledValue(color=BLACK, label='UP', value='00:00:00', position=self._layout['uptime'],
                                   label_font=fonts.Bold,
                                   text_font=fonts.Medium),

            'line1': Line(self._layout['line1'], color=BLACK),
            'line2': Line(self._layout['line2'], color=BLACK),

            'face': Text(value=faces.SLEEP, position=self._layout['face'], color=BLACK, font=fonts.Huge),

            'friend_face': Text(value=None, position=self._layout['friend_face'], font=fonts.Bold, color=BLACK),
            'friend_name': Text(value=None, position=self._layout['friend_name'], font=fonts.BoldSmall,
                                color=BLACK),

            'name': Text(value='%s>' % 'pwnagotchi', position=self._layout['name'], color=BLACK, font=fonts.Bold),

            'status': Text(value=self._voice.default(),
                           position=self._layout['status']['pos'],
                           color=BLACK,
                           font=self._layout['status']['font'],
                           wrap=True,
                           # the current maximum number of characters per line, assuming each character is 6 pixels wide
                           max_length=self._layout['status']['max']),

            'shakes': LabeledValue(label='PWND ', value='0 (00)', color=BLACK,
                                   position=self._layout['shakes'], label_font=fonts.Bold,
                                   text_font=fonts.Medium),
            'mode': Text(value='AUTO', position=self._layout['mode'],
                         font=fonts.Bold, color=BLACK),
        })

        if state:
            for key, value in state.items():
                self._state.set(key, value)

        plugins.on('ui_setup', self)

        if config['ui']['fps'] > 0.0:
            _thread.start_new_thread(self._refresh_handler, ())
            self._ignore_changes = ()
        else:
            logging.warning("ui.fps is 0, the display will only update for major changes")
            self._ignore_changes = ('uptime', 'name')

        ROOT = self
Esempio n. 13
0
class View:
    def __init__(self, config, impl, state=None):
        global ROOT

        # setup faces from the configuration in case the user customized them
        faces.load_from_config(config['ui']['faces'])

        self._agent = None
        self._render_cbs = []
        self._config = config
        self._canvas = None
        self._frozen = False
        self._lock = Lock()
        self._voice = Voice(lang=config['main']['lang'])
        self._implementation = impl
        self._layout = impl.layout()
        self._width = self._layout['width']
        self._height = self._layout['height']
        self._state = State(state={
            'channel': LabeledValue(color=BLACK, label='CH', value='00', position=self._layout['channel'],
                                    label_font=fonts.Bold,
                                    text_font=fonts.Medium),
            'aps': LabeledValue(color=BLACK, label='APS', value='0 (00)', position=self._layout['aps'],
                                label_font=fonts.Bold,
                                text_font=fonts.Medium),

            'uptime': LabeledValue(color=BLACK, label='UP', value='00:00:00', position=self._layout['uptime'],
                                   label_font=fonts.Bold,
                                   text_font=fonts.Medium),

            'line1': Line(self._layout['line1'], color=BLACK),
            'line2': Line(self._layout['line2'], color=BLACK),

            'face': Text(value=faces.SLEEP, position=self._layout['face'], color=BLACK, font=fonts.Huge),

            'friend_face': Text(value=None, position=self._layout['friend_face'], font=fonts.Bold, color=BLACK),
            'friend_name': Text(value=None, position=self._layout['friend_name'], font=fonts.BoldSmall,
                                color=BLACK),

            'name': Text(value='%s>' % 'pwnagotchi', position=self._layout['name'], color=BLACK, font=fonts.Bold),

            'status': Text(value=self._voice.default(),
                           position=self._layout['status']['pos'],
                           color=BLACK,
                           font=self._layout['status']['font'],
                           wrap=True,
                           # the current maximum number of characters per line, assuming each character is 6 pixels wide
                           max_length=self._layout['status']['max']),

            'shakes': LabeledValue(label='PWND ', value='0 (00)', color=BLACK,
                                   position=self._layout['shakes'], label_font=fonts.Bold,
                                   text_font=fonts.Medium),
            'mode': Text(value='AUTO', position=self._layout['mode'],
                         font=fonts.Bold, color=BLACK),
        })

        if state:
            for key, value in state.items():
                self._state.set(key, value)

        plugins.on('ui_setup', self)

        if config['ui']['fps'] > 0.0:
            _thread.start_new_thread(self._refresh_handler, ())
            self._ignore_changes = ()
        else:
            logging.warning("ui.fps is 0, the display will only update for major changes")
            self._ignore_changes = ('uptime', 'name')

        ROOT = self

    def set_agent(self, agent):
        self._agent = agent

    def has_element(self, key):
        self._state.has_element(key)

    def add_element(self, key, elem):
        self._state.add_element(key, elem)

    def remove_element(self, key):
        self._state.remove_element(key)

    def width(self):
        return self._width

    def height(self):
        return self._height

    def on_state_change(self, key, cb):
        self._state.add_listener(key, cb)

    def on_render(self, cb):
        if cb not in self._render_cbs:
            self._render_cbs.append(cb)

    def _refresh_handler(self):
        delay = 1.0 / self._config['ui']['fps']
        while True:
            try:
                name = self._state.get('name')
                self.set('name', name.rstrip('█').strip() if '█' in name else (name + ' █'))
                self.update()
            except Exception as e:
                logging.warning("non fatal error while updating view: %s" % e)

            time.sleep(delay)

    def set(self, key, value):
        self._state.set(key, value)

    def get(self, key):
        return self._state.get(key)

    def on_starting(self):
        self.set('status', self._voice.on_starting() + ("\n(v%s)" % pwnagotchi.__version__))
        self.set('face', faces.AWAKE)
        self.update()

    def on_ai_ready(self):
        self.set('mode', '  AI')
        self.set('face', faces.HAPPY)
        self.set('status', self._voice.on_ai_ready())
        self.update()

    def on_manual_mode(self, last_session):
        self.set('mode', 'MANU')
        self.set('face', faces.SAD if (last_session.epochs > 3 and last_session.handshakes == 0) else faces.HAPPY)
        self.set('status', self._voice.on_last_session_data(last_session))
        self.set('epoch', "%04d" % last_session.epochs)
        self.set('uptime', last_session.duration)
        self.set('channel', '-')
        self.set('aps', "%d" % last_session.associated)
        self.set('shakes', '%d (%s)' % (last_session.handshakes, \
                                        utils.total_unique_handshakes(self._config['bettercap']['handshakes'])))
        self.update()

    def is_normal(self):
        return self._state.get('face') not in (
            faces.INTENSE,
            faces.COOL,
            faces.BORED,
            faces.HAPPY,
            faces.EXCITED,
            faces.MOTIVATED,
            faces.DEMOTIVATED,
            faces.SMART,
            faces.SAD,
            faces.LONELY)

    def on_keys_generation(self):
        self.set('face', faces.AWAKE)
        self.set('status', self._voice.on_keys_generation())
        self.update()

    def on_normal(self):
        self.set('face', faces.AWAKE)
        self.set('status', self._voice.on_normal())
        self.update()

    def on_free_channel(self, channel):
        self.set('face', faces.SMART)
        self.set('status', self._voice.on_free_channel(channel))
        self.update()

    def on_reading_logs(self, lines_so_far=0):
        self.set('face', faces.SMART)
        self.set('status', self._voice.on_reading_logs(lines_so_far))
        self.update()

    def wait(self, secs, sleeping=True):
        was_normal = self.is_normal()
        part = secs / 10.0

        for step in range(0, 10):
            # if we weren't in a normal state before going
            # to sleep, keep that face and status on for
            # a while, otherwise the sleep animation will
            # always override any minor state change before it
            if was_normal or step > 5:
                if sleeping:
                    if secs > 1:
                        self.set('face', faces.SLEEP)
                        self.set('status', self._voice.on_napping(int(secs)))
                    else:
                        self.set('face', faces.SLEEP2)
                        self.set('status', self._voice.on_awakening())
                else:
                    self.set('status', self._voice.on_waiting(int(secs)))
                    good_mood = self._agent.in_good_mood()
                    if step % 2 == 0:
                        self.set('face', faces.LOOK_R_HAPPY if good_mood else faces.LOOK_R)
                    else:
                        self.set('face', faces.LOOK_L_HAPPY if good_mood else faces.LOOK_L)

            time.sleep(part)
            secs -= part

        self.on_normal()

    def on_shutdown(self):
        self.set('face', faces.SLEEP)
        self.set('status', self._voice.on_shutdown())
        self.update(force=True)
        self._frozen = True

    def on_bored(self):
        self.set('face', faces.BORED)
        self.set('status', self._voice.on_bored())
        self.update()

    def on_sad(self):
        self.set('face', faces.SAD)
        self.set('status', self._voice.on_sad())
        self.update()

    def on_angry(self):
        self.set('face', faces.ANGRY)
        self.set('status', self._voice.on_angry())
        self.update()

    def on_motivated(self, reward):
        self.set('face', faces.MOTIVATED)
        self.set('status', self._voice.on_motivated(reward))
        self.update()

    def on_demotivated(self, reward):
        self.set('face', faces.DEMOTIVATED)
        self.set('status', self._voice.on_demotivated(reward))
        self.update()

    def on_excited(self):
        self.set('face', faces.EXCITED)
        self.set('status', self._voice.on_excited())
        self.update()

    def on_assoc(self, ap):
        self.set('face', faces.INTENSE)
        self.set('status', self._voice.on_assoc(ap))
        self.update()

    def on_deauth(self, sta):
        self.set('face', faces.COOL)
        self.set('status', self._voice.on_deauth(sta))
        self.update()

    def on_miss(self, who):
        self.set('face', faces.SAD)
        self.set('status', self._voice.on_miss(who))
        self.update()

    def on_lonely(self):
        self.set('face', faces.LONELY)
        self.set('status', self._voice.on_lonely())
        self.update()

    def on_handshakes(self, new_shakes):
        self.set('face', faces.HAPPY)
        self.set('status', self._voice.on_handshakes(new_shakes))
        self.update()

    def on_unread_messages(self, count, total):
        self.set('face', faces.EXCITED)
        self.set('status', self._voice.on_unread_messages(count, total))
        self.update()
        time.sleep(5.0)

    def on_rebooting(self):
        self.set('face', faces.BROKEN)
        self.set('status', self._voice.on_rebooting())
        self.update()

    def on_custom(self, text):
        self.set('face', faces.DEBUG)
        self.set('status', self._voice.custom(text))
        self.update()

    @contextmanager
    def block_update(self, *args, **kwargs):
        self._lock.acquire()
        try:
            self.update(*args, with_lock=False, **kwargs)
            yield self
        finally:
            self._lock.release()

    def update(self, force=False, new_data={}, with_lock=True):
        for key, val in new_data.items():
            self.set(key, val)

        maybe_lock = self._lock if with_lock else nullcontext()

        with maybe_lock:
            if self._frozen:
                return

            state = self._state
            changes = state.changes(ignore=self._ignore_changes)
            min_changes = 2 if self._config['ui']['fps'] == 0.0 else 0
            if force or len(changes) > min_changes:
                logging.debug("Update screen because %s", 'it was forced.' if force else f"{changes} triggered it.")
                self._canvas = Image.new('1', (self._width, self._height), WHITE)
                drawer = ImageDraw.Draw(self._canvas)

                plugins.on('ui_update', self)

                for key, lv in state.items():
                    lv.draw(self._canvas, drawer)

                if self._config['ui']['web']['dark']:
                    print(self._canvas.mode)
                    self._canvas = ImageOps.invert(self._canvas.convert('L')).convert('1')

                web.update_frame(self._canvas)

                for cb in self._render_cbs:
                    cb(self._canvas)

                self._state.reset()
Esempio n. 14
0
    def __init__(self, config, state={}):
        self._render_cbs = []
        self._config = config
        self._canvas = None
        self._lock = Lock()
        self._voice = Voice(lang=config['main']['lang'])

        self._width, self._height, \
        face_pos, name_pos, status_pos = setup_display_specifics(config)

        self._state = State(
            state={
                'channel':
                LabeledValue(color=BLACK,
                             label='CH',
                             value='00',
                             position=(0, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'aps':
                LabeledValue(color=BLACK,
                             label='APS',
                             value='0 (00)',
                             position=(30, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),

                # 'epoch': LabeledValue(color=BLACK, label='E', value='0000', position=(145, 0), label_font=fonts.Bold,
                #                      text_font=fonts.Medium),
                'uptime':
                LabeledValue(color=BLACK,
                             label='UP',
                             value='00:00:00',
                             position=(self._width - 65, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'line1':
                Line([
                    0,
                    int(self._height * .12), self._width,
                    int(self._height * .12)
                ],
                     color=BLACK),
                'line2':
                Line([
                    0, self._height -
                    int(self._height * .12), self._width, self._height -
                    int(self._height * .12)
                ],
                     color=BLACK),
                'face':
                Text(value=faces.SLEEP,
                     position=face_pos,
                     color=BLACK,
                     font=fonts.Huge),
                'friend_face':
                Text(
                    value=None, position=(0,
                                          90), font=fonts.Bold, color=BLACK),
                'friend_name':
                Text(value=None,
                     position=(40, 93),
                     font=fonts.BoldSmall,
                     color=BLACK),
                'name':
                Text(value='%s>' % 'pwnagotchi',
                     position=name_pos,
                     color=BLACK,
                     font=fonts.Bold),
                'status':
                Text(
                    value=self._voice.default(),
                    position=status_pos,
                    color=BLACK,
                    font=fonts.Medium,
                    wrap=True,
                    # the current maximum number of characters per line, assuming each character is 6 pixels wide
                    max_length=(self._width - status_pos[0]) // 6),
                'shakes':
                LabeledValue(label='PWND ',
                             value='0 (00)',
                             color=BLACK,
                             position=(0, self._height -
                                       int(self._height * .12) + 1),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'mode':
                Text(value='AUTO',
                     position=(self._width - 25,
                               self._height - int(self._height * .12) + 1),
                     font=fonts.Bold,
                     color=BLACK),
            })

        for key, value in state.items():
            self._state.set(key, value)

        plugins.on('ui_setup', self)

        if config['ui']['fps'] > 0.0:
            _thread.start_new_thread(self._refresh_handler, ())
            self._ignore_changes = ()
        else:
            logging.warning(
                "ui.fps is 0, the display will only update for major changes")
            self._ignore_changes = ('uptime', 'name')
Esempio n. 15
0
class View(object):
    def __init__(self, config, state={}):
        self._render_cbs = []
        self._config = config
        self._canvas = None
        self._lock = Lock()
        self._voice = Voice(lang=config['main']['lang'])

        self._width, self._height, \
        face_pos, name_pos, status_pos = setup_display_specifics(config)

        self._state = State(
            state={
                'channel':
                LabeledValue(color=BLACK,
                             label='CH',
                             value='00',
                             position=(0, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'aps':
                LabeledValue(color=BLACK,
                             label='APS',
                             value='0 (00)',
                             position=(30, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),

                # 'epoch': LabeledValue(color=BLACK, label='E', value='0000', position=(145, 0), label_font=fonts.Bold,
                #                      text_font=fonts.Medium),
                'uptime':
                LabeledValue(color=BLACK,
                             label='UP',
                             value='00:00:00',
                             position=(self._width - 65, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'line1':
                Line([
                    0,
                    int(self._height * .12), self._width,
                    int(self._height * .12)
                ],
                     color=BLACK),
                'line2':
                Line([
                    0, self._height -
                    int(self._height * .12), self._width, self._height -
                    int(self._height * .12)
                ],
                     color=BLACK),
                'face':
                Text(value=faces.SLEEP,
                     position=face_pos,
                     color=BLACK,
                     font=fonts.Huge),
                'friend_face':
                Text(
                    value=None, position=(0,
                                          90), font=fonts.Bold, color=BLACK),
                'friend_name':
                Text(value=None,
                     position=(40, 93),
                     font=fonts.BoldSmall,
                     color=BLACK),
                'name':
                Text(value='%s>' % 'pwnagotchi',
                     position=name_pos,
                     color=BLACK,
                     font=fonts.Bold),
                'status':
                Text(
                    value=self._voice.default(),
                    position=status_pos,
                    color=BLACK,
                    font=fonts.Medium,
                    wrap=True,
                    # the current maximum number of characters per line, assuming each character is 6 pixels wide
                    max_length=(self._width - status_pos[0]) // 6),
                'shakes':
                LabeledValue(label='PWND ',
                             value='0 (00)',
                             color=BLACK,
                             position=(0, self._height -
                                       int(self._height * .12) + 1),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'mode':
                Text(value='AUTO',
                     position=(self._width - 25,
                               self._height - int(self._height * .12) + 1),
                     font=fonts.Bold,
                     color=BLACK),
            })

        for key, value in state.items():
            self._state.set(key, value)

        plugins.on('ui_setup', self)

        if config['ui']['fps'] > 0.0:
            _thread.start_new_thread(self._refresh_handler, ())
            self._ignore_changes = ()
        else:
            logging.warning(
                "ui.fps is 0, the display will only update for major changes")
            self._ignore_changes = ('uptime', 'name')

    def add_element(self, key, elem):
        self._state.add_element(key, elem)

    def width(self):
        return self._width

    def height(self):
        return self._height

    def on_state_change(self, key, cb):
        self._state.add_listener(key, cb)

    def on_render(self, cb):
        if cb not in self._render_cbs:
            self._render_cbs.append(cb)

    def _refresh_handler(self):
        delay = 1.0 / self._config['ui']['fps']
        # logging.info("view refresh handler started with period of %.2fs" % delay)

        while True:
            name = self._state.get('name')
            self.set(
                'name',
                name.rstrip('█').strip() if '█' in name else (name + ' █'))
            self.update()
            time.sleep(delay)

    def set(self, key, value):
        self._state.set(key, value)

    def on_starting(self):
        self.set('status', self._voice.on_starting())
        self.set('face', faces.AWAKE)

    def on_ai_ready(self):
        self.set('mode', '')
        self.set('face', faces.HAPPY)
        self.set('status', self._voice.on_ai_ready())
        self.update()

    def on_manual_mode(self, log):
        self.set('mode', 'MANU')
        self.set('face', faces.SAD if log.handshakes == 0 else faces.HAPPY)
        self.set('status', self._voice.on_log(log))
        self.set('epoch', "%04d" % log.epochs)
        self.set('uptime', log.duration)
        self.set('channel', '-')
        self.set('aps', "%d" % log.associated)
        self.set('shakes', '%d (%s)' % (log.handshakes, \
                                        core.total_unique_handshakes(self._config['bettercap']['handshakes'])))
        self.set_closest_peer(log.last_peer)

    def is_normal(self):
        return self._state.get('face') not in (faces.INTENSE, faces.COOL,
                                               faces.BORED, faces.HAPPY,
                                               faces.EXCITED, faces.MOTIVATED,
                                               faces.DEMOTIVATED, faces.SMART,
                                               faces.SAD, faces.LONELY)

    def on_normal(self):
        self.set('face', faces.AWAKE)
        self.set('status', self._voice.on_normal())
        self.update()

    def set_closest_peer(self, peer):
        if peer is None:
            self.set('friend_face', None)
            self.set('friend_name', None)
        else:
            # ref. https://www.metageek.com/training/resources/understanding-rssi-2.html
            if peer.rssi >= -67:
                num_bars = 4
            elif peer.rssi >= -70:
                num_bars = 3
            elif peer.rssi >= -80:
                num_bars = 2
            else:
                num_bars = 1

            name = '▌' * num_bars
            name += '│' * (4 - num_bars)
            name += ' %s %d (%d)' % (peer.name(), peer.pwnd_run(),
                                     peer.pwnd_total())

            self.set('friend_face', peer.face())
            self.set('friend_name', name)
        self.update()

    def on_new_peer(self, peer):
        self.set('face', faces.FRIEND)
        self.set('status', self._voice.on_new_peer(peer))
        self.update()

    def on_lost_peer(self, peer):
        self.set('face', faces.LONELY)
        self.set('status', self._voice.on_lost_peer(peer))
        self.update()

    def on_free_channel(self, channel):
        self.set('face', faces.SMART)
        self.set('status', self._voice.on_free_channel(channel))
        self.update()

    def wait(self, secs, sleeping=True):
        was_normal = self.is_normal()
        part = secs / 10.0

        for step in range(0, 10):
            # if we weren't in a normal state before goin
            # to sleep, keep that face and status on for
            # a while, otherwise the sleep animation will
            # always override any minor state change before it
            if was_normal or step > 5:
                if sleeping:
                    if secs > 1:
                        self.set('face', faces.SLEEP)
                        self.set('status', self._voice.on_napping(int(secs)))
                    else:
                        self.set('face', faces.SLEEP2)
                        self.set('status', self._voice.on_awakening())
                else:
                    self.set('status', self._voice.on_waiting(int(secs)))
                    if step % 2 == 0:
                        self.set('face', faces.LOOK_R)
                    else:
                        self.set('face', faces.LOOK_L)

            time.sleep(part)
            secs -= part

        self.on_normal()

    def on_bored(self):
        self.set('face', faces.BORED)
        self.set('status', self._voice.on_bored())
        self.update()

    def on_sad(self):
        self.set('face', faces.SAD)
        self.set('status', self._voice.on_sad())
        self.update()

    def on_motivated(self, reward):
        self.set('face', faces.MOTIVATED)
        self.set('status', self._voice.on_motivated(reward))
        self.update()

    def on_demotivated(self, reward):
        self.set('face', faces.DEMOTIVATED)
        self.set('status', self._voice.on_demotivated(reward))
        self.update()

    def on_excited(self):
        self.set('face', faces.EXCITED)
        self.set('status', self._voice.on_excited())
        self.update()

    def on_assoc(self, ap):
        self.set('face', faces.INTENSE)
        self.set('status', self._voice.on_assoc(ap))
        self.update()

    def on_deauth(self, sta):
        self.set('face', faces.COOL)
        self.set('status', self._voice.on_deauth(sta))
        self.update()

    def on_miss(self, who):
        self.set('face', faces.SAD)
        self.set('status', self._voice.on_miss(who))
        self.update()

    def on_lonely(self):
        self.set('face', faces.LONELY)
        self.set('status', self._voice.on_lonely())
        self.update()

    def on_handshakes(self, new_shakes):
        self.set('face', faces.HAPPY)
        self.set('status', self._voice.on_handshakes(new_shakes))
        self.update()

    def on_rebooting(self):
        self.set('face', faces.BROKEN)
        self.set('status', self._voice.on_rebooting())
        self.update()

    def on_custom(self, text):
        self.set('face', faces.DEBUG)
        self.set('status', self._voice.custom(text))
        self.update()

    def update(self, force=False):
        with self._lock:
            changes = self._state.changes(ignore=self._ignore_changes)
            if force or len(changes):
                self._canvas = Image.new('1', (self._width, self._height),
                                         WHITE)
                drawer = ImageDraw.Draw(self._canvas)

                plugins.on('ui_update', self)

                for key, lv in self._state.items():
                    lv.draw(self._canvas, drawer)

                for cb in self._render_cbs:
                    cb(self._canvas)

                self._state.reset()
Esempio n. 16
0
            picture = '/dev/shm/pwnagotchi.png'

            display.update()
            display.image().save(picture, 'png')
            display.set('status', 'Tweeting...')
            display.update()

            try:
                auth = tweepy.OAuthHandler(
                    config['twitter']['consumer_key'],
                    config['twitter']['consumer_secret'])
                auth.set_access_token(config['twitter']['access_token_key'],
                                      config['twitter']['access_token_secret'])
                api = tweepy.API(auth)

                tweet = Voice(lang=config['main']['lang']).on_log_tweet(log)
                api.update_with_media(filename=picture, status=tweet)
                log.save_session_id()

                core.log("tweeted: %s" % tweet)
            except Exception as e:
                core.log("error: %s" % e)

    quit()

core.logfile = config['main']['log']

agent.start_ai()
agent.setup_events()
agent.set_ready()
agent.start_monitor_mode()
Esempio n. 17
0
class View(object):
    def __init__(self, config, impl, state=None):
        global ROOT

        # setup faces from the configuration in case the user customized them
        faces.load_from_config(config['ui']['faces'])

        self._agent = None
        self._render_cbs = []
        self._config = config
        self._canvas = None
        self._frozen = False
        self._lock = Lock()
        self._voice = Voice(lang=config['main']['lang'])
        self._implementation = impl
        self._layout = impl.layout()
        self._width = self._layout['width']
        self._height = self._layout['height']
        self._state = State(
            state={
                'channel':
                LabeledValue(color=BLACK,
                             label='CH',
                             value='00',
                             position=self._layout['channel'],
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'aps':
                LabeledValue(color=BLACK,
                             label='APS',
                             value='0 (00)',
                             position=self._layout['aps'],
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'uptime':
                LabeledValue(color=BLACK,
                             label='UP',
                             value='00:00:00',
                             position=self._layout['uptime'],
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'line1':
                Line(self._layout['line1'], color=BLACK),
                'line2':
                Line(self._layout['line2'], color=BLACK),
                'face':
                Text(value=faces.SLEEP,
                     position=self._layout['face'],
                     color=BLACK,
                     font=fonts.Huge),
                'friend_face':
                Text(value=None,
                     position=self._layout['friend_face'],
                     font=fonts.Bold,
                     color=BLACK),
                'friend_name':
                Text(value=None,
                     position=self._layout['friend_name'],
                     font=fonts.BoldSmall,
                     color=BLACK),
                'name':
                Text(value='%s>' % 'pwnagotchi',
                     position=self._layout['name'],
                     color=BLACK,
                     font=fonts.Bold),
                'status':
                Text(
                    value=self._voice.default(),
                    position=self._layout['status']['pos'],
                    color=BLACK,
                    font=self._layout['status']['font'],
                    wrap=True,
                    # the current maximum number of characters per line, assuming each character is 6 pixels wide
                    max_length=self._layout['status']['max']),
                'shakes':
                LabeledValue(label='PWND ',
                             value='0 (00)',
                             color=BLACK,
                             position=self._layout['shakes'],
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'mode':
                Text(value='AUTO',
                     position=self._layout['mode'],
                     font=fonts.Bold,
                     color=BLACK),
            })

        if state:
            for key, value in state.items():
                self._state.set(key, value)

        plugins.on('ui_setup', self)

        if config['ui']['fps'] > 0.0:
            _thread.start_new_thread(self._refresh_handler, ())
            self._ignore_changes = ()
        else:
            logging.warning(
                "ui.fps is 0, the display will only update for major changes")
            self._ignore_changes = ('uptime', 'name')

        ROOT = self

    def set_agent(self, agent):
        self._agent = agent

    def has_element(self, key):
        self._state.has_element(key)

    def add_element(self, key, elem):
        self._state.add_element(key, elem)

    def remove_element(self, key):
        self._state.remove_element(key)

    def width(self):
        return self._width

    def height(self):
        return self._height

    def on_state_change(self, key, cb):
        self._state.add_listener(key, cb)

    def on_render(self, cb):
        if cb not in self._render_cbs:
            self._render_cbs.append(cb)

    def _refresh_handler(self):
        delay = 1.0 / self._config['ui']['fps']
        # logging.info("view refresh handler started with period of %.2fs" % delay)

        while True:
            name = self._state.get('name')
            self.set(
                'name',
                name.rstrip('█').strip() if '█' in name else (name + ' █'))
            self.update()
            time.sleep(delay)

    def set(self, key, value):
        self._state.set(key, value)

    def get(self, key):
        return self._state.get(key)

    def on_starting(self):
        self.set('status', self._voice.on_starting())
        self.set('face', faces.AWAKE)

    def on_ai_ready(self):
        self.set('mode', '  AI')
        self.set('face', faces.HAPPY)
        self.set('status', self._voice.on_ai_ready())
        self.update()

    def on_manual_mode(self, last_session):
        self.set('mode', 'MANU')
        self.set(
            'face', faces.SAD if
            (last_session.epochs > 3
             and last_session.handshakes == 0) else faces.HAPPY)
        self.set('status', self._voice.on_last_session_data(last_session))
        self.set('epoch', "%04d" % last_session.epochs)
        self.set('uptime', last_session.duration)
        self.set('channel', '-')
        self.set('aps', "%d" % last_session.associated)
        self.set('shakes', '%d (%s)' % (last_session.handshakes, \
                                        utils.total_unique_handshakes(self._config['bettercap']['handshakes'])))
        self.set_closest_peer(last_session.last_peer, last_session.peers)
        self.update()

    def is_normal(self):
        return self._state.get('face') not in (faces.INTENSE, faces.COOL,
                                               faces.BORED, faces.HAPPY,
                                               faces.EXCITED, faces.MOTIVATED,
                                               faces.DEMOTIVATED, faces.SMART,
                                               faces.SAD, faces.LONELY)

    def on_keys_generation(self):
        self.set('face', faces.AWAKE)
        self.set('status', self._voice.on_keys_generation())
        self.update()

    def on_normal(self):
        self.set('face', faces.AWAKE)
        self.set('status', self._voice.on_normal())
        self.update()

    def set_closest_peer(self, peer, num_total):
        if peer is None:
            self.set('friend_face', None)
            self.set('friend_name', None)
        else:
            # ref. https://www.metageek.com/training/resources/understanding-rssi-2.html
            if peer.rssi >= -67:
                num_bars = 4
            elif peer.rssi >= -70:
                num_bars = 3
            elif peer.rssi >= -80:
                num_bars = 2
            else:
                num_bars = 1

            name = '▌' * num_bars
            name += '│' * (4 - num_bars)
            name += ' %s %d (%d)' % (peer.name(), peer.pwnd_run(),
                                     peer.pwnd_total())

            if num_total > 1:
                if num_total > 9000:
                    name += ' of over 9000'
                else:
                    name += ' of %d' % num_total

            self.set('friend_face', peer.face())
            self.set('friend_name', name)
        self.update()

    def on_new_peer(self, peer):
        face = ''
        # first time they met, neutral mood
        if peer.first_encounter():
            face = random.choice((faces.AWAKE, faces.COOL))
        # a good friend, positive expression
        elif peer.is_good_friend(self._config):
            face = random.choice((faces.MOTIVATED, faces.FRIEND, faces.HAPPY))
        # normal friend, neutral-positive
        else:
            face = random.choice((faces.EXCITED, faces.HAPPY, faces.SMART))

        self.set('face', face)
        self.set('status', self._voice.on_new_peer(peer))
        self.update()
        time.sleep(3)

    def on_lost_peer(self, peer):
        self.set('face', faces.LONELY)
        self.set('status', self._voice.on_lost_peer(peer))
        self.update()

    def on_free_channel(self, channel):
        self.set('face', faces.SMART)
        self.set('status', self._voice.on_free_channel(channel))
        self.update()

    def wait(self, secs, sleeping=True):
        was_normal = self.is_normal()
        part = secs / 10.0

        for step in range(0, 10):
            # if we weren't in a normal state before going
            # to sleep, keep that face and status on for
            # a while, otherwise the sleep animation will
            # always override any minor state change before it
            if was_normal or step > 5:
                if sleeping:
                    if secs > 1:
                        self.set('face', faces.SLEEP)
                        self.set('status', self._voice.on_napping(int(secs)))
                    else:
                        self.set('face', faces.SLEEP2)
                        self.set('status', self._voice.on_awakening())
                else:
                    self.set('status', self._voice.on_waiting(int(secs)))
                    good_mood = self._agent.in_good_mood()
                    if step % 2 == 0:
                        self.set(
                            'face',
                            faces.LOOK_R_HAPPY if good_mood else faces.LOOK_R)
                    else:
                        self.set(
                            'face',
                            faces.LOOK_L_HAPPY if good_mood else faces.LOOK_L)

            time.sleep(part)
            secs -= part

        self.on_normal()

    def on_shutdown(self):
        self.set('face', faces.SLEEP)
        self.set('status', self._voice.on_shutdown())
        self.update(force=True)
        self._frozen = True

    def on_bored(self):
        self.set('face', faces.BORED)
        self.set('status', self._voice.on_bored())
        self.update()

    def on_sad(self):
        self.set('face', faces.SAD)
        self.set('status', self._voice.on_sad())
        self.update()

    def on_motivated(self, reward):
        self.set('face', faces.MOTIVATED)
        self.set('status', self._voice.on_motivated(reward))
        self.update()

    def on_demotivated(self, reward):
        self.set('face', faces.DEMOTIVATED)
        self.set('status', self._voice.on_demotivated(reward))
        self.update()

    def on_excited(self):
        self.set('face', faces.EXCITED)
        self.set('status', self._voice.on_excited())
        self.update()

    def on_assoc(self, ap):
        self.set('face', faces.INTENSE)
        self.set('status', self._voice.on_assoc(ap))
        self.update()

    def on_deauth(self, sta):
        self.set('face', faces.COOL)
        self.set('status', self._voice.on_deauth(sta))
        self.update()

    def on_miss(self, who):
        self.set('face', faces.SAD)
        self.set('status', self._voice.on_miss(who))
        self.update()

    def on_grateful(self):
        self.set('face', faces.GRATEFUL)
        self.set('status', self._voice.on_grateful())
        self.update()

    def on_lonely(self):
        self.set('face', faces.LONELY)
        self.set('status', self._voice.on_lonely())
        self.update()

    def on_handshakes(self, new_shakes):
        self.set('face', faces.HAPPY)
        self.set('status', self._voice.on_handshakes(new_shakes))
        self.update()

    def on_unread_messages(self, count, total):
        self.set('face', faces.EXCITED)
        self.set('status', self._voice.on_unread_messages(count, total))
        self.update()
        time.sleep(5.0)

    def on_rebooting(self):
        self.set('face', faces.BROKEN)
        self.set('status', self._voice.on_rebooting())
        self.update()

    def on_custom(self, text):
        self.set('face', faces.DEBUG)
        self.set('status', self._voice.custom(text))
        self.update()

    def update(self, force=False, new_data={}):
        for key, val in new_data.items():
            self.set(key, val)

        with self._lock:
            if self._frozen:
                return

            changes = self._state.changes(ignore=self._ignore_changes)
            if force or len(changes):
                self._canvas = Image.new('1', (self._width, self._height),
                                         WHITE)
                drawer = ImageDraw.Draw(self._canvas)

                plugins.on('ui_update', self)

                for key, lv in self._state.items():
                    lv.draw(self._canvas, drawer)

                for cb in self._render_cbs:
                    cb(self._canvas)

                self._state.reset()
Esempio n. 18
0
class LastSession(object):
    EPOCH_TOKEN = '[epoch '
    EPOCH_PARSER = re.compile(r'^.+\[epoch (\d+)\] (.+)')
    EPOCH_DATA_PARSER = re.compile(r'([a-z_]+)=([^\s]+)')
    TRAINING_TOKEN = ' training epoch '
    START_TOKEN = 'connecting to http'
    DEAUTH_TOKEN = 'deauthing '
    ASSOC_TOKEN = 'sending association frame to '
    HANDSHAKE_TOKEN = '!!! captured new handshake '
    PEER_TOKEN = 'detected unit '

    def __init__(self, config):
        self.config = config
        self.voice = Voice(lang=config['main']['lang'])
        self.path = config['main']['log']
        self.last_session = []
        self.last_session_id = ''
        self.last_saved_session_id = ''
        self.duration = ''
        self.duration_human = ''
        self.deauthed = 0
        self.associated = 0
        self.handshakes = 0
        self.peers = 0
        self.last_peer = None
        self.epochs = 0
        self.train_epochs = 0
        self.min_reward = 1000
        self.max_reward = -1000
        self.avg_reward = 0
        self._peer_parser = re.compile(
            'detected unit (.+)@(.+) \(v.+\) on channel \d+ \(([\d\-]+) dBm\) \[sid:(.+) pwnd_tot:(\d+) uptime:(\d+)\]')
        self.parsed = False

    def _get_last_saved_session_id(self):
        saved = ''
        try:
            with open(LAST_SESSION_FILE, 'rt') as fp:
                saved = fp.read().strip()
        except:
            saved = ''
        return saved

    def save_session_id(self):
        with open(LAST_SESSION_FILE, 'w+t') as fp:
            fp.write(self.last_session_id)
            self.last_saved_session_id = self.last_session_id

    def _parse_datetime(self, dt):
        dt = dt.split('.')[0]
        dt = dt.split(',')[0]
        dt = datetime.strptime(dt.split('.')[0], '%Y-%m-%d %H:%M:%S')
        return time.mktime(dt.timetuple())

    def _parse_stats(self):
        self.duration = ''
        self.duration_human = ''
        self.deauthed = 0
        self.associated = 0
        self.handshakes = 0
        self.epochs = 0
        self.train_epochs = 0
        self.peers = 0
        self.last_peer = None
        self.min_reward = 1000
        self.max_reward = -1000
        self.avg_reward = 0

        started_at = None
        stopped_at = None
        cache = {}

        for line in self.last_session:
            parts = line.split(']')
            if len(parts) < 2:
                continue

            try:
                line_timestamp = parts[0].strip('[')
                line = ']'.join(parts[1:])
                stopped_at = self._parse_datetime(line_timestamp)
                if started_at is None:
                    started_at = stopped_at

                if LastSession.DEAUTH_TOKEN in line and line not in cache:
                    self.deauthed += 1
                    cache[line] = 1

                elif LastSession.ASSOC_TOKEN in line and line not in cache:
                    self.associated += 1
                    cache[line] = 1

                elif LastSession.HANDSHAKE_TOKEN in line and line not in cache:
                    self.handshakes += 1
                    cache[line] = 1

                elif LastSession.TRAINING_TOKEN in line:
                    self.train_epochs += 1

                elif LastSession.EPOCH_TOKEN in line:
                    self.epochs += 1
                    m = LastSession.EPOCH_PARSER.findall(line)
                    if m:
                        epoch_num, epoch_data = m[0]
                        m = LastSession.EPOCH_DATA_PARSER.findall(epoch_data)
                        for key, value in m:
                            if key == 'reward':
                                reward = float(value)
                                self.avg_reward += reward
                                if reward < self.min_reward:
                                    self.min_reward = reward

                                elif reward > self.max_reward:
                                    self.max_reward = reward

                elif LastSession.PEER_TOKEN in line:
                    m = self._peer_parser.findall(line)
                    if m:
                        name, pubkey, rssi, sid, pwnd_tot, uptime = m[0]
                        if pubkey not in cache:
                            self.last_peer = Peer({
                                'session_id': sid,
                                'channel': 1,
                                'rssi': int(rssi),
                                'identity': pubkey,
                                'advertisement':{
                                    'name': name,
                                    'pwnd_tot': int(pwnd_tot)
                                }})
                            self.peers += 1
                            cache[pubkey] = self.last_peer
                        else:
                            cache[pubkey].adv['pwnd_tot'] = pwnd_tot
            except Exception as e:
                logging.error("error parsing line '%s': %s" % (line, e))

        if started_at is not None:
            self.duration = stopped_at - started_at
            mins, secs = divmod(self.duration, 60)
            hours, mins = divmod(mins, 60)
        else:
            hours = mins = secs = 0

        self.duration = '%02d:%02d:%02d' % (hours, mins, secs)
        self.duration_human = []
        if hours > 0:
            self.duration_human.append('%d %s' % (hours, self.voice.hhmmss(hours, 'h')))
        if mins > 0:
            self.duration_human.append('%d %s' % (mins, self.voice.hhmmss(mins, 'm')))
        if secs > 0:
            self.duration_human.append('%d %s' % (secs, self.voice.hhmmss(secs, 's')))

        self.duration_human = ', '.join(self.duration_human)
        self.avg_reward /= (self.epochs if self.epochs else 1)

    def parse(self):
        lines = []

        if os.path.exists(self.path):
            with FileReadBackwards(self.path, encoding="utf-8") as fp:
                for line in fp:
                    line = line.strip()
                    if line != "" and line[0] != '[':
                        continue
                    lines.append(line)
                    if LastSession.START_TOKEN in line:
                        break
            lines.reverse()

        if len(lines) == 0:
            lines.append("Initial Session");

        self.last_session = lines
        self.last_session_id = hashlib.md5(lines[0].encode()).hexdigest()
        self.last_saved_session_id = self._get_last_saved_session_id()

        self._parse_stats()
        self.parsed = True

    def is_new(self):
        return self.last_session_id != self.last_saved_session_id
Esempio n. 19
0
    def __init__(self, config, state={}):
        self._render_cbs = []
        self._config = config
        self._canvas = None
        self._lock = Lock()
        self._voice = Voice(lang=config['main']['lang'])

        self._width, self._height, \
        face_pos, name_pos, status_pos = setup_display_specifics(config)

        self._state = State(
            state={
                'channel':
                LabeledValue(color=BLACK,
                             label='CH',
                             value='00',
                             position=(0, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'aps':
                LabeledValue(color=BLACK,
                             label='APS',
                             value='0 (00)',
                             position=(30, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),

                # 'epoch': LabeledValue(color=BLACK, label='E', value='0000', position=(145, 0), label_font=fonts.Bold,
                #                      text_font=fonts.Medium),
                'uptime':
                LabeledValue(color=BLACK,
                             label='UP',
                             value='00:00:00',
                             position=(self._width - 65, 0),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),

                # 'square':  Rect([1, 11, 124, 111]),
                'line1':
                Line([
                    0,
                    int(self._height * .12), self._width,
                    int(self._height * .12)
                ],
                     color=BLACK),
                'line2':
                Line([
                    0, self._height -
                    int(self._height * .12), self._width, self._height -
                    int(self._height * .12)
                ],
                     color=BLACK),

                # 'histogram': Histogram([4, 94], color = BLACK),
                'face':
                Text(value=faces.SLEEP,
                     position=face_pos,
                     color=BLACK,
                     font=fonts.Huge),
                'friend_face':
                Text(
                    value=None, position=(0,
                                          90), font=fonts.Bold, color=BLACK),
                'friend_name':
                Text(value=None,
                     position=(40, 93),
                     font=fonts.BoldSmall,
                     color=BLACK),
                'name':
                Text(value='%s>' % 'pwnagotchi',
                     position=name_pos,
                     color=BLACK,
                     font=fonts.Bold),
                # 'face2':   Bitmap( '/root/pwnagotchi/data/images/face_happy.bmp', (0, 20)),
                'status':
                Text(value=self._voice.default(),
                     position=status_pos,
                     color=BLACK,
                     font=fonts.Medium),
                'shakes':
                LabeledValue(label='PWND ',
                             value='0 (00)',
                             color=BLACK,
                             position=(0, self._height -
                                       int(self._height * .12) + 1),
                             label_font=fonts.Bold,
                             text_font=fonts.Medium),
                'mode':
                Text(value='AUTO',
                     position=(self._width - 25,
                               self._height - int(self._height * .12) + 1),
                     font=fonts.Bold,
                     color=BLACK),
            })

        for key, value in state.items():
            self._state.set(key, value)

        _thread.start_new_thread(self._refresh_handler, ())
Esempio n. 20
0
class LastSession:
    EPOCH_TOKEN = '[epoch '
    EPOCH_PARSER = re.compile(r'^.+\[epoch (\d+)\] (.+)')
    EPOCH_DATA_PARSER = re.compile(r'([a-z_]+)=([^\s]+)')
    TRAINING_TOKEN = ' training epoch '
    START_TOKEN = 'connecting to http'
    DEAUTH_TOKEN = 'deauthing '
    ASSOC_TOKEN = 'sending association frame to '
    HANDSHAKE_TOKEN = '!!! captured new handshake '

    def __init__(self, config):
        self.config = config
        self.voice = Voice(lang=config['main']['lang'])
        self.path = config['main']['log']['path']
        self.last_session = []
        self.last_session_id = ''
        self.last_saved_session_id = ''
        self.duration = ''
        self.duration_human = ''
        self.deauthed = 0
        self.associated = 0
        self.handshakes = 0
        self.epochs = 0
        self.train_epochs = 0
        self.min_reward = 1000
        self.max_reward = -1000
        self.avg_reward = 0
        self.parsed = False

    def _get_last_saved_session_id(self):
        saved = ''
        try:
            with open(LAST_SESSION_FILE, 'rt') as fp:
                saved = fp.read().strip()
        except:
            saved = ''
        return saved

    def save_session_id(self):
        with open(LAST_SESSION_FILE, 'w+t') as fp:
            fp.write(self.last_session_id)
            self.last_saved_session_id = self.last_session_id

    def _parse_datetime(self, dt):
        dt = dt.split('.')[0]
        dt = dt.split(',')[0]
        dt = datetime.strptime(dt.split('.')[0], '%Y-%m-%d %H:%M:%S')
        return time.mktime(dt.timetuple())

    def _parse_stats(self):
        self.duration = ''
        self.duration_human = ''
        self.deauthed = 0
        self.associated = 0
        self.handshakes = 0
        self.epochs = 0
        self.train_epochs = 0
        self.min_reward = 1000
        self.max_reward = -1000
        self.avg_reward = 0

        started_at = None
        stopped_at = None
        cache = {}

        for line in self.last_session:
            parts = line.split(']')
            if len(parts) < 2:
                continue

            try:
                line_timestamp = parts[0].strip('[')
                line = ']'.join(parts[1:])
                stopped_at = self._parse_datetime(line_timestamp)
                if started_at is None:
                    started_at = stopped_at

                if LastSession.DEAUTH_TOKEN in line and line not in cache:
                    self.deauthed += 1
                    cache[line] = 1

                elif LastSession.ASSOC_TOKEN in line and line not in cache:
                    self.associated += 1
                    cache[line] = 1

                elif LastSession.HANDSHAKE_TOKEN in line and line not in cache:
                    self.handshakes += 1
                    cache[line] = 1

                elif LastSession.TRAINING_TOKEN in line:
                    self.train_epochs += 1

                elif LastSession.EPOCH_TOKEN in line:
                    self.epochs += 1
                    m = LastSession.EPOCH_PARSER.findall(line)
                    if m:
                        epoch_num, epoch_data = m[0]
                        m = LastSession.EPOCH_DATA_PARSER.findall(epoch_data)
                        for key, value in m:
                            if key == 'reward':
                                reward = float(value)
                                self.avg_reward += reward
                                if reward < self.min_reward:
                                    self.min_reward = reward

                                elif reward > self.max_reward:
                                    self.max_reward = reward

            except Exception as e:
                logging.error("error parsing line '%s': %s" % (line, e))

        if started_at is not None:
            self.duration = stopped_at - started_at
            mins, secs = divmod(self.duration, 60)
            hours, mins = divmod(mins, 60)
        else:
            hours = mins = secs = 0

        self.duration = '%02d:%02d:%02d' % (hours, mins, secs)
        self.duration_human = []
        if hours > 0:
            self.duration_human.append('%d %s' %
                                       (hours, self.voice.hhmmss(hours, 'h')))
        if mins > 0:
            self.duration_human.append('%d %s' %
                                       (mins, self.voice.hhmmss(mins, 'm')))
        if secs > 0:
            self.duration_human.append('%d %s' %
                                       (secs, self.voice.hhmmss(secs, 's')))

        self.duration_human = ', '.join(self.duration_human)
        self.avg_reward /= (self.epochs if self.epochs else 1)

    def parse(self, ui, skip=False):
        if skip:
            logging.debug("skipping parsing of the last session logs ...")
        else:
            logging.debug("reading last session logs ...")

            ui.on_reading_logs()

            lines = []

            if os.path.exists(self.path):
                with FileReadBackwards(self.path, encoding="utf-8") as fp:
                    for line in fp:
                        line = line.strip()
                        if line != "" and line[0] != '[':
                            continue
                        lines.append(line)
                        if LastSession.START_TOKEN in line:
                            break

                        lines_so_far = len(lines)
                        if lines_so_far % 100 == 0:
                            ui.on_reading_logs(lines_so_far)

                lines.reverse()

            if len(lines) == 0:
                lines.append("Initial Session")

            ui.on_reading_logs()

            self.last_session = lines
            self.last_session_id = hashlib.md5(lines[0].encode()).hexdigest()
            self.last_saved_session_id = self._get_last_saved_session_id()

            logging.debug("parsing last session logs (%d lines) ..." %
                          len(lines))

            self._parse_stats()
        self.parsed = True

    def is_new(self):
        return self.last_session_id != self.last_saved_session_id