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.agent import Agent
from pwnagotchi.ui.display import Display
from pwnagotch import restart
from pwnagotchi import restart
def do_clear(display):

View File

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

View File

@@ -1,12 +1,12 @@
import subprocess
import os
import logging
import time
import re
import pwnagotchi.ui.view as view
import pwnagotchi
version = '1.4.0'
version = '1.4.3'
_name = None
@@ -27,17 +27,17 @@ def set_name(new_name):
if new_name != current:
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:
fp.write(new_name)
with open('/etc/hosts', 'rt') as fp:
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:
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)
os.system("hostname '%s'" % new_name)
@@ -109,7 +109,7 @@ def shutdown():
def restart(mode):
logging.warning("restarting in %s mode ..." % mode)
logging.warning("restarting in %s mode ...", mode)
if mode == 'AUTO':
os.system("touch /root/.pwnagotchi-auto")
@@ -123,7 +123,7 @@ def restart(mode):
def reboot(mode=None):
if mode is not None:
mode = mode.upper()
logging.warning("rebooting in %s mode ..." % mode)
logging.warning("rebooting in %s mode ...", mode)
else:
logging.warning("rebooting ...")

View File

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

View File

@@ -12,19 +12,18 @@ class Automata(object):
self._epoch = Epoch(config)
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._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:
if 'is an unknown BSSID' in str(e):
self._on_miss(who)
else:
logging.error("%s" % e)
logging.error(e)
def set_starting(self):
self._view.on_starting()
@@ -58,7 +57,7 @@ class Automata(object):
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)
logging.warning("%d epochs with no activity -> bored", self._epoch.inactive_for)
self._view.on_bored()
plugins.on('bored', self)
else:
@@ -68,7 +67,7 @@ class Automata(object):
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)
logging.warning("%d epochs with no activity -> sad", self._epoch.inactive_for)
self._view.on_sad()
plugins.on('sad', self)
else:
@@ -77,7 +76,7 @@ class Automata(object):
def set_angry(self, 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()
plugins.on('angry', self)
else:
@@ -85,7 +84,7 @@ class Automata(object):
self.set_grateful()
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()
plugins.on('excited', self)
@@ -118,7 +117,7 @@ class Automata(object):
if factor >= 2.0:
self.set_angry(factor)
else:
logging.warning("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 or angry
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())
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._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,
# use /etc/pwnagotchi/config.yml to configure this unit.
#

View File

@@ -1,6 +1,7 @@
import os
import glob
import _thread
import threading
import importlib, importlib.util
import logging
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")
loaded = {}
database = {}
locks = {}
class Plugin:
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
global loaded
global loaded, locks
plugin_name = cls.__module__.split('.')[0]
plugin_instance = cls()
logging.debug("loaded plugin %s as %s" % (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):
"""
Load or unload a plugin
@@ -47,15 +58,24 @@ def on(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):
global loaded
if plugin_name in loaded:
plugin = loaded[plugin_name]
cb_name = 'on_%s' % event_name
callback = getattr(plugin, cb_name, None)
if callback is not None and callable(callback):
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:
logging.error("error while running %s.%s : %s" % (plugin_name, cb_name, e))
logging.error(e, exc_info=True)

View File

@@ -7,6 +7,7 @@ import platform
import shutil
import glob
import pkg_resources
from threading import Lock
import pwnagotchi
import pwnagotchi.plugins as plugins
@@ -150,6 +151,7 @@ class AutoUpdate(plugins.Plugin):
def __init__(self):
self.ready = False
self.status = StatusFile('/root/.auto-update')
self.lock = Lock()
def on_loaded(self):
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.")
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:
return
if not self.ready:
return
if self.status.newer_then_hours(self.options['interval']):
logging.debug("[update] last check happened less than %d hours ago" % self.options['interval'])
return
if self.status.newer_then_hours(self.options['interval']):
logging.debug("[update] last check happened less than %d hours ago" % self.options['interval'])
return
logging.info("[update] checking for updates ...")
logging.info("[update] checking for updates ...")
display = agent.view()
prev_status = display.get('status')
display = agent.view()
prev_status = display.get('status')
try:
display.update(force=True, new_data={'status': 'Checking for updates ...'})
try:
display.update(force=True, new_data={'status': 'Checking for updates ...'})
to_install = []
to_check = [
('bettercap/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
('evilsocket/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
('evilsocket/pwnagotchi', pwnagotchi.version, False, 'pwnagotchi')
]
to_install = []
to_check = [
('bettercap/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
('evilsocket/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
('evilsocket/pwnagotchi', pwnagotchi.version, False, 'pwnagotchi')
]
for repo, local_version, is_native, svc_name in to_check:
info = check(local_version, repo, is_native)
if info['url'] is not None:
logging.warning(
"update for %s available (local version is '%s'): %s" % (
repo, info['current'], info['url']))
info['service'] = svc_name
to_install.append(info)
for repo, local_version, is_native, svc_name in to_check:
info = check(local_version, repo, is_native)
if info['url'] is not None:
logging.warning(
"update for %s available (local version is '%s'): %s" % (
repo, info['current'], info['url']))
info['service'] = svc_name
to_install.append(info)
num_updates = len(to_install)
num_installed = 0
num_updates = len(to_install)
num_installed = 0
if num_updates > 0:
if self.options['install']:
for update in to_install:
plugins.on('updating')
if install(display, update):
num_installed += 1
else:
prev_status = '%d new update%c available!' % (num_updates, 's' if num_updates > 1 else '')
if num_updates > 0:
if self.options['install']:
for update in to_install:
plugins.on('updating')
if install(display, update):
num_installed += 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:
display.update(force=True, new_data={'status': 'Rebooting ...'})
pwnagotchi.reboot()
if num_installed > 0:
display.update(force=True, new_data={'status': 'Rebooting ...'})
pwnagotchi.reboot()
except Exception as e:
logging.error("[update] %s" % e)
except Exception as 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)
lon_pos = (122, 84)
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():
# guessed values, add tested ones if you can
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):
if self.coordinates and all([
# avoid 0.000... measurements

View File

@@ -44,12 +44,18 @@ class MemTemp(plugins.Plugin):
if ui.is_waveshare_v2():
h_pos = (180, 80)
v_pos = (180, 61)
elif ui.is_waveshare_v1():
h_pos = (170, 80)
v_pos = (170, 61)
elif ui.is_waveshare144lcd():
h_pos = (53, 77)
v_pos = (78, 67)
elif ui.is_inky():
h_pos = (140, 68)
v_pos = (165, 54)
elif ui.is_waveshare27inch():
h_pos = (192, 138)
v_pos = (216, 122)
else:
h_pos = (155, 76)
v_pos = (180, 61)
@@ -64,6 +70,10 @@ class MemTemp(plugins.Plugin):
position=h_pos,
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):
if self.options['scale'] == "fahrenheit":
temp = (pwnagotchi.temperature() * 9 / 5) + 32
@@ -72,7 +82,7 @@ class MemTemp(plugins.Plugin):
temp = pwnagotchi.temperature() + 273.15
symbol = "k"
else:
# default to celsius
# default to celsius
temp = pwnagotchi.temperature()
symbol = "c"

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),
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):
ui.set('ups', "%2i%%" % self.ups.capacity())

View File

@@ -304,6 +304,9 @@ class PositionFile:
elif 'Updated' in self._json:
# convert gps datetime to unix timestamp: "2019-10-05T23:12:40.422996+01:00"
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
part1, part2, part3 = re.split('\.|\+', date_iso_formated)
part2 = part2.ljust(6, '0')[:6]

View File

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

View File

@@ -10,6 +10,8 @@ import yaml
import json
import shutil
import gzip
import contextlib
import tempfile
import pwnagotchi
@@ -345,6 +347,17 @@ def extract_from_pcap(path, fields):
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):
def __init__(self, path, data_format='raw'):
@@ -378,7 +391,7 @@ class StatusFile(object):
def update(self, data=None):
self._updated = datetime.now()
self.data = data
with open(self._path, 'w') as fp:
with ensure_write(self._path, 'w') as fp:
if data is None:
fp.write(str(self._updated))

View File

@@ -161,7 +161,10 @@ class Voice:
def on_last_session_data(self, last_session):
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)
if last_session.peers == 1:
status += self._('Met 1 peer')

View File

@@ -3,6 +3,7 @@ requests==2.21.0
PyYAML==5.1
scapy==2.4.3
gym==0.14.0
scipy==1.3.1
stable-baselines==2.7.0
tensorflow==1.13.1
tensorflow-estimator==1.14.0
@@ -16,4 +17,4 @@ spidev==3.4
gast==0.2.2
flask==1.0.2
flask-cors==3.0.7
flask-wtf==0.14.2
flask-wtf==0.14.2