From 6d2af3720335c3f3ca4a56672150e48aa20c58f8 Mon Sep 17 00:00:00 2001
From: sp3nx0r
Date: Wed, 2 Oct 2019 14:05:22 -0500
Subject: [PATCH 01/80] fixing getopts, adding host specific files to backup,
refactoring
---
scripts/update_pwnagotchi.sh | 58 +++++++++++++++++++++---------------
1 file changed, 34 insertions(+), 24 deletions(-)
diff --git a/scripts/update_pwnagotchi.sh b/scripts/update_pwnagotchi.sh
index 0039e7bc..f68d9253 100644
--- a/scripts/update_pwnagotchi.sh
+++ b/scripts/update_pwnagotchi.sh
@@ -13,13 +13,14 @@ function usage() {
cat <
Date: Wed, 2 Oct 2019 16:11:51 -0500
Subject: [PATCH 02/80] fixing perms on script and uncommenting line from
debugging
---
scripts/update_pwnagotchi.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
mode change 100644 => 100755 scripts/update_pwnagotchi.sh
diff --git a/scripts/update_pwnagotchi.sh b/scripts/update_pwnagotchi.sh
old mode 100644
new mode 100755
index f68d9253..eaca8a57
--- a/scripts/update_pwnagotchi.sh
+++ b/scripts/update_pwnagotchi.sh
@@ -79,7 +79,7 @@ test_github
# clean up old files, clone master, set checkout to commit if needed.
echo "[+] Cloning to $GIT_FOLDER..."
-#rm $GIT_FOLDER -rf
+rm $GIT_FOLDER -rf
git clone $GIT_URL $GIT_FOLDER -q
cd $GIT_FOLDER
if [ $VERSION != "master" ]; then
From 690f59a846a7e38a20a093106f501deeb7c7d854 Mon Sep 17 00:00:00 2001
From: sp3nx0r
Date: Wed, 2 Oct 2019 16:16:43 -0500
Subject: [PATCH 03/80] adding /etc/network/interfaces from PR#71
---
scripts/update_pwnagotchi.sh | 2 ++
1 file changed, 2 insertions(+)
diff --git a/scripts/update_pwnagotchi.sh b/scripts/update_pwnagotchi.sh
index eaca8a57..b7bce08c 100755
--- a/scripts/update_pwnagotchi.sh
+++ b/scripts/update_pwnagotchi.sh
@@ -94,6 +94,7 @@ if [ $BACKUPCONFIG -eq 1 ]; then
mv /etc/hosts /etc/hosts.bak -f
mv /etc/hostname /etc/hostname.bak -f
mv /etc/motd /etc/motd.bak -f
+ mv /etc/network/interfaces /etc/network/interfaces.bak -f
fi
echo "[+] Installing $(git log -1 --format="%h")"
@@ -110,6 +111,7 @@ if [ $RESTORECONFIG -eq 1 ]; then
mv /etc/hosts.bak /etc/hosts -f
mv /etc/hostname.bak /etc/hostname -f
mv /etc/motd.bak /etc/motd -f
+ mv /etc/network/interfaces.bak /etc/network/interfaces -f
fi
echo "[+] Restarting pwnagotchi in $MODE mode. $( screen -X -S pwnagotchi quit)"
From 20c365e1cd2ea9fc403b754b6019480b3d6a4fdf Mon Sep 17 00:00:00 2001
From: sp3nx0r
Date: Thu, 3 Oct 2019 06:46:20 -0500
Subject: [PATCH 04/80] resolve conflict, adjust getopts args, add /etc/motd to
backup
---
scripts/update_pwnagotchi.sh | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/scripts/update_pwnagotchi.sh b/scripts/update_pwnagotchi.sh
index 97b8a89a..734ed4c2 100644
--- a/scripts/update_pwnagotchi.sh
+++ b/scripts/update_pwnagotchi.sh
@@ -13,13 +13,14 @@ function usage() {
cat <
Date: Thu, 3 Oct 2019 06:49:18 -0500
Subject: [PATCH 05/80] resolve conflict, adjust getopts args, add /etc/motd to
backup
---
scripts/update_pwnagotchi.sh | 42 +++++++++++++++++-------------------
1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/scripts/update_pwnagotchi.sh b/scripts/update_pwnagotchi.sh
index b7bce08c..734ed4c2 100755
--- a/scripts/update_pwnagotchi.sh
+++ b/scripts/update_pwnagotchi.sh
@@ -19,8 +19,8 @@ function usage() {
-v # Version to update to, can be a branch or commit. (default: master)
-u # Url to clone from. (default: https://github.com/evilsocket/pwnagotchi)
-m # Mode to restart to. (Supported: ${SUPPORTED_RESTART_MODES[*]}; default: auto)
- -b # Backup the current pwnagotchi config, then overwrite with defaults.
- -r # Restore the current pwnagotchi config after upgrade. (-b will be enabled.)
+ -b # Backup the current pwnagotchi config and hostname references, then overwrite with defaults.
+ -r # Restore the current pwnagotchi config and hostname references after upgrade. (-b will be enabled.)
-h # Shows this help.
EOF
@@ -37,10 +37,11 @@ function test_root() {
function test_github() {
wget -q --spider $GIT_URL
if [ $? -ne 0 ]; then
- echo "[!] Cannot reach github. This script requires internet access and DNS resolution, ensure connection sharing is working and valid DNS server in /etc/resolv.conf."
+ echo "[!] Cannot reach github. This script requires internet access, ensure connection sharing is working."
exit 2
fi
}
+
while getopts "v:u:m:brh" o; do
case "${o}" in
v)
@@ -49,6 +50,13 @@ while getopts "v:u:m:brh" o; do
u)
GIT_URL="${OPTARG}"
;;
+ m)
+ if [[ "${SUPPORTED_RESTART_MODES[*]}" =~ ${OPTARG} ]]; then
+ MODE="${OPTARG}"
+ else
+ usage
+ fi
+ ;;
b)
BACKUPCONFIG=1
;;
@@ -59,13 +67,6 @@ while getopts "v:u:m:brh" o; do
h)
usage
;;
- m)
- if [[ "${SUPPORTED_RESTART_MODES[*]}" =~ ${OPTARG} ]]; then
- MODE="${OPTARG}"
- else
- usage
- fi
- ;;
*)
usage
;;
@@ -86,15 +87,13 @@ if [ $VERSION != "master" ]; then
git checkout $VERSION -q
fi
-echo "[+] Updating..."
if [ $BACKUPCONFIG -eq 1 ]; then
- echo "[+] Creating backup of config.yml"
- mv /root/pwnagotchi/config.yml /root/config.yml.bak -f
- echo "[+] Creating backup of host files"
- mv /etc/hosts /etc/hosts.bak -f
- mv /etc/hostname /etc/hostname.bak -f
+ echo "[+] Creating backup of config.yml and hostname references"
+ mv /root/pwnagotchi/config.yml /root/config.bak -f
+ mv /etc/hosts /root/hosts.bak -f
+ mv /etc/hostname /root/hostname.bak -f
mv /etc/motd /etc/motd.bak -f
- mv /etc/network/interfaces /etc/network/interfaces.bak -f
+ mv /etc/network/interfaces /root/interfaces.bak -f
fi
echo "[+] Installing $(git log -1 --format="%h")"
@@ -105,13 +104,12 @@ cd /tmp
rm $GIT_FOLDER -rf
if [ $RESTORECONFIG -eq 1 ]; then
- echo "[+] Restoring backup of config.yml"
+ echo "[+] Restoring backup of config.yml and hostname references"
mv /root/config.yml.bak /root/pwnagotchi/config.yml -f
- echo "[+] Restoring backup of host files"
- mv /etc/hosts.bak /etc/hosts -f
- mv /etc/hostname.bak /etc/hostname -f
+ mv /root/hosts.bak /etc/hosts -f
+ mv /root/hostname.bak /etc/hostname -f
+ mv /root/interfaces.bak /etc/network/interfaces -f
mv /etc/motd.bak /etc/motd -f
- mv /etc/network/interfaces.bak /etc/network/interfaces -f
fi
echo "[+] Restarting pwnagotchi in $MODE mode. $( screen -X -S pwnagotchi quit)"
From af42ac615ec009bd870eb63225c11c97c960f5a0 Mon Sep 17 00:00:00 2001
From: Alex Muthmann
Date: Thu, 3 Oct 2019 14:18:51 +0200
Subject: [PATCH 06/80] Describe issue with rebooting after changing the
display
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 30ec48b5..5fcd98b6 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ The supported models are:
The only kind of displays supported are the ones listed above, but we are always happy to receive pull requests supporting new displays.
-You need to configure the display type in `config.yml` where you can find `ui.display.type`.
+You need to configure the display type in `config.yml` where you can find `ui.display.type`. If your display does not work after changing this setting, you might need to complete remove power from the Raspberry and make a clean boot.
One thing to note, not all displays are created equaly, TFT displays for example work similar to an HDMI display, and they are not supported, currently all the displays supported are I2C displays.
From d78a5aecba3beb705d53e635ce836d73dcc35f48 Mon Sep 17 00:00:00 2001
From: Cassiano Aquino
Date: Thu, 3 Oct 2019 13:24:48 +0100
Subject: [PATCH 07/80] Removed tagging from travis-ci
As we are adding tags on the repository itself, it's not required to add tags via travis-ci.
This makes our build process fail.
---
.travis.yml | 7 -------
1 file changed, 7 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 6a7249ea..a621a43e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -43,10 +43,3 @@ script:
- sudo make clean
- sudo -E env "PATH=$PATH" make install
- sudo make image -e PWN_HOSTNAME=pwnagotchi VERSION=$TRAVIS_TAG
-
-before_deploy:
- # Set up git user name and tag this commit
- - git config --local user.name "evilsocket"
- - git config --local user.email "evilsocket@gmail.com"
- - export TRAVIS_TAG=${TRAVIS_TAG:-$(date +'%Y%m%d%H%M%S')-$(git log --format=%h -1)}
- - git tag $TRAVIS_TAG
From 024bd8c6dc2c2bfd70ea036a1cc3a7051f34944d Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 14:30:06 +0200
Subject: [PATCH 08/80] integration travis-ci with slack
---
.travis.yml | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 6a7249ea..7caf1de8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,52 +1,46 @@
dist: bionic
language: go
-
go:
- 1.x
-
env:
global:
- LANG=C
- LC_ALL=C
-
deploy:
provider: releases
api_key:
- secure: "vBUokTv94n8s65STUgTiD6I0Iy8KXbBRvQUrAof8XG+U4ZMsH5PmDTpS+wz+SaxI6o0PRkfyOiPVdARhiKAFnfatG3q9EHllMQwqRR2YIju51A3aCxgEJ5uWDoybwQdipERUMMYwUO/8XZaRRpwFD2bdQBFWkBtQyMcAkrEL8BXckwQQ531oDN2hK5gAiTllqsOswV2idwUlBRU9jOtStzff+UgUYsp/ZebsRodyOYkEB2Ev15yARo2HTXbyZ2icwHPtMbx5zmNUSRtxs9a4hfzaK3m6ctK8qLYYUdQvXub/ruuACapdw4Ez88LY1agTecbZhFYmJzv8oANH1e4VUI4owuHnZCpU6LRutS4wOhglrkOrGo6lSUlJeA+RtQjyjBugjej9DDtDyyIlRU1ZaBF3qWR9N5EXKuquf0olOfmUR67ap1NykE9VUpzkYjkoVRTiPs/e2onM/nRNOvAQcIt75FD13u+Y/DcYQ8r7KpMIu1HNdtbVx8gMeq76bRhP1YdDg2jm+DdJ21KWjf5QHsbyoXDfJzdKlCloLIlAU3EPJhMoXsnNzre0/FXeUl6dfteR1axNS6U7e/vKsQ9rlUFZWIQaeVPjfXmFKblNNVQ5uFrrsB/EGHcJl7IUx5fvcRT5hMMNwC660YxVkBXDbRb5fxMW5/+K0BOi9cP6en8="
+ secure: vBUokTv94n8s65STUgTiD6I0Iy8KXbBRvQUrAof8XG+U4ZMsH5PmDTpS+wz+SaxI6o0PRkfyOiPVdARhiKAFnfatG3q9EHllMQwqRR2YIju51A3aCxgEJ5uWDoybwQdipERUMMYwUO/8XZaRRpwFD2bdQBFWkBtQyMcAkrEL8BXckwQQ531oDN2hK5gAiTllqsOswV2idwUlBRU9jOtStzff+UgUYsp/ZebsRodyOYkEB2Ev15yARo2HTXbyZ2icwHPtMbx5zmNUSRtxs9a4hfzaK3m6ctK8qLYYUdQvXub/ruuACapdw4Ez88LY1agTecbZhFYmJzv8oANH1e4VUI4owuHnZCpU6LRutS4wOhglrkOrGo6lSUlJeA+RtQjyjBugjej9DDtDyyIlRU1ZaBF3qWR9N5EXKuquf0olOfmUR67ap1NykE9VUpzkYjkoVRTiPs/e2onM/nRNOvAQcIt75FD13u+Y/DcYQ8r7KpMIu1HNdtbVx8gMeq76bRhP1YdDg2jm+DdJ21KWjf5QHsbyoXDfJzdKlCloLIlAU3EPJhMoXsnNzre0/FXeUl6dfteR1axNS6U7e/vKsQ9rlUFZWIQaeVPjfXmFKblNNVQ5uFrrsB/EGHcJl7IUx5fvcRT5hMMNwC660YxVkBXDbRb5fxMW5/+K0BOi9cP6en8=
skip_cleanup: true
file_glob: true
file: pwnagotchi-*.zip
on:
tags: true
repo: evilsocket/pwnagotchi
-
branches:
only:
- - /^v[0-9]+\.[0-9]+\.[0-9]+[A-Za-z0-9]+?$/
-
+ - "/^v[0-9]+\\.[0-9]+\\.[0-9]+[A-Za-z0-9]+?$/"
cache:
apt: true
-
before_script:
- wget https://download.qemu.org/qemu-4.1.0.tar.xz
- tar xvJf qemu-4.1.0.tar.xz
- cd qemu-4.1.0
- - ./configure --target-list=arm-softmmu
+ - "./configure --target-list=arm-softmmu"
- make -j$(nproc)
- sudo make install
- cd $TRAVIS_BUILD_DIR
- sudo apt-get -y update
- sudo apt-get -y install qemu-user-static binfmt-support bmap-tools kpartx
- sudo update-binfmts --display
-
script:
- sudo make clean
- sudo -E env "PATH=$PATH" make install
- sudo make image -e PWN_HOSTNAME=pwnagotchi VERSION=$TRAVIS_TAG
-
before_deploy:
- # Set up git user name and tag this commit
- git config --local user.name "evilsocket"
- git config --local user.email "evilsocket@gmail.com"
- export TRAVIS_TAG=${TRAVIS_TAG:-$(date +'%Y%m%d%H%M%S')-$(git log --format=%h -1)}
- git tag $TRAVIS_TAG
+notifications:
+ slack:
+ secure: aovN87lswg+TTLobxJpevC0p2F4omTAlsOzeKqLysRW55o5rRhRC1SgwRkWUl19yr49nsyffwmv/b7OcyQiWIVnz1bxxE9XOKP8zgRMA/bKKcyAcPktPqHXsALIQDseXyl0kz7fwdkRWg0UC2HpKqi5koAhmBYTX/fbzieyeHCbcQ7lbFfVFIepE1401y9m1IqUHcHuGfFhMvTaSDIpXrDXnWdA8+gDAl0HKJv41MIsgmffbh/QhD2jLBWzItjxFC3llmNfy88pnzCk0+HBMY/4272LXb0czX7et5HJeM74oxPqkb3aKXFxZgNaDl7cYdV+kzj9dfKUk47hAqwbxlirit5WvHI1Br1VyA90+PFvcC/p41J8gCv0IlcB5vjWN8NKWA1J+Y1F+KvrujMvGtgd0foHZvaSutuRODhI1cBh5rYAiLCroRSlvKMw3IJRyCRstYgUlMIJ3cI2Ova/kU44KtDVmjT9VE/pPkhkHBPvcYThL6skZTdl19E/RlormLu3XObG1aHLZ+Znxe/aL7tWHi0KMOlpy+TMDdps4go7URnJ8yitHtIvU/zMtBrztIwN0Oy2JLKXrS5qIijmRAkBLxe0NxuG01DYFzEO3KtnRirP4uSe3QcrjyP4sqPrVhrjl3TR6gwg8V1juvDXB4e2h8yCpaUW5AdSBOlx9riY=
From f6605640b30585fcca7e8e5579cc8f1db8220c14 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 14:45:39 +0200
Subject: [PATCH 09/80] custom config override file
---
sdcard/rootfs/root/pwnagotchi/config.yml | 2 +-
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 78 ++++++++++---------
.../scripts/pwnagotchi/mesh/utils.py | 6 +-
.../pwnagotchi/scripts/pwnagotchi/utils.py | 24 ++++++
4 files changed, 70 insertions(+), 40 deletions(-)
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index cc2ea20f..b71ddde8 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -95,7 +95,7 @@ ui:
# IMPORTANT: The lifespan of an eINK display depends on the cumulative amount of refreshes. If you want to
# preserve your display over time, you should set this value to 0.0 so that the display will be refreshed only
# if any of the important data fields changed (the uptime and blinking cursor won't trigger a refresh).
- fps: 0.3
+ fps: 0.0
display:
enabled: true
rotation: 180
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index 09f6ec30..3bf19c7f 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -1,11 +1,16 @@
#!/usr/bin/python3
+import os
import argparse
-import yaml
import time
import traceback
+import yaml
+
import core
-import pwnagotchi, pwnagotchi.plugins as plugins
+import pwnagotchi
+import pwnagotchi.utils as utils
+import pwnagotchi.version as version
+import pwnagotchi.plugins as plugins
from pwnagotchi.log import SessionParser
from pwnagotchi.voice import Voice
@@ -14,53 +19,52 @@ from pwnagotchi.ui.display import Display
parser = argparse.ArgumentParser()
-parser.add_argument('-C', '--config', action='store', dest='config', default='/root/pwnagotchi/config.yml')
+parser.add_argument('-C', '--config', action='store', dest='config', default='/root/pwnagotchi/config.yml',
+ help='Main configuration file.')
+parser.add_argument('-U', '--user-config', action='store', dest='user_config', default='/root/pwnagotchi.yml',
+ help='If this file exists, configuration will be merged and this will override default values.')
parser.add_argument('--manual', dest="do_manual", action="store_true", default=False, help="Manual mode.")
parser.add_argument('--clear', dest="do_clear", action="store_true", default=False,
help="Clear the ePaper display and exit.")
args = parser.parse_args()
+config = utils.load_config(args)
if args.do_clear:
print("clearing the display ...")
- with open(args.config, 'rt') as fp:
- config = yaml.safe_load(fp)
- cleardisplay = config['ui']['display']['type']
- if cleardisplay in ('inkyphat', 'inky'):
- print("inky display")
- from inky import InkyPHAT
+ cleardisplay = config['ui']['display']['type']
+ if cleardisplay in ('inkyphat', 'inky'):
+ print("inky display")
+ from inky import InkyPHAT
- epd = InkyPHAT(config['ui']['display']['color'])
- epd.set_border(InkyPHAT.BLACK)
- self._render_cb = self._inky_render
- elif cleardisplay in ('papirus', 'papi'):
- print("papirus display")
- from pwnagotchi.ui.papirus.epd import EPD
+ epd = InkyPHAT(config['ui']['display']['color'])
+ epd.set_border(InkyPHAT.BLACK)
+ self._render_cb = self._inky_render
+ elif cleardisplay in ('papirus', 'papi'):
+ print("papirus display")
+ from pwnagotchi.ui.papirus.epd import EPD
- os.environ['EPD_SIZE'] = '2.0'
- epd = EPD()
- epd.clear()
- elif cleardisplay in ('waveshare_1', 'ws_1', 'waveshare1', 'ws1'):
- print("waveshare v1 display")
- from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
+ os.environ['EPD_SIZE'] = '2.0'
+ epd = EPD()
+ epd.clear()
+ elif cleardisplay in ('waveshare_1', 'ws_1', 'waveshare1', 'ws1'):
+ print("waveshare v1 display")
+ from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
- epd = EPD()
- epd.init(epd.lut_full_update)
- epd.Clear(0xFF)
- elif cleardisplay in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2'):
- print("waveshare v2 display")
- from pwnagotchi.ui.waveshare.v2.waveshare import EPD
+ epd = EPD()
+ epd.init(epd.lut_full_update)
+ epd.Clear(0xFF)
+ elif cleardisplay in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2'):
+ print("waveshare v2 display")
+ from pwnagotchi.ui.waveshare.v2.waveshare import EPD
- epd = EPD()
- epd.init(epd.FULL_UPDATE)
- epd.Clear(0xff)
- else:
- print("unknown display type %s" % cleardisplay)
- quit()
-
-with open(args.config, 'rt') as fp:
- config = yaml.safe_load(fp)
+ epd = EPD()
+ epd.init(epd.FULL_UPDATE)
+ epd.Clear(0xff)
+ else:
+ print("unknown display type %s" % cleardisplay)
+ quit()
plugins.load_from_path(plugins.default_path)
if 'plugins' in config['main'] and config['main']['plugins'] is not None:
@@ -71,7 +75,7 @@ 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, pwnagotchi.version))
+core.log("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, version.version))
# for key, value in config['personality'].items():
# core.log(" %s: %s" % (key, value))
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
index 8c84b942..92e49394 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
@@ -1,7 +1,9 @@
import _thread
import core
-import pwnagotchi, pwnagotchi.plugins as plugins
+import pwnagotchi
+import pwnagotchi.version as version
+import pwnagotchi.plugins as plugins
from pwnagotchi.mesh import get_identity
@@ -22,7 +24,7 @@ class AsyncAdvertiser(object):
self._advertiser = Advertiser(
self._config['main']['iface'],
pwnagotchi.name(),
- pwnagotchi.version,
+ version.version,
self._identity,
period=0.3,
data=self._config['personality'])
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
new file mode 100644
index 00000000..358b2fe0
--- /dev/null
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
@@ -0,0 +1,24 @@
+import yaml
+import os
+
+# https://stackoverflow.com/questions/823196/yaml-merge-in-python
+def merge_config(user, default):
+ if isinstance(user, dict) and isinstance(default, dict):
+ for k, v in default.items():
+ if k not in user:
+ user[k] = v
+ else:
+ user[k] = merge_config(user[k], v)
+ return user
+
+
+def load_config(args):
+ with open(args.config, 'rt') as fp:
+ config = yaml.safe_load(fp)
+
+ if os.path.exists(args.user_config):
+ with open(args.user_config, 'rt') as fp:
+ user_config = yaml.safe_load(fp)
+ config = merge_config(user_config, config)
+
+ return config
\ No newline at end of file
From c0d05257124be7aae73e13ddd5e616ab25bb2471 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 14:46:42 +0200
Subject: [PATCH 10/80] releasing v1.0.0plz
---
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
index c273c83b..afa94291 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
@@ -1 +1 @@
-version = '1.0.0travistest'
+version = '1.0.0plz'
From 95b9d0ee1e9cdde176b2ba667ed3e1a64d78dec7 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 15:02:08 +0200
Subject: [PATCH 11/80] readme config override
---
README.md | 2 ++
scripts/backup.sh | 0
2 files changed, 2 insertions(+)
create mode 100644 scripts/backup.sh
diff --git a/README.md b/README.md
index 5fcd98b6..c568b0b1 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,7 @@ For hackers to learn reinforcement learning, WiFi networking and have an excuse
**THIS IS STILL ALPHA STAGE SOFTWARE, IF YOU DECIDE TO TRY TO USE IT, YOU ARE ON YOUR OWN, NO SUPPORT WILL BE PROVIDED, NEITHER FOR INSTALLATION OR FOR BUGS**
However, there's [a Slack channel](https://join.slack.com/t/pwnagotchi/shared_invite/enQtNzc4NzY3MDE2OTAzLTg5NmNmNDJiMDM3ZWFkMWUwN2Y5NDk0Y2JlZWZjODlhMmRhNDZiOGMwYjJhM2UzNzA3YjA5NjJmZGY5NGI5NmI).
+
### Hardware
- Raspberry Pi Zero W
@@ -235,6 +236,7 @@ def on_handshake(agent, filename, access_point, client_station):
- checkout the `ui.video` section of the `config.yml` - if you don't want to use a display, you can connect to it with the browser and a cable.
- If you get `[FAILED] Failed to start Remount Root and Kernel File Systems.` while booting pwnagotchi, make sure
the `PARTUUID`s for `rootfs` and `boot` partitions are the same in `/etc/fstab`. Use `sudo blkid` to find those values when you are using `create_sibling.sh`.
+- You can create a `/root/pwnagotchi.yml` configuration file to override the defaults.
## License
diff --git a/scripts/backup.sh b/scripts/backup.sh
new file mode 100644
index 00000000..e69de29b
From 335e6b1311e00edfecf386be2538b4f3eda06905 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 15:55:03 +0200
Subject: [PATCH 12/80] backups
---
README.md | 10 ++++-
scripts/backup.sh | 42 +++++++++++++++++++
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 2 +-
3 files changed, 52 insertions(+), 2 deletions(-)
mode change 100644 => 100755 scripts/backup.sh
diff --git a/README.md b/README.md
index c568b0b1..095c7eb8 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,14 @@ usage: ./update_pwnagitchi.sh [OPTIONS]
```
+#### Backup your pwnagotchi
+
+You can use the `scripts/backup.sh` script to backup the important files of your unit.
+
+```shell
+usage: ./scripts/backup.sh HOSTNAME backup.zip
+```
+
### UI
The UI is available either via display if installed, or via http://pwnagotchi.local:8080/ if you connect to the unit via `usb0` and set a static address on the network interface (change `pwnagotchi` with the hostname of your unit).
@@ -236,7 +244,7 @@ def on_handshake(agent, filename, access_point, client_station):
- checkout the `ui.video` section of the `config.yml` - if you don't want to use a display, you can connect to it with the browser and a cable.
- If you get `[FAILED] Failed to start Remount Root and Kernel File Systems.` while booting pwnagotchi, make sure
the `PARTUUID`s for `rootfs` and `boot` partitions are the same in `/etc/fstab`. Use `sudo blkid` to find those values when you are using `create_sibling.sh`.
-- You can create a `/root/pwnagotchi.yml` configuration file to override the defaults.
+- You can create a `/root/custom.yml` configuration file to override the defaults.
## License
diff --git a/scripts/backup.sh b/scripts/backup.sh
old mode 100644
new mode 100755
index e69de29b..8ebf274d
--- a/scripts/backup.sh
+++ b/scripts/backup.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+# name of the ethernet gadget interface on the host
+UNIT_HOSTNAME=${1:-10.0.0.2}
+# output backup zip file
+OUTPUT=${2:-pwnagotchi-backup.zip}
+# temporary folder
+TEMP_BACKUP_FOLDER=/tmp/pwnagotchi_backup
+# what to backup
+FILES_TO_BACKUP=(
+ /root/brain.nn
+ /root/brain.json
+ /root/custom.yaml
+ /root/handshakes
+ /etc/ssh
+ /etc/hostname
+ /etc/hosts
+ /etc/motd
+ /var/log/pwnagotchi.log
+)
+
+ping -c 1 $UNIT_HOSTNAME >/dev/null || {
+ echo "@ unit $UNIT_HOSTNAME can't be reached, make sure it's connected and a static IP assigned to the USB interface."
+ exit 1
+}
+
+echo "@ backing up $UNIT_HOSTNAME to $OUTPUT ..."
+
+rm -rf "$TEMP_BACKUP_FOLDER"
+
+for file in "${FILES_TO_BACKUP[@]}"; do
+ dir=$(dirname $file)
+ echo " $file -> $TEMP_BACKUP_FOLDER$dir/"
+ mkdir -p "$TEMP_BACKUP_FOLDER/$dir"
+ scp -Cr root@$UNIT_HOSTNAME:$file "$TEMP_BACKUP_FOLDER$dir/"
+done
+
+ZIPFILE="$PWD/$OUTPUT"
+pushd $PWD
+cd "$TEMP_BACKUP_FOLDER"
+zip -r -9 -q "$ZIPFILE" .
+popd
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index 3bf19c7f..2327955a 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -21,7 +21,7 @@ parser = argparse.ArgumentParser()
parser.add_argument('-C', '--config', action='store', dest='config', default='/root/pwnagotchi/config.yml',
help='Main configuration file.')
-parser.add_argument('-U', '--user-config', action='store', dest='user_config', default='/root/pwnagotchi.yml',
+parser.add_argument('-U', '--user-config', action='store', dest='user_config', default='/root/custom.yml',
help='If this file exists, configuration will be merged and this will override default values.')
parser.add_argument('--manual', dest="do_manual", action="store_true", default=False, help="Manual mode.")
From 50b49a52121324ad4ea4efe7402a35f8d3d4056b Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Thu, 3 Oct 2019 16:01:42 +0200
Subject: [PATCH 13/80] Fix psql repo fail
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 7caf1de8..eb856492 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,7 +29,7 @@ before_script:
- make -j$(nproc)
- sudo make install
- cd $TRAVIS_BUILD_DIR
- - sudo apt-get -y update
+ - sudo apt-get -y update || true
- sudo apt-get -y install qemu-user-static binfmt-support bmap-tools kpartx
- sudo update-binfmts --display
script:
From 3925c5675d1c7abb2c3a3f7483f6da5c9d61e009 Mon Sep 17 00:00:00 2001
From: Cassiano Aquino
Date: Thu, 3 Oct 2019 15:08:22 +0100
Subject: [PATCH 14/80] remove tagging from travis
---
.travis.yml | 5 -----
1 file changed, 5 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index eb856492..0826bfc9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -36,11 +36,6 @@ script:
- sudo make clean
- sudo -E env "PATH=$PATH" make install
- sudo make image -e PWN_HOSTNAME=pwnagotchi VERSION=$TRAVIS_TAG
-before_deploy:
- - git config --local user.name "evilsocket"
- - git config --local user.email "evilsocket@gmail.com"
- - export TRAVIS_TAG=${TRAVIS_TAG:-$(date +'%Y%m%d%H%M%S')-$(git log --format=%h -1)}
- - git tag $TRAVIS_TAG
notifications:
slack:
secure: aovN87lswg+TTLobxJpevC0p2F4omTAlsOzeKqLysRW55o5rRhRC1SgwRkWUl19yr49nsyffwmv/b7OcyQiWIVnz1bxxE9XOKP8zgRMA/bKKcyAcPktPqHXsALIQDseXyl0kz7fwdkRWg0UC2HpKqi5koAhmBYTX/fbzieyeHCbcQ7lbFfVFIepE1401y9m1IqUHcHuGfFhMvTaSDIpXrDXnWdA8+gDAl0HKJv41MIsgmffbh/QhD2jLBWzItjxFC3llmNfy88pnzCk0+HBMY/4272LXb0czX7et5HJeM74oxPqkb3aKXFxZgNaDl7cYdV+kzj9dfKUk47hAqwbxlirit5WvHI1Br1VyA90+PFvcC/p41J8gCv0IlcB5vjWN8NKWA1J+Y1F+KvrujMvGtgd0foHZvaSutuRODhI1cBh5rYAiLCroRSlvKMw3IJRyCRstYgUlMIJ3cI2Ova/kU44KtDVmjT9VE/pPkhkHBPvcYThL6skZTdl19E/RlormLu3XObG1aHLZ+Znxe/aL7tWHi0KMOlpy+TMDdps4go7URnJ8yitHtIvU/zMtBrztIwN0Oy2JLKXrS5qIijmRAkBLxe0NxuG01DYFzEO3KtnRirP4uSe3QcrjyP4sqPrVhrjl3TR6gwg8V1juvDXB4e2h8yCpaUW5AdSBOlx9riY=
From 43c476c36f6c58de134ff431938515846caac862 Mon Sep 17 00:00:00 2001
From: Cassiano Aquino
Date: Thu, 3 Oct 2019 15:50:51 +0100
Subject: [PATCH 15/80] add templates and CONTRIBUTING.md
---
.github/CODEOWNERS | 1 +
.github/ISSUE_TEMPLATE.md | 36 ++++++++++++++++
.github/PULL_REQUEST_TEMPLATE.md | 30 ++++++++++++++
CONTRIBUTING.md | 71 ++++++++++++++++++++++++++++++++
4 files changed, 138 insertions(+)
create mode 100644 .github/CODEOWNERS
create mode 100644 .github/ISSUE_TEMPLATE.md
create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
create mode 100644 CONTRIBUTING.md
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000..fe565043
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+evilsocket
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..337f961c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,36 @@
+
+
+## Expected Behaviour
+
+
+
+## Current Behaviour
+
+
+
+## Possible Solution
+
+
+
+## Steps to Reproduce (for bugs)
+
+
+1.
+2.
+3.
+4.
+
+## Context
+
+
+
+## Your Environment
+
+- [ ] You're using the official images
+
+- [ ] You're using a raspberry pi 0
+
+- [ ] You're using a supported LCD
+
+
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..60efcd47
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,30 @@
+
+
+## Description
+
+
+## Motivation and Context
+
+
+- [ ] I have raised an issue to propose this change ([required](https://github.com/evilsocket/pwnagotchi/blob/master/CONTRIBUTING.md))
+
+
+## How Has This Been Tested?
+
+
+
+
+## Types of changes
+
+- [ ] Bug fix (non-breaking change which fixes an issue)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Breaking change (fix or feature that would cause existing functionality to change)
+
+## Checklist:
+
+
+- [ ] My code follows the code style of this project.
+- [ ] My change requires a change to the documentation.
+- [ ] I have updated the documentation accordingly.
+- [ ] I've read the [CONTRIBUTION](https://github.com/evilsocket/pwnagotchi/blob/master/CONTRIBUTING.md) guide
+- [ ] I have signed-off my commits with `git commit -s`
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..08e22842
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,71 @@
+## Contributing
+
+### Guidelines
+
+Here are a few guidelines for contributing:
+
+* If you would like to contribute to the codebase **please raise an issue to propose the change**
+* Do not mix feature changes or fixes with refactoring - it makes the code harder to review and means there is more for the maintainers (with limited time) to test
+
+* If you have found a bug please raise an issue and fill out the whole template.
+* If the documentation can be improved / translated etc please raise an issue to discuss.
+* Please always provide a summary of what you changed, how you did it and how it can be tested.
+
+### License
+
+This project is licensed under the GPL3 License.
+
+#### Sign your work
+
+The sign-off is a simple line at the end of the explanation for a patch. Your
+signature certifies that you wrote the patch or otherwise have the right to pass
+it on as an open-source patch. The rules are pretty simple: if you can certify
+the below (from [developercertificate.org](http://developercertificate.org/)):
+
+```
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+1 Letterman Drive
+Suite D4700
+San Francisco, CA, 94129
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+```
+
+Then you just add a line to every git commit message:
+
+ Signed-off-by: Joe Smith
+
+If you set your `user.name` and `user.email` git configs, you can sign your
+commit automatically with `git commit -s`.
+
+* Please sign your commits with `git commit -s` so that commits are traceable.
From f0a0bd2feab8d5da8ab8577795961d24149274a9 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Thu, 3 Oct 2019 16:59:19 +0200
Subject: [PATCH 16/80] Fix all languages
---
.gitignore | 4 +-
scripts/language.sh | 2 +-
.../pwnagotchi/locale/de/LC_MESSAGES/voice.po | 50 +------
.../pwnagotchi/locale/el/LC_MESSAGES/voice.mo | Bin 4665 -> 4713 bytes
.../pwnagotchi/locale/el/LC_MESSAGES/voice.po | 116 ++++-----------
.../pwnagotchi/locale/fr/LC_MESSAGES/voice.mo | Bin 400 -> 3922 bytes
.../pwnagotchi/locale/fr/LC_MESSAGES/voice.po | 137 ++++++------------
.../pwnagotchi/locale/it/LC_MESSAGES/voice.mo | Bin 3679 -> 3759 bytes
.../pwnagotchi/locale/it/LC_MESSAGES/voice.po | 54 +------
.../pwnagotchi/locale/mk/LC_MESSAGES/voice.mo | Bin 2457 -> 4609 bytes
.../pwnagotchi/locale/mk/LC_MESSAGES/voice.po | 118 ++++-----------
.../pwnagotchi/locale/nl/LC_MESSAGES/voice.mo | Bin 3875 -> 3998 bytes
.../pwnagotchi/locale/nl/LC_MESSAGES/voice.po | 53 +------
.../scripts/pwnagotchi/locale/voice.pot | 50 +------
14 files changed, 117 insertions(+), 467 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7d065ae9..3833e984 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,12 @@
*.img
*.img.bmap
*.pcap
+*.po~
__pycache__
_backups
_emulation
_utils
config.laptop.yml
.idea
-tmp
+packer_cache
+output-pwnagotchi
diff --git a/scripts/language.sh b/scripts/language.sh
index cf653f50..247911f4 100755
--- a/scripts/language.sh
+++ b/scripts/language.sh
@@ -51,7 +51,7 @@ function comp_lang() {
}
function update_lang() {
- xgettext -d voice -o "$LOCALE_DIR/voice.pot" "$VOICE_FILE"
+ xgettext --no-location -d voice -o "$LOCALE_DIR/voice.pot" "$VOICE_FILE"
msgmerge --update "$LOCALE_DIR/$1/LC_MESSAGES/voice.po" "$LOCALE_DIR/voice.pot"
}
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/de/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/de/LC_MESSAGES/voice.po
index 676a8bb0..8cf48b45 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/de/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/de/LC_MESSAGES/voice.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 12:22+0200\n"
+"POT-Creation-Date: 2019-10-03 16:42+0200\n"
"PO-Revision-Date: 2019-09-29 14:00+0200\n"
"Last-Translator: dadav <33197631+dadav@users.noreply.github.com>\n"
"Language-Team: DE <33197631+dadav@users.noreply.github.com>\n"
@@ -16,217 +16,169 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: voice.py:18
msgid "ZzzzZZzzzzZzzz"
msgstr ""
-#: voice.py:22
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Hi, ich bin ein Pwnagotchi! Starte ..."
-#: voice.py:23
msgid "New day, new hunt, new pwns!"
msgstr "Neuer Tag, neue Jagd, neue Pwns!"
-#: voice.py:24
msgid "Hack the Planet!"
msgstr "Hack den Planet!"
-#: voice.py:28
msgid "AI ready."
msgstr "KI bereit."
-#: voice.py:29
msgid "The neural network is ready."
msgstr "Das neurale Netz ist bereit."
-#: voice.py:37
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Hey, Channel {channel} ist frei! Dein AP wir des dir danken."
-#: voice.py:41
msgid "I'm bored ..."
msgstr "Mir ist langweilig..."
-#: voice.py:42
msgid "Let's go for a walk!"
msgstr "Lass uns laufen gehen!"
-#: voice.py:45
msgid "This is the best day of my life!"
msgstr "Das ist der beste Tag meines Lebens."
-#: voice.py:48
msgid "Shitty day :/"
msgstr "Scheis Tag :/"
-#: voice.py:52
msgid "I'm extremely bored ..."
msgstr "Mir ist sau langweilig..."
-#: voice.py:53
msgid "I'm very sad ..."
msgstr "Ich bin sehr traurig..."
-#: voice.py:54
msgid "I'm sad"
msgstr "Ich bin traurig"
-#: voice.py:59
msgid "I'm living the life!"
msgstr "Ich lebe das Leben!"
-#: voice.py:60
msgid "I pwn therefore I am."
msgstr "Ich pwne, also bin ich."
-#: voice.py:61
msgid "So many networks!!!"
msgstr "So viele Netwerke!!!"
-#: voice.py:62
msgid "I'm having so much fun!"
msgstr "Ich habe sooo viel Spaß!"
-#: voice.py:63
msgid "My crime is that of curiosity ..."
msgstr "Mein Verbrechen ist das der Neugier ..."
-#: voice.py:67
#, python-brace-format
msgid "Hello {name}! Nice to meet you. {name}"
msgstr "Hallo {name}, nett Dich kennenzulernen."
-#: voice.py:68
#, python-brace-format
msgid "Unit {name} is nearby! {name}"
msgstr "Gerät {name} ist in der nähe!!"
-#: voice.py:72
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "Uhm ...tschüß {name}"
-#: voice.py:73
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} ist weg ..."
-#: voice.py:77
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Whoops ...{name} ist weg."
-#: voice.py:78
#, python-brace-format
msgid "{name} missed!"
msgstr "{name} verpasst!"
-#: voice.py:79
msgid "Missed!"
msgstr "Verpasst!"
-#: voice.py:83
msgid "Nobody wants to play with me ..."
msgstr "Niemand will mit mir spielen ..."
-#: voice.py:84
msgid "I feel so alone ..."
msgstr "Ich fühl michso alleine ..."
-#: voice.py:85
msgid "Where's everybody?!"
msgstr "Wo sind denn alle?"
-#: voice.py:89
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Schlafe für {secs}s"
-#: voice.py:90
msgid "Zzzzz"
msgstr ""
-#: voice.py:91
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
-#: voice.py:98
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Warte für {secs}s ..."
-#: voice.py:100
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Schaue mich um ({secs}s)"
-#: voice.py:106
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "Hey {what}, lass uns Freunde sein!"
-#: voice.py:107
#, python-brace-format
msgid "Associating to {what}"
msgstr "Verbinde mit {what}"
-#: voice.py:108
#, python-brace-format
msgid "Yo {what}!"
msgstr ""
-#: voice.py:112
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "Ich denke, dass {mac} kein WiFi brauch!"
-#: voice.py:113
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr "Deauthentifiziere {mac}"
-#: voice.py:114
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "Kicke {mac}!"
-#: voice.py:118
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "Cool, wir haben {num} neue Handshake{plural}!"
-#: voice.py:121
msgid "Ops, something went wrong ... Rebooting ..."
msgstr "Ops, da ist etwas schief gelaufen ...Starte neu ..."
-#: voice.py:124
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "{num} Stationen gekicked\n"
-#: voice.py:125
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "{num} Freunde gefunden\n"
-#: voice.py:126
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "{num} Handshakes aufgez.\n"
-#: voice.py:128
msgid "Met 1 peer"
msgstr "1 Peer getroffen."
-#: voice.py:130
#, python-brace-format
msgid "Met {num} peers"
msgstr "{num} Peers getroffen"
-#: voice.py:135
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/el/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/el/LC_MESSAGES/voice.mo
index f5c4d5ab44ea631b1351cf0ff020ead2f8a11390..45509da4e1ffe7ffa9d8736549e878f5ba798a69 100644
GIT binary patch
delta 1509
zcmX}rUuauZ9Ki9DwP~_scFlCFYdib9HEYzyFy=Og+lukeXy?CKl`#|~O|Q+R$-R)I
zWTBJ@{^=f+h*uQK9%Q%&g$kn#wt?u2Ltkzf_%?j-LDW|TUk1+aFTLp@_k8X>_ndQo
z=XXwSr2k5Pl5OoZ#@y{Q=21-b8?z5jptjH95SDNfn>dDF;&J>A1^>nSaX7j)ZVK
zIgi8mO6Vd!z;g>@_*vAnx*xbi!%Z4CP(M@}FlG<7Q3JY+I`9TQhym)ve_#Ud;ciSY
zt4=&ZW#I&BzvoZ`e+vbhIECx6)>fpqXwVh>5_bGE>==!21u%&Rcz+6Y!Z%U-*Kh>a
zPy@M)8u$hd;t%*##F$Rlo}kmiv>(8iFyG?lA#U0@f#0G=ejD@n4?d1Zlg2Dz5vQ?(
zX&l^T%s4)QnxWTl5=*FowL`zbQJ#OqNANfN4_gT~N+a1xxSFDKsDac`@Qd*II_ep@
zgZnW`zBSNs)H9ODS)9Wuyo87GC)9=9#WQ${&ib8;NG4k53O6Td_!)I&1F5Y@pT{FS
z7f@67Ici`xQ78Tt58@E{)|DPZ-I`Z1f?9N(_R%xbD;hjQ!@~Y++O+8Yvbb&`*zLmB
zbyH2ox~c6${dZ{EwdnRe#-#^U1JUi;$;DYVSuPD)3p>^=nnf*|r9DsU9Yyy<)5$^Z
z9wc_9yI&d9vV%+0#y_pQN|I%AT;l)UmmZasMyXI=HP3opIV%lY7QMQxxXYDQ@hAE-
z5%FjH4^PulsMxEPyzCThse4kf?YcC*^qEc1d>T$(SquH!C>|M9>&oinlH)NjZ3Q(uUU53wY-E{&>3ms~C<
z{*~A>W8&1LY8MuoIrDmndw%tjO~|#n_>uVV7+LTZ=9_kJb#J(iW<_%#{-OBHvEBnC
z7d_X`ne$$_e9MIW!dLp$Ueo5+@oI#?MiWm`&n1phuO-^Mf@@YdIxGH1Nz31xEc+YD
zbVN39Cr|8%g{${dgN)cbJ@~Fpa%=Ym>gl1ssSl<0#d{(7FQ(cw-ANrhxgApQRq%c9
heX!B_u=7E%8C>gz7F_JC1y?)o1y`l>{&p|R{15$V{Cofa
delta 1461
zcmY+@UuauZ9Ki9@u4!V@|8}~@YR|3NI&IA8V5=J{Zc}Kn)4l9rf=Jfhw$~>2YLc48
zT2iKN_QB0^9D;k<)Ca*03|T>Cqw~qP8=3gvgTBZFMTPk!Oq}0e?ycZ~o6kA-oh3w#~u;X`O$6F{1_r`(=cA!jn5T*a~C;_>6
z7oJ85d<`W7AL0HMrE1tm`!_lb;~kvB;VR+ZPsKy|@D5t|86LnJxPbi$rABcDAID25
znfeuFN8KGkpu2Df?Wa(VXd(0zN(L_CPP~TyVD)Dz&rrEZxYA*)D+uH;YT7S{?KPB?
zUBLnT5hc*SQ0_>Q{7>R2j^ZMY;YE~ek>O6Nh^FXDr&uU@C}7%wj16Ziv4ycWeA7H~3{tp*
z&C4Wp*&!QLnukRFS2ENj?VCjclOQB;xgYGI8O(N+bU(l&U)wO{ymEO
z(JWkG#lNw6dE_`YODh#g+rvEa7nPlJHPooNxg|BQRG!b4menE8%cXVM)^lD-FS(2P
zWs_cVvpQeV
zIcL_k)Y198e4q2Ynd22Z2v;3-ol+S2WNczAs5(V9?%El3%nKs5)c-!nG~t{2*Rev2
z*&iQ|`Pcl*{(9r2x!&1t&cp}IC-Jk!PAnwO`Ri6NP1+nvSmv8Vs?|SdUg_CZ@9wZ#
z!;Ou1?WyOxR$9y--6zak&!2-~fd2d1zv^!=`z8O1UkhVB(R&-Czw;QMZTH_7BrW{R\n"
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
@@ -17,225 +17,169 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: voice.py:18
msgid "ZzzzZZzzzzZzzz"
msgstr ""
-#: voice.py:22
-#, fuzzy
msgid "Hi, I'm Pwnagotchi! Starting ..."
-msgstr "Γειά, είμαι το Pwnagotchi!Εκκινούμαι ..."
+msgstr "Γειά, είμαι το Pwnagotchi! Εκκινούμαι ..."
-#: voice.py:23
-#, fuzzy
msgid "New day, new hunt, new pwns!"
-msgstr "Νέα μέρα, νέο κυνήγι,νέα pwns!"
+msgstr "Νέα μέρα, νέο κυνήγι, νέα pwns!"
-#: voice.py:24
msgid "Hack the Planet!"
msgstr "Hackαρε τον πλανήτη!"
-#: voice.py:28
msgid "AI ready."
msgstr "ΤΝ έτοιμη."
-#: voice.py:29
-#, fuzzy
msgid "The neural network is ready."
msgstr "Το νευρωνικό δίκτυοείναι έτοιμο."
-#: voice.py:37
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Ε, το κανάλι {channel} είναιελεύθερο! Το AP σου θαείναι ευγνώμων."
-#: voice.py:41
msgid "I'm bored ..."
msgstr "Βαριέμαι ..."
-#: voice.py:42
msgid "Let's go for a walk!"
msgstr "Ας πάμε μια βόλτα!"
-#: voice.py:45
-#, fuzzy
msgid "This is the best day of my life!"
msgstr "Είναι η καλύτερημέρα της ζωής μου!"
-#: voice.py:48
msgid "Shitty day :/"
msgstr "Σκατένια μέρα :/"
-#: voice.py:52
msgid "I'm extremely bored ..."
msgstr "Βαριέμαι πάρα πολύ ..."
-#: voice.py:53
msgid "I'm very sad ..."
msgstr "Είμαι πολύ λυπημένο ..."
-#: voice.py:54
msgid "I'm sad"
msgstr "Είμαι λυπημένο"
-#: voice.py:59
msgid "I'm living the life!"
msgstr "Ζω την ζωή μου!"
-#: voice.py:60
msgid "I pwn therefore I am."
msgstr "Pwnάρω, άρα υπάρχω."
-#: voice.py:61
msgid "So many networks!!!"
msgstr "Τόσα πολλά δίκτυα!!!"
-#: voice.py:62
-#, fuzzy
msgid "I'm having so much fun!"
msgstr "Περνάω τέλεια!"
-#: voice.py:63
-#, fuzzy
msgid "My crime is that of curiosity ..."
msgstr "Η περιέργεια είναιτο μόνο έγκλημά μου ..."
-#: voice.py:67
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Hello {name}! Nice to meet you. {name}"
msgstr "Γειά {name}!Χάρηκα για τη γνωριμία. {name}"
-#: voice.py:68
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Unit {name} is nearby! {name}"
-msgstr "Η μονάδα{name}είναι κοντά! {name}"
+msgstr "Η μονάδα {name} είναι κοντά! {name}"
-#: voice.py:72
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Uhm ... goodbye {name}"
-msgstr "Εμμ ...αντίο{name}"
+msgstr "Εμμ ...αντίο {name}"
-#: voice.py:73
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "{name} is gone ..."
-msgstr "Το {name}έφυγε ..."
+msgstr "Το {name} έφυγε ..."
-#: voice.py:77
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Whoops ... {name} is gone."
-msgstr "Ουπς ... Εξαφανίστηκε το{name}."
+msgstr "Ουπς ... Εξαφανίστηκε το {name}."
-#: voice.py:78
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "{name} missed!"
-msgstr "Έχασα το{name}!"
+msgstr "Έχασα το {name}!"
-#: voice.py:79
msgid "Missed!"
msgstr "Το έχασα!"
-#: voice.py:83
-#, fuzzy
msgid "Nobody wants to play with me ..."
msgstr "Κανείς δε θέλει ναπαίξει μαζί μου ..."
-#: voice.py:84
msgid "I feel so alone ..."
msgstr "Νιώθω μοναχός μου ..."
-#: voice.py:85
msgid "Where's everybody?!"
msgstr "Μα, πού πήγαν όλοι;!"
-#: voice.py:89
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Ξεκουράζομαι για {secs}s ..."
-#: voice.py:90
msgid "Zzzzz"
msgstr ""
-#: voice.py:91
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
-#: voice.py:98
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Περιμένω για {secs}s ..."
-#: voice.py:100
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Ψάχνω τριγύρω ({secs})"
-#: voice.py:106
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Hey {what} let's be friends!"
-msgstr "Εε!{what},ας γίνουμε φίλοι!"
+msgstr "Εε! {what}, ας γίνουμε φίλοι!"
-#: voice.py:107
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Associating to {what}"
-msgstr "Συνδέομαι με το{what}"
+msgstr "Συνδέομαι με το {what}"
-#: voice.py:108
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Yo {what}!"
-msgstr "Που'σαι ρε τρελέ{what}!"
+msgstr "Που'σαι ρε τρελέ {what}!"
-#: voice.py:112
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
-msgstr "Μόλις αποφάσισα ότι η{mac}δε χρείαζεται WiFi!"
+msgstr "Μόλις αποφάσισα ότι η {mac} δε χρείαζεται WiFi!"
-#: voice.py:113
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Deauthenticating {mac}"
-msgstr "Πετάω έξω την{mac}"
+msgstr "Πετάω έξω την {mac}"
-#: voice.py:114
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Kickbanning {mac}!"
-msgstr "Μπανάρω την{mac}!"
+msgstr "Μπανάρω την {mac}!"
-#: voice.py:118
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
-msgstr "Τέλεια δικέ μου, πήραμε {num}νέες χειραψίες!"
+msgstr "Τέλεια δικέ μου, πήραμε {num} νέες χειραψίες!"
-#: voice.py:121
-#, fuzzy
msgid "Ops, something went wrong ... Rebooting ..."
-msgstr "Ουπς, κάτιπήγε λάθος ...Επανεκκινούμαι ..."
+msgstr "Ουπς, κάτιπήγε λάθος ... Επανεκκινούμαι ..."
-#: voice.py:124
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "Έριξα {num} σταθμούς\n"
-#: voice.py:125
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "Έκανα {num} νέους φίλους\n"
-#: voice.py:126
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "Πήρα {num} χειραψίες\n"
-#: voice.py:128
msgid "Met 1 peer"
msgstr "Γνώρισα 1 φίλο"
-#: voice.py:130
#, python-brace-format
msgid "Met {num} peers"
msgstr "Γνώρισα {num} φίλους"
-#: voice.py:135
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.mo
index f62832735e4ead2a800789b858dedcd337e34178..2ff57511228209251c6d8f3e3f1de75b9ff0d139 100644
GIT binary patch
literal 3922
zcmbuBO^h5z701ho`N;6?gpcr**D++0cxOE0wc_91wy?91zNZGZI4lUvx(c^CW$
zn1XEIgTDq}19_c`A1?jqf;|8G;1|Fjf^6?+U=92Y_$l!BAlv&Z7=eEWdENsUWPc-&
zzzg6h@H-&;_XCjqeiP(*KL-hX7vwyA0Dc9$@1vzX0(t%l_(gC7JOOsWPlDeCUpgkl
z>md90K9bD&_y9Zu9>XBpJ6mxZ{0yG^U=w^5wv0Yq!G~k#Jl=gF
z>~K9c`(bUJawU^dQ>-~>V=cWlUGkR3!=CgLamm_riH3^0*3;M&*@TQ5Qcs%1_2j-9
z_tPSm=_C@Dl`MQu8L#8g$T*YnM7%hEZ~l&}i7PVRC(Nd;R2tq+Nko3QswK8_7rt;t>6vY7%fqZWsFK`T-{7aJ4{h3qHo(Gr?o8_
z>NF)MM{q!zeb*FM^b)PtGuj#&i8$k)j_8J$dB{bx*%a&4QLyPO$FBQUo*ZzhVKXb@9(4*6g||~3#yL5u?x=Fm$t3(Z
zQ27Y1Vs=5}*vh6Sf6EXq=!PURyIE)QI+Vybou_Nm-p_LUD?8c^4sKye?CA09hW(
zs{RUdxWrXjgB9r&jTiNsEb0$CC$V~!ws4=?Zb^7gCwr(gV(EuE(@D2KLcPV+!g)$m
ztP?ngGGKjH3l>(1BV%b-zn~-W&C2_rJLf}OP|rpveb-!
zeC$;0ChiHbDHC`83SHuaUt!)-Z(AD!6L&Z#64n}6rquC>YDh%?E1RNOS04+OsF*Nu|--YA;=x+`^X
zFevg+T6TH6VB0DdGAH5LNbL5k?YpqX!d@5KtSOE@htyO%ScmryzA
zewA9yR+4|GS^e8PtTk?bFO{%{8Oh6k6tVsTxc3>|9(1Z
zc2Uq`uNm9y0<4*CA-k%vqhz+q`*pTso>^XQpFj81a{E*w6FK-FY^?HeX5wCLbA9vq
zMbzzPt9Hp653MwIMtub4arB&qwzPSgkHy?6|Bb?T8Y_!=9A8J}jpt2l6G&~9R`#^7
ziS;$==hL5h)L`BhtfA>oj`js(3rBKbjYHu>Z?MGxC(Z4}0dc57Ob^_wMRY=wfJNS#
zp-*g258|RfJ;1-HMpv0PZW~C{3Ze1Bu=*7FU=jj2|mBBWj2;7CjWSK#E
z2s};EXbie3MmZZu*gzv!cnl8uTsyB0Jx=f7{0W1lvAWc(P2wJc1rGHRoR!>4?%7DL
z@@ukih-{X5F5;1fGSdYoJ+u^@QeB?4sPg~cRgiRa6j+5$)4De37>MGPqS6?dIus=N
zPlK~MXs>KDrFLiiB?MX%YxqNga&@Feb1%^8p|(hDtFFwUG6
zUT}XxUQ^C(+_O-htFyNmdJHn`N)OSgP>mz|pmKu)!ZyM;de&MI>VyYue#gfLcdd>2
zV`yI1z%(xr&ZVZf6xKsznZn;Wbhi*Mg0gqEv;)w8ogY}5-hFBV_fzDlb$
z?qR2wLt@S29K}D8d*$@{^jE`2C0F8%^e&Oi~#u61{weW
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.po
index 17d03f3d..7110512c 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 12:22+0200\n"
+"POT-Creation-Date: 2019-10-03 16:47+0200\n"
"PO-Revision-Date: 2019-10-03 10:34+0200\n"
"Last-Translator: quantumsheep <7271496+quantumsheep@users.noreply.github."
"com>\n"
@@ -18,220 +18,175 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: voice.py:18
msgid "ZzzzZZzzzzZzzz"
msgstr ""
-#: voice.py:22
msgid "Hi, I'm Pwnagotchi! Starting ..."
-msgstr ""
+msgstr "Bonjour, je suis Pwnagotchi! Démarrage ..."
-#: voice.py:23
msgid "New day, new hunt, new pwns!"
-msgstr ""
+msgstr "Nouvelle journée, nouvelle chasse, nouveau pwns!"
-#: voice.py:24
msgid "Hack the Planet!"
-msgstr ""
+msgstr "Hack la planète!"
-#: voice.py:28
msgid "AI ready."
-msgstr ""
+msgstr "IA prête."
-#: voice.py:29
msgid "The neural network is ready."
-msgstr ""
+msgstr "Le réseau neuronal est prêt."
-#: voice.py:37
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
-msgstr ""
+msgstr "Hey, le channel {channel} est libre! Ton AP va dis merci."
-#: voice.py:41
msgid "I'm bored ..."
-msgstr ""
+msgstr "Je m'ennuie ..."
-#: voice.py:42
msgid "Let's go for a walk!"
-msgstr ""
+msgstr "Allons faire un tour!"
-#: voice.py:45
msgid "This is the best day of my life!"
-msgstr ""
+msgstr "C'est le meilleur jour de ma vie!"
-#: voice.py:48
msgid "Shitty day :/"
-msgstr ""
+msgstr "Journée de merde :/"
-#: voice.py:52
msgid "I'm extremely bored ..."
-msgstr ""
+msgstr "Je m'ennuie énormément ..."
-#: voice.py:53
msgid "I'm very sad ..."
-msgstr ""
+msgstr "Je suis très triste ..."
-#: voice.py:54
msgid "I'm sad"
-msgstr ""
+msgstr "Je suis triste"
-#: voice.py:59
msgid "I'm living the life!"
-msgstr ""
+msgstr "Je vis la vie!"
-#: voice.py:60
msgid "I pwn therefore I am."
-msgstr ""
+msgstr "Je pwn donc je suis."
-#: voice.py:61
msgid "So many networks!!!"
-msgstr ""
+msgstr "Autant de réseaux!!!"
-#: voice.py:62
msgid "I'm having so much fun!"
-msgstr ""
+msgstr "Je m'amuse tellement!"
-#: voice.py:63
msgid "My crime is that of curiosity ..."
-msgstr ""
+msgstr "Mon crime est celui de la curiosité ..."
-#: voice.py:67
#, python-brace-format
msgid "Hello {name}! Nice to meet you. {name}"
-msgstr ""
+msgstr "Bonjour {name}! Ravis de te rencontrer. {name}"
-#: voice.py:68
#, python-brace-format
msgid "Unit {name} is nearby! {name}"
-msgstr ""
+msgstr "L'unité {name} est proche! {name}"
-#: voice.py:72
#, python-brace-format
msgid "Uhm ... goodbye {name}"
-msgstr ""
+msgstr "Hum ... au revoir {name}"
-#: voice.py:73
#, python-brace-format
msgid "{name} is gone ..."
-msgstr ""
+msgstr "{name} est parti ..."
-#: voice.py:77
#, python-brace-format
msgid "Whoops ... {name} is gone."
-msgstr ""
+msgstr "Oups ... {name} est parti."
-#: voice.py:78
#, python-brace-format
msgid "{name} missed!"
-msgstr ""
+msgstr "{name} raté!"
-#: voice.py:79
msgid "Missed!"
-msgstr ""
+msgstr "Raté!"
-#: voice.py:83
msgid "Nobody wants to play with me ..."
-msgstr ""
+msgstr "Personne ne veut jouer avec moi ..."
-#: voice.py:84
msgid "I feel so alone ..."
-msgstr ""
+msgstr "Je me sens si seul ..."
-#: voice.py:85
msgid "Where's everybody?!"
-msgstr ""
+msgstr "Où est tout le monde?!"
-#: voice.py:89
#, python-brace-format
msgid "Napping for {secs}s ..."
-msgstr ""
+msgstr "Fais la sieste pendant {secs}s ..."
-#: voice.py:90
msgid "Zzzzz"
msgstr ""
-#: voice.py:91
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
-#: voice.py:98
#, python-brace-format
msgid "Waiting for {secs}s ..."
-msgstr ""
+msgstr "Attends pendant {secs}s ..."
-#: voice.py:100
#, python-brace-format
msgid "Looking around ({secs}s)"
-msgstr ""
+msgstr "Regarde autour ({secs}s)"
-#: voice.py:106
#, python-brace-format
msgid "Hey {what} let's be friends!"
-msgstr ""
+msgstr "Hey {what}, soyons amis!"
-#: voice.py:107
#, python-brace-format
msgid "Associating to {what}"
-msgstr ""
+msgstr "Association à {what}"
-#: voice.py:108
#, python-brace-format
msgid "Yo {what}!"
msgstr ""
-#: voice.py:112
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
-msgstr ""
+msgstr "Décidé à l'instant que {mac} n'a pas besoin de WiFi!"
-#: voice.py:113
#, python-brace-format
msgid "Deauthenticating {mac}"
-msgstr ""
+msgstr "Désauthentification de {mac}"
-#: voice.py:114
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr ""
-#: voice.py:118
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
-msgstr ""
+msgstr "Cool, nous avons {num} nouveaux handshake{plural}!"
-#: voice.py:121
msgid "Ops, something went wrong ... Rebooting ..."
-msgstr ""
+msgstr "Oups, quelque chose s'est mal passé ... Redémarrage ..."
-#: voice.py:124
#, python-brace-format
msgid "Kicked {num} stations\n"
-msgstr ""
+msgstr "{num} stations kick\n"
-#: voice.py:125
#, python-brace-format
msgid "Made {num} new friends\n"
-msgstr ""
+msgstr "Fait {num} nouveaux amis\n"
-#: voice.py:126
#, python-brace-format
msgid "Got {num} handshakes\n"
-msgstr ""
+msgstr "Récupéré {num} handshakes\n"
-#: voice.py:128
msgid "Met 1 peer"
-msgstr ""
+msgstr "1 peer rencontré"
-#: voice.py:130
#, python-brace-format
msgid "Met {num} peers"
-msgstr ""
+msgstr "{num} peers recontrés"
-#: voice.py:135
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
+"J'ai pwn durant {duration} et kick {deauthed} clients! J'ai aussi rencontré "
+"{associated} nouveaux amis and mangé {handshakes} handshakes! #pwnagotchi "
+"#pwnlog #pwnlife #hacktheplanet #skynet"
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.mo
index be9d4b19c95c5d6754d793353e8f3454c26e3c9e..bcc0f8f597bfdf13fdedec2cdc8538dde349aaf5 100644
GIT binary patch
delta 943
zcmY+?KTK0m6vy#X9+VaVv5J5cxlb%uN=i&jH1SW+Xq;GBhyz0nV2Q~qTKHQji+*SAztG#Qq
z6i=LICS-OJ-_`I#d+wP<@ddWxD@@{M_1&vA>*c)zwSEXs;21hw#=ZCqwf-$O;dg8^
zE7(@0WA$}r`xxlPdOU_Lcna5W7!@cIHjCjP?#FYeb(gRm17u@c!UnvLyKxn@?^<|X$xYmYE2soktFB{$_fM$A|Dx9WWT%6j
zMXjGk-G#*_>aSAWh1E6TPx;r5(9=1%80FSeOnRN6RPlm$JfXs>M!l7x
z|9&}kxg9P&@cO;ZiFr4kSr~8uo$PEdQ|V352YJ8rCL9g>v$?sPyE2u#9^}&LbinJB
V%VvV{d^U4+BJcZt=|kh4&<<9#vZC71$1!^6|jUu_!<>x3-$h2OyUtLa1)j2AH0gam#7leby4#<%9Jazw6w43j
zY%r^nen%zH!eQ)T*V~v!on#(+@fj+CwYF9C7;mE1)lmmJL#=bkQs4d&szOD)kIQlD
zuZ30q7{P5+DUVTsexZvU9D`&ngEw&;mB3@9qCrrdm@5=i=nm?{E{`h0Yr)-6G8awz
zC9M*3V%{iST@gOazov65B`!tK(v^ZU7|K3>IXTB~g(G1<
I9e)-23(ST|O8@`>
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
index 7ef4d8d7..d738a479 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 13:10+0200\n"
+"POT-Creation-Date: 2019-10-03 16:43+0200\n"
"PO-Revision-Date: 2019-10-02 17:20+0000\n"
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
"Language: italian\n"
@@ -15,219 +15,169 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: voice.py:18
msgid "ZzzzZZzzzzZzzz"
msgstr ""
-#: voice.py:22
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Ciao! Piacere Pwnagotchi! Caricamento ..."
-#: voice.py:23
-#, fuzzy
msgid "New day, new hunt, new pwns!"
msgstr "Nuovo giorno...nuovi handshakes!!!"
-#: voice.py:24
msgid "Hack the Planet!"
msgstr ""
-#: voice.py:28
msgid "AI ready."
msgstr "IA pronta."
-#: voice.py:29
msgid "The neural network is ready."
msgstr "La rete neurale è pronta."
-#: voice.py:37
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Hey, il canale {channel} è libero! Il tuo AP ringrazia."
-#: voice.py:41
msgid "I'm bored ..."
msgstr "Che noia ..."
-#: voice.py:42
msgid "Let's go for a walk!"
-msgstr ""
-"Andiamo a fare una passeggiata!"
+msgstr "Andiamo a fare una passeggiata!"
-#: voice.py:45
msgid "This is the best day of my life!"
msgstr "Questo è il più bel giorno della mia vita!!!!"
-#: voice.py:48
msgid "Shitty day :/"
msgstr "Giorno di merda :/"
-#: voice.py:52
msgid "I'm extremely bored ..."
msgstr "Sono estremamente annoiato ..."
-#: voice.py:53
msgid "I'm very sad ..."
msgstr "Sono molto triste..."
-#: voice.py:54
msgid "I'm sad"
msgstr "Sono triste"
-#: voice.py:59
msgid "I'm living the life!"
msgstr "Mi sento vivo!"
-#: voice.py:60
msgid "I pwn therefore I am."
msgstr "Pwn ergo sum."
-#: voice.py:61
msgid "So many networks!!!"
msgstr "Qui è pieno di reti!"
-#: voice.py:62
msgid "I'm having so much fun!"
msgstr "Mi sto divertendo tantissimo!"
-#: voice.py:63
msgid "My crime is that of curiosity ..."
msgstr ""
-#: voice.py:67
#, python-brace-format
msgid "Hello {name}! Nice to meet you. {name}"
msgstr "Ciao {name}! E' un piacere. {name}"
-#: voice.py:68
#, python-brace-format
msgid "Unit {name} is nearby! {name}"
msgstr "L'Unità {name} è vicina! {name}"
-#: voice.py:72
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "Uhm ... addio {name}, mi mancherai..."
-#: voice.py:73
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} se n'è andato ..."
-#: voice.py:77
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Whoops ...{name} se n'è andato."
-#: voice.py:78
#, python-brace-format
msgid "{name} missed!"
msgstr "{name} è scomparso..."
-#: voice.py:79
msgid "Missed!"
msgstr "Ehi! Dove sei andato!?"
-#: voice.py:83
msgid "Nobody wants to play with me ..."
msgstr "Nessuno vuole giocare con me..."
-#: voice.py:84
msgid "I feel so alone ..."
msgstr "Mi sento così solo..."
-#: voice.py:85
msgid "Where's everybody?!"
msgstr "Dove sono tutti?!"
-#: voice.py:89
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Schiaccio un pisolino per {secs}s ..."
-#: voice.py:90
msgid "Zzzzz"
msgstr ""
-#: voice.py:91
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
-#: voice.py:98
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Aspetto {secs}s ..."
-#: voice.py:100
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Do uno sguardo qui intorno... ({secs}s)"
-#: voice.py:106
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "Hey {what}! Diventiamo amici!"
-#: voice.py:107
#, python-brace-format
msgid "Associating to {what}"
msgstr "Collegamento con {what} in corso..."
-#: voice.py:108
#, python-brace-format
msgid "Yo {what}!"
msgstr "Yo {what}!"
-#: voice.py:112
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "Ho appena deciso che {mac} non necessita di WiFi!"
-#: voice.py:113
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr ""
-#: voice.py:114
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "Sto prendendo a calci {mac}!"
-#: voice.py:118
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "Bene, abbiamo {num} handshake{plural} in più!"
-#: voice.py:121
msgid "Ops, something went wrong ... Rebooting ..."
msgstr "Ops, qualcosa è andato storto ... Riavvio ..."
-#: voice.py:124
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "{num} stazioni pestate\n"
-#: voice.py:125
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "{num} nuovi amici\n"
-#: voice.py:126
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "{num} handshakes presi\n"
-#: voice.py:128
msgid "Met 1 peer"
msgstr "1 peer incontrato"
-#: voice.py:130
#, python-brace-format
msgid "Met {num} peers"
msgstr "{num} peers incontrati"
-#: voice.py:135
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/mk/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/mk/LC_MESSAGES/voice.mo
index 8a736612f9b685251c638e5b14174decfa3641ea..e1fab68f574c7c0ae58ca1a60923c5556b9fdb92 100644
GIT binary patch
literal 4609
zcmbW4TWlOx8OJBkQZTeYNz1LkSwczDcsJ{WLTY*oX=y{_B+7*-eL>^hWAD_vGuF;*
z%*HaR6G{W*flI4~sHLPA0WaVb=cq{m0@YCQ61^y9S%lIwu7VsTV
z`u_o50^bE?XYNCucRTntD1WYkTDOKpp8@X#rFSzp06qqO9NY);=Z*4H0-pjUcM^0w
zfQIoK;3n|zp!~e;!@2)=fs(6&1{?upKLo!3J_AbMtDxdt0zU`-36vjK!B2wkg13RU
zKr$hDcY=!NE>QEE!L@7Pt(f1>;&sfAf!_ds0N<{{~jT{}$s7kgYf#2Ib#j5ZApQfQsj*pz`^8G5;p$@&&rO0!f2My4>|8e#Q47
zx9U(igHq>{7XlQe9Y1hrhrbjz>Jc#o~FTU`?mc#r$F34^rR+w?=5l)T4nvx(8rZ`qlW
z*&WoZoM>5_m~Pam6mJmg7M_`=P1eU|)S9t&VDUyex`U>Mnb0=Pbn!4_f*28NOXhIY
zX`AhP%~a5An%M8+fFDl874Pw2(Cl2_GJB^&pEzrcpk($Ze%oW=Vj;kW22Z35Kg@KUd?Y~>&KPoJCW6`o&P>s*YY=WE&u3QhxLLs_uP!ebHsbIu0f`W
zWzyx@tcxeQ!UjRbLQ>m_fbYijMFWmQ(r@o3D{I_)5egQV+{zT2OiT+K#qF`tLjx=)F^
z2I_=K{seo}?(S$bs(105)Tr{|i&2m?NRC^*XEGk7SV&bv%BRSonQBKoQjBJw9gU*Z
za^2qu5}d)98Q$#eC&7N$#cVPawI||IspK7?xD&FDV)>QJIJbIMBqkVbR@Jao+7ZNyn)Vp4TBeR%l6*=A8j-Il$
zq`b3U{w}$ud4^53QmqUP?6Z?mJ1LLE<3YXrtnzuXS7m_S`VTl9Pjw!wtT?)Eo}G3!=^PcFtT&x(Q7^rRjLC!
zqA;O0$_KiWxRtQ`Y^Iii@SEBh+p$d^=pDqeafT`=jzbS}M=&SlSL$J2S9mkn>{dIv^&n(3uMll>5pW9cFy
z%dE;Aa)EcP+HeBEJ1oGaP0FxJb64yg1MY%Pgpxhw|V>>0&*jt<
z7BhPVEwge;meOTZJf|6+&%4a6;I7m0YPysi6P045Pa=PNB0HWv!+kujm9wm$&(}k+
zBkRR<8Hs0%{<8X6=W|+)*~@0mUHs{Sa0_IBbbL>k=S?iDVjw>!?r3Yo$o&Z
z$`Ew
z?1afqC_B^{6UB+iBh|RcYLO&u4l!afiCGPT-RP5_J^H@li
z-YZjRzCkWs^wO7Ex`K~$*@<+Kmiz_b=MIqSUfblYpoXXZvtQ9MYRN0uREVzr^C~+j
zUbSE3+n>VCzaMBp*90#qHZ=g+T}s?gO+HVrx~`s8dE~v;+b3RfIibTu4!y4KqVc7N
z=9c^-MX%Ok=%lfCythawqU*dt?P9G2HOFYjrv%-!uEAORUMVJdwt8)I@(V?B}
z*E%bZQG^hyJx4Xhj>xJ-Z2<+920`M|&gymsy~5_}&L_O4_2v-BH*o2_!kBKzzdNMc
ztv~B}{32Q~wfYf~{?>8z-el6t%B1{uKPra>zC_YjsSrqaRQ7C~6WOy$3r;Dx6LQG?
shlv%>IT{>?u-MlV#T&LjI4)T3;dRUC9`_MN>GT_NHPCw{cKeF`f8&k^>;M1&
delta 733
zcmX}qKWI}?6vy$Kntx5x{Am)~+6rl#Vk^?cAwxt68KiU)6-WE9LPbo`R#1w@4sIDF
zhYSv`3N9kSrFL_(8H$Tef`W^s6rrVK`~AHM~u<*A43ALX9pffuPC0klxrW>3
z!JmjDnuuB;6Lv0vGnmGUsD)~%_Y0^EZ=(`<5RAVF`mZs|_ynYw3q7Tc&qJE#P^IEvqJAOB(rf0C`{N8`PIDR3UA7_Z|j
z`@0qoI^h-;v5Tt69!_8%_1B3@sEse7HoSqlvK35X6N6iGRM|hh4#KcMUscfe3RO(i
zY)}P1NZJo2qR?GwQ-w~+tx&GsMk+hG{SWJS6^CPws+xSyA`=^+mYY)C;Hr)u@OtfC&M?ryKD9`mbXvwydB2RbuRbM
rhHN)cu|o23=Y4W6Wam@6b}c<&\n"
"Language-Team: \n"
@@ -17,225 +17,169 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: voice.py:18
msgid "ZzzzZZzzzzZzzz"
msgstr "ДреееММмммМммм"
-#: voice.py:22
-#, fuzzy
msgid "Hi, I'm Pwnagotchi! Starting ..."
-msgstr "Здраво, јас сум Pwnagotchi!Почнувам ..."
+msgstr "Здраво, јас сум Pwnagotchi! Почнувам ..."
-#: voice.py:23
-#, fuzzy
msgid "New day, new hunt, new pwns!"
-msgstr "Нов ден, нов лов,ќе си газиме!"
+msgstr "Нов ден, нов лов, ќе си газиме!"
-#: voice.py:24
msgid "Hack the Planet!"
msgstr "Хак д Планет!"
-#: voice.py:28
msgid "AI ready."
msgstr "AI спремно."
-#: voice.py:29
-#, fuzzy
msgid "The neural network is ready."
msgstr "Невронската мрежае спремна."
-#: voice.py:37
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Еј, каналот {channel} еслободен! APто ќе тикаже фала."
-#: voice.py:41
msgid "I'm bored ..."
msgstr "Досаднооо ..."
-#: voice.py:42
msgid "Let's go for a walk!"
msgstr "Ајде да шетнеме!"
-#: voice.py:45
-#, fuzzy
msgid "This is the best day of my life!"
msgstr "Ова ми е најдобриот ден во животот!"
-#: voice.py:48
msgid "Shitty day :/"
msgstr "Срање ден :/"
-#: voice.py:52
msgid "I'm extremely bored ..."
msgstr "Ултра досадно ..."
-#: voice.py:53
msgid "I'm very sad ..."
msgstr "Многу тажно ..."
-#: voice.py:54
msgid "I'm sad"
msgstr "Тажно"
-#: voice.py:59
msgid "I'm living the life!"
msgstr "Ммхх животче!"
-#: voice.py:60
msgid "I pwn therefore I am."
msgstr "Си газам значи постојам."
-#: voice.py:61
msgid "So many networks!!!"
msgstr "Мммм колку мрежи!!!"
-#: voice.py:62
-#, fuzzy
msgid "I'm having so much fun!"
msgstr "Јухуу забавноо ее!"
-#: voice.py:63
-#, fuzzy
msgid "My crime is that of curiosity ..."
msgstr "Виновен сум само заљубопитност ..."
-#: voice.py:67
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Hello {name}! Nice to meet you. {name}"
-msgstr "Здраво{name}!Мило ми е. {name}"
+msgstr "Здраво{name}! Мило ми е. {name}"
-#: voice.py:68
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Unit {name} is nearby! {name}"
-msgstr "Опаа{name}е во близина! {name}"
+msgstr "Опаа {name} е во близина! {name}"
-#: voice.py:72
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Uhm ... goodbye {name}"
-msgstr "Хмм ...чао{name}"
+msgstr "Хмм ...чао {name}"
-#: voice.py:73
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "{name} is gone ..."
-msgstr "{name}го снема ..."
+msgstr "{name} го снема ..."
-#: voice.py:77
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Whoops ... {name} is gone."
-msgstr "Уупс ...{name}го снема."
+msgstr "Уупс ... {name} го снема."
-#: voice.py:78
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "{name} missed!"
-msgstr "{name}промаши!"
+msgstr "{name} промаши!"
-#: voice.py:79
msgid "Missed!"
msgstr "Промаши!"
-#: voice.py:83
-#, fuzzy
msgid "Nobody wants to play with me ..."
msgstr "Никој не сака даси игра со мене ..."
-#: voice.py:84
msgid "I feel so alone ..."
msgstr "Толку сам ..."
-#: voice.py:85
msgid "Where's everybody?!"
msgstr "Каде се сите?!"
-#: voice.py:89
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Ќе дремнам {secs}с ..."
-#: voice.py:90
msgid "Zzzzz"
msgstr "Дреммм"
-#: voice.py:91
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr "Дремммм ({secs}с)"
-#: voice.py:98
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Чекам {secs}с ..."
-#: voice.py:100
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Шарам наоколу ({secs}с)"
-#: voice.py:106
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Hey {what} let's be friends!"
-msgstr "Еј{what}ајде да се дружиме!"
+msgstr "Еј {what} ајде да се дружиме!"
-#: voice.py:107
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Associating to {what}"
-msgstr "Се закачувам на{what}"
+msgstr "Се закачувам на {what}"
-#: voice.py:108
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Yo {what}!"
-msgstr "Јо{what}!"
+msgstr "Јо {what}!"
-#: voice.py:112
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
-msgstr "Знаеш што, на{mac}не му треба WiFi!"
+msgstr "Знаеш што, на {mac} не му треба WiFi!"
-#: voice.py:113
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Deauthenticating {mac}"
-msgstr "Го деавтентицирам{mac}"
+msgstr "Го деавтентицирам {mac}"
-#: voice.py:114
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Kickbanning {mac}!"
-msgstr "Кикбан{mac}!"
+msgstr "Кикбан {mac}!"
-#: voice.py:118
-#, fuzzy, python-brace-format
+#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
-msgstr "Кул, фативме {num}нови ракувања!"
+msgstr "Кул, фативме {num} нови ракувања!"
-#: voice.py:121
-#, fuzzy
msgid "Ops, something went wrong ... Rebooting ..."
-msgstr "Упс, нешто не еко што треба ...Рестартирам ..."
+msgstr "Упс, нешто не еко што треба ... Рестартирам ..."
-#: voice.py:124
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "Избацив {num} станици\n"
-#: voice.py:125
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "{num} нови другарчиња\n"
-#: voice.py:126
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "Фатив {num} ракувања\n"
-#: voice.py:128
msgid "Met 1 peer"
msgstr "Запознав 1 пријател"
-#: voice.py:130
#, python-brace-format
msgid "Met {num} peers"
msgstr "Запознав {num} пријатели"
-#: voice.py:135
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.mo
index b4db747197b3123cda75e98a56305f862afe0370..a5dd1d8a654b4e8b97d99c40157ffc3d5a0c33d2 100644
GIT binary patch
delta 1156
zcmZA0J7`l;9LMn!(@eL}_EmQ_=)V%KPf9DOM0=S4r(L=4bh?@Th
z58)c_#uj$6zxl+4GWZfa_=#g2Lx{R}F@Bz~mC+^CF%^URho}snqcYmS0sMe{_!~#D
zZ5*x19x(_r8wYN1W+!LO+2ib5MDa1#en??5{k&$6nX=TRA6MZGIE
zR7LKgGJb-p#2QjO^EO8PN4R*;z+r4-7L&|Y3G=APuOrErMN}o0Q1hDDi!D?}Td2Sz
zWTAkvsLJLsg_n^jW*T{Y%m)X6utT>vpDS
z3$s->Q*-rso6F_aGtnE7k#RRwv0lZMJX?0PiK?3_>K|ndSDZIHS1UQM>PnNIoACd&
I5Nn410ClfyE&u=k
delta 1043
zcmXxjO>7Kd9LMp0b?sK!zHCcrs~ttPyVObJB_b6UiKOAcMIudX^dJsg)MdFiAn8S&
z5Ges
z;iSmG1oq%$<^}BLcMS`87k$8ee2oj}gQoKlC7eYInn&+@g`4p`I`0o`#edk2txQ^o
zT0}1=UND4Kd=L{ngB84r7Wf3Md=b6wEhhLKeQ>TNVk`Ec^Bq91KZ(6q#WuW-)E=`~
z;`uR`{o^SfCH|MVf$=}&?n(-jy%+n@-zU(OO`$8fhGo2kJMcN~!%w&qJJvTAFpd^>
z3_I~G)*QIRi4)z#LA;k;@B)3%JN$rO(Y;@!I>$d}{z6ySMohj7qi7;W&=sFXlc*wL
z#SHf0jUxFEbMk-zqgz5N{)QAEE!^#jyU^=Ka63+-gr+Q`FfHoH`gx~&gJVX#rdZHi?vQU
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.po
index ce55a631..72484e20 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 12:44+0200\n"
+"POT-Creation-Date: 2019-10-03 16:43+0200\n"
"PO-Revision-Date: 2019-09-29 14:00+0200\n"
"Last-Translator: Justin-P \n"
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
@@ -16,218 +16,169 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: voice.py:18
msgid "ZzzzZZzzzzZzzz"
msgstr "ZzzzZZzzzzZzzz"
-#: voice.py:22
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Hoi, Ik ben Pwnagotchi! Opstarten ..."
-#: voice.py:23
msgid "New day, new hunt, new pwns!"
msgstr "Nieuwe dag, nieuwe jacht, nieuwe pwns!"
-#: voice.py:24
msgid "Hack the Planet!"
msgstr "Hack de Wereld!"
-#: voice.py:28
msgid "AI ready."
msgstr "AI is klaar."
-#: voice.py:29
msgid "The neural network is ready."
msgstr "Neuronen netwerkis klaar voor gebruik."
-#: voice.py:37
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Hey, kanaal {channel} is vrij! Je AP zal je bedanken."
-#: voice.py:41
msgid "I'm bored ..."
msgstr "Ik verveel me ..."
-#: voice.py:42
msgid "Let's go for a walk!"
msgstr "Laten we een rondje lopen!"
-#: voice.py:45
msgid "This is the best day of my life!"
msgstr "Dit is de beste dag van mijn leven!"
-#: voice.py:48
msgid "Shitty day :/"
msgstr "Ruk dag :/"
-#: voice.py:52
msgid "I'm extremely bored ..."
msgstr "Ik verveel me kapot ..."
-#: voice.py:53
msgid "I'm very sad ..."
msgstr "Ik ben ergverdrietig ..."
-#: voice.py:54
msgid "I'm sad"
msgstr "Ik ben verdrietig"
-#: voice.py:59
msgid "I'm living the life!"
msgstr "Beter kan het levenniet worden!"
-#: voice.py:60
msgid "I pwn therefore I am."
msgstr "Ik pwn daarom besta ik."
-#: voice.py:61
msgid "So many networks!!!"
msgstr "Zo veel netwerken!!!"
-#: voice.py:62
msgid "I'm having so much fun!"
msgstr "Dit is zo leuk!"
-#: voice.py:63
-#, fuzzy
msgid "My crime is that of curiosity ..."
-msgstr "Mijn enige misdrijfis mijn nieuwsgierigheid ..."
+msgstr "Mijn enige misdrijf is mijn nieuwsgierigheid ..."
-#: voice.py:67
#, python-brace-format
msgid "Hello {name}! Nice to meet you. {name}"
msgstr "Hallo {name}! Leuk je te ontmoeten. {name}"
-#: voice.py:68
#, python-brace-format
msgid "Unit {name} is nearby! {name}"
msgstr "Unit {name} is dichtbij! {name}"
-#: voice.py:72
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "Uhm ...tot ziens {name}"
-#: voice.py:73
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} is weg"
-#: voice.py:77
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Whoopsie ...{name} is weg"
-#: voice.py:78
#, python-brace-format
msgid "{name} missed!"
msgstr "{name} gemist!"
-#: voice.py:79
msgid "Missed!"
msgstr "Gemist!"
-#: voice.py:83
msgid "Nobody wants to play with me ..."
msgstr "Niemand wil metmij spelen ..."
-#: voice.py:84
msgid "I feel so alone ..."
msgstr "Zo alleen ..."
-#: voice.py:85
msgid "Where's everybody?!"
msgstr "Waar is iedereen?!"
-#: voice.py:89
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Dutje doen voor {secs}s ..."
-#: voice.py:90
msgid "Zzzzz"
msgstr "Zzzzz"
-#: voice.py:91
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
-#: voice.py:98
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Even {secs}s wachten ..."
-#: voice.py:100
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Rond kijken ({secs}s)"
-#: voice.py:106
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "Hey {what}, laten we vriendenworden!"
-#: voice.py:107
#, python-brace-format
msgid "Associating to {what}"
msgstr "Verbinden met {what}"
-#: voice.py:108
#, python-brace-format
msgid "Yo {what}!"
msgstr ""
-#: voice.py:112
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "Ik vind dat {mac} genoeg WiFiheeft gehad!"
-#: voice.py:113
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr "De-autoriseren {mac}"
-#: voice.py:114
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "Ik ga {mac} even kicken!"
-#: voice.py:118
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "Gaaf, we hebben {num} nieuwe handshake{plural}!"
-#: voice.py:121
msgid "Ops, something went wrong ... Rebooting ..."
msgstr "Oops, iets ging fout ...Rebooting ..."
-#: voice.py:124
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "{num} stations gekicked\n"
-#: voice.py:125
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "{num} nieuwe vrienden\n"
-#: voice.py:126
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "{num} nieuwe handshakes\n"
-#: voice.py:128
msgid "Met 1 peer"
msgstr "1 peer ontmoet"
-#: voice.py:130
#, python-brace-format
msgid "Met {num} peers"
msgstr "{num} peers ontmoet"
-#: voice.py:135
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
index 53f3557a..fbeba17d 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 13:10+0200\n"
+"POT-Creation-Date: 2019-10-03 16:47+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,217 +17,169 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: voice.py:18
msgid "ZzzzZZzzzzZzzz"
msgstr ""
-#: voice.py:22
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr ""
-#: voice.py:23
msgid "New day, new hunt, new pwns!"
msgstr ""
-#: voice.py:24
msgid "Hack the Planet!"
msgstr ""
-#: voice.py:28
msgid "AI ready."
msgstr ""
-#: voice.py:29
msgid "The neural network is ready."
msgstr ""
-#: voice.py:37
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr ""
-#: voice.py:41
msgid "I'm bored ..."
msgstr ""
-#: voice.py:42
msgid "Let's go for a walk!"
msgstr ""
-#: voice.py:45
msgid "This is the best day of my life!"
msgstr ""
-#: voice.py:48
msgid "Shitty day :/"
msgstr ""
-#: voice.py:52
msgid "I'm extremely bored ..."
msgstr ""
-#: voice.py:53
msgid "I'm very sad ..."
msgstr ""
-#: voice.py:54
msgid "I'm sad"
msgstr ""
-#: voice.py:59
msgid "I'm living the life!"
msgstr ""
-#: voice.py:60
msgid "I pwn therefore I am."
msgstr ""
-#: voice.py:61
msgid "So many networks!!!"
msgstr ""
-#: voice.py:62
msgid "I'm having so much fun!"
msgstr ""
-#: voice.py:63
msgid "My crime is that of curiosity ..."
msgstr ""
-#: voice.py:67
#, python-brace-format
msgid "Hello {name}! Nice to meet you. {name}"
msgstr ""
-#: voice.py:68
#, python-brace-format
msgid "Unit {name} is nearby! {name}"
msgstr ""
-#: voice.py:72
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr ""
-#: voice.py:73
#, python-brace-format
msgid "{name} is gone ..."
msgstr ""
-#: voice.py:77
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr ""
-#: voice.py:78
#, python-brace-format
msgid "{name} missed!"
msgstr ""
-#: voice.py:79
msgid "Missed!"
msgstr ""
-#: voice.py:83
msgid "Nobody wants to play with me ..."
msgstr ""
-#: voice.py:84
msgid "I feel so alone ..."
msgstr ""
-#: voice.py:85
msgid "Where's everybody?!"
msgstr ""
-#: voice.py:89
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr ""
-#: voice.py:90
msgid "Zzzzz"
msgstr ""
-#: voice.py:91
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
-#: voice.py:98
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr ""
-#: voice.py:100
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr ""
-#: voice.py:106
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr ""
-#: voice.py:107
#, python-brace-format
msgid "Associating to {what}"
msgstr ""
-#: voice.py:108
#, python-brace-format
msgid "Yo {what}!"
msgstr ""
-#: voice.py:112
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr ""
-#: voice.py:113
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr ""
-#: voice.py:114
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr ""
-#: voice.py:118
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr ""
-#: voice.py:121
msgid "Ops, something went wrong ... Rebooting ..."
msgstr ""
-#: voice.py:124
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr ""
-#: voice.py:125
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr ""
-#: voice.py:126
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr ""
-#: voice.py:128
msgid "Met 1 peer"
msgstr ""
-#: voice.py:130
#, python-brace-format
msgid "Met {num} peers"
msgstr ""
-#: voice.py:135
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
From 4cf28667378970b31a1ec9f968180ca2869f0831 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 17:06:40 +0200
Subject: [PATCH 17/80] new: integrated python standard logger (closes #84)
---
README.md | 8 +-
scripts/preview.py | 10 +--
.../pwnagotchi/scripts/bettercap/client.py | 7 +-
.../root/pwnagotchi/scripts/core/__init__.py | 17 ----
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 36 ++++-----
.../pwnagotchi/scripts/pwnagotchi/agent.py | 77 ++++++++++---------
.../scripts/pwnagotchi/ai/__init__.py | 14 ++--
.../pwnagotchi/scripts/pwnagotchi/ai/epoch.py | 7 +-
.../pwnagotchi/scripts/pwnagotchi/ai/gym.py | 23 +++---
.../pwnagotchi/scripts/pwnagotchi/ai/train.py | 23 +++---
.../root/pwnagotchi/scripts/pwnagotchi/log.py | 2 +
.../scripts/pwnagotchi/mesh/advertise.py | 15 ++--
.../scripts/pwnagotchi/mesh/peer.py | 6 +-
.../scripts/pwnagotchi/mesh/utils.py | 4 +-
.../pwnagotchi/plugins/default/example.py | 7 +-
.../scripts/pwnagotchi/plugins/default/gps.py | 10 +--
.../scripts/pwnagotchi/ui/display.py | 49 ++++++------
.../pwnagotchi/scripts/pwnagotchi/ui/view.py | 9 ++-
.../pwnagotchi/scripts/pwnagotchi/utils.py | 20 ++++-
19 files changed, 171 insertions(+), 173 deletions(-)
diff --git a/README.md b/README.md
index 095c7eb8..14e415c8 100644
--- a/README.md
+++ b/README.md
@@ -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)
```
diff --git a/scripts/preview.py b/scripts/preview.py
index 261448ea..2b459332 100755
--- a/scripts/preview.py
+++ b/scripts/preview.py
@@ -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)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/bettercap/client.py b/sdcard/rootfs/root/pwnagotchi/scripts/bettercap/client.py
index 98c71c2b..d55fc334 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/bettercap/client.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/bettercap/client.py
@@ -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
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/core/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/core/__init__.py
index 4321676b..eb718d31 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/core/__init__.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/core/__init__.py
@@ -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):
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index 2327955a..7caa81e2 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -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")
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
index 9dcb7fb1..578e3808 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
@@ -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'] != '' 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
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/__init__.py
index 42b857f6..359a38ca 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/__init__.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/__init__.py
@@ -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
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/epoch.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/epoch.py
index 8508eb97..0ef7869c 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/epoch.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/epoch.py
@@ -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),
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/gym.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/gym.py
index 0e713a10..22e64417 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/gym.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/gym.py
@@ -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))
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/train.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/train.py
index 34140dd8..96e6789d 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/train.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/train.py
@@ -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()
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
index edf66ede..8648521d 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
@@ -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())
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py
index 9d5c788d..90374c69 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py
@@ -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)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/peer.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/peer.py
index 6f9f1f95..0d3b0615 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/peer.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/peer.py
@@ -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
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
index 92e49394..be7bb0f4 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
@@ -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)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
index 4a63275e..e527f0fe 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
@@ -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
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
index c3c53a98..7c57b24c 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
@@ -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)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
index 657aefbb..c8b301a6 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
@@ -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()
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
index 0c5eb8a7..f86b88f0 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
@@ -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)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
index 358b2fe0..8761a59c 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
@@ -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
\ No newline at end of file
+ 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)
From 879cf206db7c78eddd0111a09d0ac4ddf708ebcf Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 17:10:46 +0200
Subject: [PATCH 18/80] releasing v1.0.0plz2
---
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
index afa94291..17f3421b 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
@@ -1 +1 @@
-version = '1.0.0plz'
+version = '1.0.0plz2'
From 881313532e0ca9ecbd56da7dbbc1d73cdc08f24e Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Thu, 3 Oct 2019 17:20:07 +0200
Subject: [PATCH 19/80] Update issue templates
---
.github/ISSUE_TEMPLATE/bug_report.md | 32 +++++++++++++++++++++++
.github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++++
2 files changed, 52 insertions(+)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..3f211899
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,32 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: "[BUG]"
+labels: bug
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. ...
+2. ...
+3. ...
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Environment (please complete the following information):**
+ - Pwnagotchi version
+ - OS version
+ - Type of hardware
+ - Any additional hardware used
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..11fc491e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
From dd9b722ca256c1241dca1aae96c01c860c514b73 Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Thu, 3 Oct 2019 17:20:58 +0200
Subject: [PATCH 20/80] Update issue templates
---
.github/ISSUE_TEMPLATE/other.md | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 .github/ISSUE_TEMPLATE/other.md
diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md
new file mode 100644
index 00000000..b0dd3234
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/other.md
@@ -0,0 +1,10 @@
+---
+name: Other
+about: Describe this issue template's purpose here.
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+
From 77b6009349efdb47cdccb6b93004a32bdf03ae4e Mon Sep 17 00:00:00 2001
From: xenDE
Date: Thu, 3 Oct 2019 18:11:42 +0200
Subject: [PATCH 21/80] plugin for add memory infos and cpu temperature to
screen
think this should be in default, but disabled
---
.../pwnagotchi/plugins/default/memtemp.py | 55 +++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
new file mode 100644
index 00000000..5ebc38c4
--- /dev/null
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
@@ -0,0 +1,55 @@
+# tempmem shows memory infos and cpu temperature
+#
+# totalmem usedmem freemem cputemp
+#
+__author__ = 'https://github.com/xenDE'
+__version__ = '1.0.0'
+__name__ = 'memtemp'
+__license__ = 'GPL3'
+__description__ = 'A plugin that will add a memory and temperature indicator'
+__enabled__ = False
+
+import struct
+
+from pwnagotchi.ui.components import LabeledValue
+from pwnagotchi.ui.view import BLACK
+import pwnagotchi.ui.fonts as fonts
+
+
+class MEMTEMP:
+ def __init__(self):
+ # only import when the module is loaded and enabled
+ import os
+
+ def get_temp(self):
+ try:
+ temp = os.popen('/opt/vc/bin/vcgencmd measure_temp').readlines()[0].split('=')[1].replace("\n", '').replace("'","")
+ return 'cpu:' + temp
+ except:
+ return 'cpu:0.0C'
+ # cpu:37.4C
+
+ def get_mem_info(self):
+ try:
+ total, used, free = map(int, os.popen('free -t -m').readlines()[-1].split()[1:])
+ return "tm:"+str(total)+" um:"+str(used)+" fm:"+str(free)
+ except:
+ return "tm:0 um:0 fm:0"
+ # tm:532 um:82 fm:353
+
+
+memtemp = None
+
+
+def on_loaded():
+ global memtemp
+ memtemp = MEMTEMP()
+
+
+def on_ui_setup(ui):
+ ui.add_element('memtemp', LabeledValue(color=BLACK, label='SYS', value='tm:0 um:0 fm:0 0.0C', position=(0, ui.height()-28),
+ label_font=fonts.Bold, text_font=fonts.Medium))
+
+
+def on_ui_update(ui):
+ ui.set('memtemp', "%s %s" % (memtemp.get_mem_info(), memtemp.get_temp()))
From cac5b6adfeb62187b87875aced361c250902aa92 Mon Sep 17 00:00:00 2001
From: Cassiano Aquino
Date: Thu, 3 Oct 2019 17:44:07 +0100
Subject: [PATCH 22/80] fix broken memusage script
---
builder/pwnagotchi.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml
index 279dcf53..515ee705 100644
--- a/builder/pwnagotchi.yml
+++ b/builder/pwnagotchi.yml
@@ -172,7 +172,7 @@
dest: /usr/bin/memusage
mode: 0755
content: |
- #!/usr/bin/env
+ #!/usr/bin/env bash
free -m | awk '/Mem/ { printf( "%d %", $3 / $2 * 100 + 0.5 ) }'
- name: create monstart script
From fcd3ae650a244750448b203ea0468751eb530673 Mon Sep 17 00:00:00 2001
From: xenDE
Date: Thu, 3 Oct 2019 18:46:46 +0200
Subject: [PATCH 23/80] =?UTF-8?q?eine=20configurierbare=20wartezeit=20hinz?=
=?UTF-8?q?ugef=C3=BCgt,=20bevor=20die=20werte=20aktualisiert=20werden?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
to protect the display lifetime
---
.../scripts/pwnagotchi/plugins/default/memtemp.py | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
index 5ebc38c4..85a4552a 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
@@ -7,7 +7,7 @@ __version__ = '1.0.0'
__name__ = 'memtemp'
__license__ = 'GPL3'
__description__ = 'A plugin that will add a memory and temperature indicator'
-__enabled__ = False
+__enabled__ = True
import struct
@@ -15,8 +15,16 @@ from pwnagotchi.ui.components import LabeledValue
from pwnagotchi.ui.view import BLACK
import pwnagotchi.ui.fonts as fonts
+import time
+
class MEMTEMP:
+
+ # set the minimum seconds before refresh the values
+ refresh_wait = 30
+
+ refresh_ts_last = time.time() - refresh_wait
+
def __init__(self):
# only import when the module is loaded and enabled
import os
@@ -52,4 +60,7 @@ def on_ui_setup(ui):
def on_ui_update(ui):
- ui.set('memtemp', "%s %s" % (memtemp.get_mem_info(), memtemp.get_temp()))
+ if time.time() > memtemp.refresh_ts_last + memtemp.refresh_wait:
+ ui.set('memtemp', "%s %s" % (memtemp.get_mem_info(), memtemp.get_temp()))
+ memtemp.refresh_ts_last = time.time()
+
From 9b5a12bd0cf5225900eb154001675c30ca1ca44e Mon Sep 17 00:00:00 2001
From: xenDE
Date: Thu, 3 Oct 2019 18:52:38 +0200
Subject: [PATCH 24/80] default: disable the plugin
---
.../pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
index 85a4552a..43c64c6b 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
@@ -7,7 +7,7 @@ __version__ = '1.0.0'
__name__ = 'memtemp'
__license__ = 'GPL3'
__description__ = 'A plugin that will add a memory and temperature indicator'
-__enabled__ = True
+__enabled__ = False
import struct
From fb1d3e919919da3e3b8702a8c0fb3047d6088007 Mon Sep 17 00:00:00 2001
From: xenDE
Date: Thu, 3 Oct 2019 19:59:35 +0200
Subject: [PATCH 25/80] show only real mem useage without swap
removed swap size from showed memory
---
.../scripts/pwnagotchi/plugins/default/memtemp.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
index 43c64c6b..33249a4a 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
@@ -7,7 +7,7 @@ __version__ = '1.0.0'
__name__ = 'memtemp'
__license__ = 'GPL3'
__description__ = 'A plugin that will add a memory and temperature indicator'
-__enabled__ = False
+__enabled__ = True
import struct
@@ -39,7 +39,10 @@ class MEMTEMP:
def get_mem_info(self):
try:
- total, used, free = map(int, os.popen('free -t -m').readlines()[-1].split()[1:])
+ # includes RAM + Swap Memory:
+# total, used, free = map(int, os.popen('free -t -m').readlines()[-1].split()[1:])
+ # without Swap, only real memory:
+ total, used, free = map(int, os.popen('free -t -m').readlines()[-3].split()[1:4])
return "tm:"+str(total)+" um:"+str(used)+" fm:"+str(free)
except:
return "tm:0 um:0 fm:0"
From ca6b71db19176bccfc0ed182c2896aab73620666 Mon Sep 17 00:00:00 2001
From: xenDE
Date: Thu, 3 Oct 2019 20:00:46 +0200
Subject: [PATCH 26/80] disable plaugin as default
"__enabled__ = False" as default
---
.../pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
index 33249a4a..2b1fc3da 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
@@ -7,7 +7,7 @@ __version__ = '1.0.0'
__name__ = 'memtemp'
__license__ = 'GPL3'
__description__ = 'A plugin that will add a memory and temperature indicator'
-__enabled__ = True
+__enabled__ = False
import struct
From 26fe8ca059254679a67123eff92ba4c033fcd1c0 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 20:18:50 +0200
Subject: [PATCH 27/80] new on_internet_available event
---
docs/about.md | 19 +++++++++
docs/configure.md | 0
docs/connect.md | 0
docs/index.md | 5 +++
docs/install.md | 0
docs/plugins.md | 0
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 39 ++++++++++---------
.../pwnagotchi/plugins/default/example.py | 5 +++
8 files changed, 50 insertions(+), 18 deletions(-)
create mode 100644 docs/about.md
create mode 100644 docs/configure.md
create mode 100644 docs/connect.md
create mode 100644 docs/index.md
create mode 100644 docs/install.md
create mode 100644 docs/plugins.md
diff --git a/docs/about.md b/docs/about.md
new file mode 100644
index 00000000..f1cb536a
--- /dev/null
+++ b/docs/about.md
@@ -0,0 +1,19 @@
+## About the Project
+
+[Pwnagotchi](https://twitter.com/pwnagotchi) is an "AI" that learns from the WiFi environment and instruments
+[bettercap](https://www.bettercap.org/) in order to maximize the WPA key material that's being captured either passively
+ or by performing deauthentication and association attakcs. This material is collected as pcap files containing any form
+ of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/),
+full and half WPA handshakes.
+
+
+
+Instead of playing [Super Mario or Atari games](https://becominghuman.ai/getting-mario-back-into-the-gym-setting-up-super-mario-bros-in-openais-gym-8e39a96c1e41?gi=c4b66c3d5ced), pwnagotchi will tune over time [its own parameters](https://github.com/evilsocket/pwnagotchi/blob/master/sdcard/rootfs/root/pwnagotchi/config.yml#L54), effectively learning to get better at pwning WiFi things. **Keep in mind:** unlike the usual RL simulations, pwnagotchi learns over time (where a single epoch can last from a few seconds to minutes, depending on how many access points and client stations are visible), do not expect it to perform amazingly well at the beginning, as it'll be exploring several combinations of parameters ... but listen to it when it's bored, bring it with you and have it observe new networks and capture new handshakes and you'll see :)
+
+Multiple units can talk to each other, advertising their own presence using a parasite protocol I've built on top of the existing dot11 standard, by broadcasting custom information elements. Over time, two or more units learn to cooperate if they detect each other's presence, by dividing the available channels among them.
+
+
+
+Depending on the status of the unit, several states and states transitions are configurable and represented on the display as different moods, expressions and sentences.
+
+If instead you just want to use your own parameters and save battery and CPU cycles, you can disable the AI in `config.yml` and enjoy an automated deauther, WPA handshake sniffer and portable bettercap + webui dedicated hardware.
diff --git a/docs/configure.md b/docs/configure.md
new file mode 100644
index 00000000..e69de29b
diff --git a/docs/connect.md b/docs/connect.md
new file mode 100644
index 00000000..e69de29b
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..4af5b898
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,5 @@
+# Documentation
+
+- [About the Project](https://github.com/evilsocket/pwnagotchi/blob/master/docs/about.md)
+- [How to Install](https://github.com/evilsocket/pwnagotchi/blob/master/docs/install.md)
+- [Configuration](https://github.com/evilsocket/pwnagotchi/blob/master/docs/configure.md)
diff --git a/docs/install.md b/docs/install.md
new file mode 100644
index 00000000..e69de29b
diff --git a/docs/plugins.md b/docs/plugins.md
new file mode 100644
index 00000000..e69de29b
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index 7caa81e2..b4730d04 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -101,30 +101,33 @@ if args.do_manual:
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
+ if Agent.is_connected():
+ plugins.on('internet_available', config, log)
- logging.info("detected a new session and internet connectivity!")
+ if config['twitter']['enabled'] and log.is_new() and log.handshakes > 0:
+ import tweepy
- picture = '/dev/shm/pwnagotchi.png'
+ logging.info("detected a new session and internet connectivity!")
- display.update(force=True)
- display.image().save(picture, 'png')
- display.set('status', 'Tweeting...')
- display.update(force=True)
+ picture = '/dev/shm/pwnagotchi.png'
- 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)
+ display.update(force=True)
+ display.image().save(picture, 'png')
+ display.set('status', 'Tweeting...')
+ display.update(force=True)
- tweet = Voice(lang=config['main']['lang']).on_log_tweet(log)
- api.update_with_media(filename=picture, status=tweet)
- log.save_session_id()
+ 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)
- logging.info("tweeted: %s" % tweet)
- except Exception as e:
- logging.exception("error while tweeting")
+ 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")
quit()
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
index e527f0fe..9c1c8c42 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
@@ -17,6 +17,11 @@ def on_loaded():
logging.warning("WARNING: plugin %s should be disabled!" % __name__)
+# called in manual mode when there's internet connectivity
+def on_internet_available(config, log):
+ pass
+
+
# called to setup the ui elements
def on_ui_setup(ui):
# add custom UI elements
From 76bccec57235054292319e1002e55f187d70a265 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Thu, 3 Oct 2019 21:09:34 +0200
Subject: [PATCH 28/80] Outsource twitter-code to plugin
---
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 25 ---------
.../pwnagotchi/plugins/default/twitter.py | 53 +++++++++++++++++++
2 files changed, 53 insertions(+), 25 deletions(-)
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index b4730d04..c401c8e1 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -104,31 +104,6 @@ if args.do_manual:
if Agent.is_connected():
plugins.on('internet_available', config, log)
- if config['twitter']['enabled'] and log.is_new() and log.handshakes > 0:
- import tweepy
-
- logging.info("detected a new session and internet connectivity!")
-
- picture = '/dev/shm/pwnagotchi.png'
-
- display.update(force=True)
- display.image().save(picture, 'png')
- display.set('status', 'Tweeting...')
- display.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")
-
quit()
agent.start_ai()
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
new file mode 100644
index 00000000..6eb61a80
--- /dev/null
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
@@ -0,0 +1,53 @@
+__author__ = '33197631+dadav@users.noreply.github.com'
+__version__ = '1.0.0'
+__name__ = 'twitter'
+__license__ = 'GPL3'
+__description__ = 'This plugin creates tweets about the recent activity of pwnagotchi'
+__enabled__ = True
+
+import logging
+from pwnagotchi.voice import Voice
+
+UI = None
+
+
+def on_loaded():
+ logging.info("Twitter plugin loaded.")
+
+
+# called in manual mode when there's internet connectivity
+def on_internet_available(config, log):
+ if config['twitter']['enabled'] and log.is_new() and log.handshakes > 0 and UI:
+ 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.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")
+
+
+def on_ui_setup(ui):
+ # need that object
+ global UI
+ UI = ui
From 62350a37ea91704df83910c3c623303b81e696bf Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Thu, 3 Oct 2019 21:18:32 +0200
Subject: [PATCH 29/80] Set manual ui view
---
.../pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
index 6eb61a80..7aa4364b 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
@@ -28,6 +28,7 @@ def on_internet_available(config, log):
picture = '/dev/shm/pwnagotchi.png'
+ UI.on_manual_mode(log)
UI.update(force=True)
UI.image().save(picture, 'png')
UI.set('status', 'Tweeting...')
From 2bba3eafc4ceee190a3f4d46c49057253d0ece84 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 21:47:34 +0200
Subject: [PATCH 30/80] working on #101
---
README.md | 230 ++---------------------
docs/about.md | 4 +
docs/configure.md | 51 +++++
docs/connect.md | 0
docs/dev.md | 52 +++++
docs/faq.md | 13 ++
docs/index.md | 14 ++
docs/install.md | 48 +++++
docs/plugins.md | 57 ++++++
docs/usage.md | 53 ++++++
sdcard/rootfs/root/pwnagotchi/config.yml | 2 +-
11 files changed, 304 insertions(+), 220 deletions(-)
delete mode 100644 docs/connect.md
create mode 100644 docs/dev.md
create mode 100644 docs/faq.md
create mode 100644 docs/usage.md
diff --git a/README.md b/README.md
index 14e415c8..9a918906 100644
--- a/README.md
+++ b/README.md
@@ -18,233 +18,25 @@ Instead of playing [Super Mario or Atari games](https://becominghuman.ai/getting
Multiple units can talk to each other, advertising their own presence using a parasite protocol I've built on top of the existing dot11 standard, by broadcasting custom information elements. Over time, two or more units learn to cooperate if they detect each other's presence, by dividing the available channels among them.
-
-
-Depending on the status of the unit, several states and states transitions are configurable and represented on the display as different moods, expressions and sentences.
-
-If instead you just want to use your own parameters and save battery and CPU cycles, you can disable the AI in `config.yml` and enjoy an automated deauther, WPA handshake sniffer and portable bettercap + webui dedicated hardware.
-
-**NOTE:** The software **requires at least bettercap v2.25**.
-
-
-
## Why
For hackers to learn reinforcement learning, WiFi networking and have an excuse to take a walk more often. And **it's cute as f---**.
## Documentation
-**THIS IS STILL ALPHA STAGE SOFTWARE, IF YOU DECIDE TO TRY TO USE IT, YOU ARE ON YOUR OWN, NO SUPPORT WILL BE PROVIDED, NEITHER FOR INSTALLATION OR FOR BUGS**
+- [About the Project](https://github.com/evilsocket/pwnagotchi/blob/master/docs/about.md)
+- [How to Install](https://github.com/evilsocket/pwnagotchi/blob/master/docs/install.md)
+- [Configuration](https://github.com/evilsocket/pwnagotchi/blob/master/docs/configure.md)
+- [Usage](https://github.com/evilsocket/pwnagotchi/blob/master/docs/usage.md)
+- [Plugins](https://github.com/evilsocket/pwnagotchi/blob/master/docs/plugins.md)
+- [Developement](https://github.com/evilsocket/pwnagotchi/blob/master/docs/dev.md)
+- [FAQ](https://github.com/evilsocket/pwnagotchi/blob/master/docs/faq.md)
-However, there's [a Slack channel](https://join.slack.com/t/pwnagotchi/shared_invite/enQtNzc4NzY3MDE2OTAzLTg5NmNmNDJiMDM3ZWFkMWUwN2Y5NDk0Y2JlZWZjODlhMmRhNDZiOGMwYjJhM2UzNzA3YjA5NjJmZGY5NGI5NmI).
+## Links
-### Hardware
-
-- Raspberry Pi Zero W
-- A decent power bank (with 1500 mAh you get ~2 hours with AI on)
-
-#### Display (optional)
-
-The display is optional if you connect to `usb0` (by using the data port on the unit) and point your browser to the web ui (see config.yml).
-
-The supported models are:
-
-- [Waveshare eInk Display (both V1 and V2)](https://www.waveshare.com/2.13inch-e-paper-hat.htm)
-- [Pimoroni Inky pHAT](https://shop.pimoroni.com/products/inky-phat)
-- [PaPiRus eInk Screen](https://uk.pi-supply.com/products/papirus-zero-epaper-screen-phat-pi-zero)
-
-The only kind of displays supported are the ones listed above, but we are always happy to receive pull requests supporting new displays.
-
-You need to configure the display type in `config.yml` where you can find `ui.display.type`. If your display does not work after changing this setting, you might need to complete remove power from the Raspberry and make a clean boot.
-
-One thing to note, not all displays are created equaly, TFT displays for example work similar to an HDMI display, and they are not supported, currently all the displays supported are I2C displays.
-
-### Color and Black & White displays
-
-Some of the supported displays support Black & White and Coloured versions, one common question is regarding refresh speed of said displays.
-
-Color displays have a much slower refresh rate, in some cases it can take up to 15 seconds, if slow refresh rates is something that you want to avoid we advise you to use Black & White displays
-
-### FPS
-
-You can configure the refresh interval of the display on config.yml, we advise to use a slow refresh to not shorten the lifetime of your display.
-
-Another option is to change fps to 0, which will only refresh when changes are made to the screen.
-
-### Software
-
-- Raspbian + [nexmon patches](https://re4son-kernel.com/re4son-pi-kernel/) for monitor mode, or any Linux with a monitor mode enabled interface (if you tune config.yml).
-
-**Do not try with Kali on the Raspberry Pi 0 W, it is compiled without hardware floating point support and TensorFlow is simply not available for it, use Raspbian.**
-
-#### Automatically create an image
-
-You can use the `scripts/create_sibling.sh` script to create an - ready to flash - rasbian image with pwnagotchi.
-
-```shell
-usage: ./scripts/create_sibling.sh [OPTIONS]
-
- Options:
- -n # Name of the pwnagotchi (default: pwnagotchi)
- -i # Provide the path of an already downloaded raspbian image
- -o # Name of the img-file (default: pwnagotchi.img)
- -s # Size which should be added to second partition (in Gigabyte) (default: 4)
- -v # Version of raspbian (Supported: latest; default: latest)
- -p # Only run provisioning (assumes the image is already mounted)
- -d # Only run dependencies checks
- -h # Show this help
-```
-
-#### Host Connection Share
-
-If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/linux_connection_share.sh` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it.
-
-#### Update your pwnagotchi
-
-You can use the `scripts/update_pwnagotchi.sh` script to update to the most recent version of pwnagotchi.
-
-```shell
-usage: ./update_pwnagitchi.sh [OPTIONS]
-
- Options:
- -v # Version to update to, can be a branch or commit. (default: master)
- -u # Url to clone from. (default: https://github.com/evilsocket/pwnagotchi)
- -m # Mode to restart to. (Supported: auto manual; default: auto)
- -b # Backup the current pwnagotchi config.
- -r # Restore the current pwnagotchi config. -b will be enabled.
- -h # Shows this help. Shows this help.
-
-```
-
-#### Backup your pwnagotchi
-
-You can use the `scripts/backup.sh` script to backup the important files of your unit.
-
-```shell
-usage: ./scripts/backup.sh HOSTNAME backup.zip
-```
-
-### UI
-
-The UI is available either via display if installed, or via http://pwnagotchi.local:8080/ if you connect to the unit via `usb0` and set a static address on the network interface (change `pwnagotchi` with the hostname of your unit).
-
-
-
-* **CH**: Current channel the unit is operating on or `*` when hopping on all channels.
-* **APS**: Number of access points on the current channel and total visible access points.
-* **UP**: Time since the unit has been activated.
-* **PWND**: Number of handshakes captured in this session and number of unique networks we own at least one handshake of, from the beginning.
-* **AUTO**: This indicates that the algorithm is running with AI disabled (or still loading), it disappears once the AI dependencies have been bootrapped and the neural network loaded.
-
-#### Languages
-
-Pwnagotchi is able to speak multiple languages!! Currently supported are:
-
-* **english** (default)
-* german
-* dutch
-* greek
-* macedonian
-* italian
-* french
-
-If you want to add a language use the `language.sh` script. If you want to add for example the language **italian** you would type:
-
-```shell
-./scripts/language.sh add it
-# Now make your changes to the file
-# sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
-./scripts/language.sh compile it
-# DONE
-```
-
-If you changed the `voice.py`- File, the translations need an update. Do it like this:
-
-```shell
-./scripts/language.sh update it
-# Now make your changes to the file (changed lines are marked with "fuzzy")
-# sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
-./scripts/language.sh compile it
-# DONE
-```
-
-Now you can use the `preview.py`-script to preview the changes:
-
-```shell
-./scripts/preview.py --lang it --display ws2 --port 8080 &
-./scripts/preview.py --lang it --display inky --port 8081 &
-# Now open http://localhost:8080 and http://localhost:8081
-```
-
-### Plugins
-
-Pwnagotchi has a simple plugins system that you can use to customize your unit and its behaviour. You can place your plugins anywhere
-as python files and then edit the `config.yml` file (`main.plugins` value) to point to their containing folder. Check the [plugins folder](https://github.com/evilsocket/pwnagotchi/tree/master/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/) for a list of default
-plugins and all the callbacks that you can define for your own customizations.
-
-Here's as an example the GPS plugin:
-
-```python
-__author__ = 'evilsocket@gmail.com'
-__version__ = '1.0.0'
-__name__ = 'gps'
-__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 json
-import os
-
-device = '/dev/ttyUSB0'
-speed = 19200
-running = False
-
-
-def on_loaded():
- logging.info("GPS plugin loaded for %s" % device)
-
-
-def on_ready(agent):
- global running
-
- if os.path.exists(device):
- logging.info("enabling GPS bettercap's module for %s" % device)
- try:
- agent.run('gps off')
- except:
- pass
-
- agent.run('set gps.device %s' % device)
- agent.run('set gps.speed %d' % speed)
- agent.run('gps on')
- running = True
- else:
- logging.info("no GPS detected")
-
-
-def on_handshake(agent, filename, access_point, client_station):
- if running:
- info = agent.session()
- gps = info['gps']
- gps_filename = filename.replace('.pcap', '.gps.json')
-
- logging.info("saving GPS to %s (%s)" % (gps_filename, gps))
- with open(gps_filename, 'w+t') as fp:
- json.dump(gps, fp)
-```
-
-### Random Info
-
-- `hostname` sets the unit name.
-- At first boot, each unit generates a unique RSA keypair that can be used to authenticate advertising packets.
-- **On a rpi0w, it'll take approximately 30 minutes to load the AI**.
-- `/var/log/pwnagotchi.log` is your friend.
-- if connected to a laptop via usb data port, with internet connectivity shared, magic things will happen.
-- checkout the `ui.video` section of the `config.yml` - if you don't want to use a display, you can connect to it with the browser and a cable.
-- If you get `[FAILED] Failed to start Remount Root and Kernel File Systems.` while booting pwnagotchi, make sure
-the `PARTUUID`s for `rootfs` and `boot` partitions are the same in `/etc/fstab`. Use `sudo blkid` to find those values when you are using `create_sibling.sh`.
-- You can create a `/root/custom.yml` configuration file to override the defaults.
+- [Project Slack](https://join.slack.com/t/pwnagotchi/shared_invite/enQtNzc4NzY3MDE2OTAzLTg5NmNmNDJiMDM3ZWFkMWUwN2Y5NDk0Y2JlZWZjODlhMmRhNDZiOGMwYjJhM2UzNzA3YjA5NjJmZGY5NGI5NmI)
+- [Project Twitter](https://twitter.com/pwnagotchi)
+- [Project Website](https://pwnagotchi.ai/)
## License
diff --git a/docs/about.md b/docs/about.md
index f1cb536a..8f141adf 100644
--- a/docs/about.md
+++ b/docs/about.md
@@ -17,3 +17,7 @@ Multiple units can talk to each other, advertising their own presence using a pa
Depending on the status of the unit, several states and states transitions are configurable and represented on the display as different moods, expressions and sentences.
If instead you just want to use your own parameters and save battery and CPU cycles, you can disable the AI in `config.yml` and enjoy an automated deauther, WPA handshake sniffer and portable bettercap + webui dedicated hardware.
+
+## License
+
+`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
\ No newline at end of file
diff --git a/docs/configure.md b/docs/configure.md
index e69de29b..98cd01ca 100644
--- a/docs/configure.md
+++ b/docs/configure.md
@@ -0,0 +1,51 @@
+### Connecting to your Pwnagotchi
+
+Once you wrote the image file on the SD card, there're a few steps you'll have to follow in order to configure your unit properly, first, start with connecting the USB cable to the
+data port of the Raspberry Pi and the RPi to your computer. After a few seconds the board will boot and you will see a new Ethernet interface on your host computer.
+
+You'll need to configure it with a static IP address:
+
+- IP: `10.0.0.2`
+- Netmask: `255.255.255.0`
+- Gateway: `10.0.0.1`
+- DNS (if required): `8.8.8.8` (or whatever)
+
+If everything's been configured properly, you will now be able to `ping` both `10.0.0.2` or `pwnagotchi.local` (if you haven't customized the hostname yet).
+
+You can now connect to your unit using SSH:
+
+```bash
+ssh pi@10.0.0.2
+```
+
+The default password is `raspberry`, you should change it as soon as you log in for the first time by issuing the `passwd`command and selecting a new and more complex passphrase.
+
+Moreover, it is recommended that you copy your SSH public key among the unit's authorized ones, so you can directly log in without entering a password:
+
+```bash
+ssh-copy-id -i ~/.ssh/id_rsa.pub pi@10.0.0.2
+```
+
+### Configuration
+
+You can now set a new name for your unit by [changing the hostname](https://geek-university.com/raspberry-pi/change-raspberry-pis-hostname/). Create the `/root/custom.yml` file (either via SSH or by direclty editing the SD card contents from a computer) that will override
+the [default configuration](https://github.com/evilsocket/pwnagotchi/blob/master/sdcard/rootfs/root/pwnagotchi/config.yml) with your custom values.
+
+For instance, you can change `main.lang` to one of the supported languages:
+
+* **english** (default)
+* german
+* dutch
+* greek
+* macedonian
+* italian
+* french
+
+The set the type of display you want to use via `ui.display.type` (if your display does not work after changing this setting, you might need to complete remove power from the Raspberry and make a clean boot).
+
+You can configure the refresh interval of the display via `ui.fps`, we advise to use a slow refresh to not shorten the lifetime of your display. The default value is 0, which will only refresh when changes are made to the screen.
+
+### Host Connection Share
+
+If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/linux_connection_share.sh` or
+ `scripts/macos_connection_share.sh` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it.
\ No newline at end of file
diff --git a/docs/connect.md b/docs/connect.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/docs/dev.md b/docs/dev.md
new file mode 100644
index 00000000..5a4df640
--- /dev/null
+++ b/docs/dev.md
@@ -0,0 +1,52 @@
+## Software
+
+- Raspbian + [nexmon patches](https://re4son-kernel.com/re4son-pi-kernel/) for monitor mode, or any Linux with a monitor mode enabled interface (if you tune config.yml).
+
+**Do not try with Kali on the Raspberry Pi 0 W, it is compiled without hardware floating point support and TensorFlow is simply not available for it, use Raspbian.**
+
+## Creating an Image
+
+You can use the `scripts/create_sibling.sh` script to create an - ready to flash - rasbian image with pwnagotchi.
+
+```shell
+usage: ./scripts/create_sibling.sh [OPTIONS]
+
+ Options:
+ -n # Name of the pwnagotchi (default: pwnagotchi)
+ -i # Provide the path of an already downloaded raspbian image
+ -o # Name of the img-file (default: pwnagotchi.img)
+ -s # Size which should be added to second partition (in Gigabyte) (default: 4)
+ -v # Version of raspbian (Supported: latest; default: latest)
+ -p # Only run provisioning (assumes the image is already mounted)
+ -d # Only run dependencies checks
+ -h # Show this help
+```
+## Adding a Language
+
+If you want to add a language use the `language.sh` script. If you want to add for example the language **italian** you would type:
+
+```shell
+./scripts/language.sh add it
+# Now make your changes to the file
+# sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
+./scripts/language.sh compile it
+# DONE
+```
+
+If you changed the `voice.py`- File, the translations need an update. Do it like this:
+
+```shell
+./scripts/language.sh update it
+# Now make your changes to the file (changed lines are marked with "fuzzy")
+# sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.po
+./scripts/language.sh compile it
+# DONE
+```
+
+Now you can use the `preview.py`-script to preview the changes:
+
+```shell
+./scripts/preview.py --lang it --display ws2 --port 8080 &
+./scripts/preview.py --lang it --display inky --port 8081 &
+# Now open http://localhost:8080 and http://localhost:8081
+```
diff --git a/docs/faq.md b/docs/faq.md
new file mode 100644
index 00000000..ed4a1f37
--- /dev/null
+++ b/docs/faq.md
@@ -0,0 +1,13 @@
+# FAQ
+
+## Why eINK?
+
+Because!
+
+## Why the AI takes 30 minutes to load?
+
+Because Python sucks and TF is huge.
+
+## Why ...?
+
+Because!
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index 4af5b898..3c23b8c5 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -3,3 +3,17 @@
- [About the Project](https://github.com/evilsocket/pwnagotchi/blob/master/docs/about.md)
- [How to Install](https://github.com/evilsocket/pwnagotchi/blob/master/docs/install.md)
- [Configuration](https://github.com/evilsocket/pwnagotchi/blob/master/docs/configure.md)
+- [Usage](https://github.com/evilsocket/pwnagotchi/blob/master/docs/usage.md)
+- [Plugins](https://github.com/evilsocket/pwnagotchi/blob/master/docs/plugins.md)
+- [Developement](https://github.com/evilsocket/pwnagotchi/blob/master/docs/dev.md)
+- [FAQ](https://github.com/evilsocket/pwnagotchi/blob/master/docs/faq.md)
+
+## Links
+
+- [Project Slack](https://join.slack.com/t/pwnagotchi/shared_invite/enQtNzc4NzY3MDE2OTAzLTg5NmNmNDJiMDM3ZWFkMWUwN2Y5NDk0Y2JlZWZjODlhMmRhNDZiOGMwYjJhM2UzNzA3YjA5NjJmZGY5NGI5NmI)
+- [Project Twitter](https://twitter.com/pwnagotchi)
+- [Project Website](https://pwnagotchi.ai/)
+
+## License
+
+`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
\ No newline at end of file
diff --git a/docs/install.md b/docs/install.md
index e69de29b..4081e955 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -0,0 +1,48 @@
+# Installation
+
+The project has been developed to run on a Raspberry Pi 0 W configured as an [USB Ethernet gadget](https://learn.adafruit.com/turning-your-raspberry-pi-zero-into-a-usb-gadget/ethernet-gadget) device in order to connect to it via USB.
+However, given the proper configuration tweaks, any GNU/Linux computer with a WiFi interface that supports monitor mode could be used.
+
+## Required Hardware
+
+- [Raspberry Pi Zero W](https://www.raspberrypi.org/products/raspberry-pi-zero-w/).
+- A micro SD card, 8GB recomended, **preferably of good quality and speed**.
+- A decent power bank (with 1500 mAh you get ~2 hours with AI on).
+- One of the supported displays (optional).
+
+### Display
+
+The display is an optional component as the UI is also rendered via a web interface available via the USB cable. If you connect to `usb0` (by using the data port on the unit) and point your browser to the web ui (see config.yml), your unit can work in "headless mode".
+
+If instead you want to fully enjoy walking around and literally looking at your unit's face, the supported display models are:
+
+- [Waveshare eInk Display (both V1 and V2)](https://www.waveshare.com/2.13inch-e-paper-hat.htm)
+- [Pimoroni Inky pHAT](https://shop.pimoroni.com/products/inky-phat)
+- [PaPiRus eInk Screen](https://uk.pi-supply.com/products/papirus-zero-epaper-screen-phat-pi-zero)
+
+Needless to say, we are always happy to receive pull requests adding support for new models.
+
+One thing to note, not all displays are created equaly, TFT displays for example work similar to an HDMI display, and they are not supported, currently all the displays supported are I2C displays.
+
+#### Color and Black & White displays
+
+Some of the supported displays support Black & White and Coloured versions, one common question is regarding refresh speed of said displays.
+
+Color displays have a much slower refresh rate, in some cases it can take up to 15 seconds, if slow refresh rates is something that you want to avoid we advise you to use Black & White displays
+
+## Flashing an Image
+
+The easiest way to create a new Pwnagotchi is downloading the latest stable image from [our release page](https://github.com/evilsocket/pwnagotchi/releases) and write it to your SD card. You will need to use an image writing tool to install the image you have downloaded on your SD card.
+
+[balenaEtcher](https://www.balena.io/etcher/) is a graphical SD card writing tool that works on Mac OS, Linux and Windows,
+and is the easiest option for most users. balenaEtcher also supports writing images directly from the zip file,
+without any unzipping required. To write your image with balenaEtcher:
+
+- Download the latest [Pwnagotchi .img file](https://github.com/evilsocket/pwnagotchi/releases).
+- Download [balenaEtcher](https://www.balena.io/etcher/) and install it.
+- Connect an SD card reader with the SD card inside.
+- Open balenaEtcher and select from your hard drive the Raspberry Pi .img or .zip file you wish to write to the SD card.
+- Select the SD card you wish to write your image to.
+- Review your selections and click 'Flash!' to begin writing data to the SD card.
+
+Your SD card is now ready for the first boot!
\ No newline at end of file
diff --git a/docs/plugins.md b/docs/plugins.md
index e69de29b..512c872a 100644
--- a/docs/plugins.md
+++ b/docs/plugins.md
@@ -0,0 +1,57 @@
+# Plugins
+
+Pwnagotchi has a simple plugins system that you can use to customize your unit and its behaviour. You can place your plugins anywhere
+as python files and then edit the `config.yml` file (`main.plugins` value) to point to their containing folder. Check the [plugins folder](https://github.com/evilsocket/pwnagotchi/tree/master/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/) for a list of default
+plugins and all the callbacks that you can define for your own customizations.
+
+Here's as an example the GPS plugin:
+
+```python
+__author__ = 'evilsocket@gmail.com'
+__version__ = '1.0.0'
+__name__ = 'gps'
+__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 json
+import os
+
+device = '/dev/ttyUSB0'
+speed = 19200
+running = False
+
+
+def on_loaded():
+ logging.info("GPS plugin loaded for %s" % device)
+
+
+def on_ready(agent):
+ global running
+
+ if os.path.exists(device):
+ logging.info("enabling GPS bettercap's module for %s" % device)
+ try:
+ agent.run('gps off')
+ except:
+ pass
+
+ agent.run('set gps.device %s' % device)
+ agent.run('set gps.speed %d' % speed)
+ agent.run('gps on')
+ running = True
+ else:
+ logging.info("no GPS detected")
+
+
+def on_handshake(agent, filename, access_point, client_station):
+ if running:
+ info = agent.session()
+ gps = info['gps']
+ gps_filename = filename.replace('.pcap', '.gps.json')
+
+ logging.info("saving GPS to %s (%s)" % (gps_filename, gps))
+ with open(gps_filename, 'w+t') as fp:
+ json.dump(gps, fp)
+```
diff --git a/docs/usage.md b/docs/usage.md
new file mode 100644
index 00000000..7d6c5d84
--- /dev/null
+++ b/docs/usage.md
@@ -0,0 +1,53 @@
+### UI
+
+The UI is available either via display if installed, or via http://pwnagotchi.local:8080/ if you connect to the unit via `usb0` and set a static address on the network interface (change `pwnagotchi` with the hostname of your unit).
+
+
+
+* **CH**: Current channel the unit is operating on or `*` when hopping on all channels.
+* **APS**: Number of access points on the current channel and total visible access points.
+* **UP**: Time since the unit has been activated.
+* **PWND**: Number of handshakes captured in this session and number of unique networks we own at least one handshake of, from the beginning.
+* **AUTO**: This indicates that the algorithm is running with AI disabled (or still loading), it disappears once the AI dependencies have been bootrapped and the neural network loaded.
+
+### BetterCAP's Web UI
+
+Moreover, given that the unit is running bettercap with API and Web UI, you'll be able to use the unit as a WiFi penetration testing portable station
+by accessing `http://pwnagotchi.local/`.
+
+
+
+### Update your Pwnagotchi
+
+You can use the `scripts/update_pwnagotchi.sh` script to update to the most recent version of pwnagotchi.
+
+```shell
+usage: ./update_pwnagitchi.sh [OPTIONS]
+
+ Options:
+ -v # Version to update to, can be a branch or commit. (default: master)
+ -u # Url to clone from. (default: https://github.com/evilsocket/pwnagotchi)
+ -m # Mode to restart to. (Supported: auto manual; default: auto)
+ -b # Backup the current pwnagotchi config.
+ -r # Restore the current pwnagotchi config. -b will be enabled.
+ -h # Shows this help. Shows this help.
+
+```
+
+### Backup your Pwnagotchi
+
+You can use the `scripts/backup.sh` script to backup the important files of your unit.
+
+```shell
+usage: ./scripts/backup.sh HOSTNAME backup.zip
+```
+
+### Random Info
+
+- **On a rpi0w, it'll take approximately 30 minutes to load the AI**.
+- `/var/log/pwnagotchi.log` is your friend.
+- if connected to a laptop via usb data port, with internet connectivity shared, magic things will happen.
+- checkout the `ui.video` section of the `config.yml` - if you don't want to use a display, you can connect to it with the browser and a cable.
+- If you get `[FAILED] Failed to start Remount Root and Kernel File Systems.` while booting pwnagotchi, make sure
+the `PARTUUID`s for `rootfs` and `boot` partitions are the same in `/etc/fstab`. Use `sudo blkid` to find those values when you are using `create_sibling.sh`.
+
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index b71ddde8..28f27705 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -23,7 +23,7 @@ main:
ai:
# if false, only the default 'personality' will be used
- enabled: false
+ enabled: true
path: /root/brain.nn
# 1.0 - laziness = probability of start training
laziness: 0.1
From 6f0ec08c47150dca5986ba24292abcd4eafce685 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 22:31:27 +0200
Subject: [PATCH 31/80] documented the reward function (closes #50)
---
docs/usage.md | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 98 insertions(+), 1 deletion(-)
diff --git a/docs/usage.md b/docs/usage.md
index 7d6c5d84..e9777bc5 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -1,4 +1,101 @@
-### UI
+### Usage
+
+At its core Pwnagotchi is a very simple creature: we could summarize its main algorithm as:
+
+```python
+# main loop
+while True:
+ # ask bettercap for all visible access points and their clients
+ aps = get_all_visible_access_points()
+ # loop each AP
+ for ap in aps:
+ # send an association frame in order to grab the PMKID
+ send_assoc(ap)
+ # loop each client station of the AP
+ for client in ap.clients:
+ # deauthenticate the client to get its half or full handshake
+ deauthenticate(client)
+
+ wait_for_loot()
+```
+
+Despite its simplicity, this logic is controlled by several parameters that regulate the wait times, the timeouts, on which channels to hop and so on.
+
+From `config.yml`:
+
+```yaml
+personality:
+ # advertise our presence
+ advertise: true
+ # perform a deauthentication attack to client stations in order to get full or half handshakes
+ deauth: true
+ # send association frames to APs in order to get the PMKID
+ associate: true
+ # list of channels to recon on, or empty for all channels
+ channels: []
+ # minimum WiFi signal strength in dBm
+ min_rssi: -200
+ # number of seconds for wifi.ap.ttl
+ ap_ttl: 120
+ # number of seconds for wifi.sta.ttl
+ sta_ttl: 300
+ # time in seconds to wait during channel recon
+ recon_time: 30
+ # number of inactive epochs after which recon_time gets multiplied by recon_inactive_multiplier
+ max_inactive_scale: 2
+ # if more than max_inactive_scale epochs are inactive, recon_time *= recon_inactive_multiplier
+ recon_inactive_multiplier: 2
+ # time in seconds to wait during channel hopping if activity has been performed
+ hop_recon_time: 10
+ # time in seconds to wait during channel hopping if no activity has been performed
+ min_recon_time: 5
+ # maximum amount of deauths/associations per BSSID per session
+ max_interactions: 3
+ # maximum amount of misses before considering the data stale and triggering a new recon
+ max_misses_for_recon: 5
+ # number of active epochs that triggers the excited state
+ excited_num_epochs: 10
+ # number of inactive epochs that triggers the bored state
+ bored_num_epochs: 15
+ # number of inactive epochs that triggers the sad state
+ sad_num_epochs: 25
+```
+
+There is no optimal set of parameters for every situation: when the unit is moving (during a walk for instance) smaller timeouts and RSSI thresholds might be preferred
+in order to quickly remove routers that are not in range anymore, while when stationary in high density areas (like an office) other parameters might be better.
+The role of the AI is to observe what's going on at the WiFi level, and adjust those parameters in order to maximize the cumulative reward of that loop / epoch.
+
+#### Reward Function
+
+After each iteration of the main loop (an `epoch`), the reward, a score that represents how well the parameters performed, is computed as
+(an excerpt from `pwnagotchi/ai/reward.py`):
+
+```python
+# state contains the information of the last epoch
+# epoch_n is the number of the last epoch
+tot_epochs = epoch_n + 1e-20 # 1e-20 is added to avoid a division by 0
+tot_interactions = max(state['num_deauths'] + state['num_associations'], state['num_handshakes']) + 1e-20
+tot_channels = wifi.NumChannels
+
+# ideally, for each interaction we would have an handshake
+h = state['num_handshakes'] / tot_interactions
+# small positive rewards the more active epochs we have
+a = .2 * (state['active_for_epochs'] / tot_epochs)
+# make sure we keep hopping on the widest channel spectrum
+c = .1 * (state['num_hops'] / tot_channels)
+# small negative reward if we don't see aps for a while
+b = -.3 * (state['blind_for_epochs'] / tot_epochs)
+# small negative reward if we interact with things that are not in range anymore
+m = -.3 * (state['missed_interactions'] / tot_interactions)
+# small negative reward for inactive epochs
+i = -.2 * (state['inactive_for_epochs'] / tot_epochs)
+
+reward = h + a + c + b + i + m
+```
+
+By maximizing this reward value, the AI learns over time to find the set of parameters that better perform with the current environmental conditions.
+
+### User Interface
The UI is available either via display if installed, or via http://pwnagotchi.local:8080/ if you connect to the unit via `usb0` and set a static address on the network interface (change `pwnagotchi` with the hostname of your unit).
From 780664b1c0222c54d0592163deb52de758a168cc Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 22:37:55 +0200
Subject: [PATCH 32/80] fix
---
docs/usage.md | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/docs/usage.md b/docs/usage.md
index e9777bc5..e23dc686 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -1,4 +1,16 @@
-### Usage
+### User Interface
+
+The UI is available either via display if installed, or via http://pwnagotchi.local:8080/ if you connect to the unit via `usb0` and set a static address on the network interface (change `pwnagotchi` with the hostname of your unit).
+
+
+
+* **CH**: Current channel the unit is operating on or `*` when hopping on all channels.
+* **APS**: Number of access points on the current channel and total visible access points.
+* **UP**: Time since the unit has been activated.
+* **PWND**: Number of handshakes captured in this session and number of unique networks we own at least one handshake of, from the beginning.
+* **AUTO**: This indicates that the algorithm is running with AI disabled (or still loading), it disappears once the AI dependencies have been bootrapped and the neural network loaded.
+
+### Training the AI
At its core Pwnagotchi is a very simple creature: we could summarize its main algorithm as:
@@ -95,17 +107,6 @@ reward = h + a + c + b + i + m
By maximizing this reward value, the AI learns over time to find the set of parameters that better perform with the current environmental conditions.
-### User Interface
-
-The UI is available either via display if installed, or via http://pwnagotchi.local:8080/ if you connect to the unit via `usb0` and set a static address on the network interface (change `pwnagotchi` with the hostname of your unit).
-
-
-
-* **CH**: Current channel the unit is operating on or `*` when hopping on all channels.
-* **APS**: Number of access points on the current channel and total visible access points.
-* **UP**: Time since the unit has been activated.
-* **PWND**: Number of handshakes captured in this session and number of unique networks we own at least one handshake of, from the beginning.
-* **AUTO**: This indicates that the algorithm is running with AI disabled (or still loading), it disappears once the AI dependencies have been bootrapped and the neural network loaded.
### BetterCAP's Web UI
From 56b1d21bb04d62a165b55a21371cc7217e89c3d0 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 22:59:57 +0200
Subject: [PATCH 33/80] refactored main.py
---
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 142 +++++++-----------
.../pwnagotchi/plugins/default/example.py | 2 +-
.../scripts/pwnagotchi/plugins/default/gps.py | 4 +-
.../pwnagotchi/plugins/default/twitter.py | 24 +--
.../scripts/pwnagotchi/ui/display.py | 27 +++-
5 files changed, 87 insertions(+), 112 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index c401c8e1..cba98d5e 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -12,7 +12,6 @@ import pwnagotchi.version as version
import pwnagotchi.plugins as plugins
from pwnagotchi.log import SessionParser
-from pwnagotchi.voice import Voice
from pwnagotchi.agent import Agent
from pwnagotchi.ui.display import Display
@@ -34,41 +33,6 @@ args = parser.parse_args()
config = utils.load_config(args)
utils.setup_logging(args, config)
-if args.do_clear:
- print("clearing the display ...")
- cleardisplay = config['ui']['display']['type']
- if cleardisplay in ('inkyphat', 'inky'):
- print("inky display")
- from inky import InkyPHAT
-
- epd = InkyPHAT(config['ui']['display']['color'])
- epd.set_border(InkyPHAT.BLACK)
- self._render_cb = self._inky_render
- elif cleardisplay in ('papirus', 'papi'):
- print("papirus display")
- from pwnagotchi.ui.papirus.epd import EPD
-
- os.environ['EPD_SIZE'] = '2.0'
- epd = EPD()
- epd.clear()
- elif cleardisplay in ('waveshare_1', 'ws_1', 'waveshare1', 'ws1'):
- print("waveshare v1 display")
- from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
-
- epd = EPD()
- epd.init(epd.lut_full_update)
- epd.Clear(0xFF)
- elif cleardisplay in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2'):
- print("waveshare v2 display")
- from pwnagotchi.ui.waveshare.v2.waveshare import EPD
-
- epd = EPD()
- epd.init(epd.FULL_UPDATE)
- epd.Clear(0xff)
- else:
- print("unknown display type %s" % cleardisplay)
- quit()
-
plugins.load_from_path(plugins.default_path)
if 'plugins' in config['main'] and config['main']['plugins'] is not None:
plugins.load_from_path(config['main']['plugins'])
@@ -79,74 +43,78 @@ display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
agent = Agent(view=display, config=config)
logging.info("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, version.version))
-# for key, value in config['personality'].items():
-# logging.info(" %s: %s" % (key, value))
for _, plugin in plugins.loaded.items():
- logging.info("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
+ logging.debug("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
-if args.do_manual:
+if args.do_clear:
+ logging.info("clearing the display ...")
+ display.clear()
+
+elif args.do_manual:
logging.info("entering manual mode ...")
log = SessionParser(config['main']['log'])
- 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,
- log.avg_reward,
- log.min_reward,
- log.max_reward))
+ 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,
+ log.avg_reward,
+ log.min_reward,
+ log.max_reward))
while True:
display.on_manual_mode(log)
time.sleep(1)
if Agent.is_connected():
- plugins.on('internet_available', config, log)
+ plugins.on('internet_available', display, config, log)
- quit()
+else:
+ logging.info("entering auto mode ...")
-agent.start_ai()
-agent.setup_events()
-agent.set_starting()
-agent.start_monitor_mode()
-agent.start_event_polling()
+ agent.start_ai()
+ agent.setup_events()
+ agent.set_starting()
+ agent.start_monitor_mode()
+ agent.start_event_polling()
-# print initial stats
-agent.next_epoch()
+ # print initial stats
+ agent.next_epoch()
-agent.set_ready()
+ agent.set_ready()
-while True:
- try:
- # recon on all channels
- agent.recon()
- # get nearby access points grouped by channel
- channels = agent.get_access_points_by_channel()
- # check for free channels to use
- agent.check_channels(channels)
- # for each channel
- for ch, aps in channels:
- agent.set_channel(ch)
+ while True:
+ try:
+ # recon on all channels
+ agent.recon()
+ # get nearby access points grouped by channel
+ channels = agent.get_access_points_by_channel()
+ # check for free channels to use
+ agent.check_channels(channels)
+ # for each channel
+ for ch, aps in channels:
+ agent.set_channel(ch)
- if not agent.is_stale() and agent.any_activity():
- logging.info("%d access points on channel %d" % (len(aps), ch))
+ if not agent.is_stale() and agent.any_activity():
+ logging.info("%d access points on channel %d" % (len(aps), ch))
- # for each ap on this channel
- for ap in aps:
- # send an association frame in order to get for a PMKID
- agent.associate(ap)
- # deauth all client stations in order to get a full handshake
- for sta in ap['clients']:
- agent.deauth(ap, sta)
+ # for each ap on this channel
+ for ap in aps:
+ # send an association frame in order to get for a PMKID
+ agent.associate(ap)
+ # deauth all client stations in order to get a full handshake
+ for sta in ap['clients']:
+ agent.deauth(ap, sta)
- # An interesting effect of this:
- #
- # From Pwnagotchi's perspective, the more new access points
- # and / or client stations nearby, the longer one epoch of
- # its relative time will take ... basically, in Pwnagotchi's universe,
- # WiFi electromagnetic fields affect time like gravitational fields
- # affect ours ... neat ^_^
- agent.next_epoch()
- except Exception as e:
- logging.exception("main loop exception")
+ # An interesting effect of this:
+ #
+ # From Pwnagotchi's perspective, the more new access points
+ # and / or client stations nearby, the longer one epoch of
+ # its relative time will take ... basically, in Pwnagotchi's universe,
+ # WiFi electromagnetic fields affect time like gravitational fields
+ # affect ours ... neat ^_^
+ agent.next_epoch()
+ except Exception as e:
+ logging.exception("main loop exception")
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
index 9c1c8c42..4166e4ad 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
@@ -18,7 +18,7 @@ def on_loaded():
# called in manual mode when there's internet connectivity
-def on_internet_available(config, log):
+def on_internet_available(ui, config, log):
pass
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
index 7c57b24c..cd292eae 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
@@ -15,14 +15,14 @@ running = False
def on_loaded():
- logging.info("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):
- logging.info("enabling GPS bettercap's module for %s" % device)
+ logging.info("enabling gps bettercap's module for %s" % device)
try:
agent.run('gps off')
except:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
index 7aa4364b..0c7d8d98 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
@@ -8,16 +8,14 @@ __enabled__ = True
import logging
from pwnagotchi.voice import Voice
-UI = None
-
def on_loaded():
- logging.info("Twitter plugin loaded.")
+ logging.info("twitter plugin loaded.")
# called in manual mode when there's internet connectivity
-def on_internet_available(config, log):
- if config['twitter']['enabled'] and log.is_new() and log.handshakes > 0 and UI:
+def on_internet_available(ui, config, log):
+ if config['twitter']['enabled'] and log.is_new() and log.handshakes > 0:
try:
import tweepy
except ImportError:
@@ -28,11 +26,11 @@ def on_internet_available(config, log):
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)
+ 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'])
@@ -46,9 +44,3 @@ def on_internet_available(config, log):
logging.info("tweeted: %s" % tweet)
except Exception as e:
logging.exception("error while tweeting")
-
-
-def on_ui_setup(ui):
- # need that object
- global UI
- UI = ui
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
index c8b301a6..ed6b188f 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
@@ -102,12 +102,15 @@ class Display(View):
def _is_papirus(self):
return self._display_type in ('papirus', 'papi')
- def _is_waveshare1(self):
+ def _is_waveshare_v1(self):
return self._display_type in ('waveshare_1', 'ws_1', 'waveshare1', 'ws1')
- def _is_waveshare2(self):
+ def _is_waveshare_v2(self):
return self._display_type in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2')
+ def _is_waveshare(self):
+ return self._is_waveshare_v1() or self._is_waveshare_v2()
+
def _init_display(self):
if self._is_inky():
logging.info("initializing inky display")
@@ -124,7 +127,7 @@ class Display(View):
self._display.clear()
self._render_cb = self._papirus_render
- elif self._is_waveshare1():
+ elif self._is_waveshare_v1():
logging.info("initializing waveshare v1 display")
from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
self._display = EPD()
@@ -133,7 +136,7 @@ class Display(View):
self._display.init(self._display.lut_partial_update)
self._render_cb = self._waveshare_render
- elif self._is_waveshare2():
+ elif self._is_waveshare_v2():
logging.info("initializing waveshare v2 display")
from pwnagotchi.ui.waveshare.v2.waveshare import EPD
self._display = EPD()
@@ -149,6 +152,18 @@ class Display(View):
self.on_render(self._on_view_rendered)
+ def clear(self):
+ if self._display is None:
+ logging.error("no display object created")
+ elif self._is_inky():
+ self._display.Clear()
+ elif self._is_papirus():
+ self._display.clear()
+ elif self._is_waveshare():
+ self._display.Clear(WHITE)
+ else:
+ logging.critical("unknown display type %s" % self._display_type)
+
def _inky_render(self):
if self._display_color != 'mono':
display_colors = 3
@@ -183,9 +198,9 @@ class Display(View):
def _waveshare_render(self):
buf = self._display.getbuffer(self._canvas)
- if self._is_waveshare1():
+ if self._is_waveshare_v1():
self._display.display(buf)
- elif self._is_waveshare2():
+ elif self._is_waveshare_v2():
self._display.displayPartial(buf)
def image(self):
From 92a63c38636b3eeca578c65d05c0652fe89ae8d8 Mon Sep 17 00:00:00 2001
From: Forrest Fuqua
Date: Thu, 3 Oct 2019 17:05:07 -0400
Subject: [PATCH 34/80] Update File to randomize gender in build scripts
---
scripts/create_sibling.sh | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/scripts/create_sibling.sh b/scripts/create_sibling.sh
index 55b784f4..f2f5c5fd 100755
--- a/scripts/create_sibling.sh
+++ b/scripts/create_sibling.sh
@@ -335,7 +335,13 @@ fi
setup_raspbian
provision_raspbian
-echo -e "[+] Congratz, it's a boy (⌐■_■)!"
+#Make a baby with a random gender, maybe do something fun with this later!
+gender[0]="boy"
+gender[1]="girl"
+
+rand=$[ $RANDOM % 2 ]
+
+echo -e "[+] Congratz, it's a ${arr[$rand]} (⌐■_■)!"
echo -e "[+] One more step: dd if=../${PWNI_OUTPUT} of= bs=4M status=progress"
if [ "${OPT_SPARSE}" -eq 1 ];
From de2a13c1e1c2803155cc2d3b2ed88fe5df0909c6 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Thu, 3 Oct 2019 22:51:26 +0200
Subject: [PATCH 35/80] Add wpa-sec-upload plugin
---
.../pwnagotchi/plugins/default/wpa-sec.py | 76 +++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
new file mode 100644
index 00000000..48ea525c
--- /dev/null
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
@@ -0,0 +1,76 @@
+__author__ = '33197631+dadav@users.noreply.github.com'
+__version__ = '1.0.0'
+__name__ = 'wpa_sec'
+__license__ = 'GPL3'
+__description__ = 'This plugin automatically uploades handshakes to https://wpa-sec.stanev.org'
+__enabled__ = False
+
+import os
+import logging
+import subprocess
+
+READY = False
+API_KEY = None
+ALREADY_UPLOADED = None
+
+# INSTALLATION:
+## apt-get install libcurl4-openssl-dev
+## https://github.com/ZerBea/hcxtools.git
+## cd hcxtools; gcc wlancap2wpasec.c -o wlancap2wpasec -lcurl
+## mv wlancap2wpasec /usr/bin/
+
+def on_loaded():
+ global READY
+ global API_KEY
+ global ALREADY_UPLOADED
+
+ if not API_KEY:
+ logging.error("WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org")
+ return
+
+ try:
+ subprocess.call("wlancap2wpasec -h >/dev/null".split(), stdout=open(os.devnull, 'wb'))
+ except OSError:
+ logging.error("WPA_SEC: Can't find wlancap2wpasec. Install hcxtools to use this plugin!")
+ return
+
+ try:
+ with open('/root/.wpa_sec_uploads', 'r') as f:
+ ALREADY_UPLOADED = f.read().splitlines()
+ except OSError:
+ logging.error('WPA_SEC: No upload-file found.')
+ ALREADY_UPLOADED = []
+
+ READY = True
+
+
+def _upload_to_wpasec(path):
+ try:
+ subprocess.call(f"wlancap2wpasec -k {API_KEY} {path}".split(), stdout=open(os.devnull, 'wb'))
+ except OSError as os_e:
+ logging.error(f"WPA_SEC: Error while uploading {path}")
+ raise os_e
+
+# called in manual mode when there's internet connectivity
+def on_internet_available(display, config, log):
+ if READY:
+
+ handshake_dir = config['bettercap']['handshakes']
+ handshake_filenames = os.listdir(handshake_dir)
+ handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames]
+ handshake_new = set(handshake_paths) - set(ALREADY_UPLOADED)
+
+ if handhake_new:
+ logging.info("Internet connectivity detected.\
+ Uploading new handshakes to wpa-sec.stanev.org")
+
+ for idx, handshake in enumerate(handshake_new):
+ display.set('status', f"Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new})")
+ display.update(force=True)
+ try:
+ _upload_to_wpasec(handshake)
+ ALREADY_UPLOADED.append(handshake)
+ with open('/root/.wpa_sec_uploads', 'a') as f:
+ f.write(handshake + "\n")
+ except OSError:
+ pass
From bbe5540c43014f5fe26c8dc6f7ab225e2608d904 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 23:24:48 +0200
Subject: [PATCH 36/80] plugins are now enabled by config.yml or custom.yml
(closes #114)
---
sdcard/rootfs/root/pwnagotchi/config.yml | 10 ++++++++--
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 7 +++----
.../pwnagotchi/scripts/pwnagotchi/plugins/__init__.py | 5 ++---
.../scripts/pwnagotchi/plugins/default/example.py | 1 -
.../scripts/pwnagotchi/plugins/default/gps.py | 1 -
.../scripts/pwnagotchi/plugins/default/memtemp.py | 1 -
.../scripts/pwnagotchi/plugins/default/twitter.py | 1 -
.../scripts/pwnagotchi/plugins/default/ups_lite.py | 1 -
8 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index 28f27705..5d786c59 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -3,7 +3,11 @@ main:
# currently implemented: en (default), de, nl, it
lang: en
# custom plugins path, if null only default plugins with be loaded
- plugins: null
+ custom_plugins:
+ # which plugins to load and enable
+ plugins:
+ - gps
+ - twitter
# monitor interface to use
iface: mon0
# command to run to bring the mon interface up in case it's not up already
@@ -15,7 +19,9 @@ main:
# if true, will not restart the wifi module
no_restart: false
# access points to ignore
- whitelist: []
+ whitelist:
+ - EXAMPLE_NETWORK
+ - ANOTHER_EXAMPLE_NETWORK
# if not null, filter access points by this regular expression
filter: null
# cryptographic key for identity
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index cba98d5e..ac5bacd1 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -1,5 +1,4 @@
#!/usr/bin/python3
-import os
import argparse
import time
import logging
@@ -33,9 +32,9 @@ args = parser.parse_args()
config = utils.load_config(args)
utils.setup_logging(args, config)
-plugins.load_from_path(plugins.default_path)
-if 'plugins' in config['main'] and config['main']['plugins'] is not None:
- plugins.load_from_path(config['main']['plugins'])
+plugins.load_from_path(plugins.default_path, enabled=config['main']['plugins'])
+if 'custom_plugins' in config['main'] and config['main']['custom_plugins'] is not None:
+ plugins.load_from_path(config['main']['custom_plugins'], enabled=config['main']['plugins'])
plugins.on('loaded')
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
index bcb89f8e..89afe109 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
@@ -27,14 +27,13 @@ def load_from_file(filename):
return plugin_name, instance
-def load_from_path(path):
+def load_from_path(path, enabled=()):
global loaded
-
for filename in glob.glob(os.path.join(path, "*.py")):
name, plugin = load_from_file(filename)
if name in loaded:
raise Exception("plugin %s already loaded from %s" % (name, plugin.__file__))
- elif not plugin.__enabled__:
+ elif name not in enabled:
# print("plugin %s is not enabled" % name)
pass
else:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
index 4166e4ad..b425d6ee 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
@@ -3,7 +3,6 @@ __version__ = '1.0.0'
__name__ = 'hello_world'
__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
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
index cd292eae..f7aa56e6 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/gps.py
@@ -3,7 +3,6 @@ __version__ = '1.0.0'
__name__ = 'gps'
__license__ = 'GPL3'
__description__ = 'Save GPS coordinates whenever an handshake is captured.'
-__enabled__ = True # set to false if you just don't use GPS
import logging
import json
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
index 2b1fc3da..4ef823b0 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/memtemp.py
@@ -7,7 +7,6 @@ __version__ = '1.0.0'
__name__ = 'memtemp'
__license__ = 'GPL3'
__description__ = 'A plugin that will add a memory and temperature indicator'
-__enabled__ = False
import struct
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
index 0c7d8d98..03aa2514 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
@@ -3,7 +3,6 @@ __version__ = '1.0.0'
__name__ = 'twitter'
__license__ = 'GPL3'
__description__ = 'This plugin creates tweets about the recent activity of pwnagotchi'
-__enabled__ = True
import logging
from pwnagotchi.voice import Voice
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/ups_lite.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/ups_lite.py
index 7ddcecdd..d9a37d28 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/ups_lite.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/ups_lite.py
@@ -12,7 +12,6 @@ __version__ = '1.0.0'
__name__ = 'ups_lite'
__license__ = 'GPL3'
__description__ = 'A plugin that will add a voltage indicator for the UPS Lite v1.1'
-__enabled__ = False
import struct
From 2749079d256655bfad6b744a38d3cb22e1620f69 Mon Sep 17 00:00:00 2001
From: dipsylala
Date: Thu, 3 Oct 2019 22:28:19 +0100
Subject: [PATCH 37/80] Friend status is positioned based on %age of screen
height
It takes it's queue from the bottom line and places text above it.
Tested on WaveShare v2 and Inkyphat.
---
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
index f86b88f0..ca748a0a 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
@@ -86,8 +86,8 @@ class View(object):
'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),
+ 'friend_face': Text(value=None, position=(0, (self._height * 0.88) - 15 ), font=fonts.Bold, color=BLACK),
+ 'friend_name': Text(value=None, position=(40,(self._height * 0.88) - 13 ), font=fonts.BoldSmall, color=BLACK),
'name': Text(value='%s>' % 'pwnagotchi', position=name_pos, color=BLACK, font=fonts.Bold),
From d58e416edea2a5545d7fa9eeea4e71174b07a7c2 Mon Sep 17 00:00:00 2001
From: sp3nx0r
Date: Thu, 3 Oct 2019 16:35:06 -0500
Subject: [PATCH 38/80] markdown style formatting, adding content to configure
---
docs/about.md | 10 +++-------
docs/configure.md | 39 ++++++++++++++++++++++-----------------
docs/dev.md | 3 ++-
docs/faq.md | 2 +-
docs/index.md | 2 +-
docs/install.md | 9 +++------
docs/plugins.md | 3 +--
docs/usage.md | 41 ++++++++++++++++++-----------------------
8 files changed, 51 insertions(+), 58 deletions(-)
diff --git a/docs/about.md b/docs/about.md
index 8f141adf..e5f0f375 100644
--- a/docs/about.md
+++ b/docs/about.md
@@ -1,10 +1,6 @@
-## About the Project
+# About the Project
-[Pwnagotchi](https://twitter.com/pwnagotchi) is an "AI" that learns from the WiFi environment and instruments
-[bettercap](https://www.bettercap.org/) in order to maximize the WPA key material that's being captured either passively
- or by performing deauthentication and association attakcs. This material is collected as pcap files containing any form
- of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/),
-full and half WPA handshakes.
+[Pwnagotchi](https://twitter.com/pwnagotchi) is an "AI" that learns from the WiFi environment and instruments [bettercap](https://www.bettercap.org/) in order to maximize the WPA key material that's being captured either passively or by performing deauthentication and association attakcs. This material is collected as pcap files containing any form of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/), full and half WPA handshakes.

@@ -20,4 +16,4 @@ If instead you just want to use your own parameters and save battery and CPU cyc
## License
-`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
\ No newline at end of file
+`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
diff --git a/docs/configure.md b/docs/configure.md
index 98cd01ca..fbefe701 100644
--- a/docs/configure.md
+++ b/docs/configure.md
@@ -1,7 +1,6 @@
-### Connecting to your Pwnagotchi
+# Connecting to your Pwnagotchi
-Once you wrote the image file on the SD card, there're a few steps you'll have to follow in order to configure your unit properly, first, start with connecting the USB cable to the
-data port of the Raspberry Pi and the RPi to your computer. After a few seconds the board will boot and you will see a new Ethernet interface on your host computer.
+Once you wrote the image file on the SD card, there're a few steps you'll have to follow in order to configure your unit properly, first, start with connecting the USB cable to the data port of the Raspberry Pi and the RPi to your computer. After a few seconds the board will boot and you will see a new Ethernet interface on your host computer.
You'll need to configure it with a static IP address:
@@ -26,26 +25,32 @@ Moreover, it is recommended that you copy your SSH public key among the unit's a
ssh-copy-id -i ~/.ssh/id_rsa.pub pi@10.0.0.2
```
-### Configuration
+## Configuration
-You can now set a new name for your unit by [changing the hostname](https://geek-university.com/raspberry-pi/change-raspberry-pis-hostname/). Create the `/root/custom.yml` file (either via SSH or by direclty editing the SD card contents from a computer) that will override
-the [default configuration](https://github.com/evilsocket/pwnagotchi/blob/master/sdcard/rootfs/root/pwnagotchi/config.yml) with your custom values.
+You can now set a new name for your unit by [changing the hostname](https://geek-university.com/raspberry-pi/change-raspberry-pis-hostname/). Create the `/root/custom.yml` file (either via SSH or by direclty editing the SD card contents from a computer) that will override the [default configuration](https://github.com/evilsocket/pwnagotchi/blob/master/sdcard/rootfs/root/pwnagotchi/config.yml) with your custom values.
+
+## Language Selection
For instance, you can change `main.lang` to one of the supported languages:
-* **english** (default)
-* german
-* dutch
-* greek
-* macedonian
-* italian
-* french
+- **english** (default)
+- german
+- dutch
+- greek
+- macedonian
+- italian
+- french
-The set the type of display you want to use via `ui.display.type` (if your display does not work after changing this setting, you might need to complete remove power from the Raspberry and make a clean boot).
+## Display Selection
+
+Set the type of display you want to use via `ui.display.type` (if your display does not work after changing this setting, you might need to completely remove power from the Raspberry and make a clean boot).
You can configure the refresh interval of the display via `ui.fps`, we advise to use a slow refresh to not shorten the lifetime of your display. The default value is 0, which will only refresh when changes are made to the screen.
-### Host Connection Share
+## Host Connection Share
-If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/linux_connection_share.sh` or
- `scripts/macos_connection_share.sh` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it.
\ No newline at end of file
+If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/linux_connection_share.sh` or `scripts/macos_connection_share.sh` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it. Note this script takes as inputs the two interfaces and shouldn't be run without arguments.
+
+## Troubleshooting
+
+If your network connection keeps flapping on your device connecting to your pwnagotchi, check if `usb0` (or equivalent) device is being controlled by NetworkManager. You can check this via `nmcli dev status`.
diff --git a/docs/dev.md b/docs/dev.md
index 5a4df640..09d2a465 100644
--- a/docs/dev.md
+++ b/docs/dev.md
@@ -1,4 +1,4 @@
-## Software
+# Software
- Raspbian + [nexmon patches](https://re4son-kernel.com/re4son-pi-kernel/) for monitor mode, or any Linux with a monitor mode enabled interface (if you tune config.yml).
@@ -21,6 +21,7 @@ usage: ./scripts/create_sibling.sh [OPTIONS]
-d # Only run dependencies checks
-h # Show this help
```
+
## Adding a Language
If you want to add a language use the `language.sh` script. If you want to add for example the language **italian** you would type:
diff --git a/docs/faq.md b/docs/faq.md
index ed4a1f37..ff19087a 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -10,4 +10,4 @@ Because Python sucks and TF is huge.
## Why ...?
-Because!
\ No newline at end of file
+Because!
diff --git a/docs/index.md b/docs/index.md
index 3c23b8c5..36e97f88 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -16,4 +16,4 @@
## License
-`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
\ No newline at end of file
+`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
diff --git a/docs/install.md b/docs/install.md
index 4081e955..6902979a 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -1,7 +1,6 @@
# Installation
-The project has been developed to run on a Raspberry Pi 0 W configured as an [USB Ethernet gadget](https://learn.adafruit.com/turning-your-raspberry-pi-zero-into-a-usb-gadget/ethernet-gadget) device in order to connect to it via USB.
-However, given the proper configuration tweaks, any GNU/Linux computer with a WiFi interface that supports monitor mode could be used.
+The project has been developed to run on a Raspberry Pi 0 W configured as an [USB Ethernet gadget](https://learn.adafruit.com/turning-your-raspberry-pi-zero-into-a-usb-gadget/ethernet-gadget) device in order to connect to it via USB. However, given the proper configuration tweaks, any GNU/Linux computer with a WiFi interface that supports monitor mode could be used.
## Required Hardware
@@ -34,9 +33,7 @@ Color displays have a much slower refresh rate, in some cases it can take up to
The easiest way to create a new Pwnagotchi is downloading the latest stable image from [our release page](https://github.com/evilsocket/pwnagotchi/releases) and write it to your SD card. You will need to use an image writing tool to install the image you have downloaded on your SD card.
-[balenaEtcher](https://www.balena.io/etcher/) is a graphical SD card writing tool that works on Mac OS, Linux and Windows,
-and is the easiest option for most users. balenaEtcher also supports writing images directly from the zip file,
-without any unzipping required. To write your image with balenaEtcher:
+[balenaEtcher](https://www.balena.io/etcher/) is a graphical SD card writing tool that works on Mac OS, Linux and Windows, and is the easiest option for most users. balenaEtcher also supports writing images directly from the zip file, without any unzipping required. To write your image with balenaEtcher:
- Download the latest [Pwnagotchi .img file](https://github.com/evilsocket/pwnagotchi/releases).
- Download [balenaEtcher](https://www.balena.io/etcher/) and install it.
@@ -45,4 +42,4 @@ without any unzipping required. To write your image with balenaEtcher:
- Select the SD card you wish to write your image to.
- Review your selections and click 'Flash!' to begin writing data to the SD card.
-Your SD card is now ready for the first boot!
\ No newline at end of file
+Your SD card is now ready for the first boot!
diff --git a/docs/plugins.md b/docs/plugins.md
index 512c872a..0038df9f 100644
--- a/docs/plugins.md
+++ b/docs/plugins.md
@@ -1,8 +1,7 @@
# Plugins
Pwnagotchi has a simple plugins system that you can use to customize your unit and its behaviour. You can place your plugins anywhere
-as python files and then edit the `config.yml` file (`main.plugins` value) to point to their containing folder. Check the [plugins folder](https://github.com/evilsocket/pwnagotchi/tree/master/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/) for a list of default
-plugins and all the callbacks that you can define for your own customizations.
+as python files and then edit the `config.yml` file (`main.plugins` value) to point to their containing folder. Check the [plugins folder](https://github.com/evilsocket/pwnagotchi/tree/master/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/) for a list of default plugins and all the callbacks that you can define for your own customizations.
Here's as an example the GPS plugin:
diff --git a/docs/usage.md b/docs/usage.md
index e23dc686..8883cb70 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -1,4 +1,6 @@
-### User Interface
+# Usage
+
+## User Interface
The UI is available either via display if installed, or via http://pwnagotchi.local:8080/ if you connect to the unit via `usb0` and set a static address on the network interface (change `pwnagotchi` with the hostname of your unit).
@@ -10,7 +12,7 @@ The UI is available either via display if installed, or via http://pwnagotchi.lo
* **PWND**: Number of handshakes captured in this session and number of unique networks we own at least one handshake of, from the beginning.
* **AUTO**: This indicates that the algorithm is running with AI disabled (or still loading), it disappears once the AI dependencies have been bootrapped and the neural network loaded.
-### Training the AI
+## Training the AI
At its core Pwnagotchi is a very simple creature: we could summarize its main algorithm as:
@@ -27,7 +29,7 @@ while True:
for client in ap.clients:
# deauthenticate the client to get its half or full handshake
deauthenticate(client)
-
+
wait_for_loot()
```
@@ -73,14 +75,11 @@ personality:
sad_num_epochs: 25
```
-There is no optimal set of parameters for every situation: when the unit is moving (during a walk for instance) smaller timeouts and RSSI thresholds might be preferred
-in order to quickly remove routers that are not in range anymore, while when stationary in high density areas (like an office) other parameters might be better.
-The role of the AI is to observe what's going on at the WiFi level, and adjust those parameters in order to maximize the cumulative reward of that loop / epoch.
+There is no optimal set of parameters for every situation: when the unit is moving (during a walk for instance) smaller timeouts and RSSI thresholds might be preferred in order to quickly remove routers that are not in range anymore, while when stationary in high density areas (like an office) other parameters might be better. The role of the AI is to observe what's going on at the WiFi level, and adjust those parameters in order to maximize the cumulative reward of that loop / epoch.
-#### Reward Function
+## Reward Function
-After each iteration of the main loop (an `epoch`), the reward, a score that represents how well the parameters performed, is computed as
-(an excerpt from `pwnagotchi/ai/reward.py`):
+After each iteration of the main loop (an `epoch`), the reward, a score that represents how well the parameters performed, is computed as (an excerpt from `pwnagotchi/ai/reward.py`):
```python
# state contains the information of the last epoch
@@ -107,15 +106,13 @@ reward = h + a + c + b + i + m
By maximizing this reward value, the AI learns over time to find the set of parameters that better perform with the current environmental conditions.
+## BetterCAP's Web UI
-### BetterCAP's Web UI
-
-Moreover, given that the unit is running bettercap with API and Web UI, you'll be able to use the unit as a WiFi penetration testing portable station
-by accessing `http://pwnagotchi.local/`.
+Moreover, given that the unit is running bettercap with API and Web UI, you'll be able to use the unit as a WiFi penetration testing portable station by accessing `http://pwnagotchi.local/`.

-### Update your Pwnagotchi
+## Update your Pwnagotchi
You can use the `scripts/update_pwnagotchi.sh` script to update to the most recent version of pwnagotchi.
@@ -132,7 +129,7 @@ usage: ./update_pwnagitchi.sh [OPTIONS]
```
-### Backup your Pwnagotchi
+## Backup your Pwnagotchi
You can use the `scripts/backup.sh` script to backup the important files of your unit.
@@ -140,12 +137,10 @@ You can use the `scripts/backup.sh` script to backup the important files of your
usage: ./scripts/backup.sh HOSTNAME backup.zip
```
-### Random Info
-
-- **On a rpi0w, it'll take approximately 30 minutes to load the AI**.
-- `/var/log/pwnagotchi.log` is your friend.
-- if connected to a laptop via usb data port, with internet connectivity shared, magic things will happen.
-- checkout the `ui.video` section of the `config.yml` - if you don't want to use a display, you can connect to it with the browser and a cable.
-- If you get `[FAILED] Failed to start Remount Root and Kernel File Systems.` while booting pwnagotchi, make sure
-the `PARTUUID`s for `rootfs` and `boot` partitions are the same in `/etc/fstab`. Use `sudo blkid` to find those values when you are using `create_sibling.sh`.
+## Random Info
+* **On a rpi0w, it'll take approximately 30 minutes to load the AI**.
+* `/var/log/pwnagotchi.log` is your friend.
+* if connected to a laptop via usb data port, with internet connectivity shared, magic things will happen.
+* checkout the `ui.video` section of the `config.yml` - if you don't want to use a display, you can connect to it with the browser and a cable.
+* If you get `[FAILED] Failed to start Remount Root and Kernel File Systems.` while booting pwnagotchi, make sure the `PARTUUID`s for `rootfs` and `boot` partitions are the same in `/etc/fstab`. Use `sudo blkid` to find those values when you are using `create_sibling.sh`.
From 703f334f6e7666d186fd696f4e7e8d44009f36bc Mon Sep 17 00:00:00 2001
From: waxwing
Date: Thu, 3 Oct 2019 17:38:49 -0400
Subject: [PATCH 39/80] minor copyediting for typos
---
docs/about.md | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/docs/about.md b/docs/about.md
index 8f141adf..816b6c50 100644
--- a/docs/about.md
+++ b/docs/about.md
@@ -1,23 +1,23 @@
## About the Project
-[Pwnagotchi](https://twitter.com/pwnagotchi) is an "AI" that learns from the WiFi environment and instruments
-[bettercap](https://www.bettercap.org/) in order to maximize the WPA key material that's being captured either passively
- or by performing deauthentication and association attakcs. This material is collected as pcap files containing any form
- of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/),
+[Pwnagotchi](https://twitter.com/pwnagotchi) is an [A2C](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752)-based "AI" leveraging [bettercap](https://www.bettercap.org/) that learns from its surrounding WiFi environment in order to maximize the WPA key material it captures (either passively, or by performing deauthentication and association attacks). This material is collected as PCAP files containing any form of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/),
full and half WPA handshakes.

-Instead of playing [Super Mario or Atari games](https://becominghuman.ai/getting-mario-back-into-the-gym-setting-up-super-mario-bros-in-openais-gym-8e39a96c1e41?gi=c4b66c3d5ced), pwnagotchi will tune over time [its own parameters](https://github.com/evilsocket/pwnagotchi/blob/master/sdcard/rootfs/root/pwnagotchi/config.yml#L54), effectively learning to get better at pwning WiFi things. **Keep in mind:** unlike the usual RL simulations, pwnagotchi learns over time (where a single epoch can last from a few seconds to minutes, depending on how many access points and client stations are visible), do not expect it to perform amazingly well at the beginning, as it'll be exploring several combinations of parameters ... but listen to it when it's bored, bring it with you and have it observe new networks and capture new handshakes and you'll see :)
+Instead of merely playing [Super Mario or Atari games](https://becominghuman.ai/getting-mario-back-into-the-gym-setting-up-super-mario-bros-in-openais-gym-8e39a96c1e41?gi=c4b66c3d5ced) like most reinforcement learning based "AI" *(yawn)*, Pwnagotchi tunes [its own parameters](https://github.com/evilsocket/pwnagotchi/blob/master/sdcard/rootfs/root/pwnagotchi/config.yml#L54) over time to **get better at pwning WiFi things** in the environments you expose it to.
-Multiple units can talk to each other, advertising their own presence using a parasite protocol I've built on top of the existing dot11 standard, by broadcasting custom information elements. Over time, two or more units learn to cooperate if they detect each other's presence, by dividing the available channels among them.
+**Keep in mind:** Unlike the usual RL simulations, Pwnagotchi actually learns over time. Time for a Pwnagotchi is measured in epochs; a single epoch can last from a few seconds to minutes, depending on how many access points and client stations are visible. Do not expect your Pwnagotchi to perform amazingly well at the very beginning, as it will be [exploring](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752) several combinations of [key parameters](https://github.com/evilsocket/pwnagotchi/blob/master/docs/usage.md#training-the-ai) to determine ideal adjustments for pwning the particular environment you are exposing it to during its beginning epochs ... but **definitely listen to your pwnagotchi when it tells you it's bored!** Bring it into novel WiFi environments with you and have it observe new networks and capture new handshakes—and you'll see. :)
+
+Multiple units within close physical proximity can "talk" to each other, advertising their own presence to each other by broadcasting custom information elements using a parasite protocol I've built on top of the existing dot11 standard. Over time, two or more units trained together will learn to cooperate upon detecting each other's presence by dividing the available channels among them for optimal pwnage.

-Depending on the status of the unit, several states and states transitions are configurable and represented on the display as different moods, expressions and sentences.
+[Depending on the status of the unit](), several states and states transitions are configurable and represented on the display as different moods, expressions and sentences. Pwnagotchi speaks [many languages](https://github.com/evilsocket/pwnagotchi/blob/master/docs/configure.md#configuration), too!
+
+Of course, it is possible to run your Pwnagotchi with the AI disabled (configurable in `config.yml`). Why might you want to do this? Perhaps you simply want to use your own fixed parameters (instead of letting the AI decide for you), or maybe you want to save battery and CPU cycles, or maybe it's just you have strong concerns about aiding and abetting baby Skynet. Whatever your particular reasons may be: an AI-disabled Pwnagotchi is still a simple and very effective automated deauther, WPA handshake sniffer, and portable [bettercap](https://www.bettercap.org/) + [webui](https://github.com/evilsocket/pwnagotchi/blob/master/docs/usage.md#bettercaps-web-ui) dedicated hardware.
-If instead you just want to use your own parameters and save battery and CPU cycles, you can disable the AI in `config.yml` and enjoy an automated deauther, WPA handshake sniffer and portable bettercap + webui dedicated hardware.
## License
-`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
\ No newline at end of file
+`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
From 061a5771aec71a29b379028b8eb036f0d395adbe Mon Sep 17 00:00:00 2001
From: Justin-p
Date: Thu, 3 Oct 2019 23:44:21 +0200
Subject: [PATCH 40/80] Added powershell script to automate internet connection
sharing on windows
---
scripts/win_connection_share.ps1 | 265 +++++++++++++++++++++++++++++++
1 file changed, 265 insertions(+)
create mode 100644 scripts/win_connection_share.ps1
diff --git a/scripts/win_connection_share.ps1 b/scripts/win_connection_share.ps1
new file mode 100644
index 00000000..ee899112
--- /dev/null
+++ b/scripts/win_connection_share.ps1
@@ -0,0 +1,265 @@
+<#
+ .SYNOPSIS
+ A script that setups Internet Connection Sharing for Pwnagotchi.
+
+ .DESCRIPTION
+ A script that setups Internet Connection Sharing for Pwnagotchi.
+
+ Note: Internet Connection Sharing on Windows can be a bit unstable on windows between reboots.
+ You might need to run this script occasionally to disable and re-enable Internet Connection Sharing.
+
+ .PARAMETER EnableInternetConnectionSharing
+ Enable Internet Connection Sharing
+
+ .PARAMETER DisableInternetConnectionSharing
+ Disable Internet Connection Sharing
+
+ .PARAMETER SetPwnagotchiSubnet
+ Change the Internet Connection Sharing subnet to the Pwnagotchi. Defaults to 10.0.0.1.
+
+ .PARAMETER ScopeAddress
+ Custom ScopeAddress (The IP Address of the USB Gadget Interface.)
+
+ .EXAMPLE
+ # Enable Internet Connection Sharing
+ PS C:\> .\win_connection_share -EnableInternetConnectionSharing
+
+ .EXAMPLE
+ # Disable Internet Connection Sharing
+ PS C:\> .\win_connection_share -DisableInternetConnectionSharing
+
+ .EXAMPLE
+ # Change the regkeys of Internet Connection Sharing to the Pwnagotchi Subnet
+ PS C:\> .\win_connection_share -SetPwnagotchiSubnet
+
+ .EXAMPLE
+ # Change the regkeys of Internet Connection Sharing to the Pwnagotchi Subnet with a custom ScopeAddress (The IP Address of the USB Gadget Interface.)
+ PS C:\> .\win_connection_share -SetPwnagotchiSubnet -ScopeAddress 10.0.0.10
+#>
+
+#Requires -Version 5
+#Requires -RunAsAdministrator
+[Cmdletbinding()]
+Param (
+ [switch]$EnableInternetConnectionSharing,
+ [switch]$DisableInternetConnectionSharing,
+ [switch]$SetPwnagotchiSubnet,
+ [ipaddress]$ScopeAddress = '10.0.0.1'
+)
+
+# Load helper functions
+Function Create-HNetObjects {
+ <#
+ .SYNOPSIS
+ A helper function that does the heavy lifiting with NetCfg.HNetShare
+
+ .DESCRIPTION
+ A helper function that does the heavy lifiting with NetCfg.HNetShare. This returns a PSObject containing the `INetSharingConfigurationForINetConnection` info of 2 Adapters.
+ By default it tries to get the correct interfaces. This method might not be foolproof for every setup, but should work in most default senarios, if this causes issues these
+ can be passed as a param.
+
+ .PARAMETER InternetAdaptor
+ The output of Get-NetAdaptor filtered down to the 'main' uplink interface. Should default to the correct value.
+
+ .PARAMETER RNDISGadget
+ The output of Get-NetAdaptor filtered down to the 'USB Ethernet/RNDIS Gadget' interface. Should default to the correct value.
+
+ .EXAMPLE
+ PS> $HNetObject = Create-HNetObjects
+ PS> $HNetObject
+ RNDISIntConfig InternetIntConfig
+ -------------- -----------------
+ System.__ComObject System.__ComObject
+ #>
+ [Cmdletbinding()]
+ Param (
+ $InternetAdaptor = $(Get-NetAdapter | Where-Object {$_.MediaConnectionState -eq 'Connected' -and $_.PhysicalMediaType -ne 'Unspecified'} | Sort-Object LinkSpeed -Descending),
+ $RNDISGadget = $(Get-NetAdapter | Where-Object {$_.MediaConnectionState -eq 'Connected' -and $_.InterfaceDescription -eq "USB Ethernet/RNDIS Gadget"})
+ )
+ Begin {
+ regsvr32.exe /s hnetcfg.dll
+ $HNetShare = New-Object -ComObject HNetCfg.HNetShare
+ }
+ Process {
+ if ($HNetShare.EnumEveryConnection -ne $null) {
+ $InternetInt = $HNetShare.EnumEveryConnection | Where-Object { $HNetShare.NetConnectionProps.Invoke($_).Name -eq ($InternetAdaptor).Name }
+ $InternetIntConfig = $HNetShare.INetSharingConfigurationForINetConnection.Invoke($InternetInt)
+ $RNDISInt = $HNetShare.EnumEveryConnection | Where-Object { $HNetShare.NetConnectionProps.Invoke($_).Name -eq ($RNDISGadget).Name }
+ $RNDISIntConfig = $HNetShare.INetSharingConfigurationForINetConnection.Invoke($RNDISInt)
+ }
+ }
+ End {
+ Return $(New-Object -TypeName PSObject -Property @{InternetIntConfig=$InternetIntConfig;RNDISIntConfig=$RNDISIntConfig;})
+ }
+}
+Function Enable-InternetConnectionSharing {
+ <#
+ .SYNOPSIS
+ Enables internet connection sharing between the 'main' uplink interface and the 'USB Ethernet/RNDIS Gadget' interface.
+
+ .DESCRIPTION
+ Enables internet connection sharing between the 'main' uplink interface and the 'USB Ethernet/RNDIS Gadget' interface.
+
+ .EXAMPLE
+ PS> Enable-InternetConnectionSharing
+
+ #>
+ [Cmdletbinding()]
+ $HNetObject = Create-HNetObjects
+ $HNetObject.InternetIntConfig.EnableSharing(0)
+ $HNetObject.RNDISIntConfig.EnableSharing(1)
+ Write-Output "[x] Enabled Internet Connection Sharing."
+}
+Function Disable-InternetConnectionSharing {
+ <#
+ .SYNOPSIS
+ Disables internet connection sharing between the 'main' uplink interface and the 'USB Ethernet/RNDIS Gadget' interface.
+
+ .DESCRIPTION
+ Disables internet connection sharing between the 'main' uplink interface and the 'USB Ethernet/RNDIS Gadget' interface.
+
+ .EXAMPLE
+ PS> Disable-InternetConnectionSharing
+
+ #>
+ [Cmdletbinding()]
+ $HNetObject = $(Create-HNetObjects)
+ $HNetObject.InternetIntConfig.DisableSharing()
+ $HNetObject.RNDISIntConfig.DisableSharing()
+ Write-Output "[x] Disabled Internet Connection Sharing."
+}
+Function Test-PwnagotchiSubnet {
+ <#
+ .SYNOPSIS
+ Tests the registry for the correct ScopeAddress.
+
+ .DESCRIPTION
+ Tests the registry for the correct ScopeAddress. By default windows uses a 192.168.137.x subnet for Internet Connection Sharing. This value can be changed
+ in the registry.
+
+ .EXAMPLE
+ PS> Test-PwnagotchiSubnet
+ [!] By default Internet Connection Sharing uses a 192.168.137.x subnet. Run Set-PwnagotchiSubnet to ensure you and your little friend are on the same subnet.
+ #>
+ [Cmdletbinding()]
+ $RegKeys = Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters -ErrorAction Stop
+ If ($RegKeys.ScopeAddress -notmatch '10.0.0.') {
+ Write-Error "By default Internet Connection Sharing uses a 192.168.137.x subnet. Run Set-PwnagotchiSubnet to ensure you and your little friend are on the same subnet." -ErrorAction Stop
+ }
+ If ($RegKeys.ScopeAddressBackup -notmatch '10.0.0.') {
+ Write-Error "By default Internet Connection Sharing uses a 192.168.137.x subnet. Run Set-PwnagotchiSubnet to ensure you and your little friend are on the same subnet." -ErrorAction Stop
+ }
+}
+Function Set-PwnagotchiSubnet {
+ <#
+ .SYNOPSIS
+ Set the registry for the correct ScopeAddress.
+
+ .DESCRIPTION
+ Set the registry for the correct ScopeAddress. By default windows uses a 192.168.137.x subnet for Internet Connection Sharing. This value can be changed
+ in the registry. By default it will be changed to 10.0.0.1
+
+ .PARAMETER ScopeAddress
+ The IP address the USB Gadget interface should use.
+
+ .EXAMPLE
+ Set-PwnagotchiSubnet
+
+ #>
+ [Cmdletbinding()]
+ Param (
+ $ScopeAddress = '10.0.0.1'
+ )
+ Try {
+ [void]([ipaddress]$ScopeAddress)
+ [void]([byte[]] $ScopeAddress.split('.'))
+ } Catch {
+ Write-Error "$ScopeAddress is not a valid IP."
+ }
+ Try {
+ Set-ItemProperty -Name ScopeAddress -Path "HKLM:\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\" -Value $ScopeAddress -ErrorAction Stop
+ Set-ItemProperty -Name ScopeAddressBackup -Path "HKLM:\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\" -Value $ScopeAddress -ErrorAction Stop
+ Write-Warning "The Internet Connection Sharing subnet has been updated. A reboot of windows is required !"
+ } Catch {
+ $PSCmdlet.ThrowTerminatingError($PSItem)
+ }
+
+}
+
+# Main Function
+Function Setup-PwnagotchiNetwork {
+ <#
+ .SYNOPSIS
+ Function to setup networking.
+
+ .DESCRIPTION
+ Function to setup networking. Main function calls helpers functions.
+
+ .PARAMETER EnableInternetConnectionSharing
+ Enable Internet Connection Sharing
+
+ .PARAMETER DisableInternetConnectionSharing
+ Disable Internet Connection Sharing
+
+ .PARAMETER SetPwnagotchiSubnet
+ Change the Internet Connection Sharing subnet to the Pwnagotchi. Defaults to 10.0.0.1.
+
+ .PARAMETER ScopeAddress
+ Custom ScopeAddress (the ICS ip address)
+
+ .EXAMPLE
+ PS> Setup-PwnagotchiNetwork -EnableInternetConnectionSharing
+
+ #>
+
+ Param (
+ [switch]$EnableInternetConnectionSharing,
+ [switch]$DisableInternetConnectionSharing,
+ [switch]$SetPwnagotchiSubnet,
+ $ScopeAddress = '10.0.0.1'
+ )
+ Begin {
+ Try {
+ Write-Debug "Begin"
+ $ErrorSplat=@{ErrorAction="stop"}
+ Write-Debug "Testing subnet"
+ Try {
+ Test-PwnagotchiSubnet @ErrorSplat
+ } Catch {
+ If ($SetPwnagotchiSubnet) {
+ Write-Debug "Setting subnet"
+ Set-PwnagotchiSubnet -ScopeAddress $ScopeAddress @ErrorSplat
+ } Else {
+ Write-Error "By default Internet Connection Sharing uses a 192.168.137.x subnet. Run this script with the -SetPwnagotchiSubnet to setup the network." -ErrorAction Stop
+ }
+ }
+ } Catch {
+ $PSCmdlet.ThrowTerminatingError($PSItem)
+ }
+ }
+ Process {
+ Write-Debug "Process"
+ Try {
+ If ($EnableInternetConnectionSharing) {
+ Write-Debug "Enable network Sharing"
+ Enable-InternetConnectionSharing @ErrorSplat
+ } ElseIf ($DisableInternetConnectionSharing) {
+ Write-Debug "Disable network Sharing"
+ Disable-InternetConnectionSharing @ErrorSplat
+ }
+ } Catch {
+ $PSCmdlet.ThrowTerminatingError($PSItem)
+ }
+ }
+ End {
+ Write-Debug "End"
+ Try {
+ # Nothing to return.
+ } Catch {
+ $PSCmdlet.ThrowTerminatingError($PSItem)
+ }
+ }
+}
+
+# Dynamically create params for Setup-PwnagotchiNetwork function based of param input of script.
+Setup-PwnagotchiNetwork @psBoundParameters
\ No newline at end of file
From 5fc0d69fda33e2ddbb754c296b99f5d3e927e22e Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 23:46:54 +0200
Subject: [PATCH 41/80] fix
---
.../pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
index 48ea525c..f783d209 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
@@ -60,12 +60,12 @@ def on_internet_available(display, config, log):
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames]
handshake_new = set(handshake_paths) - set(ALREADY_UPLOADED)
- if handhake_new:
+ if handshake_new:
logging.info("Internet connectivity detected.\
Uploading new handshakes to wpa-sec.stanev.org")
for idx, handshake in enumerate(handshake_new):
- display.set('status', f"Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new})")
+ display.set('status', "Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new})")
display.update(force=True)
try:
_upload_to_wpasec(handshake)
From 177804328ceaa4d8696f76461681aa8e5a4e921d Mon Sep 17 00:00:00 2001
From: Justin-p
Date: Thu, 3 Oct 2019 23:48:36 +0200
Subject: [PATCH 42/80] updated configure.md and added small note on
Create-HNetObjects function
---
docs/configure.md | 4 ++--
scripts/win_connection_share.ps1 | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/configure.md b/docs/configure.md
index 98cd01ca..83fbc300 100644
--- a/docs/configure.md
+++ b/docs/configure.md
@@ -47,5 +47,5 @@ You can configure the refresh interval of the display via `ui.fps`, we advise to
### Host Connection Share
-If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/linux_connection_share.sh` or
- `scripts/macos_connection_share.sh` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it.
\ No newline at end of file
+If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/linux_connection_share.sh` ,
+ `scripts/macos_connection_share.sh` or `scripts/win_connection_share.ps1` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it.
\ No newline at end of file
diff --git a/scripts/win_connection_share.ps1 b/scripts/win_connection_share.ps1
index ee899112..ecbed3b8 100644
--- a/scripts/win_connection_share.ps1
+++ b/scripts/win_connection_share.ps1
@@ -56,7 +56,7 @@ Function Create-HNetObjects {
.DESCRIPTION
A helper function that does the heavy lifiting with NetCfg.HNetShare. This returns a PSObject containing the `INetSharingConfigurationForINetConnection` info of 2 Adapters.
By default it tries to get the correct interfaces. This method might not be foolproof for every setup, but should work in most default senarios, if this causes issues these
- can be passed as a param.
+ could be passed as a param, they would need to be implemented in Setup-PwnagotchiNetwork and the Param block of this file.
.PARAMETER InternetAdaptor
The output of Get-NetAdaptor filtered down to the 'main' uplink interface. Should default to the correct value.
From 3a3c5911cbb465d16e7e4ba5628a1ef302e112c3 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Thu, 3 Oct 2019 23:49:58 +0200
Subject: [PATCH 43/80] fix
---
.../pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
index f783d209..64df84e7 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
@@ -3,7 +3,6 @@ __version__ = '1.0.0'
__name__ = 'wpa_sec'
__license__ = 'GPL3'
__description__ = 'This plugin automatically uploades handshakes to https://wpa-sec.stanev.org'
-__enabled__ = False
import os
import logging
@@ -13,6 +12,7 @@ READY = False
API_KEY = None
ALREADY_UPLOADED = None
+
# INSTALLATION:
## apt-get install libcurl4-openssl-dev
## https://github.com/ZerBea/hcxtools.git
@@ -51,6 +51,7 @@ def _upload_to_wpasec(path):
logging.error(f"WPA_SEC: Error while uploading {path}")
raise os_e
+
# called in manual mode when there's internet connectivity
def on_internet_available(display, config, log):
if READY:
From 3c241b2cbfd043a3f12523ef8f0a70f027adf2d3 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:00:47 +0200
Subject: [PATCH 44/80] added hexwaxwing to derek users
---
.DEREK.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.DEREK.yml b/.DEREK.yml
index c63d9d15..9598f24d 100644
--- a/.DEREK.yml
+++ b/.DEREK.yml
@@ -3,6 +3,7 @@ maintainers:
- caquino
- dadav
- justin-p
+ - hexwaxwing
features:
- comments
From cc19fb5b6eb81da7d60a230b28472b042fbc6a1d Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:11:31 +0200
Subject: [PATCH 45/80] refactor
---
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 13 +------------
.../root/pwnagotchi/scripts/pwnagotchi/agent.py | 10 ++++++++++
2 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index ac5bacd1..5ecb7ff2 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -3,8 +3,6 @@ import argparse
import time
import logging
-import yaml
-
import pwnagotchi
import pwnagotchi.utils as utils
import pwnagotchi.version as version
@@ -73,16 +71,7 @@ elif args.do_manual:
else:
logging.info("entering auto mode ...")
- agent.start_ai()
- agent.setup_events()
- agent.set_starting()
- agent.start_monitor_mode()
- agent.start_event_polling()
-
- # print initial stats
- agent.next_epoch()
-
- agent.set_ready()
+ agent.start()
while True:
try:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
index 578e3808..69c594ef 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
@@ -138,6 +138,16 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
self.start_advertising()
+ def start(self):
+ self.start_ai()
+ self.setup_events()
+ self.set_starting()
+ self.start_monitor_mode()
+ self.start_event_polling()
+ # print initial stats
+ self.next_epoch()
+ self.set_ready()
+
def wait_for(self, t, sleeping=True):
plugins.on('sleep' if sleeping else 'wait', self, t)
self._view.wait(t, sleeping)
From ba15d1940a7d9c2ecde778abb72de392845e71b7 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:26:00 +0200
Subject: [PATCH 46/80] refactor
---
.../root/pwnagotchi/scripts/core/__init__.py | 48 -------------------
.../pwnagotchi/scripts/pwnagotchi/agent.py | 9 ++--
.../pwnagotchi/scripts/pwnagotchi/ai/epoch.py | 34 ++++++-------
.../pwnagotchi/scripts/pwnagotchi/ui/view.py | 9 ++--
.../pwnagotchi/scripts/pwnagotchi/utils.py | 42 +++++++++++++++-
5 files changed, 67 insertions(+), 75 deletions(-)
delete mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/core/__init__.py
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/core/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/core/__init__.py
deleted file mode 100644
index eb718d31..00000000
--- a/sdcard/rootfs/root/pwnagotchi/scripts/core/__init__.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import glob
-import os
-import time
-import subprocess
-
-
-def secs_to_hhmmss(secs):
- mins, secs = divmod(secs, 60)
- hours, mins = divmod(mins, 60)
- return '%02d:%02d:%02d' % (hours, mins, secs)
-
-
-def total_unique_handshakes(path):
- expr = os.path.join(path, "*.pcap")
- return len(glob.glob(expr))
-
-
-def iface_address(ifname):
- output = subprocess.getoutput("/usr/sbin/ifconfig %s" % ifname)
- for line in output.split("\n"):
- line = line.strip()
- if line.startswith("inet "):
- return line.split(' ')[1].strip()
- return None
-
-
-def iface_channels(ifname):
- channels = []
- output = subprocess.getoutput("/sbin/iwlist %s freq" % ifname)
- for line in output.split("\n"):
- line = line.strip()
- if line.startswith("Channel "):
- channels.append(int(line.split()[1]))
- return channels
-
-
-def led(on=True):
- with open('/sys/class/leds/led0/brightness', 'w+t') as fp:
- fp.write("%d" % (0 if on is True else 1))
-
-
-def blink(times=1, delay=0.3):
- for t in range(0, times):
- led(True)
- time.sleep(delay)
- led(False)
- time.sleep(delay)
- led(True)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
index 69c594ef..fe1455c4 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
@@ -9,6 +9,7 @@ import _thread
import core
+import pwnagotchi.utils as utils
import pwnagotchi.plugins as plugins
from bettercap.client import Client
from pwnagotchi.mesh.utils import AsyncAdvertiser
@@ -30,7 +31,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
self._started_at = time.time()
self._filter = None if config['main']['filter'] is None else re.compile(config['main']['filter'])
self._current_channel = 0
- self._supported_channels = core.iface_channels(config['main']['iface'])
+ self._supported_channels = utils.iface_channels(config['main']['iface'])
self._view = view
self._access_points = []
self._last_pwnd = None
@@ -252,7 +253,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
def _update_uptime(self, s):
secs = time.time() - self._started_at
- self._view.set('uptime', core.secs_to_hhmmss(secs))
+ self._view.set('uptime', utils.secs_to_hhmmss(secs))
self._view.set('epoch', '%04d' % self._epoch.epoch)
def _update_counters(self):
@@ -272,7 +273,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
if new_shakes > 0:
self._epoch.track(handshake=True, inc=new_shakes)
- tot = core.total_unique_handshakes(self._config['bettercap']['handshakes'])
+ tot = utils.total_unique_handshakes(self._config['bettercap']['handshakes'])
txt = '%d (%d)' % (len(self._handshakes), tot)
if self._last_pwnd is not None:
@@ -285,7 +286,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
def _update_advertisement(self, s):
run_handshakes = len(self._handshakes)
- tot_handshakes = core.total_unique_handshakes(self._config['bettercap']['handshakes'])
+ tot_handshakes = utils.total_unique_handshakes(self._config['bettercap']['handshakes'])
started = s['started_at'].split('.')[0]
started = datetime.strptime(started, '%Y-%m-%dT%H:%M:%S')
started = time.mktime(started.timetuple())
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/epoch.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/epoch.py
index 0ef7869c..11c2b6da 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/epoch.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ai/epoch.py
@@ -2,8 +2,8 @@ import time
import threading
import logging
-import core
import pwnagotchi
+import pwnagotchi.utils as utils
import pwnagotchi.mesh.wifi as wifi
from pwnagotchi.ai.reward import RewardFunction
@@ -174,22 +174,22 @@ class Epoch(object):
self._epoch_data_ready.set()
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),
- core.secs_to_hhmmss(self.num_slept),
- self.blind_for,
- self.inactive_for,
- self.active_for,
- self.num_hops,
- self.num_missed,
- self.num_deauths,
- self.num_assocs,
- self.num_shakes,
- cpu * 100,
- mem * 100,
- temp,
- self._epoch_data['reward']))
+ "deauths=%d assocs=%d handshakes=%d cpu=%d%% mem=%d%% temperature=%dC reward=%s" % (
+ self.epoch,
+ utils.secs_to_hhmmss(self.epoch_duration),
+ utils.secs_to_hhmmss(self.num_slept),
+ self.blind_for,
+ self.inactive_for,
+ self.active_for,
+ self.num_hops,
+ self.num_missed,
+ self.num_deauths,
+ self.num_assocs,
+ self.num_shakes,
+ cpu * 100,
+ mem * 100,
+ temp,
+ self._epoch_data['reward']))
self.epoch += 1
self.epoch_started = now
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
index ca748a0a..78e75b6c 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/view.py
@@ -4,7 +4,7 @@ import time
import logging
from PIL import Image, ImageDraw
-import core
+import pwnagotchi.utils as utils
import pwnagotchi.plugins as plugins
from pwnagotchi.voice import Voice
@@ -86,8 +86,9 @@ class View(object):
'face': Text(value=faces.SLEEP, position=face_pos, color=BLACK, font=fonts.Huge),
- 'friend_face': Text(value=None, position=(0, (self._height * 0.88) - 15 ), font=fonts.Bold, color=BLACK),
- 'friend_name': Text(value=None, position=(40,(self._height * 0.88) - 13 ), font=fonts.BoldSmall, color=BLACK),
+ 'friend_face': Text(value=None, position=(0, (self._height * 0.88) - 15), font=fonts.Bold, color=BLACK),
+ 'friend_name': Text(value=None, position=(40, (self._height * 0.88) - 13), font=fonts.BoldSmall,
+ color=BLACK),
'name': Text(value='%s>' % 'pwnagotchi', position=name_pos, color=BLACK, font=fonts.Bold),
@@ -166,7 +167,7 @@ class View(object):
self.set('channel', '-')
self.set('aps', "%d" % log.associated)
self.set('shakes', '%d (%s)' % (log.handshakes, \
- core.total_unique_handshakes(self._config['bettercap']['handshakes'])))
+ utils.total_unique_handshakes(self._config['bettercap']['handshakes'])))
self.set_closest_peer(log.last_peer)
def is_normal(self):
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
index 8761a59c..28a627a4 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
@@ -1,6 +1,9 @@
-import yaml
-import os
import logging
+import glob
+import os
+import time
+import subprocess
+import yaml
# https://stackoverflow.com/questions/823196/yaml-merge-in-python
@@ -40,3 +43,38 @@ def setup_logging(args, config):
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
root.addHandler(console_handler)
+
+
+def secs_to_hhmmss(secs):
+ mins, secs = divmod(secs, 60)
+ hours, mins = divmod(mins, 60)
+ return '%02d:%02d:%02d' % (hours, mins, secs)
+
+
+def total_unique_handshakes(path):
+ expr = os.path.join(path, "*.pcap")
+ return len(glob.glob(expr))
+
+
+def iface_channels(ifname):
+ channels = []
+ output = subprocess.getoutput("/sbin/iwlist %s freq" % ifname)
+ for line in output.split("\n"):
+ line = line.strip()
+ if line.startswith("Channel "):
+ channels.append(int(line.split()[1]))
+ return channels
+
+
+def led(on=True):
+ with open('/sys/class/leds/led0/brightness', 'w+t') as fp:
+ fp.write("%d" % (0 if on is True else 1))
+
+
+def blink(times=1, delay=0.3):
+ for t in range(0, times):
+ led(True)
+ time.sleep(delay)
+ led(False)
+ time.sleep(delay)
+ led(True)
From 499f1377201f76ec46d70920cca59167e4e8b643 Mon Sep 17 00:00:00 2001
From: evilsocket
Date: Fri, 4 Oct 2019 00:27:05 +0200
Subject: [PATCH 47/80] Create CODE_OF_CONDUCT.md
---
CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 CODE_OF_CONDUCT.md
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..047f1e29
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at pwnagotchi@gmail.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
From aeebf66fa7b187550859947912fe65fdcfa743d6 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:28:49 +0200
Subject: [PATCH 48/80] added project subreddit
---
docs/index.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/index.md b/docs/index.md
index 36e97f88..806c648d 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -12,6 +12,7 @@
- [Project Slack](https://join.slack.com/t/pwnagotchi/shared_invite/enQtNzc4NzY3MDE2OTAzLTg5NmNmNDJiMDM3ZWFkMWUwN2Y5NDk0Y2JlZWZjODlhMmRhNDZiOGMwYjJhM2UzNzA3YjA5NjJmZGY5NGI5NmI)
- [Project Twitter](https://twitter.com/pwnagotchi)
+- [Project Subreddit](https://www.reddit.com/r/pwnagotchi/)
- [Project Website](https://pwnagotchi.ai/)
## License
From affb8c27c3719e31d3113626c8a10c7cc29036ff Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:33:06 +0200
Subject: [PATCH 49/80] refactor
---
scripts/release.sh | 2 +-
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 3 +--
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/__init__.py | 2 ++
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py | 3 +--
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/scripts/release.sh b/scripts/release.sh
index 8b8d8cd8..2f1343af 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# nothing to see here, just a utility i use to create new releases ^_^
-VERSION_FILE=$(dirname "${BASH_SOURCE[0]}")/../sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
+VERSION_FILE=$(dirname "${BASH_SOURCE[0]}")/../sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/__init__.py
echo "version file is $VERSION_FILE"
CURRENT_VERSION=$(cat $VERSION_FILE | grep version | cut -d"'" -f2)
TO_UPDATE=(
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index 5ecb7ff2..4f881f39 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -5,7 +5,6 @@ import logging
import pwnagotchi
import pwnagotchi.utils as utils
-import pwnagotchi.version as version
import pwnagotchi.plugins as plugins
from pwnagotchi.log import SessionParser
@@ -39,7 +38,7 @@ plugins.on('loaded')
display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
agent = Agent(view=display, config=config)
-logging.info("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, version.version))
+logging.info("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, pwnagotchi.version))
for _, plugin in plugins.loaded.items():
logging.debug("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/__init__.py
index dacb09c6..c894d45f 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/__init__.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/__init__.py
@@ -1,5 +1,7 @@
import subprocess
+version = '1.0.0plz2'
+
_name = None
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
index be7bb0f4..3b63d092 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/utils.py
@@ -2,7 +2,6 @@ import _thread
import logging
import pwnagotchi
-import pwnagotchi.version as version
import pwnagotchi.plugins as plugins
from pwnagotchi.mesh import get_identity
@@ -24,7 +23,7 @@ class AsyncAdvertiser(object):
self._advertiser = Advertiser(
self._config['main']['iface'],
pwnagotchi.name(),
- version.version,
+ pwnagotchi.version,
self._identity,
period=0.3,
data=self._config['personality'])
From 074f30f06fa0b7b09e16f7d516c1bf5f21cde504 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:33:44 +0200
Subject: [PATCH 50/80] refactor
---
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py | 1 -
1 file changed, 1 deletion(-)
delete mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
deleted file mode 100644
index 17f3421b..00000000
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/version.py
+++ /dev/null
@@ -1 +0,0 @@
-version = '1.0.0plz2'
From b5f02f617224721de240919c893c773919020e37 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:36:25 +0200
Subject: [PATCH 51/80] misc: small fix or general refactoring i did not bother
commenting
---
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
index fe1455c4..0018bc38 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
@@ -7,8 +7,6 @@ from datetime import datetime
import logging
import _thread
-import core
-
import pwnagotchi.utils as utils
import pwnagotchi.plugins as plugins
from bettercap.client import Client
From 26fb21a7c761e4d87198998fc0df14f2847cee4f Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:42:12 +0200
Subject: [PATCH 52/80] misc: small fix or general refactoring i did not bother
commenting
---
sdcard/rootfs/root/pwnagotchi/scripts/bettercap/__init__.py | 0
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py | 2 +-
.../scripts/{bettercap/client.py => pwnagotchi/bettercap.py} | 0
3 files changed, 1 insertion(+), 1 deletion(-)
delete mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/bettercap/__init__.py
rename sdcard/rootfs/root/pwnagotchi/scripts/{bettercap/client.py => pwnagotchi/bettercap.py} (100%)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/bettercap/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/bettercap/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
index 0018bc38..023fa2e1 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
@@ -9,7 +9,7 @@ import _thread
import pwnagotchi.utils as utils
import pwnagotchi.plugins as plugins
-from bettercap.client import Client
+from pwnagotchi.bettercap import Client
from pwnagotchi.mesh.utils import AsyncAdvertiser
from pwnagotchi.ai.train import AsyncTrainer
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/bettercap/client.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/bettercap.py
similarity index 100%
rename from sdcard/rootfs/root/pwnagotchi/scripts/bettercap/client.py
rename to sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/bettercap.py
From dae50bc65d37dcc74a6b26d6173e9cbc97a27c7e Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:48:15 +0200
Subject: [PATCH 53/80] misc: small fix or general refactoring i did not bother
commenting
---
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 6 +-----
.../pwnagotchi/scripts/pwnagotchi/plugins/__init__.py | 8 ++++++++
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index 4f881f39..a593353e 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -29,11 +29,7 @@ args = parser.parse_args()
config = utils.load_config(args)
utils.setup_logging(args, config)
-plugins.load_from_path(plugins.default_path, enabled=config['main']['plugins'])
-if 'custom_plugins' in config['main'] and config['main']['custom_plugins'] is not None:
- plugins.load_from_path(config['main']['custom_plugins'], enabled=config['main']['plugins'])
-
-plugins.on('loaded')
+plugins.load(config)
display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
agent = Agent(view=display, config=config)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
index 89afe109..bb090dad 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
@@ -40,3 +40,11 @@ def load_from_path(path, enabled=()):
loaded[name] = plugin
return loaded
+
+
+def load(config):
+ load_from_path(default_path, enabled=config['main']['plugins'])
+ if 'custom_plugins' in config['main'] and config['main']['custom_plugins'] is not None:
+ load_from_path(config['main']['custom_plugins'], enabled=config['main']['plugins'])
+
+ on('loaded')
From 683d260c749bc240278df4690ad619360ffc697e Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 00:50:33 +0200
Subject: [PATCH 54/80] misc: small fix or general refactoring i did not bother
commenting
---
.../pwnagotchi/scripts/pwnagotchi/plugins/__init__.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
index bb090dad..b6f33f3f 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
@@ -43,8 +43,12 @@ def load_from_path(path, enabled=()):
def load(config):
- load_from_path(default_path, enabled=config['main']['plugins'])
- if 'custom_plugins' in config['main'] and config['main']['custom_plugins'] is not None:
- load_from_path(config['main']['custom_plugins'], enabled=config['main']['plugins'])
+ enabled = config['main']['plugins']
+ custom_path = config['main']['custom_plugins'] if 'custom_plugins' in config['main'] else None
+ # load default plugins
+ load_from_path(default_path, enabled=enabled)
+ # load custom ones
+ if custom_path is not None:
+ load_from_path(custom_path, enabled=enabled)
on('loaded')
From 83705c27f5e5485142a5de0aef501231eaf5ad10 Mon Sep 17 00:00:00 2001
From: gh0stshell
Date: Thu, 3 Oct 2019 16:19:47 -0700
Subject: [PATCH 55/80] Updated depends, bmaptool check update
Removed bmap-tools from depends as the check on line 96 looks for bmaptools and would use it if available if not continue to build, but have it as a depend check made the check null and if someone is on a kernel/file-system that does not support SEEK_HOLE and SEEK_DATA the script just fails.
Fixed bmap-tools check as the line which bmaptool >/dev/null 2>&1 does not return 0 so it kept ending at this line, if bmap-tools were not installed
The original code below looks for sparse to be 0 and if which bmaptool >/dev/null 2>&1 returns 0 to use bmap-tools, but I think its the reverse so swapped the last then and else sections as it would then look if sparse is 0 and which bmaptool >/dev/null 2>&1 is 0 to not use bmap-tools, but if it is 1 to use bmap-tools. If tool is available = 1 use bmap-tools, if tools is unavailable=0 do not use bmap-tools:
if [ "${OPT_SPARSE}" -eq 0 ];
then
which bmaptool >/dev/null 2>&1
if [ $? -eq 0 ];
then
echo "[+] Defaulting to sparse image generation as bmaptool is available"
OPT_SPARSE=1
---
scripts/create_sibling.sh | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/scripts/create_sibling.sh b/scripts/create_sibling.sh
index f2f5c5fd..973e95ec 100755
--- a/scripts/create_sibling.sh
+++ b/scripts/create_sibling.sh
@@ -5,7 +5,7 @@
set -eu
REQUIREMENTS=( wget gunzip git dd e2fsck resize2fs parted losetup qemu-system-x86_64 )
-DEBREQUIREMENTS=( wget gzip git parted qemu-system-x86 qemu-user-static bmap-tools )
+DEBREQUIREMENTS=( wget gzip git parted qemu-system-x86 qemu-user-static )
REPO_DIR="$(dirname "$(dirname "$(realpath "$0")")")"
TMP_DIR="${REPO_DIR}/tmp"
MNT_DIR="${TMP_DIR}/mnt"
@@ -93,11 +93,8 @@ function provide_raspbian() {
function setup_raspbian(){
# Detect the ability to create sparse files
- if [ "${OPT_SPARSE}" -eq 0 ];
- then
- which bmaptool >/dev/null 2>&1
- if [ $? -eq 0 ];
- then
+ if [ "${OPT_SPARSE}" -eq 0 ]; then
+ if [ which bmaptool -eq 0 ]; then
echo "[+] Defaulting to sparse image generation as bmaptool is available"
OPT_SPARSE=1
else
From 79871cd29149472e8717c7c0ce5367a95a3ed510 Mon Sep 17 00:00:00 2001
From: gh0stshell
Date: Thu, 3 Oct 2019 16:21:02 -0700
Subject: [PATCH 56/80] Updated depends, bmap check update
Removed bmap-tools from depends as the check on line 96 looks for bmaptools and would use it if available if not continue to build, but have it as a depend check made the check null and if someone is on a kernel/file-system that does not support SEEK_HOLE and SEEK_DATA the script just fails.
Fixed bmap-tools check as the line which bmaptool >/dev/null 2>&1 does not return 0 so it kept ending at this line, if bmap-tools were not installed
The original code below looks for sparse to be 0 and if which bmaptool >/dev/null 2>&1 returns 0 to use bmap-tools, but I think its the reverse so swapped the last then and else sections as it would then look if sparse is 0 and which bmaptool >/dev/null 2>&1 is 0 to not use bmap-tools, but if it is 1 to use bmap-tools. If tool is available = 1 use bmap-tools, if tools is unavailable=0 do not use bmap-tools:
if [ "${OPT_SPARSE}" -eq 0 ];
then
which bmaptool >/dev/null 2>&1
if [ $? -eq 0 ];
then
echo "[+] Defaulting to sparse image generation as bmaptool is available"
OPT_SPARSE=1
---
scripts/create_sibling.sh | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/scripts/create_sibling.sh b/scripts/create_sibling.sh
index 973e95ec..8dfc2522 100755
--- a/scripts/create_sibling.sh
+++ b/scripts/create_sibling.sh
@@ -95,10 +95,11 @@ function setup_raspbian(){
# Detect the ability to create sparse files
if [ "${OPT_SPARSE}" -eq 0 ]; then
if [ which bmaptool -eq 0 ]; then
+ echo "[!] bmaptool not available, not creating a sparse image"
+
+ else
echo "[+] Defaulting to sparse image generation as bmaptool is available"
OPT_SPARSE=1
- else
- echo "[!] bmaptool not available, not creating a sparse image"
fi
fi
From 31db4d062cb8a52300c084094b30337b296556c3 Mon Sep 17 00:00:00 2001
From: Forrest Fuqua
Date: Thu, 3 Oct 2019 19:48:44 -0400
Subject: [PATCH 57/80] Update Inky Render to not crash the script
Updated Inky so in case the render cannot display anything to the hardware everything else works (like the webbrowser) Other renders should do the same
---
.../rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
index ed6b188f..76e9a24d 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/ui/display.py
@@ -190,7 +190,10 @@ class Display(View):
])
self._display.set_image(img_buffer)
- self._display.show()
+ try:
+ self._display.show()
+ except:
+ print("")
def _papirus_render(self):
self._display.display(self._canvas)
From 01535176ed10695bc68d886ad21f6d7f8f1f4757 Mon Sep 17 00:00:00 2001
From: Forrest Fuqua
Date: Thu, 3 Oct 2019 19:49:38 -0400
Subject: [PATCH 58/80] Update create_sibling.sh
Fixed Array Call for the gender
---
scripts/create_sibling.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/create_sibling.sh b/scripts/create_sibling.sh
index f2f5c5fd..b7cbbeb0 100755
--- a/scripts/create_sibling.sh
+++ b/scripts/create_sibling.sh
@@ -341,7 +341,7 @@ gender[1]="girl"
rand=$[ $RANDOM % 2 ]
-echo -e "[+] Congratz, it's a ${arr[$rand]} (⌐■_■)!"
+echo -e "[+] Congratz, it's a ${gender[$rand]} (⌐■_■)!"
echo -e "[+] One more step: dd if=../${PWNI_OUTPUT} of= bs=4M status=progress"
if [ "${OPT_SPARSE}" -eq 1 ];
From b7133e00404134cba71a8f214d6ae11bdbde9751 Mon Sep 17 00:00:00 2001
From: gh0stshell
Date: Thu, 3 Oct 2019 19:07:13 -0700
Subject: [PATCH 59/80] Added known bug
Added known package bug, not sure what it affects, only shows during create script run
---
README.md | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 9a918906..b1dfb15c 100644
--- a/README.md
+++ b/README.md
@@ -38,9 +38,17 @@ For hackers to learn reinforcement learning, WiFi networking and have an excuse
- [Project Twitter](https://twitter.com/pwnagotchi)
- [Project Website](https://pwnagotchi.ai/)
+## Known Bugs
+
+- GLib-ERROR **: 20:50:46.361: getauxval () failed: No such file or directory
+
+Affected DEB & Versions: QEMU <=2.11
+
+Fix: Upgrade QEMU to >=3.1
+
+Bug Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=923289
+
## License
`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
-
-
From b8e6f9f979d8f1d34c2132400014e04b13285149 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Fri, 4 Oct 2019 09:11:32 +0200
Subject: [PATCH 60/80] Upload via python library
---
.../pwnagotchi/plugins/default/wpa-sec.py | 56 ++++++++++---------
1 file changed, 30 insertions(+), 26 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
index 64df84e7..30e136ef 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
@@ -1,25 +1,22 @@
__author__ = '33197631+dadav@users.noreply.github.com'
__version__ = '1.0.0'
-__name__ = 'wpa_sec'
+__name__ = 'wpa-sec'
__license__ = 'GPL3'
__description__ = 'This plugin automatically uploades handshakes to https://wpa-sec.stanev.org'
import os
import logging
-import subprocess
+import requests
READY = False
API_KEY = None
ALREADY_UPLOADED = None
-# INSTALLATION:
-## apt-get install libcurl4-openssl-dev
-## https://github.com/ZerBea/hcxtools.git
-## cd hcxtools; gcc wlancap2wpasec.c -o wlancap2wpasec -lcurl
-## mv wlancap2wpasec /usr/bin/
-
def on_loaded():
+ """
+ Gets called when the plugin gets loaded
+ """
global READY
global API_KEY
global ALREADY_UPLOADED
@@ -28,50 +25,57 @@ def on_loaded():
logging.error("WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org")
return
- try:
- subprocess.call("wlancap2wpasec -h >/dev/null".split(), stdout=open(os.devnull, 'wb'))
- except OSError:
- logging.error("WPA_SEC: Can't find wlancap2wpasec. Install hcxtools to use this plugin!")
- return
-
try:
with open('/root/.wpa_sec_uploads', 'r') as f:
ALREADY_UPLOADED = f.read().splitlines()
except OSError:
- logging.error('WPA_SEC: No upload-file found.')
+ logging.warning('WPA_SEC: No upload-file found.')
ALREADY_UPLOADED = []
READY = True
-def _upload_to_wpasec(path):
- try:
- subprocess.call(f"wlancap2wpasec -k {API_KEY} {path}".split(), stdout=open(os.devnull, 'wb'))
- except OSError as os_e:
- logging.error(f"WPA_SEC: Error while uploading {path}")
- raise os_e
+def _upload_to_wpasec(path, timeout=30):
+ """
+ Uploads the file to wpa-sec.stanev.org
+ """
+ with open(path, 'rb') as file_to_upload:
+ headers = {'key': API_KEY}
+ payload = {'file': file_to_upload}
+
+ try:
+ requests.post('https://wpa-sec.stanev.org/?submit',
+ headers=headers,
+ files=payload,
+ timeout=timeout)
+ except requests.exceptions.RequestException as e:
+ logging.error(f"WPA_SEC: Got an exception while uploading {path} -> {e}")
+ raise e
-# called in manual mode when there's internet connectivity
def on_internet_available(display, config, log):
+ """
+ Called in manual mode when there's internet connectivity
+ """
if READY:
-
handshake_dir = config['bettercap']['handshakes']
handshake_filenames = os.listdir(handshake_dir)
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames]
handshake_new = set(handshake_paths) - set(ALREADY_UPLOADED)
if handshake_new:
- logging.info("Internet connectivity detected.\
+ logging.info("WPA_SEC: Internet connectivity detected.\
Uploading new handshakes to wpa-sec.stanev.org")
for idx, handshake in enumerate(handshake_new):
- display.set('status', "Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new})")
+ display.set('status', f"Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new)})")
display.update(force=True)
try:
_upload_to_wpasec(handshake)
ALREADY_UPLOADED.append(handshake)
with open('/root/.wpa_sec_uploads', 'a') as f:
f.write(handshake + "\n")
- except OSError:
+ except requests.exceptions.RequestException:
pass
+ except OSError as os_e:
+ logging.error(f"WPA_SEC: Got the following error: {os_e}")
From 20a89f732344c58e680d1c9de4ab101d7b22d821 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Fri, 4 Oct 2019 09:24:42 +0200
Subject: [PATCH 61/80] Add code
---
.../plugins/default/onlinehashcrack.py | 83 +++++++++++++++++++
1 file changed, 83 insertions(+)
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
new file mode 100644
index 00000000..5715be6b
--- /dev/null
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
@@ -0,0 +1,83 @@
+__author__ = '33197631+dadav@users.noreply.github.com'
+__version__ = '1.0.0'
+__name__ = 'onlinehashcrack'
+__license__ = 'GPL3'
+__description__ = 'This plugin automatically uploades handshakes to https://onlinehashcrack.com'
+
+import os
+import logging
+import requests
+
+READY = False
+EMAIL = None
+ALREADY_UPLOADED = None
+
+
+def on_loaded():
+ """
+ Gets called when the plugin gets loaded
+ """
+ global READY
+ global EMAIL
+ global ALREADY_UPLOADED
+
+ if not EMAIL:
+ logging.error("OHC: EMAIL isn't set. Can't upload to onlinehashcrack.com")
+ return
+
+ try:
+ with open('/root/.ohc_uploads', 'r') as f:
+ ALREADY_UPLOADED = f.read().splitlines()
+ except OSError:
+ logging.warning('OHC: No upload-file found.')
+ ALREADY_UPLOADED = []
+
+ READY = True
+
+
+def _upload_to_ohc(path, timeout=30):
+ """
+ Uploads the file to onlinehashcrack.com
+ """
+ with open(path, 'rb') as file_to_upload:
+ data = {'email': EMAIL}
+ payload = {'file': file_to_upload}
+
+ try:
+ result = requests.post('https://api.onlinehashcrack.com',
+ data=data,
+ files=payload,
+ timeout=timeout)
+ if 'already been sent' in result.text:
+ logging.warning(f"{path} was already uploaded.")
+ except requests.exceptions.RequestException as e:
+ logging.error(f"OHC: Got an exception while uploading {path} -> {e}")
+ raise e
+
+
+def on_internet_available(display, config, log):
+ """
+ Called in manual mode when there's internet connectivity
+ """
+ if READY:
+ handshake_dir = config['bettercap']['handshakes']
+ handshake_filenames = os.listdir(handshake_dir)
+ handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames]
+ handshake_new = set(handshake_paths) - set(ALREADY_UPLOADED)
+
+ if handshake_new:
+ logging.info("OHC: Internet connectivity detected. Uploading new handshakes to onelinehashcrack.com")
+
+ for idx, handshake in enumerate(handshake_new):
+ display.set('status', f"Uploading handshake to onlinehashcrack.com ({idx + 1}/{len(handshake_new)})")
+ display.update(force=True)
+ try:
+ _upload_to_ohc(handshake)
+ ALREADY_UPLOADED.append(handshake)
+ with open('/root/.ohc_uploads', 'a') as f:
+ f.write(handshake + "\n")
+ except requests.exceptions.RequestException:
+ pass
+ except OSError as os_e:
+ logging.error(f"OHC: Got the following error: {os_e}")
+
From bc10be69a0c0ceefa925497ef7fae5c863bd4dae Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Fri, 4 Oct 2019 09:26:08 +0200
Subject: [PATCH 62/80] Add already submitted check
---
.../pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
index 30e136ef..e3267e0e 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
@@ -44,10 +44,12 @@ def _upload_to_wpasec(path, timeout=30):
payload = {'file': file_to_upload}
try:
- requests.post('https://wpa-sec.stanev.org/?submit',
+ result = requests.post('https://wpa-sec.stanev.org/?submit',
headers=headers,
files=payload,
timeout=timeout)
+ if ' already submitted' in result.text:
+ logging.warning(f"{path} was already submitted.")
except requests.exceptions.RequestException as e:
logging.error(f"WPA_SEC: Got an exception while uploading {path} -> {e}")
raise e
From 11f35f1230ddc2bc500b4d29ac82cd85b4464907 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Fri, 4 Oct 2019 09:32:04 +0200
Subject: [PATCH 63/80] Be a lil bit more verbose
---
.../scripts/pwnagotchi/plugins/default/onlinehashcrack.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
index 5715be6b..39f73dd8 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
@@ -76,6 +76,7 @@ def on_internet_available(display, config, log):
ALREADY_UPLOADED.append(handshake)
with open('/root/.ohc_uploads', 'a') as f:
f.write(handshake + "\n")
+ logging.info(f"OHC: Successfuly uploaded {handshake}")
except requests.exceptions.RequestException:
pass
except OSError as os_e:
From d52ea8718f306418ab85e9c354be4eee412f365f Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Fri, 4 Oct 2019 09:33:11 +0200
Subject: [PATCH 64/80] Be a lil bit more verbose
---
.../pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
index e3267e0e..b4ee86c7 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
@@ -77,6 +77,7 @@ def on_internet_available(display, config, log):
ALREADY_UPLOADED.append(handshake)
with open('/root/.wpa_sec_uploads', 'a') as f:
f.write(handshake + "\n")
+ logging.info(f"WPA_SEC: Successfuly uploaded {handshake}")
except requests.exceptions.RequestException:
pass
except OSError as os_e:
From b402f0dad3675ce4677433a966001394010b31e2 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 10:42:25 +0200
Subject: [PATCH 65/80] misc: small fix or general refactoring i did not bother
commenting
---
README.md | 13 +------------
docs/dev.md | 8 ++++++++
2 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index b1dfb15c..c7625f22 100644
--- a/README.md
+++ b/README.md
@@ -38,17 +38,6 @@ For hackers to learn reinforcement learning, WiFi networking and have an excuse
- [Project Twitter](https://twitter.com/pwnagotchi)
- [Project Website](https://pwnagotchi.ai/)
-## Known Bugs
-
-- GLib-ERROR **: 20:50:46.361: getauxval () failed: No such file or directory
-
-Affected DEB & Versions: QEMU <=2.11
-
-Fix: Upgrade QEMU to >=3.1
-
-Bug Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=923289
-
## License
-`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
-
+`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It's released under the GPL3 license.
\ No newline at end of file
diff --git a/docs/dev.md b/docs/dev.md
index 09d2a465..75b7ea0f 100644
--- a/docs/dev.md
+++ b/docs/dev.md
@@ -22,6 +22,14 @@ usage: ./scripts/create_sibling.sh [OPTIONS]
-h # Show this help
```
+#### Known Issues
+
+`GLib-ERROR **: 20:50:46.361: getauxval () failed: No such file or directory`
+
+- Affected DEB & Versions: QEMU <= 2.11
+- Fix: Upgrade QEMU to >= 3.1
+- Bug Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=923289
+
## Adding a Language
If you want to add a language use the `language.sh` script. If you want to add for example the language **italian** you would type:
From a99c21bbc5e10e4eaab2dc811e68919ec5e26e39 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Fri, 4 Oct 2019 10:38:30 +0200
Subject: [PATCH 66/80] Configure plugins via config.yml
---
sdcard/rootfs/root/pwnagotchi/config.yml | 24 ++++++++++++-------
.../scripts/pwnagotchi/plugins/__init__.py | 12 +++++++---
.../pwnagotchi/plugins/default/example.py | 3 +++
.../plugins/default/onlinehashcrack.py | 8 +++----
.../pwnagotchi/plugins/default/twitter.py | 7 +++---
.../pwnagotchi/plugins/default/wpa-sec.py | 5 ++--
6 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index 5d786c59..ee91c79a 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -6,8 +6,21 @@ main:
custom_plugins:
# which plugins to load and enable
plugins:
- - gps
- - twitter
+ gps:
+ enabled: false
+ twitter:
+ enabled: false
+ consumer_key: aaa
+ consumer_secret: aaa
+ access_token_key: aaa
+ access_token_secret: aaa
+ onlinehashcrack:
+ enabled: false
+ email: ~
+ wpa-sec:
+ enabled: false
+ api_key: ~
+
# monitor interface to use
iface: mon0
# command to run to bring the mon interface up in case it's not up already
@@ -114,13 +127,6 @@ ui:
address: '10.0.0.2'
port: 8080
-# twitter bot data
-twitter:
- enabled: false
- consumer_key: aaa
- consumer_secret: aaa
- access_token_key: aaa
- access_token_secret: aaa
# bettercap rest api configuration
bettercap:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
index b6f33f3f..38d29e73 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/__init__.py
@@ -43,12 +43,18 @@ def load_from_path(path, enabled=()):
def load(config):
- enabled = config['main']['plugins']
+ enabled = [name for name, options in config['main']['plugins'].items() if 'enabled' in options and options['enabled']]
custom_path = config['main']['custom_plugins'] if 'custom_plugins' in config['main'] else None
# load default plugins
- load_from_path(default_path, enabled=enabled)
+ loaded = load_from_path(default_path, enabled=enabled)
+ # set the options
+ for name, plugin in loaded.items():
+ plugin.__dict__['OPTIONS'] = config['main']['plugins'][name]
# load custom ones
if custom_path is not None:
- load_from_path(custom_path, enabled=enabled)
+ loaded = load_from_path(custom_path, enabled=enabled)
+ # set the options
+ for name, plugin in loaded.items():
+ plugin.__dict__['OPTIONS'] = config['main']['plugins'][name]
on('loaded')
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
index b425d6ee..dfca16a7 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
@@ -11,6 +11,9 @@ from pwnagotchi.ui.view import BLACK
import pwnagotchi.ui.fonts as fonts
+# Will be set with the options in config.yml config['main']['plugins'][__name__]
+OPTIONS = dict()
+
# called when the plugin is loaded
def on_loaded():
logging.warning("WARNING: plugin %s should be disabled!" % __name__)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
index 39f73dd8..249ea19a 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/onlinehashcrack.py
@@ -9,8 +9,8 @@ import logging
import requests
READY = False
-EMAIL = None
ALREADY_UPLOADED = None
+OPTIONS = dict()
def on_loaded():
@@ -21,8 +21,8 @@ def on_loaded():
global EMAIL
global ALREADY_UPLOADED
- if not EMAIL:
- logging.error("OHC: EMAIL isn't set. Can't upload to onlinehashcrack.com")
+ if not 'email' in OPTIONS or ('email' in OPTIONS and OPTIONS['email'] is None):
+ logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com")
return
try:
@@ -40,7 +40,7 @@ def _upload_to_ohc(path, timeout=30):
Uploads the file to onlinehashcrack.com
"""
with open(path, 'rb') as file_to_upload:
- data = {'email': EMAIL}
+ data = {'email': OPTIONS['email']}
payload = {'file': file_to_upload}
try:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
index 03aa2514..560903a0 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/twitter.py
@@ -7,6 +7,7 @@ __description__ = 'This plugin creates tweets about the recent activity of pwnag
import logging
from pwnagotchi.voice import Voice
+OPTIONS = dict()
def on_loaded():
logging.info("twitter plugin loaded.")
@@ -14,7 +15,7 @@ def on_loaded():
# called in manual mode when there's internet connectivity
def on_internet_available(ui, config, log):
- if config['twitter']['enabled'] and log.is_new() and log.handshakes > 0:
+ if log.is_new() and log.handshakes > 0:
try:
import tweepy
except ImportError:
@@ -32,8 +33,8 @@ def on_internet_available(ui, config, log):
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'])
+ 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_log_tweet(log)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
index b4ee86c7..68e41717 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/wpa-sec.py
@@ -9,7 +9,6 @@ import logging
import requests
READY = False
-API_KEY = None
ALREADY_UPLOADED = None
@@ -21,7 +20,7 @@ def on_loaded():
global API_KEY
global ALREADY_UPLOADED
- if not API_KEY:
+ if not 'api_key' in OPTIONS or ('api_key' in OPTIONS and OPTIONS['api_key'] is None):
logging.error("WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org")
return
@@ -40,7 +39,7 @@ def _upload_to_wpasec(path, timeout=30):
Uploads the file to wpa-sec.stanev.org
"""
with open(path, 'rb') as file_to_upload:
- headers = {'key': API_KEY}
+ headers = {'key': OPTIONS['api_key']}
payload = {'file': file_to_upload}
try:
From 05e0cd161d4243f3740b917b1c0c224f6c16b8f6 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Fri, 4 Oct 2019 12:22:16 +0200
Subject: [PATCH 67/80] Fix name conflict
---
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
index 023fa2e1..98f8aabe 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/agent.py
@@ -129,11 +129,11 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
wifi_running = self.is_module_running('wifi')
if wifi_running and restart:
logging.debug("restarting wifi module ...")
- self.restart('wifi.recon')
+ self.restart_module('wifi.recon')
self.run('wifi.clear')
elif not wifi_running:
logging.debug("starting wifi module ...")
- self.start('wifi.recon')
+ self.start_module('wifi.recon')
self.start_advertising()
@@ -388,10 +388,10 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
return m['running']
return False
- def start(self, module):
+ def start_module(self, module):
self.run('%s on' % module)
- def restart(self, module):
+ def restart_module(self, module):
self.run('%s off; %s on' % (module, module))
def _has_handshake(self, bssid):
From 6e4fe624ecdb369f52edaf22d7e16a7790475b2e Mon Sep 17 00:00:00 2001
From: Ross Simpson
Date: Fri, 4 Oct 2019 22:01:44 +1000
Subject: [PATCH 68/80] Fix incorrect config filename in update script
The update script backs up the config file to `/root/config.bak`, but
then tries to restore it from `/root/config.yml.bak` (which obviously
won't be found).
This looks like a typo in the backup command, so update that command to
use the same filename as the restore command.
Signed-off-by: Ross Simpson
---
scripts/update_pwnagotchi.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/update_pwnagotchi.sh b/scripts/update_pwnagotchi.sh
index 734ed4c2..9299f1a7 100755
--- a/scripts/update_pwnagotchi.sh
+++ b/scripts/update_pwnagotchi.sh
@@ -89,7 +89,7 @@ fi
if [ $BACKUPCONFIG -eq 1 ]; then
echo "[+] Creating backup of config.yml and hostname references"
- mv /root/pwnagotchi/config.yml /root/config.bak -f
+ mv /root/pwnagotchi/config.yml /root/config.yml.bak -f
mv /etc/hosts /root/hosts.bak -f
mv /etc/hostname /root/hostname.bak -f
mv /etc/motd /etc/motd.bak -f
From aedf670bcf3b4ce15903fb143fddf5a7c7ca42f0 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 15:38:07 +0200
Subject: [PATCH 69/80] misc: small fix or general refactoring i did not bother
commenting
---
.../pwnagotchi/scripts/pwnagotchi/plugins/default/example.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
index dfca16a7..c18177c2 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/example.py
@@ -84,7 +84,7 @@ def on_ai_best_reward(agent, reward):
pass
-# called when the AI got the best reward so far
+# called when the AI got the worst reward so far
def on_ai_worst_reward(agent, reward):
pass
From 3c3ae2b30b86402aa7b46b6263d0834daabca617 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 18:27:48 +0200
Subject: [PATCH 70/80] fixed docs
---
docs/configure.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/configure.md b/docs/configure.md
index b9d8f531..733abc96 100644
--- a/docs/configure.md
+++ b/docs/configure.md
@@ -4,7 +4,7 @@ Once you wrote the image file on the SD card, there're a few steps you'll have t
You'll need to configure it with a static IP address:
-- IP: `10.0.0.2`
+- IP: `10.0.0.1`
- Netmask: `255.255.255.0`
- Gateway: `10.0.0.1`
- DNS (if required): `8.8.8.8` (or whatever)
From 22f06df0a38c59b858dfd10d19e7db7ab1242caf Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Fri, 4 Oct 2019 19:03:33 +0200
Subject: [PATCH 71/80] added hh mm ss localization (fix #134)
---
sdcard/rootfs/root/pwnagotchi/scripts/main.py | 2 +-
.../scripts/pwnagotchi/locale/voice.pot | 19 +++++++++++++++++++
.../root/pwnagotchi/scripts/pwnagotchi/log.py | 14 ++++++++------
3 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/main.py b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
index a593353e..60469e82 100755
--- a/sdcard/rootfs/root/pwnagotchi/scripts/main.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/main.py
@@ -46,7 +46,7 @@ if args.do_clear:
elif args.do_manual:
logging.info("entering manual mode ...")
- log = SessionParser(config['main']['log'])
+ log = SessionParser(config)
logging.info(
"the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
log.duration_human,
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
index fbeba17d..c11874e3 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
@@ -186,3 +186,22 @@ msgid ""
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
+
+msgid "hours"
+msgstr ""
+
+msgid "hour"
+msgstr ""
+
+msgid "minutes"
+msgstr ""
+
+msgid "minute"
+msgstr ""
+
+msgid "hours"
+msgstr ""
+
+msgid "hour"
+msgstr ""
+
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
index 8648521d..c6a108f3 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
@@ -1,10 +1,10 @@
-import os
import hashlib
import time
import re
import os
from datetime import datetime
+from pwnagotchi.voice import Voice
from pwnagotchi.mesh.peer import Peer
from file_read_backwards import FileReadBackwards
@@ -125,17 +125,19 @@ class SessionParser(object):
self.duration = '%02d:%02d:%02d' % (hours, mins, secs)
self.duration_human = []
if hours > 0:
- self.duration_human.append('%d hours' % hours)
+ self.duration_human.append('%d %s' % (hours, self.voice.custom('hours' if hours > 1 else 'hour')))
if mins > 0:
- self.duration_human.append('%d minutes' % mins)
+ self.duration_human.append('%d %s' % (mins, self.voice.custom('minutes' if mins > 1 else 'minute')))
if secs > 0:
- self.duration_human.append('%d seconds' % secs)
+ self.duration_human.append('%d %s' % (secs, self.voice.custom('seconds' if secs > 1 else 'second')))
self.duration_human = ', '.join(self.duration_human)
self.avg_reward /= (self.epochs if self.epochs else 1)
- def __init__(self, path='/var/log/pwnagotchi.log'):
- self.path = path
+ 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 = ''
From 2bbe5cc9c3fe8c8a97352a88c3670e0a083e6375 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Sat, 5 Oct 2019 11:19:53 +0200
Subject: [PATCH 72/80] Add auto-backup plugin
---
sdcard/rootfs/root/pwnagotchi/config.yml | 7 +++
.../pwnagotchi/plugins/default/auto-backup.py | 63 +++++++++++++++++++
2 files changed, 70 insertions(+)
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index ee91c79a..33ea10ff 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -6,6 +6,13 @@ main:
custom_plugins:
# which plugins to load and enable
plugins:
+ auto-backup:
+ enabled: false
+ interval: 1 # every day
+ files:
+ - /root/brain.nn
+ backup_cmd: 'tar czf /tmp/backup.tar.gz {files}'
+ upload_cmd: 'scp /tmp/backup.tar.gz 10.0.0.1:/backups/backup-$(date).tar.gz'
gps:
enabled: false
twitter:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
new file mode 100644
index 00000000..348f8414
--- /dev/null
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
@@ -0,0 +1,63 @@
+__author__ = '33197631+dadav@users.noreply.github.com'
+__version__ = '1.0.0'
+__name__ = 'auto-backup'
+__license__ = 'GPL3'
+__description__ = 'This plugin backups files when internet is availaible.'
+
+import os
+import logging
+import subprocess
+from datetime import datetime
+
+OPTIONS = dict()
+LAST_BACKUP = None
+READY = False
+
+def on_loaded():
+ """
+ Gets called when the plugin gets loaded
+ """
+ global READY
+ global LAST_BACKUP
+
+ if 'files' not in OPTIONS or ('files' in OPTIONS and OPTIONS['files'] is None):
+ logging.error("AUTO-BACKUP: No files to backup.")
+ return
+
+ if 'interval' not in OPTIONS or ('interval' in OPTIONS and OPTIONS['interval'] is None):
+ logging.error("AUTO-BACKUP: Interval is not set.")
+ return
+
+ if 'backup_cmd' not in OPTIONS or ('backup_cmd' in OPTIONS and OPTIONS['backup_cmd'] is None):
+ logging.error("AUTO-BACKUP: No backup_cmd given.")
+ return
+
+ if os.path.exists('/root/.auto-backup'):
+ LAST_BACKUP = datetime.fromtimestamp(os.path.getmtime('/root/.auto-backup'))
+
+ READY = True
+
+
+def on_internet_available(display, config, log):
+ """
+ Called in manual mode when there's internet connectivity
+ """
+ global LAST_BACKUP
+
+ if READY:
+ if LAST_BACKUP is not None:
+ if (datetime.now() - LAST_BACKUP).days < OPTIONS['interval']:
+ return
+
+ files_to_backup = " ".join(OPTIONS['files'])
+ try:
+ subprocess.call(OPTIONS['backup_cmd'].format(files=files_to_backup).split(), stdout=open(os.devnull, 'wb'))
+ if 'upload_cmd' in OPTIONS and OPTIONS['upload_cmd'] is not None:
+ subprocess.call(OPTIONS['upload_cmd'].split(), stdout=open(os.devnull, 'wb'))
+ logging.info("AUTO-BACKUP: Successfuly ran backup commands.")
+ LAST_BACKUP = datetime.now()
+ with open('/root/.auto-backup', 'w') as f:
+ f.write('success')
+ except OSError as os_e:
+ logging.info(f"AUTO-BACKUP: Error: {os_e}")
+
From 7db7874d8e1a1aef80320e70ebed43610a305f5b Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Sat, 5 Oct 2019 11:32:54 +0200
Subject: [PATCH 73/80] More general variable
---
sdcard/rootfs/root/pwnagotchi/config.yml | 5 +++--
.../scripts/pwnagotchi/plugins/default/auto-backup.py | 9 ++++-----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index 33ea10ff..24bcdb79 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -11,8 +11,9 @@ main:
interval: 1 # every day
files:
- /root/brain.nn
- backup_cmd: 'tar czf /tmp/backup.tar.gz {files}'
- upload_cmd: 'scp /tmp/backup.tar.gz 10.0.0.1:/backups/backup-$(date).tar.gz'
+ commands:
+ - 'tar czf /tmp/backup.tar.gz {files}'
+ - 'scp /tmp/backup.tar.gz 10.0.0.1:/backups/backup-$(date).tar.gz'
gps:
enabled: false
twitter:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
index 348f8414..1e4acb9a 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
@@ -28,8 +28,8 @@ def on_loaded():
logging.error("AUTO-BACKUP: Interval is not set.")
return
- if 'backup_cmd' not in OPTIONS or ('backup_cmd' in OPTIONS and OPTIONS['backup_cmd'] is None):
- logging.error("AUTO-BACKUP: No backup_cmd given.")
+ if 'commands' not in OPTIONS or ('commands' in OPTIONS and OPTIONS['commands'] is None):
+ logging.error("AUTO-BACKUP: No commands given.")
return
if os.path.exists('/root/.auto-backup'):
@@ -51,9 +51,8 @@ def on_internet_available(display, config, log):
files_to_backup = " ".join(OPTIONS['files'])
try:
- subprocess.call(OPTIONS['backup_cmd'].format(files=files_to_backup).split(), stdout=open(os.devnull, 'wb'))
- if 'upload_cmd' in OPTIONS and OPTIONS['upload_cmd'] is not None:
- subprocess.call(OPTIONS['upload_cmd'].split(), stdout=open(os.devnull, 'wb'))
+ for cmd in OPTIONS['commands']:
+ subprocess.call(cmd.format(files=files_to_backup).split(), stdout=open(os.devnull, 'wb'))
logging.info("AUTO-BACKUP: Successfuly ran backup commands.")
LAST_BACKUP = datetime.now()
with open('/root/.auto-backup', 'w') as f:
From 03094264f0830e202c6e934c89290392e52c4683 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Sat, 5 Oct 2019 12:55:37 +0200
Subject: [PATCH 74/80] fix: possible fix for ENOBUFS error while advertising
(fixes #141)
---
.../root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py
index 90374c69..ff797a35 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/mesh/advertise.py
@@ -86,7 +86,9 @@ class Advertiser(object):
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)
+ sendp(self._frame, iface=self._iface, verbose=False, count=1, inter=self._period)
+ except OSError as ose:
+ logging.warning("non critical issue while sending advertising packet: %s" % ose)
except Exception as e:
logging.exception("error")
time.sleep(self._period)
From e9b9a1edb920ebe601acebf117e32228f1872cea Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Sat, 5 Oct 2019 13:25:34 +0200
Subject: [PATCH 75/80] new: new auto-update plugin
---
sdcard/rootfs/root/pwnagotchi/config.yml | 3 +
.../pwnagotchi/plugins/default/auto-backup.py | 6 +-
.../pwnagotchi/plugins/default/auto-update.py | 59 +++++++++++++++++++
3 files changed, 65 insertions(+), 3 deletions(-)
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-update.py
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index 24bcdb79..7a2fa4f2 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -6,6 +6,9 @@ main:
custom_plugins:
# which plugins to load and enable
plugins:
+ auto-update:
+ enabled: false
+ interval: 1 # every day
auto-backup:
enabled: false
interval: 1 # every day
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
index 1e4acb9a..5bc186d0 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
@@ -10,7 +10,7 @@ import subprocess
from datetime import datetime
OPTIONS = dict()
-LAST_BACKUP = None
+LAST_UPDATE = None
READY = False
def on_loaded():
@@ -18,7 +18,7 @@ def on_loaded():
Gets called when the plugin gets loaded
"""
global READY
- global LAST_BACKUP
+ global LAST_UPDATE
if 'files' not in OPTIONS or ('files' in OPTIONS and OPTIONS['files'] is None):
logging.error("AUTO-BACKUP: No files to backup.")
@@ -42,7 +42,7 @@ def on_internet_available(display, config, log):
"""
Called in manual mode when there's internet connectivity
"""
- global LAST_BACKUP
+ global LAST_UPDATE
if READY:
if LAST_BACKUP is not None:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-update.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-update.py
new file mode 100644
index 00000000..ca2d6fc6
--- /dev/null
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-update.py
@@ -0,0 +1,59 @@
+__author__ = 'evilsocket@gmail.com'
+__version__ = '1.0.0'
+__name__ = 'auto-update'
+__license__ = 'GPL3'
+__description__ = 'This plugin performs an "apt update && apt upgrade" when internet is availaible.'
+
+import os
+import logging
+import subprocess
+from datetime import datetime
+
+OPTIONS = dict()
+LAST_UPDATE = None
+READY = False
+STATUS_FILE = '/root/.auto-update'
+
+
+def on_loaded():
+ global READY
+ global LAST_UPDATE
+
+ if 'interval' not in OPTIONS or ('interval' in OPTIONS and OPTIONS['interval'] is None):
+ logging.error("AUTO-UPDATE: Interval is not set.")
+ return
+
+ if os.path.exists(STATUS_FILE):
+ LAST_UPDATE = datetime.fromtimestamp(os.path.getmtime(STATUS_FILE))
+
+ READY = True
+
+
+def on_internet_available(display, config, log):
+ global LAST_UPDATE
+
+ if READY:
+ if LAST_UPDATE is not None:
+ if (datetime.now() - LAST_UPDATE).days < OPTIONS['interval']:
+ return
+
+ try:
+ logging.info("AUTO-UPDATE: updating packages index ...")
+
+ update = subprocess.Popen('apt update -y', shell=True, stdin=None,
+ stdout=open("/dev/null", "w"), stderr=None, executable="/bin/bash")
+ update.wait()
+
+ logging.info("AUTO-UPDATE: updating packages ...")
+
+ upgrade = subprocess.Popen('apt upgrade -y', shell=True, stdin=None,
+ stdout=open("/dev/null", "w"), stderr=None, executable="/bin/bash")
+ upgrade.wait()
+
+ logging.info("AUTO-UPDATE: complete.")
+
+ LAST_UPDATE = datetime.now()
+ with open(STATUS_FILE, 'w') as f:
+ f.write('success')
+ except Exception as e:
+ logging.exception("AUTO-UPDATE ERROR")
From 0edd0e9d49ad05b8d76399512d9961be4d3a261a Mon Sep 17 00:00:00 2001
From: swedishmike
Date: Sat, 5 Oct 2019 12:32:53 +0100
Subject: [PATCH 76/80] Updated existing translations
---
sdcard/rootfs/root/pwnagotchi/config.yml | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index 7a2fa4f2..175d9909 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -1,6 +1,6 @@
# main algorithm configuration
main:
- # currently implemented: en (default), de, nl, it
+ # currently implemented: en (default), de, el, fr, it, mk, nl
lang: en
# custom plugins path, if null only default plugins with be loaded
custom_plugins:
@@ -166,6 +166,3 @@ bettercap:
- wifi.ap.new
- wifi.ap.lost
- mod.started
-
-
-
From 918da69cba98d5957c8f0ba454110911e2fb4e27 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Sat, 5 Oct 2019 14:15:36 +0200
Subject: [PATCH 77/80] Fix translation
---
.../pwnagotchi/locale/de/LC_MESSAGES/voice.mo | Bin 3902 -> 4126 bytes
.../pwnagotchi/locale/de/LC_MESSAGES/voice.po | 20 +++++++++++++++++-
.../pwnagotchi/locale/el/LC_MESSAGES/voice.po | 20 +++++++++++++++++-
.../pwnagotchi/locale/fr/LC_MESSAGES/voice.po | 20 +++++++++++++++++-
.../pwnagotchi/locale/it/LC_MESSAGES/voice.mo | Bin 3759 -> 3966 bytes
.../pwnagotchi/locale/it/LC_MESSAGES/voice.po | 20 +++++++++++++++++-
.../pwnagotchi/locale/mk/LC_MESSAGES/voice.po | 20 +++++++++++++++++-
.../pwnagotchi/locale/nl/LC_MESSAGES/voice.po | 20 +++++++++++++++++-
.../scripts/pwnagotchi/locale/voice.pot | 15 ++++++-------
.../root/pwnagotchi/scripts/pwnagotchi/log.py | 6 +++---
.../pwnagotchi/scripts/pwnagotchi/voice.py | 20 ++++++++++++++++--
11 files changed, 142 insertions(+), 19 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/de/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/de/LC_MESSAGES/voice.mo
index 9a26d44bfa3a51370d4f0dc64d46f2b5f5d99314..fd5058bf9014298b2e0eb5961ac5631aaafd9374 100644
GIT binary patch
delta 1258
zcmY+^Pe>GD7{~F)T>n&V)~2aj=~!)<>uzlp1x6rI5f~kWpp!*Ap+qA%D-je6bqG&U
zVTS@C_Sz-30;8f^P&f0`p|)d1g{LBj`u=9#pk8?9Gw-`I@1N%xecnCimEWZjvql>v
zHV_Z%%#PqlJr~+|!fZKCU^|Am9cOSIR^9k3Tur}*TX6|BUuT2aKHP&I2DlclBlDH5
z!cCHadF;TK&iB|x|2sBeOJlr18$O|*K`m6n6gKgYHk3xaSHMm@jGA{0SKtL~#Vgpv
z`gW6>UIy-<9(;=0`67C_gjq~A#~VF>I>89)xl`!jWz+`da3elK&G!cN{AWz#ZzMUE
zCan#uZ#~>_2+JUA*?{ZscKspL2@m2bJb^=XW-ry@ACWTJ66*b*sINcCg~~+fRYuuI
z^w-jZRO7!^P*3&G{WBb8!S(eK4G=nknl`AmjPMAZP)(&!(?+_9enQ#XOi;mSqdL@j
zLfMHvK2$6BafwonI>AmtEgKVEmEv85YN<4;BpKpw)4z&dVuu@0=17R;36(`n^^V%`
zQE$pWUA&mL;V_)6eygt}`o<@xr%ad7&QAo>CEpQR=%1MkijJ^)qj{z=KU$g&ioV4J
Vb}W7)Ca_WeT>NuvaI32|^9Oa`d6NJD
delta 1042
zcmXxjPe@cz6vy#1IXYVE
zZ8l`qhQ}AU5Ib3BdAN($@CfTM6gDfyIBNVcUdBGG!z60G*Z2TGpu+>af{|=LFR(H?
z1q?J|2|h~Oi&y!d!U)cyHh6^_xPaQIFUKr~0V<(+)VvkEj+>};f8a$t!6=?#!~zCc
zy^?_#>c(bN=H2KpiE*4mCAyA!g0HCiexk!uR074hX62Ybt@i|V{{WWab5z3fSjhgi
zM5iTW_7RogAL^|M|4_#gWl#&X;SGF>szeHJ;|x~eGPdG3ti#+(=Lz0N&F@AX)gWq}
zDGbzkOGg{7qDr%cny`)Ac!=8QbG{ir+vlQre^F1IPgzvzYSg?|EW#ethQp|LXd1Q7
z3)B&<7Epgj=L-XJ51TN%@VwLyQ8#v?O8pFLa1yogB0Bt({{J0S+TW-I^)&ilimF%w
zDYTDjuC+RUWu6I5Qs$Y^<_euBYx+=yGQo-Ygj5xkoR7ml@hwzT(C*Tdtj@lHrb_Vc
z`l!\n"
"Language-Team: DE <33197631+dadav@users.noreply.github.com>\n"
@@ -188,3 +188,21 @@ msgstr ""
"Ich war {duration} am Pwnen und habe {deauthed} Clients gekickt! Außerdem "
"habe ich {associated} neue Freunde getroffen und {handshakes} Handshakes "
"gefressen! #pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
+
+msgid "hours"
+msgstr "Stunden"
+
+msgid "minutes"
+msgstr "Minuten"
+
+msgid "seconds"
+msgstr "Sekunden"
+
+msgid "hour"
+msgstr "Stunde"
+
+msgid "minute"
+msgstr "Minute"
+
+msgid "second"
+msgstr "Sekunde"
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/el/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/el/LC_MESSAGES/voice.po
index fe6d817f..f113ce12 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/el/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/el/LC_MESSAGES/voice.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 16:44+0200\n"
+"POT-Creation-Date: 2019-10-05 14:10+0200\n"
"PO-Revision-Date: 2019-10-03 08:00+0000\n"
"Last-Translator: Periklis Fregkos \n"
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
@@ -189,3 +189,21 @@ msgstr ""
"Pwnαρα για {duration} και έριξα {deauthed} πελάτες! Επίσης γνώρισα "
"{associated} νέους φίλους και καταβρόχθισα {handshakes} χειραψίες! "
"#pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
+
+msgid "hours"
+msgstr ""
+
+msgid "minutes"
+msgstr ""
+
+msgid "seconds"
+msgstr ""
+
+msgid "hour"
+msgstr ""
+
+msgid "minute"
+msgstr ""
+
+msgid "second"
+msgstr ""
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.po
index 7110512c..1172f7fe 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/fr/LC_MESSAGES/voice.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 16:47+0200\n"
+"POT-Creation-Date: 2019-10-05 14:10+0200\n"
"PO-Revision-Date: 2019-10-03 10:34+0200\n"
"Last-Translator: quantumsheep <7271496+quantumsheep@users.noreply.github."
"com>\n"
@@ -190,3 +190,21 @@ msgstr ""
"J'ai pwn durant {duration} et kick {deauthed} clients! J'ai aussi rencontré "
"{associated} nouveaux amis and mangé {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
+
+msgid "hours"
+msgstr ""
+
+msgid "minutes"
+msgstr ""
+
+msgid "seconds"
+msgstr ""
+
+msgid "hour"
+msgstr ""
+
+msgid "minute"
+msgstr ""
+
+msgid "second"
+msgstr ""
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/it/LC_MESSAGES/voice.mo
index bcc0f8f597bfdf13fdedec2cdc8538dde349aaf5..53dfa24c6ee7141767fc5df35c0b2466db1ae926 100644
GIT binary patch
delta 1179
zcmYk*Pe>GD7{~FacH7lVO)E`Xbt?b0yX|I&QX?XzlXj|$L4lO$Dmk>91wkwkQ5`x(
zpr<-4bm(BRQWOOdd5P*EcIZ$?qYmN8OAvj3GjGs~?|f$7oq6BqeV*6(mOrhG%
zF8X}{6RdA%xbYaciYc5$MfeUC`7&x}tLR~*B3!r~TX;T#ns5a5{v~Y2Tc`jYA<3{O
z$R6w|5~DrCIP2SMH?X7uo=xPmqK9V;ozI%+~)_CghAFpCP{9PYs@sKDk>rFf1i
z*%~Ti%~jzBd$72Lfn(gX;xOvNDb&Jukw2T|q7;{K316Vji#}Fn7El3v!ZuvRE{u^z
zZ6t$rcpMeLDd%K0`R`!h1_O%xF=~SMsGa>pP0&O%Iy`AqY6mcjXHnnZ!`)a$mEbdK
z!5`@1Z)Ee9;2`K+cR5qFe&Ih4rw<%MXzIh+eP03k`~E(*OVf
delta 971
zcmZA0IV?m`6vpwx%$Tt=_Wjw$GD0R%NGw4ls%a=hp;0J>P$^6ymR<;zf=Z)6Y!#wH
zCxSvq^r#dP@&BHoaFaW~_vXEO?>Xn*_f@`A7JCeOSBw^>m(r&b%-ZoPkssQj$1E9-
zFb~hM0q^7Y9Vcx
z51=v|LkH(j3vXc=o}d=IN4@`!#pnzC1mK_o4r2y(VKP;Y>N)G%5cRFbQEbKq)P(z3
zh1aNs-cY5@Agu=MM+Gv83U~?Aa23mO6E*G(weSu>~>$vkG`8Y+P8xTjdl{T(XsFVy%-qEli$sPPl1voM!V{Z*=U{%FBH)C4bB
zi7AAwk~X0h>_!I%kl<|!i*Obd$Qn{v_Z?M$qh*bBRZE#`P6fnk?pXA7;X#mTS8Z+s;UxDuxd(5Tj1AzlC1lQ#lJXr
c&s6>p{ePpPZmZdicxSx3H-W*V\n"
"Language: italian\n"
@@ -187,3 +187,21 @@ msgstr ""
"Ho lavorato per {duration} e preso a calci {deauthed} clients! Ho anche "
"incontrato {associate} nuovi amici e ho mangiato {handshakes} handshakes! "
"#pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
+
+msgid "hours"
+msgstr "ore"
+
+msgid "minutes"
+msgstr "minuti"
+
+msgid "seconds"
+msgstr "secondi"
+
+msgid "hour"
+msgstr "ora"
+
+msgid "minute"
+msgstr "minuto"
+
+msgid "second"
+msgstr "secondo"
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/mk/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/mk/LC_MESSAGES/voice.po
index 61d6a3fa..9dff7da0 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/mk/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/mk/LC_MESSAGES/voice.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 16:35+0200\n"
+"POT-Creation-Date: 2019-10-05 14:10+0200\n"
"PO-Revision-Date: 2019-09-30 23:53+0200\n"
"Last-Translator: kovach <2214005+kovachwt@users.noreply.github.com>\n"
"Language-Team: \n"
@@ -189,3 +189,21 @@ msgstr ""
"Си газам веќе {duration} и избацив {deauthed} клиенти! Запознав {associated} "
"нови другарчиња и лапнав {handshakes} ракувања! #pwnagotchi #pwnlog #pwnlife "
"#hacktheplanet #skynet"
+
+msgid "hours"
+msgstr ""
+
+msgid "minutes"
+msgstr ""
+
+msgid "seconds"
+msgstr ""
+
+msgid "hour"
+msgstr ""
+
+msgid "minute"
+msgstr ""
+
+msgid "second"
+msgstr ""
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.po
index 72484e20..6f6f3e3a 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/nl/LC_MESSAGES/voice.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 16:43+0200\n"
+"POT-Creation-Date: 2019-10-05 14:10+0200\n"
"PO-Revision-Date: 2019-09-29 14:00+0200\n"
"Last-Translator: Justin-P \n"
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
@@ -188,3 +188,21 @@ msgstr ""
"Ik heb gepwned voor {duration} and heb {deauthed} clients gekicked! Ik heb "
"ook {associated} nieuwe vrienden gevonden en heb {handshakes} handshakes "
"gegeten! #pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
+
+msgid "hours"
+msgstr ""
+
+msgid "minutes"
+msgstr ""
+
+msgid "seconds"
+msgstr ""
+
+msgid "hour"
+msgstr ""
+
+msgid "minute"
+msgstr ""
+
+msgid "second"
+msgstr ""
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
index c11874e3..b6489ba4 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/voice.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-10-03 16:47+0200\n"
+"POT-Creation-Date: 2019-10-05 14:10+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -190,18 +190,17 @@ msgstr ""
msgid "hours"
msgstr ""
-msgid "hour"
+msgid "minutes"
msgstr ""
-msgid "minutes"
+msgid "seconds"
+msgstr ""
+
+msgid "hour"
msgstr ""
msgid "minute"
msgstr ""
-msgid "hours"
+msgid "second"
msgstr ""
-
-msgid "hour"
-msgstr ""
-
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
index c6a108f3..416ae4f8 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/log.py
@@ -125,11 +125,11 @@ class SessionParser(object):
self.duration = '%02d:%02d:%02d' % (hours, mins, secs)
self.duration_human = []
if hours > 0:
- self.duration_human.append('%d %s' % (hours, self.voice.custom('hours' if hours > 1 else 'hour')))
+ self.duration_human.append('%d %s' % (hours, self.voice.hhmmss(hours, 'h')))
if mins > 0:
- self.duration_human.append('%d %s' % (mins, self.voice.custom('minutes' if mins > 1 else 'minute')))
+ self.duration_human.append('%d %s' % (mins, self.voice.hhmmss(mins, 'm')))
if secs > 0:
- self.duration_human.append('%d %s' % (secs, self.voice.custom('seconds' if secs > 1 else 'second')))
+ 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)
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py
index 536bc179..9268b113 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py
@@ -138,5 +138,21 @@ class Voice:
associated=log.associated,
handshakes=log.handshakes)
- def custom(self, text):
- return self._(text)
+ def hhmmss(self, count, fmt):
+ if count > 1:
+ # plural
+ if fmt == "h":
+ return self._("hours")
+ if fmt == "m":
+ return self._("minutes")
+ if fmt == "s":
+ return self._("seconds")
+ else:
+ # sing
+ if fmt == "h":
+ return self._("hour")
+ if fmt == "m":
+ return self._("minute")
+ if fmt == "s":
+ return self._("second")
+ return fmt
From 02e6ccbd8ea2b33611993ca612688ddf45d3383e Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Sat, 5 Oct 2019 14:22:20 +0200
Subject: [PATCH 78/80] misc: refactored backup and update plugins
---
sdcard/rootfs/root/pwnagotchi/config.yml | 10 +++++-
.../pwnagotchi/plugins/default/auto-backup.py | 36 ++++++++-----------
.../pwnagotchi/plugins/default/auto-update.py | 27 +++++++-------
.../pwnagotchi/scripts/pwnagotchi/utils.py | 18 ++++++++++
4 files changed, 54 insertions(+), 37 deletions(-)
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index 7a2fa4f2..f45f7f4d 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -14,9 +14,17 @@ main:
interval: 1 # every day
files:
- /root/brain.nn
+ - /root/brain.json
+ - /root/custom.yaml
+ - /root/handshakes
+ - /etc/ssh
+ - /etc/hostname
+ - /etc/hosts
+ - /etc/motd
+ - /var/log/pwnagotchi.log
commands:
- 'tar czf /tmp/backup.tar.gz {files}'
- - 'scp /tmp/backup.tar.gz 10.0.0.1:/backups/backup-$(date).tar.gz'
+ - 'scp /tmp/backup.tar.gz pwnagotchi@10.0.0.1:/home/pwnagotchi/backups/backup-$(date).tar.gz'
gps:
enabled: false
twitter:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
index 5bc186d0..73122017 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-backup.py
@@ -4,21 +4,18 @@ __name__ = 'auto-backup'
__license__ = 'GPL3'
__description__ = 'This plugin backups files when internet is availaible.'
-import os
+from pwnagotchi.utils import StatusFile
import logging
+import os
import subprocess
-from datetime import datetime
OPTIONS = dict()
-LAST_UPDATE = None
READY = False
+STATUS = StatusFile('/root/.auto-backup')
+
def on_loaded():
- """
- Gets called when the plugin gets loaded
- """
global READY
- global LAST_UPDATE
if 'files' not in OPTIONS or ('files' in OPTIONS and OPTIONS['files'] is None):
logging.error("AUTO-BACKUP: No files to backup.")
@@ -32,31 +29,28 @@ def on_loaded():
logging.error("AUTO-BACKUP: No commands given.")
return
- if os.path.exists('/root/.auto-backup'):
- LAST_BACKUP = datetime.fromtimestamp(os.path.getmtime('/root/.auto-backup'))
-
READY = True
def on_internet_available(display, config, log):
- """
- Called in manual mode when there's internet connectivity
- """
- global LAST_UPDATE
+ global STATUS
if READY:
- if LAST_BACKUP is not None:
- if (datetime.now() - LAST_BACKUP).days < OPTIONS['interval']:
- return
+ if STATUS.newer_then_days(OPTIONS['interval']):
+ return
files_to_backup = " ".join(OPTIONS['files'])
try:
+ display.set('status', 'Backing up ...')
+ display.update()
+
for cmd in OPTIONS['commands']:
subprocess.call(cmd.format(files=files_to_backup).split(), stdout=open(os.devnull, 'wb'))
- logging.info("AUTO-BACKUP: Successfuly ran backup commands.")
- LAST_BACKUP = datetime.now()
- with open('/root/.auto-backup', 'w') as f:
- f.write('success')
+
+ logging.info("AUTO-BACKUP: backup done")
+ STATUS.update()
except OSError as os_e:
logging.info(f"AUTO-BACKUP: Error: {os_e}")
+ display.set('status', 'Backup done!')
+ display.update()
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-update.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-update.py
index ca2d6fc6..4a1f1352 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-update.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/plugins/default/auto-update.py
@@ -4,40 +4,36 @@ __name__ = 'auto-update'
__license__ = 'GPL3'
__description__ = 'This plugin performs an "apt update && apt upgrade" when internet is availaible.'
-import os
import logging
import subprocess
-from datetime import datetime
+from pwnagotchi.utils import StatusFile
OPTIONS = dict()
-LAST_UPDATE = None
READY = False
-STATUS_FILE = '/root/.auto-update'
+STATUS = StatusFile('/root/.auto-update')
def on_loaded():
global READY
- global LAST_UPDATE
if 'interval' not in OPTIONS or ('interval' in OPTIONS and OPTIONS['interval'] is None):
logging.error("AUTO-UPDATE: Interval is not set.")
return
- if os.path.exists(STATUS_FILE):
- LAST_UPDATE = datetime.fromtimestamp(os.path.getmtime(STATUS_FILE))
-
READY = True
def on_internet_available(display, config, log):
- global LAST_UPDATE
+ global STATUS
if READY:
- if LAST_UPDATE is not None:
- if (datetime.now() - LAST_UPDATE).days < OPTIONS['interval']:
- return
+ if STATUS.newer_then_days(OPTIONS['interval']):
+ return
try:
+ display.set('status', 'Updating ...')
+ display.update()
+
logging.info("AUTO-UPDATE: updating packages index ...")
update = subprocess.Popen('apt update -y', shell=True, stdin=None,
@@ -52,8 +48,9 @@ def on_internet_available(display, config, log):
logging.info("AUTO-UPDATE: complete.")
- LAST_UPDATE = datetime.now()
- with open(STATUS_FILE, 'w') as f:
- f.write('success')
+ STATUS.update()
except Exception as e:
logging.exception("AUTO-UPDATE ERROR")
+
+ display.set('status', 'Updated!')
+ display.update()
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
index 28a627a4..d1b2ba0d 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
@@ -1,3 +1,4 @@
+from datetime import datetime
import logging
import glob
import os
@@ -78,3 +79,20 @@ def blink(times=1, delay=0.3):
led(False)
time.sleep(delay)
led(True)
+
+
+class StatusFile(object):
+ def __init__(self, path):
+ self._path = path
+ self._updated = None
+
+ if os.path.exists(path):
+ self._updated = datetime.fromtimestamp(os.path.getmtime(path))
+
+ def newer_then_days(self, days):
+ return self._updated is not None and (datetime.now() - self._updated).days < days
+
+ def update(self, data=None):
+ self._updated = datetime.now()
+ with open(self._path, 'w') as fp:
+ fp.write(str(self._updated) if data is None else data)
From 8742e333c5055ed3c0fa1c630c1002cc70f909a7 Mon Sep 17 00:00:00 2001
From: Simone Margaritelli
Date: Sat, 5 Oct 2019 14:31:44 +0200
Subject: [PATCH 79/80] misc: small fix or general refactoring i did not bother
commenting
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index c7625f22..8ed53696 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
+
From 31f7f1c318692d50705a5bf48694d0fafe56b45f Mon Sep 17 00:00:00 2001
From: swedishmike
Date: Sat, 5 Oct 2019 13:34:01 +0100
Subject: [PATCH 80/80] Swedish translation added, config.yml update to reflect
this as well.
---
sdcard/rootfs/root/pwnagotchi/config.yml | 2 +-
.../pwnagotchi/locale/se/LC_MESSAGES/voice.mo | Bin 0 -> 3902 bytes
.../pwnagotchi/locale/se/LC_MESSAGES/voice.po | 202 ++++++++++++++++++
3 files changed, 203 insertions(+), 1 deletion(-)
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/se/LC_MESSAGES/voice.mo
create mode 100644 sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/se/LC_MESSAGES/voice.po
diff --git a/sdcard/rootfs/root/pwnagotchi/config.yml b/sdcard/rootfs/root/pwnagotchi/config.yml
index 175d9909..b089f935 100644
--- a/sdcard/rootfs/root/pwnagotchi/config.yml
+++ b/sdcard/rootfs/root/pwnagotchi/config.yml
@@ -1,6 +1,6 @@
# main algorithm configuration
main:
- # currently implemented: en (default), de, el, fr, it, mk, nl
+ # currently implemented: en (default), de, el, fr, it, mk, nl, se
lang: en
# custom plugins path, if null only default plugins with be loaded
custom_plugins:
diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/se/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/se/LC_MESSAGES/voice.mo
new file mode 100644
index 0000000000000000000000000000000000000000..7c0eb0f9b8f56af66f34a1653ae9fdec715f46c0
GIT binary patch
literal 3902
zcmbW3&yO5O6~`;Y#91j^8DX}XTgs^miKS41%3)X13n31EblBX0Z1Uvy8*Jk_dx-7$Ll4K^X^B@^S404_%|T?`wt*~;;*={
zUH=5x-~R>K-=|<4kDmhB@6Uql*K;6#qKgaM?%x4k27w)%>_@f&wJ$pPWA;KFvr`$_idc)
z8-&0g>}R%>{qX`$jtd{(sUeyz?enU6Brf6xq4hrJ_{@)`9vLOWsw(pnxn=+ZC%xn|c>=+ME;;1`XmQplv6OH@e&HiXIIW
zWLix!(}kk?*=SO*4Mq*MQPd-uVc21TIRsGP)(7zljQ$h8a^s#~iR6)>$WkCZM4hX#Y5V2giYioCU1jxXs^ZI;sinX(2|W
zvGB;pnHFqXA>QJ((mD#&APJ!y!hrR2IpBp=XsOV2H+eM)#OsarKEbT>b|HJ#eCQ+X
z4VE;KSsI8nty6Y_G`fW07x%3i*aLe>^koR`=Q-Ng)e?PJeU(N^8Gl>P;Gq@$#99>w
zqF>R#B)Q@o@>=R44N8+}o4CqHcwLT0bJy1^*3aR=P$D1wwkQi%-@#Q#)OEe9!wPyM
z4xHw24n~QK5efhG#>lpj8Hh{F!Y2qAO^n7ZGLN>@uGaJ1+>R3mWw016UJ=`frYtHf
z>n7TyHV6W-gH$RM@5k9=wx`+OJ2CFPd7Mie6$pZvdDW!f?KtBRsJLAu
zyz}{`&-6}f9_3B!HjUm>1J~(=ojZsrcEloWF5P^6>DCI}S=rj|ZLGJp)JPlG
z>Dwp?J2%S6c6Rh4wKg|8TWXx}H=SkV{vzF5S=#FKH#*Bpw7Rj_?_IvXvA)t;lh$>1
zj4W&>oi>ZqPf|rICP}fE3c8+S_==sVFtIV;ceROrfUk^iO8r`8QAkvq#tF7P3QWC|s=5ZG
zGUd`E&2hzFolo)=V?Lv<`jWF9*{M+OR@EM4H#rl~j#1+*i5yAi$eHQka4798qh@n`
z|DkMp*>hrc%n;aG#@*XCdIoFTl%OzNO%qY3C6;A`e+C>e
z?w|(Mwved#J1D1YYMvUdy?GLy=q0OoGur@jYtc%k58!fi6Zk&Qu+wKx>bcERX~Yek
zqpM&A+BF(iPB_-zr*TmY@oC{>wyoKOI#ws@=Q, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-10-03 16:47+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Mike Eriksson \n"
+"Language-Team: LANGUAGE \n"
+"Language: swedish\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "ZzzzZZzzzzZzzz"
+msgstr ""
+
+msgid "Hi, I'm Pwnagotchi! Starting ..."
+msgstr "Hej, jag är Pwnagotchi! Startar ..."
+
+msgid "New day, new hunt, new pwns!"
+msgstr "Ny dag, ny jakt, nya pwns!"
+
+msgid "Hack the Planet!"
+msgstr "Hacka planeten!"
+
+msgid "AI ready."
+msgstr "AI klar."
+
+msgid "The neural network is ready."
+msgstr "Det neurala nätverket är klart."
+
+#, python-brace-format
+msgid "Hey, channel {channel} is free! Your AP will say thanks."
+msgstr "Du, kanal {channel} är ledig! Din AP will gilla detta."
+
+msgid "I'm bored ..."
+msgstr "Jag har det så tråkigt..."
+
+msgid "Let's go for a walk!"
+msgstr "Dags för en promenad!"
+
+msgid "This is the best day of my life!"
+msgstr "Det här är den bästa dagen i mitt liv!"
+
+msgid "Shitty day :/"
+msgstr "Idag suger :/"
+
+msgid "I'm extremely bored ..."
+msgstr "Jag är extremt uttråkad ..."
+
+msgid "I'm very sad ..."
+msgstr "Jag är jätteledsen ..."
+
+msgid "I'm sad"
+msgstr "Jag är ledsen"
+
+msgid "I'm living the life!"
+msgstr "Nu leker livet!"
+
+msgid "I pwn therefore I am."
+msgstr "Jag pwnar därför är jag."
+
+msgid "So many networks!!!"
+msgstr "Så många nätverk!!!"
+
+msgid "I'm having so much fun!"
+msgstr "Fan vad skoj jag har!"
+
+msgid "My crime is that of curiosity ..."
+msgstr "Mitt brott är att vara nyfiken ..."
+
+#, python-brace-format
+msgid "Hello {name}! Nice to meet you. {name}"
+msgstr "Hejsan {name}! Trevligt att träffas {name}"
+
+#, python-brace-format
+msgid "Unit {name} is nearby! {name}"
+msgstr "Enheten {name} är nära! {name}"
+
+#, python-brace-format
+msgid "Uhm ... goodbye {name}"
+msgstr "Uhm ... farväl {name}"
+
+#, python-brace-format
+msgid "{name} is gone ..."
+msgstr "{name} är borta ..."
+
+#, python-brace-format
+msgid "Whoops ... {name} is gone."
+msgstr "Hoppsan ... {name} är borta."
+
+#, python-brace-format
+msgid "{name} missed!"
+msgstr "{name} missade!"
+
+msgid "Missed!"
+msgstr "Bom!"
+
+msgid "Nobody wants to play with me ..."
+msgstr "Ingen vill leka med mig ..."
+
+msgid "I feel so alone ..."
+msgstr "Jag är så ensam ..."
+
+msgid "Where's everybody?!"
+msgstr "Var är alla?!"
+
+#, python-brace-format
+msgid "Napping for {secs}s ..."
+msgstr "Sover för {secs}s ..."
+
+msgid "Zzzzz"
+msgstr ""
+
+#, python-brace-format
+msgid "ZzzZzzz ({secs}s)"
+msgstr ""
+
+#, python-brace-format
+msgid "Waiting for {secs}s ..."
+msgstr "Väntar {secs}s ..."
+
+#, python-brace-format
+msgid "Looking around ({secs}s)"
+msgstr "Tittar omkring mig ({secs}s)"
+
+#, python-brace-format
+msgid "Hey {what} let's be friends!"
+msgstr "Hejsan {what} låt oss vara vänner"
+
+#, python-brace-format
+msgid "Associating to {what}"
+msgstr "Ansluter till {what}"
+
+#, python-brace-format
+msgid "Yo {what}!"
+msgstr ""
+
+#, python-brace-format
+msgid "Just decided that {mac} needs no WiFi!"
+msgstr "Jag bestämde just att {mac} inte behöver WiFi!"
+
+#, python-brace-format
+msgid "Deauthenticating {mac}"
+msgstr ""
+
+#, python-brace-format
+msgid "Kickbanning {mac}!"
+msgstr ""
+
+#, python-brace-format
+msgid "Cool, we got {num} new handshake{plural}!"
+msgstr "Lysande, vi har {num} ny handskakningar{plural}!"
+
+msgid "Ops, something went wrong ... Rebooting ..."
+msgstr "Hoppsan, någpt gick fel ... Startar om ..."
+
+#, python-brace-format
+msgid "Kicked {num} stations\n"
+msgstr "Sparkade {num} stationer\n"
+
+#, python-brace-format
+msgid "Made {num} new friends\n"
+msgstr "Har {num} nya vänner\n"
+
+#, python-brace-format
+msgid "Got {num} handshakes\n"
+msgstr "Har {num} handskakningar\n"
+
+msgid "Met 1 peer"
+msgstr "Mötte 1 jämlike"
+
+#, python-brace-format
+msgid "Met {num} peers"
+msgstr "Mötte {num} jämlikar"
+
+#, python-brace-format
+msgid ""
+"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
+"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
+"#pwnlog #pwnlife #hacktheplanet #skynet"
+msgstr "Jag har pwnat för {duration} och sparkat ut {deauthed} klienter, Jag "
+"har också träffat {associated} nya vänner och har skakat {handshakes} händer! "
+"#pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
+
+msgid "hours"
+msgstr "timmar"
+
+msgid "hour"
+msgstr "timme"
+
+msgid "minutes"
+msgstr "minuter"
+
+msgid "minute"
+msgstr "minut"