49 Commits

Author SHA1 Message Date
Simone Margaritelli
63dc672b11 releasing v1.4.3 2019-12-23 11:21:28 +01:00
evilsocket
0dac137df0 Merge pull request #746 from dadav/fix/scipy_version
Add scipy to requirements.txt
2019-12-23 11:16:53 +01:00
dadav
3db9ccb47e Add scipy to requirements.txt 2019-12-21 17:20:05 +01:00
Simone Margaritelli
a7164ea742 releasing v1.4.2 2019-12-19 17:36:09 +01:00
evilsocket
cae2a18016 Merge pull request #735 from dadav/fix/add_unload
add unload method
2019-12-17 16:48:23 +01:00
dadav
9d63eba232 add unload method 2019-12-16 18:50:40 +01:00
evilsocket
f141e15ba3 Merge pull request #727 from ArnCo/master
Set correct position for memtemp plugin so that it does not overlap with regular messages for waveshare27inch.
2019-12-16 12:00:46 +02:00
evilsocket
e68165ce06 Merge pull request #732 from xenDE/patch-5
webgpsmap: fix parsing new timezone format "Z" in gps data
2019-12-16 12:00:17 +02:00
evilsocket
3758806919 Merge pull request #725 from dadav/fix/remove_sysd_process_limits
remove process limits
2019-12-16 11:59:59 +02:00
evilsocket
1f91c6f09e Merge pull request #724 from dadav/feature/ensure_write
add ensure_write
2019-12-16 11:59:40 +02:00
evilsocket
3e8b6eafbd Merge pull request #722 from dadav/fix/no_comment
no comment
2019-12-16 11:59:12 +02:00
xenDE
44138ba463 webgpsmap: fix parsing new timezone format "Z" in gps data
fix timezone "Z": "2019-11-28T04:44:46.79231Z" >> "2019-11-28T04:44:46.79231+00:00"
issue: https://github.com/evilsocket/pwnagotchi/issues/708
2019-12-15 23:37:48 +01:00
ACO
4b71fea404 Set correct position for memtemp plugin so that it does not overlap with regular messages for waveshare27inch.
Signed-off-by: ArnCo <arnaud@cordier.work>
2019-12-14 11:49:21 +01:00
dadav
6babad0d02 remove process limits 2019-12-14 09:00:54 +01:00
dadav
e8513240ea add ensure_write 2019-12-13 19:42:04 +01:00
dadav
00101ccd07 no comment 2019-12-13 19:29:44 +01:00
Simone Margaritelli
e0a66f5c99 misc: small fix or general refactoring i did not bother commenting 2019-12-10 21:22:44 +02:00
Simone Margaritelli
81061cea24 fix: fixed locked callback call on plugins 2019-12-10 21:17:46 +02:00
evilsocket
93bb633010 Merge pull request #713 from alanyee/patch-1
Replace string formatting with logging laziness in __init__.py
2019-12-10 21:06:57 +02:00
evilsocket
dbb64e0fab Merge pull request #711 from dadav/fix/bugs
Unknown variable; Logic error
2019-12-10 19:40:57 +02:00
Alan Yee
fa8751017d Update __init__.py 2019-12-09 15:36:26 -08:00
dadav
9d56c97aa5 Unknown variable; Logic error 2019-12-09 20:12:34 +01:00
evilsocket
1523dfc1ef Merge pull request #701 from alanyee/patch-1
Update automata.py
2019-12-09 18:10:15 +02:00
evilsocket
a02960b56d Merge pull request #705 from hmax42/master
UI adjustments for waveshare1
2019-12-09 18:09:19 +02:00
evilsocket
b6f59f99d4 Merge pull request #707 from AliceGrey/master
Added text overflow checking for over 999 associations
2019-12-09 18:08:33 +02:00
Simone Margaritelli
09a00adab9 fix: added a plugin::callback level mutex to avoid calling a callback while a previous call is still running 2019-12-09 17:46:44 +02:00
AliceGrey
7fa30c2868 Added text overflow checking for over 999 associations 2019-12-08 17:16:05 -08:00
hmax42
774d9c693c Update defaults.yml 2019-12-08 16:26:14 +01:00
hmax42
87b6cf7d40 Merge branch 'master' of https://github.com/hmax42/pwnagotchi 2019-12-08 16:25:23 +01:00
hmax42
88928eec82 remove buttonshim 2019-12-08 16:25:07 +01:00
hmax42
60f7849838 Merge branch 'master' into pr/3 2019-12-08 08:46:24 +01:00
hmax42
3cf041617c Update memtemp.py 2019-12-08 08:44:20 +01:00
evilsocket
ee6c06f306 Merge pull request #700 from dadav/fix/auto-update-lock
Add Lock
2019-12-07 16:28:57 +02:00
dadav
2e22a17610 Add Lock 2019-12-07 15:27:41 +01:00
Simone Margaritelli
1615fc8817 releasing v1.4.1 2019-12-07 15:45:15 +02:00
Simone Margaritelli
714cb00610 misc: small fix or general refactoring i did not bother commenting 2019-12-07 15:44:03 +02:00
Simone Margaritelli
a0a790635a fix: fuck me for trusting people's PR without checking 10000 times 2019-12-07 15:43:10 +02:00
Alan Yee
f8ffab426b Update automata.py
Replace string formatting with logging laziness in automata.py
2019-12-06 12:20:54 -08:00
hmax42
f563d71477 Update gps.py 2019-12-01 14:27:13 +01:00
hmax42
7b219fd139 Update memtemp.py 2019-12-01 14:27:10 +01:00
hmax42
42ed698583 Update memtemp.py 2019-12-01 08:06:14 +01:00
hmax42
6df7bcd885 add ws1 2019-12-01 07:56:09 +01:00
hmax42
1c299832ae add ws1 2019-12-01 07:56:03 +01:00
hmax42
11476433ca Merge pull request #2 from evilsocket/master
update
2019-12-01 07:49:23 +01:00
hmax42
b1ad247e11 Merge pull request #1 from evilsocket/master
pull
2019-11-18 17:19:52 +01:00
hmax42
30b1874a0a New defaults for buttonshim 2019-11-11 19:08:12 +01:00
hmax42
b903f636d2 Blinking works now freely 2019-11-11 19:04:56 +01:00
hmax42
92c1b6b005 blinking with static colors 2019-11-10 13:44:35 +01:00
hmax42
eddfdb3ebc Plugin for the Pimoroni Button Shim
this plugin enabled support for the 5 buttons of the shim. the rgb led is not supported yet. an example for config.yml lloks like this

      buttonshim:
        enabled: true
        buttons:
          - "date >> /home/pi/buttonA.txt"
          - "date >> /home/pi/buttonB.txt"
          - "date >> /home/pi/buttonC.txt"
          - "date >> /home/pi/buttonD.txt"
          - "date >> /home/pi/buttonE.txt"
