new: integrated python standard logger (closes #84)

This commit is contained in:
Simone Margaritelli 2019-10-03 17:06:40 +02:00
parent 335e6b1311
commit 4cf2866737
19 changed files with 171 additions and 173 deletions

View File

@ -202,14 +202,14 @@ running = False
def on_loaded():
core.log("GPS plugin loaded for %s" % device)
logging.info("GPS plugin loaded for %s" % device)
def on_ready(agent):
global running
if os.path.exists(device):
core.log("enabling GPS bettercap's module for %s" % device)
logging.info("enabling GPS bettercap's module for %s" % device)
try:
agent.run('gps off')
except:
@ -220,7 +220,7 @@ def on_ready(agent):
agent.run('gps on')
running = True
else:
core.log("no GPS detected")
logging.info("no GPS detected")
def on_handshake(agent, filename, access_point, client_station):
@ -229,7 +229,7 @@ def on_handshake(agent, filename, access_point, client_station):
gps = info['gps']
gps_filename = filename.replace('.pcap', '.gps.json')
core.log("saving GPS to %s (%s)" % (gps_filename, gps))
logging.info("saving GPS to %s (%s)" % (gps_filename, gps))
with open(gps_filename, 'w+t') as fp:
json.dump(gps, fp)
```

View File

@ -6,6 +6,7 @@ import time
import argparse
from http.server import HTTPServer
import shutil
import logging
import yaml
sys.path.insert(0,
@ -13,7 +14,6 @@ sys.path.insert(0,
'../sdcard/rootfs/root/pwnagotchi/scripts/'))
from pwnagotchi.ui.display import Display, VideoHandler
import core
class CustomDisplay(Display):
@ -22,11 +22,11 @@ class CustomDisplay(Display):
if self._video_address is not None:
self._httpd = HTTPServer((self._video_address, self._video_port),
CustomVideoHandler)
core.log("ui available at http://%s:%d/" % (self._video_address,
logging.info("ui available at http://%s:%d/" % (self._video_address,
self._video_port))
self._httpd.serve_forever()
else:
core.log("could not get ip of usb0, video server not starting")
logging.info("could not get ip of usb0, video server not starting")
def _on_view_rendered(self, img):
CustomVideoHandler.render(img)
@ -45,7 +45,7 @@ class CustomVideoHandler(VideoHandler):
try:
img.save("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), format='PNG')
except BaseException:
core.log("could not write preview")
logging.exception("could not write preview")
def do_GET(self):
if self.path == '/':
@ -69,7 +69,7 @@ class CustomVideoHandler(VideoHandler):
with open("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), 'rb') as fp:
shutil.copyfileobj(fp, self.wfile)
except BaseException:
core.log("could not open preview")
logging.exception("could not open preview")
else:
self.send_response(404)

View File

@ -1,8 +1,7 @@
import logging
import requests
from requests.auth import HTTPBasicAuth
import core
class Client(object):
def __init__(self, hostname='localhost', scheme='http', port=8081, username='user', password='pass'):
@ -19,11 +18,11 @@ class Client(object):
return r.json()
except Exception as e:
if r.status_code == 200:
core.log("error while decoding json: error='%s' resp='%s'" % (e, r.text))
logging.error("error while decoding json: error='%s' resp='%s'" % (e, r.text))
else:
err = "error %d: %s" % (r.status_code, r.text.strip())
if verbose_errors:
core.log(err)
logging.info(err)
raise Exception(err)
return r.text

View File

@ -1,24 +1,7 @@
import sys
import glob
import os
import time
import subprocess
from threading import Lock
from datetime import datetime
logfile = None
loglock = Lock()
def log(msg):
tstamp = str(datetime.now())
line = "[%s] %s" % (tstamp, msg.rstrip())
print(line)
sys.stdout.flush()
if logfile is not None:
with loglock:
with open(logfile, 'a+t') as fp:
fp.write("%s\n" % line)
def secs_to_hhmmss(secs):

View File

@ -2,11 +2,10 @@
import os
import argparse
import time
import traceback
import logging
import yaml
import core
import pwnagotchi
import pwnagotchi.utils as utils
import pwnagotchi.version as version
@ -28,8 +27,12 @@ parser.add_argument('--manual', dest="do_manual", action="store_true", default=F
parser.add_argument('--clear', dest="do_clear", action="store_true", default=False,
help="Clear the ePaper display and exit.")
parser.add_argument('--debug', dest="debug", action="store_true", default=False,
help="Enable debug logs.")
args = parser.parse_args()
config = utils.load_config(args)
utils.setup_logging(args, config)
if args.do_clear:
print("clearing the display ...")
@ -75,19 +78,18 @@ plugins.on('loaded')
display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
agent = Agent(view=display, config=config)
core.log("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, version.version))
logging.info("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, version.version))
# for key, value in config['personality'].items():
# core.log(" %s: %s" % (key, value))
# logging.info(" %s: %s" % (key, value))
for _, plugin in plugins.loaded.items():
core.log("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
logging.info("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
if args.do_manual:
core.log("entering manual mode ...")
logging.info("entering manual mode ...")
log = SessionParser(config['main']['log'])
core.log("the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
logging.info("the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
log.duration_human,
log.epochs,
log.train_epochs,
@ -98,17 +100,18 @@ if args.do_manual:
while True:
display.on_manual_mode(log)
time.sleep(1)
if config['twitter']['enabled'] and log.is_new() and Agent.is_connected() and log.handshakes > 0:
import tweepy
core.log("detected a new session and internet connectivity!")
logging.info("detected a new session and internet connectivity!")
picture = '/dev/shm/pwnagotchi.png'
display.update()
display.update(force=True)
display.image().save(picture, 'png')
display.set('status', 'Tweeting...')
display.update()
display.update(force=True)
try:
auth = tweepy.OAuthHandler(config['twitter']['consumer_key'], config['twitter']['consumer_secret'])
@ -119,14 +122,12 @@ if args.do_manual:
api.update_with_media(filename=picture, status=tweet)
log.save_session_id()
core.log("tweeted: %s" % tweet)
logging.info("tweeted: %s" % tweet)
except Exception as e:
core.log("error: %s" % e)
logging.exception("error while tweeting")
quit()
core.logfile = config['main']['log']
agent.start_ai()
agent.setup_events()
agent.set_starting()
@ -151,7 +152,7 @@ while True:
agent.set_channel(ch)
if not agent.is_stale() and agent.any_activity():
core.log("%d access points on channel %d" % (len(aps), ch))
logging.info("%d access points on channel %d" % (len(aps), ch))
# for each ap on this channel
for ap in aps:
@ -170,5 +171,4 @@ while True:
# affect ours ... neat ^_^
agent.next_epoch()
except Exception as e:
core.log("main loop exception: %s" % e)
core.log("%s" % traceback.format_exc())
logging.exception("main loop exception")

View File

@ -4,6 +4,7 @@ import os
import re
import socket
from datetime import datetime
import logging
import _thread
import core
@ -82,7 +83,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
plugins.on('rebooting', self)
def setup_events(self):
core.log("connecting to %s ..." % self.url)
logging.info("connecting to %s ..." % self.url)
for tag in self._config['bettercap']['silence']:
try:
@ -109,30 +110,30 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
s = self.session()
for iface in s['interfaces']:
if iface['name'] == mon_iface:
core.log("found monitor interface: %s" % iface['name'])
logging.info("found monitor interface: %s" % iface['name'])
has_mon = True
break
if has_mon is False:
if mon_start_cmd is not None and mon_start_cmd != '':
core.log("starting monitor interface ...")
logging.info("starting monitor interface ...")
self.run('!%s' % mon_start_cmd)
else:
core.log("waiting for monitor interface %s ..." % mon_iface)
logging.info("waiting for monitor interface %s ..." % mon_iface)
time.sleep(1)
core.log("supported channels: %s" % self._supported_channels)
core.log("handshakes will be collected inside %s" % self._config['bettercap']['handshakes'])
logging.info("supported channels: %s" % self._supported_channels)
logging.info("handshakes will be collected inside %s" % self._config['bettercap']['handshakes'])
self._reset_wifi_settings()
wifi_running = self.is_module_running('wifi')
if wifi_running and restart:
core.log("restarting wifi module ...")
logging.debug("restarting wifi module ...")
self.restart('wifi.recon')
self.run('wifi.clear')
elif not wifi_running:
core.log("starting wifi module ...")
logging.debug("starting wifi module ...")
self.start('wifi.recon')
self.start_advertising()
@ -150,13 +151,13 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
for ch in self._epoch.non_overlapping_channels:
if ch not in busy_channels:
self._epoch.non_overlapping_channels[ch] += 1
core.log("channel %d is free from %d epochs" % (ch, self._epoch.non_overlapping_channels[ch]))
logging.info("channel %d is free from %d epochs" % (ch, self._epoch.non_overlapping_channels[ch]))
elif self._epoch.non_overlapping_channels[ch] > 0:
self._epoch.non_overlapping_channels[ch] -= 1
# report any channel that has been free for at least 3 epochs
for ch, num_epochs_free in self._epoch.non_overlapping_channels.items():
if num_epochs_free >= 3:
core.log("channel %d has been free for %d epochs" % (ch, num_epochs_free))
logging.info("channel %d has been free for %d epochs" % (ch, num_epochs_free))
self.set_free_channel(ch)
def recon(self):
@ -172,14 +173,14 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
if not channels:
self._current_channel = 0
# core.log("RECON %ds" % recon_time)
logging.debug("RECON %ds" % recon_time)
self.run('wifi.recon.channel clear')
else:
# core.log("RECON %ds ON CHANNELS %s" % (recon_time, ','.join(map(str, channels))))
logging.debug("RECON %ds ON CHANNELS %s" % (recon_time, ','.join(map(str, channels))))
try:
self.run('wifi.recon.channel %s' % ','.join(map(str, channels)))
except Exception as e:
core.log("error: %s" % e)
logging.exception("error")
self.wait_for(recon_time, sleeping=False)
@ -204,7 +205,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
if self._filter_included(ap):
aps.append(ap)
except Exception as e:
core.log("error: %s" % e)
logging.exception("error")
aps.sort(key=lambda ap: ap['channel'])
return self.set_access_points(aps)
@ -289,7 +290,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
self._view.set_closest_peer(peer)
def _save_recovery_data(self):
core.log("writing recovery data to %s ..." % RECOVERY_DATA_FILE)
logging.warning("writing recovery data to %s ..." % RECOVERY_DATA_FILE)
with open(RECOVERY_DATA_FILE, 'w') as fp:
data = {
'started_at': self._started_at,
@ -304,7 +305,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
try:
with open(RECOVERY_DATA_FILE, 'rt') as fp:
data = json.load(fp)
core.log("found recovery data: %s" % data)
logging.info("found recovery data: %s" % data)
self._started_at = data['started_at']
self._epoch.epoch = data['epoch']
self._handshakes = data['handshakes']
@ -312,7 +313,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
self._last_pwnd = data['last_pwnd']
if delete:
core.log("deleting %s" % RECOVERY_DATA_FILE)
logging.info("deleting %s" % RECOVERY_DATA_FILE)
os.unlink(RECOVERY_DATA_FILE)
except:
if not no_exceptions:
@ -323,7 +324,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
self.run('events.clear')
core.log("event polling started ...")
logging.debug("event polling started ...")
while True:
time.sleep(1)
@ -349,21 +350,21 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
new_shakes += 1
ap_and_station = self._find_ap_sta_in(sta_mac, ap_mac, s)
if ap_and_station is None:
core.log("!!! captured new handshake: %s !!!" % key)
logging.warning("!!! captured new handshake: %s !!!" % key)
self._last_pwnd = ap_mac
plugins.on('handshake', self, filename, ap_mac, sta_mac)
else:
(ap, sta) = ap_and_station
self._last_pwnd = ap['hostname'] if ap['hostname'] != '' and ap[
'hostname'] != '<hidden>' else ap_mac
core.log("!!! captured new handshake on channel %d: %s (%s) -> %s [%s (%s)] !!!" % ( \
logging.warning("!!! captured new handshake on channel %d: %s (%s) -> %s [%s (%s)] !!!" % ( \
ap['channel'],
sta['mac'], sta['vendor'],
ap['hostname'], ap['mac'], ap['vendor']))
plugins.on('handshake', self, filename, ap, sta)
except Exception as e:
core.log("error: %s" % e)
logging.exception("error")
finally:
self._update_handshakes(new_shakes)
@ -404,7 +405,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
return self._history[who] < self._config['personality']['max_interactions']
def _on_miss(self, who):
core.log("it looks like %s is not in range anymore :/" % who)
logging.info("it looks like %s is not in range anymore :/" % who)
self._epoch.track(miss=True)
self._view.on_miss(who)
@ -416,18 +417,18 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
if 'is an unknown BSSID' in error:
self._on_miss(who)
else:
core.log("error: %s" % e)
logging.error("%s" % e)
def associate(self, ap, throttle=0):
if self.is_stale():
core.log("recon is stale, skipping assoc(%s)" % ap['mac'])
logging.debug("recon is stale, skipping assoc(%s)" % ap['mac'])
return
if self._config['personality']['associate'] and self._should_interact(ap['mac']):
self._view.on_assoc(ap)
try:
core.log("sending association frame to %s (%s %s) on channel %d [%d clients]..." % ( \
logging.info("sending association frame to %s (%s %s) on channel %d [%d clients]..." % ( \
ap['hostname'], ap['mac'], ap['vendor'], ap['channel'], len(ap['clients'])))
self.run('wifi.assoc %s' % ap['mac'])
self._epoch.track(assoc=True)
@ -441,14 +442,14 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
def deauth(self, ap, sta, throttle=0):
if self.is_stale():
core.log("recon is stale, skipping deauth(%s)" % sta['mac'])
logging.debug("recon is stale, skipping deauth(%s)" % sta['mac'])
return
if self._config['personality']['deauth'] and self._should_interact(sta['mac']):
self._view.on_deauth(sta)
try:
core.log("deauthing %s (%s) from %s (%s %s) on channel %d ..." % (
logging.info("deauthing %s (%s) from %s (%s %s) on channel %d ..." % (
sta['mac'], sta['vendor'], ap['hostname'], ap['mac'], ap['vendor'], ap['channel']))
self.run('wifi.deauth %s' % sta['mac'])
self._epoch.track(deauth=True)
@ -462,7 +463,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
def set_channel(self, channel, verbose=True):
if self.is_stale():
core.log("recon is stale, skipping set_channel(%d)" % channel)
logging.debug("recon is stale, skipping set_channel(%d)" % channel)
return
# if in the previous loop no client stations has been deauthenticated
@ -478,10 +479,12 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
if channel != self._current_channel:
if self._current_channel != 0 and wait > 0:
if verbose:
core.log("waiting for %ds on channel %d ..." % (wait, self._current_channel))
logging.info("waiting for %ds on channel %d ..." % (wait, self._current_channel))
else:
logging.debug("waiting for %ds on channel %d ..." % (wait, self._current_channel))
self.wait_for(wait)
if verbose and self._epoch.any_activity:
core.log("CHANNEL %d" % channel)
logging.info("CHANNEL %d" % channel)
try:
self.run('wifi.recon.channel %d' % channel)
self._current_channel = channel
@ -491,7 +494,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
plugins.on('channel_hop', self, channel)
except Exception as e:
core.log("error: %s" % e)
logging.error("error: %s" % e)
def is_stale(self):
return self._epoch.num_missed > self._config['personality']['max_misses_for_recon']
@ -502,7 +505,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
def _reboot(self):
self.set_rebooting()
self._save_recovery_data()
core.log("rebooting the system ...")
logging.warning("rebooting the system ...")
os.system("/usr/bin/sync")
os.system("/usr/sbin/shutdown -r now")
@ -514,24 +517,24 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
# after X misses during an epoch, set the status to lonely
if was_stale:
core.log("agent missed %d interactions -> lonely" % did_miss)
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']:
core.log("%d epochs with no activity -> sad" % self._epoch.inactive_for)
logging.warning("%d epochs with no activity -> sad" % self._epoch.inactive_for)
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']:
core.log("%d epochs with no activity -> bored" % self._epoch.inactive_for)
logging.warning("%d epochs with no activity -> bored" % self._epoch.inactive_for)
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']:
core.log("%d epochs with activity -> excited" % self._epoch.active_for)
logging.warning("%d epochs with activity -> excited" % self._epoch.active_for)
self.set_excited()
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']:
core.log("%d epochs without visible access points -> rebooting ..." % self._epoch.blind_for)
logging.critical("%d epochs without visible access points -> rebooting ..." % self._epoch.blind_for)
self._reboot()
self._epoch.blind_for = 0

View File

@ -7,16 +7,16 @@ import warnings
# https://stackoverflow.com/questions/15777951/how-to-suppress-pandas-future-warning
warnings.simplefilter(action='ignore', category=FutureWarning)
import core
import logging
def load(config, agent, epoch, from_disk=True):
config = config['ai']
if not config['enabled']:
core.log("ai disabled")
logging.info("ai disabled")
return False
core.log("[ai] bootstrapping dependencies ...")
logging.info("[ai] bootstrapping dependencies ...")
from stable_baselines import A2C
from stable_baselines.common.policies import MlpLstmPolicy
@ -27,16 +27,16 @@ def load(config, agent, epoch, from_disk=True):
env = wrappers.Environment(agent, epoch)
env = DummyVecEnv([lambda: env])
core.log("[ai] bootstrapping model ...")
logging.info("[ai] bootstrapping model ...")
a2c = A2C(MlpLstmPolicy, env, **config['params'])
if from_disk and os.path.exists(config['path']):
core.log("[ai] loading %s ..." % config['path'])
logging.info("[ai] loading %s ..." % config['path'])
a2c.load(config['path'], env)
else:
core.log("[ai] model created:")
logging.info("[ai] model created:")
for key, value in config['params'].items():
core.log(" %s: %s" % (key, value))
logging.info(" %s: %s" % (key, value))
return a2c

View File

@ -1,5 +1,6 @@
import time
import threading
import logging
import core
import pwnagotchi
@ -87,13 +88,13 @@ class Epoch(object):
aps_per_chan[ch_idx] += 1.0
sta_per_chan[ch_idx] += len(ap['clients'])
except IndexError as e:
core.log("got data on channel %d, we can store %d channels" % (ap['channel'], wifi.NumChannels))
logging.error("got data on channel %d, we can store %d channels" % (ap['channel'], wifi.NumChannels))
for peer in peers:
try:
peers_per_chan[peer.last_channel - 1] += 1.0
except IndexError as e:
core.log(
logging.error(
"got peer data on channel %d, we can store %d channels" % (peer.last_channel, wifi.NumChannels))
# normalize
@ -172,7 +173,7 @@ class Epoch(object):
self._epoch_data['reward'] = self._reward(self.epoch + 1, self._epoch_data)
self._epoch_data_ready.set()
core.log("[epoch %d] duration=%s slept_for=%s blind=%d inactive=%d active=%d hops=%d missed=%d "
logging.info("[epoch %d] duration=%s slept_for=%s blind=%d inactive=%d active=%d hops=%d missed=%d "
"deauths=%d assocs=%d handshakes=%d cpu=%d%% mem=%d%% temperature=%dC reward=%s" % (
self.epoch,
core.secs_to_hhmmss(self.epoch_duration),

View File

@ -1,8 +1,8 @@
import logging
import gym
from gym import spaces
import numpy as np
import core
import pwnagotchi.ai.featurizer as featurizer
import pwnagotchi.ai.reward as reward
from pwnagotchi.ai.parameter import Parameter
@ -83,7 +83,7 @@ class Environment(gym.Env):
return params
def _next_epoch(self):
# core.log("[ai] waiting for epoch to finish ...")
logging.debug("[ai] waiting for epoch to finish ...")
return self._epoch.wait_for_epoch_data()
def _apply_policy(self, policy):
@ -110,7 +110,7 @@ class Environment(gym.Env):
return self.last['state_v'], self.last['reward'], not self._agent.is_training(), {}
def reset(self):
# core.log("[ai] resetting environment ...")
# logging.info("[ai] resetting environment ...")
self._epoch_num = 0
state = self._next_epoch()
self.last['state'] = state
@ -120,7 +120,7 @@ class Environment(gym.Env):
def _render_histogram(self, hist):
for ch in range(featurizer.histogram_size):
if hist[ch]:
core.log(" CH %d: %s" % (ch + 1, hist[ch]))
logging.info(" CH %d: %s" % (ch + 1, hist[ch]))
def render(self, mode='human', close=False, force=False):
# when using a vectorialized environment, render gets called twice
@ -133,18 +133,13 @@ class Environment(gym.Env):
self._last_render = self._epoch_num
core.log("[ai] --- training epoch %d/%d ---" % (self._epoch_num, self._agent.training_epochs()))
core.log("[ai] REWARD: %f" % self.last['reward'])
logging.info("[ai] --- training epoch %d/%d ---" % (self._epoch_num, self._agent.training_epochs()))
logging.info("[ai] REWARD: %f" % self.last['reward'])
# core.log("[ai] policy: %s" % ', '.join("%s:%s" % (name, value) for name, value in self.last['params'].items()))
logging.debug("[ai] policy: %s" % ', '.join("%s:%s" % (name, value) for name, value in self.last['params'].items()))
core.log("[ai] observation:")
logging.info("[ai] observation:")
for name, value in self.last['state'].items():
if 'histogram' in name:
core.log(" %s" % name.replace('_histogram', ''))
logging.info(" %s" % name.replace('_histogram', ''))
self._render_histogram(value)
# core.log("[ai] outcome:")
# for name, value in self.last['state'].items():
# if 'histogram' not in name:
# core.log(" %s: %s" % (name, value))

View File

@ -4,8 +4,7 @@ import time
import random
import os
import json
import core
import logging
import pwnagotchi.plugins as plugins
import pwnagotchi.ai as ai
@ -56,7 +55,7 @@ class Stats(object):
def load(self):
with self._lock:
if os.path.exists(self.path) and os.path.getsize(self.path) > 0:
core.log("[ai] loading %s" % self.path)
logging.info("[ai] loading %s" % self.path)
with open(self.path, 'rt') as fp:
obj = json.load(fp)
@ -66,7 +65,7 @@ class Stats(object):
def save(self):
with self._lock:
core.log("[ai] saving %s" % self.path)
logging.info("[ai] saving %s" % self.path)
data = json.dumps({
'born_at': self.born_at,
@ -114,7 +113,7 @@ class AsyncTrainer(object):
_thread.start_new_thread(self._ai_worker, ())
def _save_ai(self):
core.log("[ai] saving model to %s ..." % self._nn_path)
logging.info("[ai] saving model to %s ..." % self._nn_path)
temp = "%s.tmp" % self._nn_path
self._model.save(temp)
os.replace(temp, self._nn_path)
@ -133,15 +132,15 @@ class AsyncTrainer(object):
def on_ai_policy(self, new_params):
plugins.on('ai_policy', self, new_params)
core.log("[ai] setting new policy:")
logging.info("[ai] setting new policy:")
for name, value in new_params.items():
if name in self._config['personality']:
curr_value = self._config['personality'][name]
if curr_value != value:
core.log("[ai] ! %s: %s -> %s" % (name, curr_value, value))
logging.info("[ai] ! %s: %s -> %s" % (name, curr_value, value))
self._config['personality'][name] = value
else:
core.log("[ai] param %s not in personality configuration!" % name)
logging.error("[ai] param %s not in personality configuration!" % name)
self.run('set wifi.ap.ttl %d' % self._config['personality']['ap_ttl'])
self.run('set wifi.sta.ttl %d' % self._config['personality']['sta_ttl'])
@ -152,12 +151,12 @@ class AsyncTrainer(object):
plugins.on('ai_ready', self)
def on_ai_best_reward(self, r):
core.log("[ai] best reward so far: %s" % r)
logging.info("[ai] best reward so far: %s" % r)
self._view.on_motivated(r)
plugins.on('ai_best_reward', self, r)
def on_ai_worst_reward(self, r):
core.log("[ai] worst reward so far: %s" % r)
logging.info("[ai] worst reward so far: %s" % r)
self._view.on_demotivated(r)
plugins.on('ai_worst_reward', self, r)
@ -174,12 +173,12 @@ class AsyncTrainer(object):
self._model.env.render()
# enter in training mode?
if random.random() > self._config['ai']['laziness']:
core.log("[ai] learning for %d epochs ..." % epochs_per_episode)
logging.info("[ai] learning for %d epochs ..." % epochs_per_episode)
try:
self.set_training(True, epochs_per_episode)
self._model.learn(total_timesteps=epochs_per_episode, callback=self.on_ai_training_step)
except Exception as e:
core.log("[ai] error while training: %s" % e)
logging.exception("[ai] error while training")
finally:
self.set_training(False)
obs = self._model.env.reset()

View File

@ -37,6 +37,8 @@ class SessionParser(object):
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())

View File

@ -2,9 +2,9 @@ import time
import json
import _thread
import threading
import logging
from scapy.all import Dot11, Dot11FCS, Dot11Elt, RadioTap, sendp, sniff
import core
import pwnagotchi.ui.faces as faces
import pwnagotchi.mesh.wifi as wifi
@ -54,7 +54,6 @@ class Advertiser(object):
self._lost_peer_cb = lost_cb
def on_face_change(self, old, new):
# core.log("face change: %s -> %s" % (old, new))
self.update({'face': new})
def start(self):
@ -84,12 +83,12 @@ class Advertiser(object):
self._stopped.set()
def _sender(self):
core.log("started advertiser thread (period:%s sid:%s) ..." % (str(self._period), self._me.session_id))
logging.info("started advertiser thread (period:%s sid:%s) ..." % (str(self._period), self._me.session_id))
while self._running:
try:
sendp(self._frame, iface=self._iface, verbose=False, count=5, inter=self._period)
except Exception as e:
core.log("error: %s" % e)
logging.exception("error")
time.sleep(self._period)
def _on_advertisement(self, src_session_id, channel, rssi, adv):
@ -97,7 +96,7 @@ class Advertiser(object):
with self._peers_lock:
if ident not in self._peers:
peer = Peer(src_session_id, channel, rssi, adv)
core.log("detected unit %s (v%s) on channel %d (%s dBm) [sid:%s pwnd_tot:%d uptime:%d]" % ( \
logging.info("detected unit %s (v%s) on channel %d (%s dBm) [sid:%s pwnd_tot:%d uptime:%d]" % ( \
peer.full_name(),
peer.version(),
channel,
@ -158,10 +157,10 @@ class Advertiser(object):
raise Exception("unknown frame id %d" % dot11elt.ID)
except Exception as e:
core.log("error decoding packet from %s: %s" % (dot11.addr3, e))
logging.exception("error decoding packet from %s" % dot11.addr3)
def _listener(self):
# core.log("started advertisements listener ...")
# logging.info("started advertisements listener ...")
expr = "type mgt subtype beacon and ether src %s" % wifi.SignatureAddress
sniff(iface=self._iface, filter=expr, prn=self._on_packet, store=0, stop_filter=lambda x: self._stopped.isSet())
@ -173,7 +172,7 @@ class Advertiser(object):
for ident, peer in self._peers.items():
inactive_for = peer.inactive_for()
if inactive_for >= Advertiser.MAX_STALE_TIME:
core.log("peer %s lost (inactive for %ds)" % (peer.full_name(), inactive_for))
logging.info("peer %s lost (inactive for %ds)" % (peer.full_name(), inactive_for))
self._lost_peer_cb(peer)
stale.append(ident)

View File

@ -1,8 +1,8 @@
import time
import logging
import pwnagotchi.mesh.wifi as wifi
import pwnagotchi.ui.faces as faces
import core
class Peer(object):
@ -18,10 +18,10 @@ class Peer(object):
def update(self, sid, channel, rssi, adv):
if self.name() != adv['name']:
core.log("peer %s changed name: %s -> %s" % (self.full_name(), self.name(), adv['name']))
logging.info("peer %s changed name: %s -> %s" % (self.full_name(), self.name(), adv['name']))
if self.session_id != sid:
core.log("peer %s changed session id: %s -> %s" % (self.full_name(), self.session_id, sid))
logging.info("peer %s changed session id: %s -> %s" % (self.full_name(), self.session_id, sid))
self.presence[channel - 1] += 1
self.adv = adv

View File

@ -1,6 +1,6 @@
import _thread
import logging
import core
import pwnagotchi
import pwnagotchi.version as version
import pwnagotchi.plugins as plugins
@ -35,7 +35,7 @@ class AsyncAdvertiser(object):
self._advertiser.start()
self._view.on_state_change('face', self._advertiser.on_face_change)
else:
core.log("advertising is disabled")
logging.warning("advertising is disabled")
def _on_new_unit(self, peer):
self._view.on_new_peer(peer)

View File

@ -5,15 +5,16 @@ __license__ = 'GPL3'
__description__ = 'An example plugin for pwnagotchi that implements all the available callbacks.'
__enabled__ = False # IMPORTANT: set this to True to enable your plugin.
import logging
from pwnagotchi.ui.components import LabeledValue
from pwnagotchi.ui.view import BLACK
import pwnagotchi.ui.fonts as fonts
import core
# called when the plugin is loaded
def on_loaded():
core.log("WARNING: plugin %s should be disabled!" % __name__)
logging.warning("WARNING: plugin %s should be disabled!" % __name__)
# called to setup the ui elements
@ -39,7 +40,7 @@ def on_display_setup(display):
# called when everything is ready and the main loop is about to start
def on_ready(agent):
core.log("unit is ready")
logging.info("unit is ready")
# you can run custom bettercap commands if you want
# agent.run('ble.recon on')
# or set a custom state

View File

@ -5,7 +5,7 @@ __license__ = 'GPL3'
__description__ = 'Save GPS coordinates whenever an handshake is captured.'
__enabled__ = True # set to false if you just don't use GPS
import core
import logging
import json
import os
@ -15,14 +15,14 @@ running = False
def on_loaded():
core.log("GPS plugin loaded for %s" % device)
logging.info("GPS plugin loaded for %s" % device)
def on_ready(agent):
global running
if os.path.exists(device):
core.log("enabling GPS bettercap's module for %s" % device)
logging.info("enabling GPS bettercap's module for %s" % device)
try:
agent.run('gps off')
except:
@ -33,7 +33,7 @@ def on_ready(agent):
agent.run('gps on')
running = True
else:
core.log("no GPS detected")
logging.warning("no GPS detected")
def on_handshake(agent, filename, access_point, client_station):
@ -42,6 +42,6 @@ def on_handshake(agent, filename, access_point, client_station):
gps = info['gps']
gps_filename = filename.replace('.pcap', '.gps.json')
core.log("saving GPS to %s (%s)" % (gps_filename, gps))
logging.info("saving GPS to %s (%s)" % (gps_filename, gps))
with open(gps_filename, 'w+t') as fp:
json.dump(gps, fp)

View File

@ -2,7 +2,7 @@ import _thread
from threading import Lock
import shutil
import core
import logging
import os
import pwnagotchi, pwnagotchi.plugins as plugins
@ -78,13 +78,12 @@ class Display(View):
self._render_cb = None
self._display = None
self._httpd = None
self.canvas = None
if self._enabled:
self._init_display()
else:
self.on_render(self._on_view_rendered)
core.log("display module is disabled")
logging.warning("display module is disabled")
if self._video_enabled:
_thread.start_new_thread(self._http_serve, ())
@ -92,10 +91,10 @@ class Display(View):
def _http_serve(self):
if self._video_address is not None:
self._httpd = HTTPServer((self._video_address, self._video_port), VideoHandler)
core.log("ui available at http://%s:%d/" % (self._video_address, self._video_port))
logging.info("ui available at http://%s:%d/" % (self._video_address, self._video_port))
self._httpd.serve_forever()
else:
core.log("could not get ip of usb0, video server not starting")
logging.info("could not get ip of usb0, video server not starting")
def _is_inky(self):
return self._display_type in ('inkyphat', 'inky')
@ -111,14 +110,14 @@ class Display(View):
def _init_display(self):
if self._is_inky():
core.log("initializing inky display")
logging.info("initializing inky display")
from inky import InkyPHAT
self._display = InkyPHAT(self._display_color)
self._display.set_border(InkyPHAT.BLACK)
self._render_cb = self._inky_render
elif self._is_papirus():
core.log("initializing papirus display")
logging.info("initializing papirus display")
from pwnagotchi.ui.papirus.epd import EPD
os.environ['EPD_SIZE'] = '2.0'
self._display = EPD()
@ -126,7 +125,7 @@ class Display(View):
self._render_cb = self._papirus_render
elif self._is_waveshare1():
core.log("initializing waveshare v1 display")
logging.info("initializing waveshare v1 display")
from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
self._display = EPD()
self._display.init(self._display.lut_full_update)
@ -135,7 +134,7 @@ class Display(View):
self._render_cb = self._waveshare_render
elif self._is_waveshare2():
core.log("initializing waveshare v2 display")
logging.info("initializing waveshare v2 display")
from pwnagotchi.ui.waveshare.v2.waveshare import EPD
self._display = EPD()
self._display.init(self._display.FULL_UPDATE)
@ -144,63 +143,61 @@ class Display(View):
self._render_cb = self._waveshare_render
else:
core.log("unknown display type %s" % self._display_type)
logging.critical("unknown display type %s" % self._display_type)
plugins.on('display_setup', self._display)
self.on_render(self._on_view_rendered)
def image(self):
img = None
if self.canvas is not None:
img = self.canvas if self._rotation == 0 else self.canvas.rotate(-self._rotation)
return img
def _inky_render(self):
if self._display_color != 'mono':
display_colors = 3
else:
display_colors = 2
imgbuf = self.canvas.convert('RGB').convert('P', palette=1, colors=display_colors)
img_buffer = self._canvas.convert('RGB').convert('P', palette=1, colors=display_colors)
if self._display_color == 'red':
imgbuf.putpalette([
img_buffer.putpalette([
255, 255, 255, # index 0 is white
0, 0, 0, # index 1 is black
255, 0, 0 # index 2 is red
])
elif self._display_color == 'yellow':
imgbuf.putpalette([
img_buffer.putpalette([
255, 255, 255, # index 0 is white
0, 0, 0, # index 1 is black
255, 255, 0 # index 2 is yellow
])
else:
imgbuf.putpalette([
img_buffer.putpalette([
255, 255, 255, # index 0 is white
0, 0, 0 # index 1 is black
])
self._display.set_image(imgbuf)
self._display.set_image(img_buffer)
self._display.show()
def _papirus_render(self):
self._display.display(self.canvas)
self._display.display(self._canvas)
self._display.partial_update()
def _waveshare_render(self):
buf = self._display.getbuffer(self.canvas)
buf = self._display.getbuffer(self._canvas)
if self._is_waveshare1():
self._display.display(buf)
elif self._is_waveshare2():
self._display.displayPartial(buf)
def image(self):
img = None
if self._canvas is not None:
img = self._canvas if self._rotation == 0 else self._canvas.rotate(-self._rotation)
return img
def _on_view_rendered(self, img):
# core.log("display::_on_view_rendered")
VideoHandler.render(img)
if self._enabled:
self.canvas = (img if self._rotation == 0 else img.rotate(self._rotation))
self._canvas = (img if self._rotation == 0 else img.rotate(self._rotation))
if self._render_cb is not None:
self._render_cb()

View File

@ -1,6 +1,7 @@
import _thread
from threading import Lock
import time
import logging
from PIL import Image, ImageDraw
import core
@ -114,7 +115,7 @@ class View(object):
_thread.start_new_thread(self._refresh_handler, ())
self._ignore_changes = ()
else:
core.log("ui.fps is 0, the display will only update for major changes")
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):
@ -135,7 +136,7 @@ class View(object):
def _refresh_handler(self):
delay = 1.0 / self._config['ui']['fps']
# core.log("view refresh handler started with period of %.2fs" % delay)
# logging.info("view refresh handler started with period of %.2fs" % delay)
while True:
name = self._state.get('name')
@ -313,10 +314,10 @@ class View(object):
self.set('status', self._voice.custom(text))
self.update()
def update(self):
def update(self, force=False):
with self._lock:
changes = self._state.changes(ignore=self._ignore_changes)
if len(changes):
if force or len(changes):
self._canvas = Image.new('1', (self._width, self._height), WHITE)
drawer = ImageDraw.Draw(self._canvas)

View File

@ -1,5 +1,7 @@
import yaml
import os
import logging
# https://stackoverflow.com/questions/823196/yaml-merge-in-python
def merge_config(user, default):
@ -21,4 +23,20 @@ def load_config(args):
user_config = yaml.safe_load(fp)
config = merge_config(user_config, config)
return config
return config
def setup_logging(args, config):
formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s")
root = logging.getLogger()
root.setLevel(logging.DEBUG if args.debug else logging.INFO)
if config['main']['log']:
file_handler = logging.FileHandler(config['main']['log'])
file_handler.setFormatter(formatter)
root.addHandler(file_handler)
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
root.addHandler(console_handler)