119 lines
4.3 KiB
Python
119 lines
4.3 KiB
Python
import logging
|
|
|
|
import pwnagotchi.plugins as plugins
|
|
from pwnagotchi.ai.epoch import Epoch
|
|
|
|
|
|
# basic mood system
|
|
class Automata(object):
|
|
def __init__(self, config, view):
|
|
self._config = config
|
|
self._view = view
|
|
self._epoch = Epoch(config)
|
|
|
|
def _on_miss(self, who):
|
|
logging.info("it looks like %s is not in range anymore :/" % who)
|
|
self._epoch.track(miss=True)
|
|
self._view.on_miss(who)
|
|
|
|
def _on_error(self, who, e):
|
|
error = "%s" % e
|
|
# when we're trying to associate or deauth something that is not in range anymore
|
|
# (if we are moving), we get the following error from bettercap:
|
|
# error 400: 50:c7:bf:2e:d3:37 is an unknown BSSID or it is in the association skip list.
|
|
if 'is an unknown BSSID' in error:
|
|
self._on_miss(who)
|
|
else:
|
|
logging.error("%s" % e)
|
|
|
|
def set_starting(self):
|
|
self._view.on_starting()
|
|
|
|
def set_ready(self):
|
|
plugins.on('ready', self)
|
|
|
|
def _has_support_network_for(self, factor):
|
|
bond_factor = self._config['personality']['bond_encounters_factor']
|
|
total_encounters = sum(peer.encounters for _, peer in self._peers.items())
|
|
support_factor = total_encounters / bond_factor
|
|
return support_factor >= factor
|
|
|
|
# triggered when it's a sad/bad day but you have good friends around ^_^
|
|
def set_grateful(self):
|
|
self._view.on_grateful()
|
|
plugins.on('grateful', self)
|
|
|
|
def set_lonely(self):
|
|
if not self._has_support_network_for(1.0):
|
|
self._view.on_lonely()
|
|
plugins.on('lonely', self)
|
|
else:
|
|
self.set_grateful()
|
|
|
|
def set_bored(self):
|
|
factor = self._epoch.inactive_for / self._config['personality']['bored_num_epochs']
|
|
if not self._has_support_network_for(factor):
|
|
logging.warning("%d epochs with no activity -> bored" % self._epoch.inactive_for)
|
|
self._view.on_bored()
|
|
plugins.on('bored', self)
|
|
else:
|
|
self.set_grateful()
|
|
|
|
def set_sad(self):
|
|
factor = self._epoch.inactive_for / self._config['personality']['sad_num_epochs']
|
|
if not self._has_support_network_for(factor):
|
|
logging.warning("%d epochs with no activity -> sad" % self._epoch.inactive_for)
|
|
self._view.on_sad()
|
|
plugins.on('sad', self)
|
|
else:
|
|
self.set_grateful()
|
|
|
|
def set_excited(self):
|
|
logging.warning("%d epochs with activity -> excited" % self._epoch.active_for)
|
|
self._view.on_excited()
|
|
plugins.on('excited', self)
|
|
|
|
def set_rebooting(self):
|
|
self._view.on_rebooting()
|
|
plugins.on('rebooting', self)
|
|
|
|
def wait_for(self, t, sleeping=True):
|
|
plugins.on('sleep' if sleeping else 'wait', self, t)
|
|
self._view.wait(t, sleeping)
|
|
self._epoch.track(sleep=True, inc=t)
|
|
|
|
def is_stale(self):
|
|
return self._epoch.num_missed > self._config['personality']['max_misses_for_recon']
|
|
|
|
def any_activity(self):
|
|
return self._epoch.any_activity
|
|
|
|
def next_epoch(self):
|
|
was_stale = self.is_stale()
|
|
did_miss = self._epoch.num_missed
|
|
|
|
self._epoch.next()
|
|
|
|
# after X misses during an epoch, set the status to lonely
|
|
if was_stale:
|
|
logging.warning("agent missed %d interactions -> lonely" % did_miss)
|
|
self.set_lonely()
|
|
# after X times being bored, the status is set to sad
|
|
elif self._epoch.inactive_for >= self._config['personality']['sad_num_epochs']:
|
|
self.set_sad()
|
|
# after X times being inactive, the status is set to bored
|
|
elif self._epoch.inactive_for >= self._config['personality']['bored_num_epochs']:
|
|
self.set_bored()
|
|
# after X times being active, the status is set to happy / excited
|
|
elif self._epoch.active_for >= self._config['personality']['excited_num_epochs']:
|
|
self.set_excited()
|
|
elif self._has_support_network_for(1.0):
|
|
self.set_grateful()
|
|
|
|
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
|
|
|
|
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']:
|
|
logging.critical("%d epochs without visible access points -> rebooting ..." % self._epoch.blind_for)
|
|
self._reboot()
|
|
self._epoch.blind_for = 0
|