2019-11-10 08:54:04 +01:00
16 changed files with 142 additions and 74 deletions

View File

@@ -13,7 +13,7 @@ import pwnagotchi.plugins as plugins
from pwnagotchi.identity import KeyPair from pwnagotchi.identity import KeyPair
from pwnagotchi.agent import Agent from pwnagotchi.agent import Agent
from pwnagotchi.ui.display import Display from pwnagotchi.ui.display import Display
from pwnagotch import restart from pwnagotchi import restart
def do_clear(display): def do_clear(display):

View File

@@ -10,6 +10,8 @@ PermissionsStartOnly=true
ExecStart=/usr/bin/pwnagotchi-launcher ExecStart=/usr/bin/pwnagotchi-launcher
Restart=always Restart=always
RestartSec=30 RestartSec=30
TasksMax=infinity
LimitNPROC=infinity
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@@ -1,12 +1,12 @@
import subprocess
import os import os
import logging import logging
import time import time
import re import re
import pwnagotchi.ui.view as view import pwnagotchi.ui.view as view
import pwnagotchi import pwnagotchi
version = '1.4.0' version = '1.4.3'
_name = None _name = None
@@ -27,17 +27,17 @@ def set_name(new_name):
if new_name != current: if new_name != current:
global _name global _name
logging.info("setting unit hostname '%s' -> '%s'" % (current, new_name)) logging.info("setting unit hostname '%s' -> '%s'", current, new_name)
with open('/etc/hostname', 'wt') as fp: with open('/etc/hostname', 'wt') as fp:
fp.write(new_name) fp.write(new_name)
with open('/etc/hosts', 'rt') as fp: with open('/etc/hosts', 'rt') as fp:
prev = fp.read() prev = fp.read()
logging.debug("old hosts:\n%s\n" % prev) logging.debug("old hosts:\n%s\n", prev)
with open('/etc/hosts', 'wt') as fp: with open('/etc/hosts', 'wt') as fp:
patched = prev.replace(current, new_name, -1) patched = prev.replace(current, new_name, -1)
logging.debug("new hosts:\n%s\n" % patched) logging.debug("new hosts:\n%s\n", patched)
fp.write(patched) fp.write(patched)
os.system("hostname '%s'" % new_name) os.system("hostname '%s'" % new_name)
@@ -109,7 +109,7 @@ def shutdown():
def restart(mode): def restart(mode):
logging.warning("restarting in %s mode ..." % mode) logging.warning("restarting in %s mode ...", mode)
if mode == 'AUTO': if mode == 'AUTO':
os.system("touch /root/.pwnagotchi-auto") os.system("touch /root/.pwnagotchi-auto")
@@ -123,7 +123,7 @@ def restart(mode):
def reboot(mode=None): def reboot(mode=None):
if mode is not None: if mode is not None:
mode = mode.upper() mode = mode.upper()
logging.warning("rebooting in %s mode ..." % mode) logging.warning("rebooting in %s mode ...", mode)
else: else:
logging.warning("rebooting ...") logging.warning("rebooting ...")

View File

@@ -67,7 +67,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
for tag in self._config['bettercap']['silence']: for tag in self._config['bettercap']['silence']:
try: try:
self.run('events.ignore %s', tag, verbose_errors=False) self.run('events.ignore %s' % tag, verbose_errors=False)
except Exception as e: except Exception as e:
pass pass
@@ -156,7 +156,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
else: else:
logging.debug("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: try:
self.run('wifi.recon.channel %s', ','.join(map(str, channels))) self.run('wifi.recon.channel %s' % ','.join(map(str, channels)))
except Exception as e: except Exception as e:
logging.exception("error") logging.exception("error")
@@ -212,7 +212,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
ch = ap['channel'] ch = ap['channel']
# if we're sticking to a channel, skip anything # if we're sticking to a channel, skip anything
# which is not on that channel # which is not on that channel
if not channels and ch not in channels: if channels and ch not in channels:
continue continue
if ch not in grouped: if ch not in grouped:

View File

@@ -12,19 +12,18 @@ class Automata(object):
self._epoch = Epoch(config) self._epoch = Epoch(config)
def _on_miss(self, who): def _on_miss(self, who):
logging.info("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._epoch.track(miss=True)
self._view.on_miss(who) self._view.on_miss(who)
def _on_error(self, who, e): def _on_error(self, who, e):
error = "%s" % e
# when we're trying to associate or deauth something that is not in range anymore # 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: # (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. # 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: if 'is an unknown BSSID' in str(e):
self._on_miss(who) self._on_miss(who)
else: else:
logging.error("%s" % e) logging.error(e)
def set_starting(self): def set_starting(self):
self._view.on_starting() self._view.on_starting()
@@ -58,7 +57,7 @@ class Automata(object):
def set_bored(self): def set_bored(self):
factor = self._epoch.inactive_for / self._config['personality']['bored_num_epochs'] factor = self._epoch.inactive_for / self._config['personality']['bored_num_epochs']
if not self._has_support_network_for(factor): if not self._has_support_network_for(factor):
logging.warning("%d epochs with no activity -> bored" % self._epoch.inactive_for) logging.warning("%d epochs with no activity -> bored", self._epoch.inactive_for)
self._view.on_bored() self._view.on_bored()
plugins.on('bored', self) plugins.on('bored', self)
else: else:
@@ -68,7 +67,7 @@ class Automata(object):
def set_sad(self): def set_sad(self):
factor = self._epoch.inactive_for / self._config['personality']['sad_num_epochs'] factor = self._epoch.inactive_for / self._config['personality']['sad_num_epochs']
if not self._has_support_network_for(factor): if not self._has_support_network_for(factor):
logging.warning("%d epochs with no activity -> sad" % self._epoch.inactive_for) logging.warning("%d epochs with no activity -> sad", self._epoch.inactive_for)
self._view.on_sad() self._view.on_sad()
plugins.on('sad', self) plugins.on('sad', self)
else: else:
@@ -77,7 +76,7 @@ class Automata(object):
def set_angry(self, factor): def set_angry(self, factor):
if not self._has_support_network_for(factor): if not self._has_support_network_for(factor):
logging.warning("%d epochs with no activity -> angry" % self._epoch.inactive_for) logging.warning("%d epochs with no activity -> angry", self._epoch.inactive_for)
self._view.on_angry() self._view.on_angry()
plugins.on('angry', self) plugins.on('angry', self)
else: else:
@@ -85,7 +84,7 @@ class Automata(object):
self.set_grateful() self.set_grateful()
def set_excited(self): def set_excited(self):
logging.warning("%d epochs with activity -> excited" % self._epoch.active_for) logging.warning("%d epochs with activity -> excited", self._epoch.active_for)
self._view.on_excited() self._view.on_excited()
plugins.on('excited', self) plugins.on('excited', self)
@@ -118,7 +117,7 @@ class Automata(object):
if factor >= 2.0: if factor >= 2.0:
self.set_angry(factor) self.set_angry(factor)
else: else:
logging.warning("agent missed %d interactions -> lonely" % did_miss) logging.warning("agent missed %d interactions -> lonely", did_miss)
self.set_lonely() self.set_lonely()
# after X times being bored, the status is set to sad or angry # after X times being bored, the status is set to sad or angry
elif self._epoch.inactive_for >= self._config['personality']['sad_num_epochs']: elif self._epoch.inactive_for >= self._config['personality']['sad_num_epochs']:
@@ -139,6 +138,6 @@ class Automata(object):
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data()) plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']: 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) logging.critical("%d epochs without visible access points -> rebooting ...", self._epoch.blind_for)
self._reboot() self._reboot()
self._epoch.blind_for = 0 self._epoch.blind_for = 0

View File

@@ -1,5 +1,4 @@
# WARNING WARNING WARNING WARNING #
#
# This file is recreated with default settings on every pwnagotchi restart, # This file is recreated with default settings on every pwnagotchi restart,
# use /etc/pwnagotchi/config.yml to configure this unit. # use /etc/pwnagotchi/config.yml to configure this unit.
# #

View File

@@ -1,6 +1,7 @@
import os import os
import glob import glob
import _thread import _thread
import threading
import importlib, importlib.util import importlib, importlib.util
import logging import logging
from pwnagotchi.ui import view from pwnagotchi.ui import view
@@ -8,17 +9,27 @@ from pwnagotchi.ui import view
default_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "default") default_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "default")
loaded = {} loaded = {}
database = {} database = {}
locks = {}
class Plugin: class Plugin:
@classmethod @classmethod
def __init_subclass__(cls, **kwargs): def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs) super().__init_subclass__(**kwargs)
global loaded global loaded, locks
plugin_name = cls.__module__.split('.')[0] plugin_name = cls.__module__.split('.')[0]
plugin_instance = cls() plugin_instance = cls()
logging.debug("loaded plugin %s as %s" % (plugin_name, plugin_instance)) logging.debug("loaded plugin %s as %s" % (plugin_name, plugin_instance))
loaded[plugin_name] = plugin_instance loaded[plugin_name] = plugin_instance
for attr_name in plugin_instance.__dir__():
if attr_name.startswith('on_'):
cb = getattr(plugin_instance, attr_name, None)
if cb is not None and callable(cb):
locks["%s::%s" % (plugin_name, attr_name)] = threading.Lock()
def toggle_plugin(name, enable=True): def toggle_plugin(name, enable=True):
""" """
Load or unload a plugin Load or unload a plugin
@@ -47,15 +58,24 @@ def on(event_name, *args, **kwargs):
one(plugin_name, event_name, *args, **kwargs) one(plugin_name, event_name, *args, **kwargs)
def locked_cb(lock_name, cb, *args, **kwargs):
global locks
with locks[lock_name]:
cb(*args, *kwargs)
def one(plugin_name, event_name, *args, **kwargs): def one(plugin_name, event_name, *args, **kwargs):
global loaded global loaded
if plugin_name in loaded: if plugin_name in loaded:
plugin = loaded[plugin_name] plugin = loaded[plugin_name]
cb_name = 'on_%s' % event_name cb_name = 'on_%s' % event_name
callback = getattr(plugin, cb_name, None) callback = getattr(plugin, cb_name, None)
if callback is not None and callable(callback): if callback is not None and callable(callback):
try: try:
_thread.start_new_thread(callback, (*args, *kwargs)) lock_name = "%s::%s" % (plugin_name, cb_name)
locked_cb_args = (lock_name, callback, *args, *kwargs)
_thread.start_new_thread(locked_cb, locked_cb_args)
except Exception as e: except Exception as e:
logging.error("error while running %s.%s : %s" % (plugin_name, cb_name, e)) logging.error("error while running %s.%s : %s" % (plugin_name, cb_name, e))
logging.error(e, exc_info=True) logging.error(e, exc_info=True)

View File

@@ -7,6 +7,7 @@ import platform
import shutil import shutil
import glob import glob
import pkg_resources import pkg_resources
from threading import Lock
import pwnagotchi import pwnagotchi
import pwnagotchi.plugins as plugins import pwnagotchi.plugins as plugins
@@ -150,6 +151,7 @@ class AutoUpdate(plugins.Plugin):
def __init__(self): def __init__(self):
self.ready = False self.ready = False
self.status = StatusFile('/root/.auto-update') self.status = StatusFile('/root/.auto-update')
self.lock = Lock()
def on_loaded(self): def on_loaded(self):
if 'interval' not in self.options or ('interval' in self.options and self.options['interval'] is None): if 'interval' not in self.options or ('interval' in self.options and self.options['interval'] is None):
@@ -159,60 +161,61 @@ class AutoUpdate(plugins.Plugin):
logging.info("[update] plugin loaded.") logging.info("[update] plugin loaded.")
def on_internet_available(self, agent): def on_internet_available(self, agent):
logging.debug("[update] internet connectivity is available (ready %s)" % self.ready) with self.lock:
logging.debug("[update] internet connectivity is available (ready %s)" % self.ready)
if not self.ready: if not self.ready:
return return
if self.status.newer_then_hours(self.options['interval']): if self.status.newer_then_hours(self.options['interval']):
logging.debug("[update] last check happened less than %d hours ago" % self.options['interval']) logging.debug("[update] last check happened less than %d hours ago" % self.options['interval'])
return return
logging.info("[update] checking for updates ...") logging.info("[update] checking for updates ...")
display = agent.view() display = agent.view()
prev_status = display.get('status') prev_status = display.get('status')
try: try:
display.update(force=True, new_data={'status': 'Checking for updates ...'}) display.update(force=True, new_data={'status': 'Checking for updates ...'})
to_install = [] to_install = []
to_check = [ to_check = [
('bettercap/bettercap', parse_version('bettercap -version'), True, 'bettercap'), ('bettercap/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
('evilsocket/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'), ('evilsocket/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
('evilsocket/pwnagotchi', pwnagotchi.version, False, 'pwnagotchi') ('evilsocket/pwnagotchi', pwnagotchi.version, False, 'pwnagotchi')
] ]
for repo, local_version, is_native, svc_name in to_check: for repo, local_version, is_native, svc_name in to_check:
info = check(local_version, repo, is_native) info = check(local_version, repo, is_native)
if info['url'] is not None: if info['url'] is not None:
logging.warning( logging.warning(
"update for %s available (local version is '%s'): %s" % ( "update for %s available (local version is '%s'): %s" % (
repo, info['current'], info['url'])) repo, info['current'], info['url']))
info['service'] = svc_name info['service'] = svc_name
to_install.append(info) to_install.append(info)
num_updates = len(to_install) num_updates = len(to_install)
num_installed = 0 num_installed = 0
if num_updates > 0: if num_updates > 0:
if self.options['install']: if self.options['install']:
for update in to_install: for update in to_install:
plugins.on('updating') plugins.on('updating')
if install(display, update): if install(display, update):
num_installed += 1 num_installed += 1
else: else:
prev_status = '%d new update%c available!' % (num_updates, 's' if num_updates > 1 else '') prev_status = '%d new update%c available!' % (num_updates, 's' if num_updates > 1 else '')
logging.info("[update] done") logging.info("[update] done")
self.status.update() self.status.update()
if num_installed > 0: if num_installed > 0:
display.update(force=True, new_data={'status': 'Rebooting ...'}) display.update(force=True, new_data={'status': 'Rebooting ...'})
pwnagotchi.reboot() pwnagotchi.reboot()
except Exception as e: except Exception as e:
logging.error("[update] %s" % e) logging.error("[update] %s" % e)
display.update(force=True, new_data={'status': prev_status if prev_status is not None else ''}) display.update(force=True, new_data={'status': prev_status if prev_status is not None else ''})

View File

@@ -54,6 +54,10 @@ class GPS(plugins.Plugin):
lat_pos = (127, 75) lat_pos = (127, 75)
lon_pos = (122, 84) lon_pos = (122, 84)
alt_pos = (127, 94) alt_pos = (127, 94)
elif ui.is_waveshare_v1():
lat_pos = (130, 70)
lon_pos = (125, 80)
alt_pos = (130, 90)
elif ui.is_inky(): elif ui.is_inky():
# guessed values, add tested ones if you can # guessed values, add tested ones if you can
lat_pos = (112, 30) lat_pos = (112, 30)
@@ -109,6 +113,13 @@ class GPS(plugins.Plugin):
), ),
) )
def on_unload(self, ui):
with ui._lock:
ui.remove_element('latitude')
ui.remove_element('longitude')
ui.remove_element('altitude')
def on_ui_update(self, ui): def on_ui_update(self, ui):
if self.coordinates and all([ if self.coordinates and all([
# avoid 0.000... measurements # avoid 0.000... measurements

View File

@@ -44,12 +44,18 @@ class MemTemp(plugins.Plugin):
if ui.is_waveshare_v2(): if ui.is_waveshare_v2():
h_pos = (180, 80) h_pos = (180, 80)
v_pos = (180, 61) v_pos = (180, 61)
elif ui.is_waveshare_v1():
h_pos = (170, 80)
v_pos = (170, 61)
elif ui.is_waveshare144lcd(): elif ui.is_waveshare144lcd():
h_pos = (53, 77) h_pos = (53, 77)
v_pos = (78, 67) v_pos = (78, 67)
elif ui.is_inky(): elif ui.is_inky():
h_pos = (140, 68) h_pos = (140, 68)
v_pos = (165, 54) v_pos = (165, 54)
elif ui.is_waveshare27inch():
h_pos = (192, 138)
v_pos = (216, 122)
else: else:
h_pos = (155, 76) h_pos = (155, 76)
v_pos = (180, 61) v_pos = (180, 61)
@@ -64,6 +70,10 @@ class MemTemp(plugins.Plugin):
position=h_pos, position=h_pos,
label_font=fonts.Small, text_font=fonts.Small)) label_font=fonts.Small, text_font=fonts.Small))
def on_unload(self, ui):
with ui._lock:
ui.remove_element('memtemp')
def on_ui_update(self, ui): def on_ui_update(self, ui):
if self.options['scale'] == "fahrenheit": if self.options['scale'] == "fahrenheit":
temp = (pwnagotchi.temperature() * 9 / 5) + 32 temp = (pwnagotchi.temperature() * 9 / 5) + 32

View File

@@ -58,5 +58,9 @@ class UPSLite(plugins.Plugin):
ui.add_element('ups', LabeledValue(color=BLACK, label='UPS', value='0%/0V', position=(ui.width() / 2 + 15, 0), ui.add_element('ups', LabeledValue(color=BLACK, label='UPS', value='0%/0V', position=(ui.width() / 2 + 15, 0),
label_font=fonts.Bold, text_font=fonts.Medium)) label_font=fonts.Bold, text_font=fonts.Medium))
def on_unload(self, ui):
with ui._lock:
ui.remove_element('ups')
def on_ui_update(self, ui): def on_ui_update(self, ui):
ui.set('ups', "%2i%%" % self.ups.capacity()) ui.set('ups', "%2i%%" % self.ups.capacity())

View File

@@ -304,6 +304,9 @@ class PositionFile:
elif 'Updated' in self._json: elif 'Updated' in self._json:
# convert gps datetime to unix timestamp: "2019-10-05T23:12:40.422996+01:00" # convert gps datetime to unix timestamp: "2019-10-05T23:12:40.422996+01:00"
date_iso_formated = self._json['Updated'] date_iso_formated = self._json['Updated']
#fix timezone "Z": "2019-11-28T04:44:46.79231Z" >> "2019-11-28T04:44:46.79231+00:00"
if date_iso_formated.endswith("Z"):
date_iso_formated = date_iso_formated[:-1] + "+00:00"
# bad microseconds fix: fill/cut microseconds to 6 numbers # bad microseconds fix: fill/cut microseconds to 6 numbers
part1, part2, part3 = re.split('\.|\+', date_iso_formated) part1, part2, part3 = re.split('\.|\+', date_iso_formated)
part2 = part2.ljust(6, '0')[:6] part2 = part2.ljust(6, '0')[:6]

View File

@@ -6,7 +6,7 @@ from pwnagotchi.ui.hw.base import DisplayImpl
class Waveshare27inch(DisplayImpl): class Waveshare27inch(DisplayImpl):
def __init__(self, config): def __init__(self, config):
super(Waveshare27inch, self).__init__(config, 'waveshare_2_7inch') super(Waveshare27inch, self).__init__(config, 'waveshare27inch')
self._display = None self._display = None
def layout(self): def layout(self):

View File

@@ -10,6 +10,8 @@ import yaml
import json import json
import shutil import shutil
import gzip import gzip
import contextlib
import tempfile
import pwnagotchi import pwnagotchi
@@ -345,6 +347,17 @@ def extract_from_pcap(path, fields):
return results return results
@contextlib.contextmanager
def ensure_write(filename, mode='w'):
path = os.path.dirname(filename)
fd, tmp = tempfile.mkstemp(dir=path)
with os.fdopen(fd, mode) as f:
yield f
f.flush()
os.fsync(f.fileno())
os.replace(tmp, filename)
class StatusFile(object): class StatusFile(object):
def __init__(self, path, data_format='raw'): def __init__(self, path, data_format='raw'):
@@ -378,7 +391,7 @@ class StatusFile(object):
def update(self, data=None): def update(self, data=None):
self._updated = datetime.now() self._updated = datetime.now()
self.data = data self.data = data
with open(self._path, 'w') as fp: with ensure_write(self._path, 'w') as fp:
if data is None: if data is None:
fp.write(str(self._updated)) fp.write(str(self._updated))

View File

@@ -161,7 +161,10 @@ class Voice:
def on_last_session_data(self, last_session): def on_last_session_data(self, last_session):
status = self._('Kicked {num} stations\n').format(num=last_session.deauthed) status = self._('Kicked {num} stations\n').format(num=last_session.deauthed)
status += self._('Made {num} new friends\n').format(num=last_session.associated) if last_session.associated > 999:
status += self._('Made >999 new friends\n')
else:
status += self._('Made {num} new friends\n').format(num=last_session.associated)
status += self._('Got {num} handshakes\n').format(num=last_session.handshakes) status += self._('Got {num} handshakes\n').format(num=last_session.handshakes)
if last_session.peers == 1: if last_session.peers == 1:
status += self._('Met 1 peer') status += self._('Met 1 peer')

View File

@@ -3,6 +3,7 @@ requests==2.21.0
PyYAML==5.1 PyYAML==5.1
scapy==2.4.3 scapy==2.4.3
gym==0.14.0 gym==0.14.0
scipy==1.3.1
stable-baselines==2.7.0 stable-baselines==2.7.0
tensorflow==1.13.1 tensorflow==1.13.1
tensorflow-estimator==1.14.0 tensorflow-estimator==1.14.0