26 Commits

Author SHA1 Message Date
Simone Margaritelli
10cba6872a fix: fixed travis-ci regexp 2019-10-19 17:26:03 +02:00
Simone Margaritelli
b213f9f214 releasing v1.0.0 2019-10-19 17:22:34 +02:00
evilsocket
fa72a53129 Merge pull request #330 from python273/patch-2
Fix waveshare v1 layout: status pos
2019-10-19 12:07:03 +02:00
Kirill
49f7c652c7 Fix waveshare v1 layout: status pos 2019-10-19 12:53:46 +03:00
evilsocket
9c78e16c1b Merge pull request #328 from szymex73/polish-lang
Add polish translation
2019-10-19 10:10:43 +02:00
evilsocket
22ebc09c9d Merge pull request #329 from ggiraudon/master
Adding support for Waveshare LCD Hat (ST7789 chip)
2019-10-19 10:08:41 +02:00
root
0ea67cb97f Adding support for Waveshare LCD Hat (ST7789 chip) 2019-10-19 04:49:38 +01:00
Szymon Borecki
2324423cab Add polish translation files
Signed-off-by: Szymon Borecki <szymex73@gmail.com>
2019-10-19 00:55:48 +02:00
evilsocket
be2cd8293f Merge pull request #326 from dadav/fix/gast-version
need old gast version
2019-10-18 21:23:41 +02:00
dadav
86cbe01081 need old gast version 2019-10-18 20:31:10 +02:00
Simone Margaritelli
eea4feee71 new: bump pwngrid binary to 1.8.0 2019-10-18 19:51:07 +02:00
evilsocket
cff487008c Merge pull request #325 from dadav/fix/bt-dbus-bug
Fix str comparison and add sleep
2019-10-18 19:35:27 +02:00
dadav
6cecca67a4 Fix str comparison and add sleep 2019-10-18 19:20:25 +02:00
Simone Margaritelli
fb4d46d71a fix: fixed Invalid cross-device link error 2019-10-18 17:43:45 +02:00
Simone Margaritelli
e220a869e0 new: user config is now copied from /boot/config.yml 2019-10-18 16:34:58 +02:00
Simone Margaritelli
f4a59549fa fix: update process will be reflash based for a while 2019-10-18 15:58:53 +02:00
Simone Margaritelli
a058d2e00d fix: removed deprecated script 2019-10-18 15:57:40 +02:00
Simone Margaritelli
8c73e32853 fix: handling corrupted log lines (fixes #321) 2019-10-18 10:30:27 +02:00
evilsocket
eeee4bdd3c Merge pull request #314 from ChipWolf/patch-1
Only show ui complication if you have unread pwnmail
2019-10-18 09:45:10 +02:00
evilsocket
1ddf020ba8 Merge pull request #318 from colossus700/colossus700-patch-1
Fix LM75B import error for Papirus Screens
2019-10-18 09:44:32 +02:00
evilsocket
e992834b37 Merge pull request #316 from spees/master
Minor fixes to the UI to prevent overlap
2019-10-18 09:43:59 +02:00
colossus700
55bac8a8b9 Update epd.py
Fixed LM75B import error
2019-10-17 19:03:04 -04:00
Chip Wolf ‮
61a6b77a52 Only show ui complication if you have unread pwnmail 2019-10-17 23:09:49 +01:00
spees
0aa4f95235 Made the memtemp plugin usable and added to default.yml
Signed-off-by: spees <speeskonijn@gmail.com>
2019-10-17 23:55:11 +02:00
spees
299bd9a5ca Moved APs status to prevent overlap with channel status on inky screens
Signed-off-by: spees <speeskonijn@gmail.com>
2019-10-17 20:10:43 +02:00
spees
10688ca7b0 Moved BT status to prevent overlap with last recon total APS
Signed-off-by: spees <speeskonijn@gmail.com>
2019-10-17 20:07:56 +02:00
25 changed files with 644 additions and 491 deletions

View File

@@ -20,7 +20,7 @@ deploy:
repo: evilsocket/pwnagotchi repo: evilsocket/pwnagotchi
branches: branches:
only: only:
- "/^v[0-9]+\\.[0-9]+\\.[0-9]+[A-Za-z0-9]+?$/" - "/^v[0-9]+\\.[0-9]+\\.[0-9]+[A-Za-z0-9]*$/"
cache: cache:
apt: true apt: true
before_script: before_script:

View File

@@ -34,7 +34,7 @@
url: "https://github.com/bettercap/bettercap/releases/download/v2.25/bettercap_linux_armv6l_2.25.zip" url: "https://github.com/bettercap/bettercap/releases/download/v2.25/bettercap_linux_armv6l_2.25.zip"
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip" ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
pwngrid: pwngrid:
url: "https://github.com/evilsocket/pwngrid/releases/download/v1.7.6/pwngrid_linux_armv6l_1.7.6.zip" url: "https://github.com/evilsocket/pwngrid/releases/download/v1.8.0/pwngrid_linux_armhf_v1.8.0.zip"
apt: apt:
hold: hold:
- firmware-atheros - firmware-atheros

View File

@@ -4,7 +4,7 @@ import logging
import time import time
import pwnagotchi.ui.view as view import pwnagotchi.ui.view as view
version = '1.0.0RC5' version = '1.0.0'
_name = None _name = None

View File

@@ -17,10 +17,6 @@ main:
report: false # don't report pwned networks by default! report: false # don't report pwned networks by default!
exclude: # do not report the following networks (accepts both ESSIDs and BSSIDs) exclude: # do not report the following networks (accepts both ESSIDs and BSSIDs)
- YourHomeNetworkHere - YourHomeNetworkHere
auto-update:
enabled: false
system: false # set to true to also enable system updates via apt
interval: 1 # every day
auto-backup: auto-backup:
enabled: false enabled: false
interval: 1 # every day interval: 1 # every day
@@ -74,6 +70,8 @@ main:
netmask: 24 netmask: 24
interval: 1 # check every x minutes for device interval: 1 # check every x minutes for device
share_internet: false share_internet: false
memtemp: # Display memory usage and cpu temperature on screen
enabled: false
# monitor interface to use # monitor interface to use
iface: mon0 iface: mon0
# command to run to bring the mon interface up in case it's not up already # command to run to bring the mon interface up in case it's not up already

Binary file not shown.

View File

@@ -0,0 +1,215 @@
# Polish voice data for pwnagotchi.
# Copyright (C) 2019
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR szymex73 <szymex73@gmail.com>, 2019.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-10-09 17:42+0200\n"
"PO-Revision-Date: 2019-10-09 17:42+0200\n"
"Last-Translator: szymex73 <szymex73@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: polish\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr "ZzzzZZzzzzZzzz"
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Hej, jestem Pwnagotchi! Uruchamianie ..."
msgid "New day, new hunt, new pwns!"
msgstr "Nowy dzień, nowe łowy, nowe pwny!"
msgid "Hack the Planet!"
msgstr "Hakujmy planetę!"
msgid "AI ready."
msgstr "SI gotowa."
msgid "The neural network is ready."
msgstr "Sieć neuronowa jest gotowa."
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Hej, kanał {channel} jest wolny! Twój AP mi podziękuje."
msgid "I'm bored ..."
msgstr "Nudzi mi się ..."
msgid "Let's go for a walk!"
msgstr "Chodźmy na spacer!"
msgid "This is the best day of my life!"
msgstr "To jest najlepszy dzień w moim życiu!"
msgid "Shitty day :/"
msgstr "Ten dzień jest do dupy :/"
msgid "I'm extremely bored ..."
msgstr "Straaaasznie się nudzę ..."
msgid "I'm very sad ..."
msgstr "Jest mi bardzo smutno ..."
msgid "I'm sad"
msgstr "Jest mi smutno"
msgid "I'm living the life!"
msgstr "Cieszę się życiem!"
msgid "I pwn therefore I am."
msgstr "Pwnuje więc jestem."
msgid "So many networks!!!"
msgstr "Jak dużo sieci!!!"
msgid "I'm having so much fun!"
msgstr "Ale jest super!"
msgid "My crime is that of curiosity ..."
msgstr "Moją zbrodnią jest ciekawość ..."
#, python-brace-format
msgid "Hello {name}! Nice to meet you. {name}"
msgstr "Cześć {name}! Miło cię poznać. {name}"
#, python-brace-format
msgid "Unit {name} is nearby! {name}"
msgstr "Jednostka {name} jest niedaleko! {name}"
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "Umm ... żegnaj {name}"
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} zniknął ..."
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Ups ... {name} zniknął."
#, python-brace-format
msgid "{name} missed!"
msgstr "{name} przeoczył!"
msgid "Missed!"
msgstr "Spóźniony!"
msgid "Nobody wants to play with me ..."
msgstr "Nikt się nie chce ze mną bawić ..."
msgid "I feel so alone ..."
msgstr "Czuję się tak samotnie ..."
msgid "Where's everybody?!"
msgstr "Gdzie są wszyscy?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Zdrzemnę się przez {secs}s ..."
msgid "Zzzzz"
msgstr "Zzzzz"
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr "ZzzZzzz ({secs}s)"
msgid "Good night."
msgstr "Dobranoc."
msgid "Zzz"
msgstr "Zzz"
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Czekam {secs}s ..."
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Rozglądam się ({secs}s)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "Hej {what}, zostańmy przyjaciółmi!"
#, python-brace-format
msgid "Associating to {what}"
msgstr "Łączenie się z {what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr "Ej {what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "Według mnie {mac} nie potrzebuje WiFi!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr "Rozłączam {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "Banowanie {mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "Super, zdobylismy {num} handshake{plural}!"
msgid "Ops, something went wrong ... Rebooting ..."
msgstr "Ups, coś się stało ... Restartuję ..."
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "Wyrzucono {num} stacji\n"
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "Zdobyto {num} przyjaciół\n"
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "Zdobyto {num} handshakow\n"
msgid "Met 1 peer"
msgstr "Spotkano 1 kolegę"
#, python-brace-format
msgid "Met {num} peers"
msgstr "Spotkano {num} kolegów"
#, 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 ""
"Pwnowalem przez {duration} i wyrzuciłem {deauthed} klientów! Spotkałem także "
"{associated} nowych przyjaciół i zjadłem {handshakes} handshaków! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours"
msgstr "godzin"
msgid "minutes"
msgstr "minut"
msgid "seconds"
msgstr "sekund"
msgid "hour"
msgstr "godzina"
msgid "minute"
msgstr "minuta"
msgid "second"
msgstr "sekunda"

View File

@@ -2,6 +2,7 @@ import hashlib
import time import time
import re import re
import os import os
import logging
from datetime import datetime from datetime import datetime
from pwnagotchi.voice import Voice from pwnagotchi.voice import Voice
@@ -87,61 +88,65 @@ class LastSession(object):
parts = line.split(']') parts = line.split(']')
if len(parts) < 2: if len(parts) < 2:
continue continue
line_timestamp = parts[0].strip('[')
line = ']'.join(parts[1:])
stopped_at = self._parse_datetime(line_timestamp)
if started_at is None:
started_at = stopped_at
if LastSession.DEAUTH_TOKEN in line and line not in cache: try:
self.deauthed += 1 line_timestamp = parts[0].strip('[')
cache[line] = 1 line = ']'.join(parts[1:])
stopped_at = self._parse_datetime(line_timestamp)
if started_at is None:
started_at = stopped_at
elif LastSession.ASSOC_TOKEN in line and line not in cache: if LastSession.DEAUTH_TOKEN in line and line not in cache:
self.associated += 1 self.deauthed += 1
cache[line] = 1 cache[line] = 1
elif LastSession.HANDSHAKE_TOKEN in line and line not in cache: elif LastSession.ASSOC_TOKEN in line and line not in cache:
self.handshakes += 1 self.associated += 1
cache[line] = 1 cache[line] = 1
elif LastSession.TRAINING_TOKEN in line: elif LastSession.HANDSHAKE_TOKEN in line and line not in cache:
self.train_epochs += 1 self.handshakes += 1
cache[line] = 1
elif LastSession.EPOCH_TOKEN in line: elif LastSession.TRAINING_TOKEN in line:
self.epochs += 1 self.train_epochs += 1
m = LastSession.EPOCH_PARSER.findall(line)
if m:
epoch_num, epoch_data = m[0]
m = LastSession.EPOCH_DATA_PARSER.findall(epoch_data)
for key, value in m:
if key == 'reward':
reward = float(value)
self.avg_reward += reward
if reward < self.min_reward:
self.min_reward = reward
elif reward > self.max_reward: elif LastSession.EPOCH_TOKEN in line:
self.max_reward = reward self.epochs += 1
m = LastSession.EPOCH_PARSER.findall(line)
if m:
epoch_num, epoch_data = m[0]
m = LastSession.EPOCH_DATA_PARSER.findall(epoch_data)
for key, value in m:
if key == 'reward':
reward = float(value)
self.avg_reward += reward
if reward < self.min_reward:
self.min_reward = reward
elif LastSession.PEER_TOKEN in line: elif reward > self.max_reward:
m = self._peer_parser.findall(line) self.max_reward = reward
if m:
name, pubkey, rssi, sid, pwnd_tot, uptime = m[0] elif LastSession.PEER_TOKEN in line:
if pubkey not in cache: m = self._peer_parser.findall(line)
self.last_peer = Peer({ if m:
'session_id': sid, name, pubkey, rssi, sid, pwnd_tot, uptime = m[0]
'channel': 1, if pubkey not in cache:
'rssi': int(rssi), self.last_peer = Peer({
'identity': pubkey, 'session_id': sid,
'advertisement':{ 'channel': 1,
'name': name, 'rssi': int(rssi),
'pwnd_tot': int(pwnd_tot) 'identity': pubkey,
}}) 'advertisement':{
self.peers += 1 'name': name,
cache[pubkey] = self.last_peer 'pwnd_tot': int(pwnd_tot)
else: }})
cache[pubkey].adv['pwnd_tot'] = pwnd_tot self.peers += 1
cache[pubkey] = self.last_peer
else:
cache[pubkey].adv['pwnd_tot'] = pwnd_tot
except Exception as e:
logging.error("error parsing line '%s': %s" % (line, e))
if started_at is not None: if started_at is not None:
self.duration = stopped_at - started_at self.duration = stopped_at - started_at

View File

@@ -1,60 +0,0 @@
__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 logging
import subprocess
from pwnagotchi.utils import StatusFile
OPTIONS = dict()
READY = False
STATUS = StatusFile('/root/.auto-update')
def on_loaded():
global READY
if 'interval' not in OPTIONS or ('interval' in OPTIONS and OPTIONS['interval'] is None):
logging.error("auto-update: Interval is not set.")
return
READY = True
def run(cmd):
return subprocess.Popen(cmd, shell=True, stdin=None, stdout=open("/dev/null", "w"), stderr=None,
executable="/bin/bash")
def on_internet_available(agent):
global STATUS
if READY:
if STATUS.newer_then_days(OPTIONS['interval']):
return
display = agent.view()
try:
display.set('status', 'Updating ...')
display.update()
logging.info("auto-update: updating pwnagotchi ...")
run('pip3 install --upgrade --upgrade-strategy only-if-needed pwnagotchi').wait()
if OPTIONS['system']:
logging.info("auto-update: updating packages index ...")
run('apt update -y').wait()
logging.info("auto-update: updating packages ...")
run('apt upgrade -y').wait()
logging.info("auto-update: complete.")
STATUS.update()
except Exception as e:
logging.exception("auto-update ERROR")
display.set('status', 'Updated!')
display.update()

View File

@@ -132,7 +132,7 @@ class BTNap:
device = ifaces.get(BTNap.IFACE_DEV) device = ifaces.get(BTNap.IFACE_DEV)
if device is None: if device is None:
continue continue
if device['Address'] == device_address and path.startswith(path_prefix): if str(device['Address']) == device_address and path.startswith(path_prefix):
obj = bus.get_object(BTNap.IFACE_BASE, path) obj = bus.get_object(BTNap.IFACE_BASE, path)
return dbus.Interface(obj, BTNap.IFACE_DEV) return dbus.Interface(obj, BTNap.IFACE_DEV)
raise BTError('Bluetooth device not found') raise BTError('Bluetooth device not found')
@@ -245,6 +245,7 @@ class BTNap:
try: try:
dev_remote.Pair() dev_remote.Pair()
logging.info('BT-TETHER: Successful paired with device ;)') logging.info('BT-TETHER: Successful paired with device ;)')
time.sleep(10) # wait for bnep0
except Exception: except Exception:
# can fail because of AlreadyExists etc. # can fail because of AlreadyExists etc.
pass pass
@@ -491,5 +492,5 @@ def on_ui_update(ui):
def on_ui_setup(ui): def on_ui_setup(ui):
ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-', position=(ui.width() / 2 - 30, 0), ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-', position=(ui.width() / 2 - 15, 0),
label_font=fonts.Bold, text_font=fonts.Medium)) label_font=fonts.Bold, text_font=fonts.Medium))

View File

@@ -65,7 +65,7 @@ def is_excluded(what):
def on_ui_update(ui): def on_ui_update(ui):
new_value = ' %d (%d)' % (UNREAD_MESSAGES, TOTAL_MESSAGES) new_value = ' %d (%d)' % (UNREAD_MESSAGES, TOTAL_MESSAGES)
if not ui.has_element('mailbox') and TOTAL_MESSAGES > 0: if not ui.has_element('mailbox') and UNREAD_MESSAGES > 0:
if ui.is_inky(): if ui.is_inky():
pos = (80, 0) pos = (80, 0)
else: else:

View File

@@ -2,8 +2,19 @@
# #
# totalmem usedmem freemem cputemp # totalmem usedmem freemem cputemp
# #
###############################################################
#
# Updated 18-10-2019 by spees <speeskonijn@gmail.com>
# - Changed the place where the data was displayed on screen
# - Made the data a bit more compact and easier to read
# - removed the label so we wont waste screen space
# - Updated version to 1.0.1
#
###############################################################
__author__ = 'https://github.com/xenDE' __author__ = 'https://github.com/xenDE'
__version__ = '1.0.0' __version__ = '1.0.1'
__name__ = 'memtemp' __name__ = 'memtemp'
__license__ = 'GPL3' __license__ = 'GPL3'
__description__ = 'A plugin that will add a memory and temperature indicator' __description__ = 'A plugin that will add a memory and temperature indicator'
@@ -21,9 +32,9 @@ class MEMTEMP:
# set the minimum seconds before refresh the values # set the minimum seconds before refresh the values
refresh_wait = 30 refresh_wait = 30
refresh_ts_last = time.time() - refresh_wait refresh_ts_last = time.time() - refresh_wait
def __init__(self): def __init__(self):
# only import when the module is loaded and enabled # only import when the module is loaded and enabled
import os import os
@@ -31,9 +42,9 @@ class MEMTEMP:
def get_temp(self): def get_temp(self):
try: try:
temp = os.popen('/opt/vc/bin/vcgencmd measure_temp').readlines()[0].split('=')[1].replace("\n", '').replace("'","") temp = os.popen('/opt/vc/bin/vcgencmd measure_temp').readlines()[0].split('=')[1].replace("\n", '').replace("'","")
return 'cpu:' + temp return 't:' + temp
except: except:
return 'cpu:0.0C' return 't:-'
# cpu:37.4C # cpu:37.4C
def get_mem_info(self): def get_mem_info(self):
@@ -42,9 +53,9 @@ class MEMTEMP:
# total, used, free = map(int, os.popen('free -t -m').readlines()[-1].split()[1:]) # total, used, free = map(int, os.popen('free -t -m').readlines()[-1].split()[1:])
# without Swap, only real memory: # without Swap, only real memory:
total, used, free = map(int, os.popen('free -t -m').readlines()[-3].split()[1:4]) 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) return "\nT:"+str(total)+"M U:"+str(used)+"M\nF:"+str(free)+"M"
except: except:
return "tm:0 um:0 fm:0" return "\nT:- U:-\nF:- "
# tm:532 um:82 fm:353 # tm:532 um:82 fm:353
@@ -57,7 +68,7 @@ def on_loaded():
def on_ui_setup(ui): 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), ui.add_element('memtemp', LabeledValue(color=BLACK, label='', value='\nT:- U:-\nF:- -', position=(ui.width() / 2 + 17, ui.height() / 2),
label_font=fonts.Bold, text_font=fonts.Medium)) label_font=fonts.Bold, text_font=fonts.Medium))
@@ -66,3 +77,4 @@ def on_ui_update(ui):
ui.set('memtemp', "%s %s" % (memtemp.get_mem_info(), memtemp.get_temp())) ui.set('memtemp', "%s %s" % (memtemp.get_mem_info(), memtemp.get_temp()))
memtemp.refresh_ts_last = time.time() memtemp.refresh_ts_last = time.time()

View File

@@ -123,6 +123,10 @@ class Display(View):
def is_oledhat(self): def is_oledhat(self):
return self._implementation.name == 'oledhat' return self._implementation.name == 'oledhat'
def is_lcdhat(self):
return self._implementation.name == 'lcdhat'
def is_waveshare_any(self): def is_waveshare_any(self):
return self.is_waveshare_v1() or self.is_waveshare_v2() return self.is_waveshare_v1() or self.is_waveshare_v2()

View File

@@ -1,6 +1,7 @@
from pwnagotchi.ui.hw.inky import Inky from pwnagotchi.ui.hw.inky import Inky
from pwnagotchi.ui.hw.papirus import Papirus from pwnagotchi.ui.hw.papirus import Papirus
from pwnagotchi.ui.hw.oledhat import OledHat from pwnagotchi.ui.hw.oledhat import OledHat
from pwnagotchi.ui.hw.lcdhat import LcdHat
from pwnagotchi.ui.hw.waveshare1 import WaveshareV1 from pwnagotchi.ui.hw.waveshare1 import WaveshareV1
from pwnagotchi.ui.hw.waveshare2 import WaveshareV2 from pwnagotchi.ui.hw.waveshare2 import WaveshareV2
@@ -16,6 +17,10 @@ def display_for(config):
if config['ui']['display']['type'] == 'oledhat': if config['ui']['display']['type'] == 'oledhat':
return OledHat(config) return OledHat(config)
if config['ui']['display']['type'] == 'lcdhat':
return LcdHat(config)
elif config['ui']['display']['type'] == 'waveshare_1': elif config['ui']['display']['type'] == 'waveshare_1':
return WaveshareV1(config) return WaveshareV1(config)

View File

@@ -16,7 +16,7 @@ class Inky(DisplayImpl):
self._layout['face'] = (0, 37) self._layout['face'] = (0, 37)
self._layout['name'] = (5, 18) self._layout['name'] = (5, 18)
self._layout['channel'] = (0, 0) self._layout['channel'] = (0, 0)
self._layout['aps'] = (25, 0) self._layout['aps'] = (30, 0)
self._layout['uptime'] = (147, 0) self._layout['uptime'] = (147, 0)
self._layout['line1'] = [0, 12, 212, 12] self._layout['line1'] = [0, 12, 212, 12]
self._layout['line2'] = [0, 92, 212, 92] self._layout['line2'] = [0, 92, 212, 92]

View File

@@ -0,0 +1,46 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class LcdHat(DisplayImpl):
def __init__(self, config):
super(LcdHat, self).__init__(config, 'lcdhat')
self._display = None
def layout(self):
fonts.setup(10, 9, 10, 35)
self._layout['width'] = 240
self._layout['height'] = 240
self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0)
self._layout['uptime'] = (175, 0)
self._layout['line1'] = [0, 14, 240, 14]
self._layout['line2'] = [0, 108, 240, 108]
self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109)
self._layout['mode'] = (215, 109)
self._layout['status'] = {
'pos': (125, 20),
'font': fonts.Medium,
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing lcdhat display")
from pwnagotchi.ui.hw.libs.waveshare.lcdhat.epd import EPD
self._display = EPD()
self._display.init()
self._display.Clear()
def render(self, canvas):
self._display.display(canvas)
def clear(self):
self._display.clear()

View File

@@ -15,7 +15,7 @@
from PIL import Image from PIL import Image
from PIL import ImageOps from PIL import ImageOps
from pwnagotchi.ui.hw.libs.papirus import LM75B from pwnagotchi.ui.hw.libs.papirus.lm75b import LM75B
import re import re
import os import os
import sys import sys

View File

@@ -0,0 +1,165 @@
import spidev
import RPi.GPIO as GPIO
import time
import numpy as np
class ST7789(object):
"""class for ST7789 240*240 1.3inch OLED displays."""
def __init__(self,spi,rst = 27,dc = 25,bl = 24):
self.width = 240
self.height = 240
#Initialize DC RST pin
self._dc = dc
self._rst = rst
self._bl = bl
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(self._dc,GPIO.OUT)
GPIO.setup(self._rst,GPIO.OUT)
GPIO.setup(self._bl,GPIO.OUT)
GPIO.output(self._bl, GPIO.HIGH)
#Initialize SPI
self._spi = spi
self._spi.max_speed_hz = 40000000
""" Write register address and data """
def command(self, cmd):
GPIO.output(self._dc, GPIO.LOW)
self._spi.writebytes([cmd])
def data(self, val):
GPIO.output(self._dc, GPIO.HIGH)
self._spi.writebytes([val])
def Init(self):
"""Initialize dispaly"""
self.reset()
self.command(0x36)
self.data(0x70) #self.data(0x00)
self.command(0x3A)
self.data(0x05)
self.command(0xB2)
self.data(0x0C)
self.data(0x0C)
self.data(0x00)
self.data(0x33)
self.data(0x33)
self.command(0xB7)
self.data(0x35)
self.command(0xBB)
self.data(0x19)
self.command(0xC0)
self.data(0x2C)
self.command(0xC2)
self.data(0x01)
self.command(0xC3)
self.data(0x12)
self.command(0xC4)
self.data(0x20)
self.command(0xC6)
self.data(0x0F)
self.command(0xD0)
self.data(0xA4)
self.data(0xA1)
self.command(0xE0)
self.data(0xD0)
self.data(0x04)
self.data(0x0D)
self.data(0x11)
self.data(0x13)
self.data(0x2B)
self.data(0x3F)
self.data(0x54)
self.data(0x4C)
self.data(0x18)
self.data(0x0D)
self.data(0x0B)
self.data(0x1F)
self.data(0x23)
self.command(0xE1)
self.data(0xD0)
self.data(0x04)
self.data(0x0C)
self.data(0x11)
self.data(0x13)
self.data(0x2C)
self.data(0x3F)
self.data(0x44)
self.data(0x51)
self.data(0x2F)
self.data(0x1F)
self.data(0x1F)
self.data(0x20)
self.data(0x23)
self.command(0x21)
self.command(0x11)
self.command(0x29)
def reset(self):
"""Reset the display"""
GPIO.output(self._rst,GPIO.HIGH)
time.sleep(0.01)
GPIO.output(self._rst,GPIO.LOW)
time.sleep(0.01)
GPIO.output(self._rst,GPIO.HIGH)
time.sleep(0.01)
def SetWindows(self, Xstart, Ystart, Xend, Yend):
#set the X coordinates
self.command(0x2A)
self.data(0x00) #Set the horizontal starting point to the high octet
self.data(Xstart & 0xff) #Set the horizontal starting point to the low octet
self.data(0x00) #Set the horizontal end to the high octet
self.data((Xend - 1) & 0xff) #Set the horizontal end to the low octet
#set the Y coordinates
self.command(0x2B)
self.data(0x00)
self.data((Ystart & 0xff))
self.data(0x00)
self.data((Yend - 1) & 0xff )
self.command(0x2C)
def ShowImage(self,Image,Xstart,Ystart):
"""Set buffer to value of Python Imaging Library image."""
"""Write display buffer to physical display"""
imwidth, imheight = Image.size
if imwidth != self.width or imheight != self.height:
raise ValueError('Image must be same dimensions as display \
({0}x{1}).' .format(self.width, self.height))
img = np.asarray(Image)
pix = np.zeros((self.width,self.height,2), dtype = np.uint8)
pix[...,[0]] = np.add(np.bitwise_and(img[...,[0]],0xF8),np.right_shift(img[...,[1]],5))
pix[...,[1]] = np.add(np.bitwise_and(np.left_shift(img[...,[1]],3),0xE0),np.right_shift(img[...,[2]],3))
pix = pix.flatten().tolist()
self.SetWindows ( 0, 0, self.width, self.height)
GPIO.output(self._dc,GPIO.HIGH)
for i in range(0,len(pix),4096):
self._spi.writebytes(pix[i:i+4096])
def clear(self):
"""Clear contents of image buffer"""
_buffer = [0xff]*(self.width * self.height * 2)
self.SetWindows ( 0, 0, self.width, self.height)
GPIO.output(self._dc,GPIO.HIGH)
for i in range(0,len(_buffer),4096):
self._spi.writebytes(_buffer[i:i+4096])

Binary file not shown.

View File

@@ -0,0 +1,76 @@
# /*****************************************************************************
# * | File : config.py
# * | Author : Guillaume Giraudon
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2019-10-18
# * | Info :
# ******************************************************************************/
import RPi.GPIO as GPIO
import time
from smbus import SMBus
import spidev
import ctypes
# import spidev
# Pin definition
RST_PIN = 27
DC_PIN = 25
BL_PIN = 24
Device_SPI = 1
Device_I2C = 0
Device = Device_SPI
spi = spidev.SpiDev(0, 0)
def digital_write(pin, value):
GPIO.output(pin, value)
def digital_read(pin):
return GPIO.input(BUSY_PIN)
def delay_ms(delaytime):
time.sleep(delaytime / 1000.0)
def spi_writebyte(data):
# SPI.writebytes(data)
spi.writebytes([data[0]])
def i2c_writebyte(reg, value):
bus.write_byte_data(address, reg, value)
# time.sleep(0.01)
def module_init():
# print("module_init")
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(RST_PIN, GPIO.OUT)
GPIO.setup(DC_PIN, GPIO.OUT)
# SPI.max_speed_hz = 2000000
# SPI.mode = 0b00
# i2c_writebyte(0xff,0xff)
# spi.SYSFS_software_spi_begin()
# spi.SYSFS_software_spi_setDataMode(0);
# spi.SYSFS_software_spi_setClockDivider(1);
#spi.max_speed_hz = 2000000
#spi.mode = 0b00
GPIO.output(BL_PIN, 1)
GPIO.output(DC_PIN, 0)
return 0
def module_exit():
spi.SYSFS_software_spi_end()
GPIO.output(RST_PIN, 0)
GPIO.output(DC_PIN, 0)
### END OF FILE ###

View File

@@ -0,0 +1,28 @@
from . import ST7789
from . import config
# Display resolution
EPD_WIDTH = 240
EPD_HEIGHT = 240
disp = ST7789.ST7789(config.spi,config.RST_PIN, config.DC_PIN, config.BL_PIN)
class EPD(object):
def __init__(self):
self.reset_pin = config.RST_PIN
self.dc_pin = config.DC_PIN
#self.busy_pin = config.BUSY_PIN
#self.cs_pin = config.CS_PIN
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
def init(self):
disp.Init()
def Clear(self):
disp.clear()
def display(self, image):
rgb_im = image.convert('RGB')
disp.ShowImage(rgb_im,0,0)

View File

@@ -38,7 +38,6 @@ class WaveshareV1(DisplayImpl):
self._layout['name'] = (5, 15) self._layout['name'] = (5, 15)
self._layout['channel'] = (0, 0) self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0) self._layout['aps'] = (28, 0)
self._layout['status'] = (91, 15)
self._layout['uptime'] = (147, 0) self._layout['uptime'] = (147, 0)
self._layout['line1'] = [0, 12, 212, 12] self._layout['line1'] = [0, 12, 212, 12]
self._layout['line2'] = [0, 92, 212, 92] self._layout['line2'] = [0, 92, 212, 92]
@@ -47,9 +46,9 @@ class WaveshareV1(DisplayImpl):
self._layout['shakes'] = (0, 93) self._layout['shakes'] = (0, 93)
self._layout['mode'] = (187, 93) self._layout['mode'] = (187, 93)
self._layout['status'] = { self._layout['status'] = {
'pos': (125, 20), 'pos': (91, 15),
'font': fonts.Medium, 'font': fonts.Medium,
'max': 14 'max': 20
} }
return self._layout return self._layout

View File

@@ -31,11 +31,19 @@ def load_config(args):
ref_defaults_file = os.path.join(os.path.dirname(pwnagotchi.__file__), 'defaults.yml') ref_defaults_file = os.path.join(os.path.dirname(pwnagotchi.__file__), 'defaults.yml')
ref_defaults_data = None ref_defaults_data = None
if not os.path.exists(args.config): # check for a config.yml file on /boot/
if os.path.exists("/boot/config.yml"):
# logging not configured here yet # logging not configured here yet
print("installing /boot/config.yml to %s ...", args.user_config)
# https://stackoverflow.com/questions/42392600/oserror-errno-18-invalid-cross-device-link
shutil.move("/boot/config.yml", args.user_config)
# if not config is found, copy the defaults
if not os.path.exists(args.config):
print("copying %s to %s ..." % (ref_defaults_file, args.config)) print("copying %s to %s ..." % (ref_defaults_file, args.config))
shutil.copy(ref_defaults_file, args.config) shutil.copy(ref_defaults_file, args.config)
else: else:
# check if the user messed with the defaults
with open(ref_defaults_file) as fp: with open(ref_defaults_file) as fp:
ref_defaults_data = fp.read() ref_defaults_data = fp.read()
@@ -46,9 +54,11 @@ def load_config(args):
print("!!! file in %s is different than release defaults, overwriting !!!" % args.config) print("!!! file in %s is different than release defaults, overwriting !!!" % args.config)
shutil.copy(ref_defaults_file, args.config) shutil.copy(ref_defaults_file, args.config)
# load the defaults
with open(args.config) as fp: with open(args.config) as fp:
config = yaml.safe_load(fp) config = yaml.safe_load(fp)
# load the user config
if os.path.exists(args.user_config): if os.path.exists(args.user_config):
with open(args.user_config) as fp: with open(args.user_config) as fp:
user_config = yaml.safe_load(fp) user_config = yaml.safe_load(fp)
@@ -131,6 +141,7 @@ def blink(times=1, delay=0.3):
time.sleep(delay) time.sleep(delay)
led(True) led(True)
class WifiInfo(Enum): class WifiInfo(Enum):
""" """
Fields you can extract from a pcap file Fields you can extract from a pcap file
@@ -141,6 +152,7 @@ class WifiInfo(Enum):
CHANNEL = 3 CHANNEL = 3
RSSI = 4 RSSI = 4
class FieldNotFoundError(Exception): class FieldNotFoundError(Exception):
pass pass
@@ -172,7 +184,7 @@ def extract_from_pcap(path, fields):
if hasattr(packet[Dot11], 'addr3'): if hasattr(packet[Dot11], 'addr3'):
results[field] = packet[Dot11].addr3 results[field] = packet[Dot11].addr3
break break
else: # magic else: # magic
raise FieldNotFoundError("Could not find field [BSSID]") raise FieldNotFoundError("Could not find field [BSSID]")
except Exception: except Exception:
raise FieldNotFoundError("Could not find field [BSSID]") raise FieldNotFoundError("Could not find field [BSSID]")
@@ -188,7 +200,7 @@ def extract_from_pcap(path, fields):
if packet.haslayer(Dot11Elt) and hasattr(packet[Dot11Elt], 'info'): if packet.haslayer(Dot11Elt) and hasattr(packet[Dot11Elt], 'info'):
results[field] = packet[Dot11Elt].info.decode('utf-8') results[field] = packet[Dot11Elt].info.decode('utf-8')
break break
else: # magic else: # magic
raise FieldNotFoundError("Could not find field [ESSID]") raise FieldNotFoundError("Could not find field [ESSID]")
except Exception: except Exception:
raise FieldNotFoundError("Could not find field [ESSID]") raise FieldNotFoundError("Could not find field [ESSID]")
@@ -202,9 +214,9 @@ def extract_from_pcap(path, fields):
if packet.haslayer(Dot11Beacon) and hasattr(packet[Dot11Beacon], 'network_stats'): if packet.haslayer(Dot11Beacon) and hasattr(packet[Dot11Beacon], 'network_stats'):
stats = packet[Dot11Beacon].network_stats() stats = packet[Dot11Beacon].network_stats()
if 'crypto' in stats: if 'crypto' in stats:
results[field] = stats['crypto'] # set with encryption types results[field] = stats['crypto'] # set with encryption types
break break
else: # magic else: # magic
raise FieldNotFoundError("Could not find field [ENCRYPTION]") raise FieldNotFoundError("Could not find field [ENCRYPTION]")
except Exception: except Exception:
raise FieldNotFoundError("Could not find field [ENCRYPTION]") raise FieldNotFoundError("Could not find field [ENCRYPTION]")

View File

@@ -12,4 +12,5 @@ numpy==1.17.2
inky==0.0.5 inky==0.0.5
smbus2==0.3.0 smbus2==0.3.0
Pillow==5.4.1 Pillow==5.4.1
spidev==3.4 spidev==3.4
gast==0.2.2

View File

@@ -1,354 +0,0 @@
#!/usr/bin/env bash
# based on: https://wiki.debian.org/RaspberryPi/qemu-user-static
## and https://z4ziggy.wordpress.com/2015/05/04/from-bochs-to-chroot/
set -eu
echo "THIS SCRIPT IS DEPRECATED, PLEASE REFER TO THE OFFICIAL DOCUMENTATION AT https://pwnagotchi.ai/contributing/#creating-an-image"
exit 1
REQUIREMENTS=( wget gunzip git dd e2fsck resize2fs parted losetup qemu-system-x86_64 )
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"
THIS_DIR=$(pwd)
PWNI_NAME="pwnagotchi"
PWNI_OUTPUT="pwnagotchi.img"
PWNI_SIZE="8"
OPT_SPARSE=0
OPT_PROVISION_ONLY=0
OPT_CHECK_DEPS_ONLY=0
OPT_IMAGE_PROVIDED=0
OPT_RASPBIAN_VERSION='latest'
OPT_APTPROXY=""
SUPPORTED_RASPBIAN_VERSIONS=( 'latest' 'buster' 'stretch' )
if [[ "$EUID" -ne 0 ]]; then
echo "Run this script as root!"
exit 1
fi
function check_dependencies() {
if [ -f /etc/debian_version ];
then
echo "[+] Checking Debian dependencies"
for REQ in "${DEBREQUIREMENTS[@]}"; do
if ! dpkg -s "$REQ" >/dev/null 2>&1; then
echo "Dependency check failed for ${REQ}; use 'apt-get install ${REQ}' to install"
exit 1
fi
done
fi
echo "[+] Checking dependencies"
for REQ in "${REQUIREMENTS[@]}"; do
if ! type "$REQ" >/dev/null 2>&1; then
echo "Dependency check failed for ${REQ}"
exit 1
fi
done
if ! test -e /usr/bin/qemu-arm-static; then
echo "[-] You need the package \"qemu-user-static\" for this to work."
exit 1
fi
if ! systemctl is-active systemd-binfmt.service >/dev/null 2>&1; then
mkdir -p "/lib/binfmt.d"
echo ':qemu-arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:F' > /lib/binfmt.d/qemu-arm-static.conf
systemctl restart systemd-binfmt.service
fi
}
function get_raspbian() {
VERSION="$1"
case "$VERSION" in
latest)
URL="https://downloads.raspberrypi.org/raspbian_lite_latest"
;;
buster)
URL="https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-07-12/2019-07-10-raspbian-buster.zip"
;;
stretch)
URL="https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/2019-04-08-raspbian-stretch.zip"
;;
esac
echo "[+] Downloading raspbian.zip"
mkdir -p "${TMP_DIR}"
wget --show-progress -qcO "${TMP_DIR}/raspbian.zip" "$URL"
echo "[+] Unpacking raspbian.zip to raspbian.img"
gunzip -c "${TMP_DIR}/raspbian.zip" > "${TMP_DIR}/raspbian.img"
}
function provide_raspbian() {
echo "[+] Providing path of raspbian file"
mkdir -p "${TMP_DIR}"
echo "[+] Unpacking raspbian.zip to raspbian.img"
gunzip -c "${PWNI_INPUT}" > "${TMP_DIR}/raspbian.img"
}
function setup_raspbian(){
# Detect the ability to create sparse files
if [ "${OPT_SPARSE}" -eq 0 ]; then
if ! type "bmaptool" >/dev/null 2>&1; then
echo "[!] bmaptool not available, not creating a sparse image"
else
echo "[+] Defaulting to sparse image generation as bmaptool is available"
OPT_SPARSE=1
fi
fi
# Note that we 'extend' the raspbian.img
if [ "${OPT_SPARSE}" -eq 1 ];
then
# Resize sparse (so that we can use bmaptool later)
echo "[+] Resizing sparse image of ${PWNI_SIZE}GB (1000s)"
truncate -s ${PWNI_SIZE}GB "${TMP_DIR}/raspbian.img"
else
echo "[+] Resizing full image to ${PWNI_SIZE}G"
# Full disk-space using image (appends to raspbian image)
dd if=/dev/zero bs=1G count="${PWNI_SIZE}" >> "${TMP_DIR}/raspbian.img"
fi
echo "[+] Setup loop device"
mkdir -p "${MNT_DIR}"
LOOP_PATH="$(losetup --find --partscan --show "${TMP_DIR}/raspbian.img")"
PART2_START="$(parted -s "$LOOP_PATH" -- print | awk '$1==2{ print $2 }')"
parted -s "$LOOP_PATH" rm 2
parted -s "$LOOP_PATH" mkpart primary "$PART2_START" 100%
echo "[+] Check FS"
e2fsck -y -f "${LOOP_PATH}p2"
echo "[+] Resize FS"
resize2fs "${LOOP_PATH}p2"
echo "[+] Device is ${LOOP_PATH}"
echo "[+] Unmount if already mounted with other img"
mountpoint -q "${MNT_DIR}" && umount -R "${MNT_DIR}"
echo "[+] Mount /"
mount -o rw "${LOOP_PATH}p2" "${MNT_DIR}"
echo "[+] Mount /boot"
mount -o rw "${LOOP_PATH}p1" "${MNT_DIR}/boot"
mount --bind /dev "${MNT_DIR}/dev/"
mount --bind /sys "${MNT_DIR}/sys/"
mount --bind /proc "${MNT_DIR}/proc/"
mount --bind /dev/pts "${MNT_DIR}/dev/pts"
cp /usr/bin/qemu-arm-static "${MNT_DIR}/usr/bin"
cp /etc/resolv.conf "${MNT_DIR}/etc/resolv.conf"
}
function provision_raspbian() {
cd "${MNT_DIR}"
sed -i'' 's/^\([^#]\)/#\1/g' etc/ld.so.preload # add comments
echo "[+] Run chroot commands"
LANG=C LC_ALL=C LC_CTYPE=C chroot . bin/bash -x <<EOF
set -eu
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
if [ ! -z "${OPT_APTPROXY}" ];
then
echo "[+] Using Proxy ${OPT_APTPROXY}"
echo "Acquire::http { Proxy \"${OPT_APTPROXY}\"; }" >/etc/apt/apt.conf.d/99pwnagotchi_proxy
fi
uname -a
apt-get -y update
apt-get -y upgrade
apt-get -y install git vim screen build-essential golang python3-pip gawk
apt-get -y install libpcap-dev libusb-1.0-0-dev libnetfilter-queue-dev
apt-get -y install dphys-swapfile libopenmpi-dev libatlas-base-dev
apt-get -y install libjasper-dev libqtgui4 libqt4-test libopenjp2-7
apt-get -y install tcpdump libilmbase23 libopenexr23 libgstreamer1.0-0
apt-get -y install libavcodec58 libavformat58 libswscale5
# setup dphys-swapfile
echo "CONF_SWAPSIZE=1024" >/etc/dphys-swapfile
systemctl enable dphys-swapfile.service
# install pwnagotchi
cd /tmp
git clone https://github.com/evilsocket/pwnagotchi.git
rsync -aP pwnagotchi/sdcard/boot/* /boot/
rsync -aP pwnagotchi/sdcard/rootfs/* /
rm -rf /tmp/pwnagotchi
# configure pwnagotchi
echo -e "$PWNI_NAME" > /etc/hostname
sed -i "s@^127\.0\.0\.1 .*@127.0.0.1 localhost "$PWNI_NAME" "$PWNI_NAME".local@g" /etc/hosts
sed -i "s@alpha@$PWNI_NAME@g" /etc/motd
chmod +x /etc/rc.local
# need armv6l version of tensorflow and opencv-python, not armv7l
# PIP_OPTS="--upgrade --only-binary :all: --abi cp37m --platform linux_armv6l --target /usr/lib/python3.7/site-packages/"
# pip3 install \$PIP_OPTS opencv-python
# Should work for tensorflow too, but BUG: Hash mismatch; therefore:
wget -P /root/ -c https://www.piwheels.org/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv6l.whl
wget -P /root/ -c https://www.piwheels.org/simple/opencv-python/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl
# we need to install these on first raspberry start...
sed -i '/startup\.sh/i pip3 install --no-deps --force-reinstall --upgrade /root/tensorflow-1.13.1-cp37-none-linux_armv6l.whl /root/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl && rm /root/tensorflow-1.13.1-cp37-none-linux_armv6l.whl /root/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl && sed -i "/tensorflow/d" /etc/rc.local' /etc/rc.local
# newer version is broken
pip3 install gast==0.2.2
</root/pwnagotchi/scripts/requirements.txt xargs -I{} --max-args=1 --max-procs="$(nproc)"\
pip3 install --progress-bar off {}
# waveshare
pip3 install spidev RPi.GPIO
# install bettercap
export GOPATH=/root/go
taskset -c 1 go get -u github.com/bettercap/bettercap
mv "\$GOPATH/bin/bettercap" /usr/bin/bettercap
# install bettercap caplets (cant run bettercap in chroot)
cd /tmp
git clone https://github.com/bettercap/caplets.git
cd caplets
make install
rm -rf /tmp/caplets
cd /root # fixes getcwd error that was bugging me
# Re4son-Kernel
echo "deb http://http.re4son-kernel.com/re4son/ kali-pi main" > /etc/apt/sources.list.d/re4son.list
wget -O - https://re4son-kernel.com/keys/http/archive-key.asc | apt-key add -
apt update
apt install -y kalipi-kernel kalipi-bootloader kalipi-re4son-firmware kalipi-kernel-headers libraspberrypi0 libraspberrypi-dev libraspberrypi-doc libraspberrypi-bin
# Fix PARTUUID
PUUID_ROOT="\$(blkid "\$(df / --output=source | tail -1)" | grep -Po 'PARTUUID="\K[^"]+')"
PUUID_BOOT="\$(blkid "\$(df /boot --output=source | tail -1)" | grep -Po 'PARTUUID="\K[^"]+')"
# sed regex info: search for line containing / followed by whitespace or /boot (second sed)
# in this line, search for PARTUUID= followed by letters, numbers or "-"
# replace that match with the new PARTUUID
sed -i "/\/[ ]\+/s/PARTUUID=[A-Za-z0-9-]\+/PARTUUID=\$PUUID_ROOT/g" /etc/fstab
sed -i "/\/boot/s/PARTUUID=[A-Za-z0-9-]\+/PARTUUID=\$PUUID_BOOT/g" /etc/fstab
sed -i "s/root=[^ ]\+/root=PARTUUID=\${PUUID_ROOT}/g" /boot/cmdline.txt
# delete keys
find /etc/ssh/ -name "ssh_host_*key*" -delete
# slows down boot
systemctl disable apt-daily.timer apt-daily.service apt-daily-upgrade.timer apt-daily-upgrade.service
# unecessary services
systemctl disable triggerhappy bluetooth wpa_supplicant
EOF
sed -i'' 's/^#//g' etc/ld.so.preload
cd "${REPO_DIR}"
umount -R "${MNT_DIR}"
losetup -D "$(losetup -l | awk '/raspbian\.img/{print $1}')"
mv "${TMP_DIR}/raspbian.img" "${PWNI_OUTPUT}"
if [ "${OPT_SPARSE}" -eq 1 ];
then
bmaptool create -o "${PWNI_OUTPUT}.bmap" "${PWNI_OUTPUT}"
fi
}
function usage() {
cat <<EOF
usage: $0 [OPTIONS]
Options:
-n <name> # Name of the pwnagotchi (default: pwnagotchi)
-i <file> # Provide the path of an already downloaded raspbian image
-o <file> # Name of the img-file (default: pwnagotchi.img)
-s <size> # Size which should be added to second partition (in Gigabyte) (default: 4)
-v <version> # Version of raspbian (Supported: ${SUPPORTED_RASPBIAN_VERSIONS[*]}; default: latest)
-p # Only run provisioning (assumes the image is already mounted)
-d # Only run dependencies checks
-h # Show this help
EOF
exit 0
}
while getopts "A:n:i:o:s:v:dph" o; do
case "${o}" in
A)
OPT_APTPROXY="${OPTARG}"
;;
n)
PWNI_NAME="${OPTARG}"
;;
i)
PWNI_INPUT="${OPTARG}"
OPT_IMAGE_PROVIDED=1
;;
o)
PWNI_OUTPUT="${OPTARG}"
;;
s)
PWNI_SIZE="${OPTARG}"
;;
p)
OPT_PROVISION_ONLY=1
;;
d)
OPT_CHECK_DEPS_ONLY=1
;;
v)
if [[ "${SUPPORTED_RASPBIAN_VERSIONS[*]}" =~ ${OPTARG} ]]; then
OPT_RASPBIAN_VERSION="${OPTARG}"
else
usage
fi
;;
h)
usage
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
if [[ "$OPT_PROVISION_ONLY" -eq 1 ]]; then
provision_raspbian
exit 0
elif [[ "$OPT_CHECK_DEPS_ONLY" -eq 1 ]]; then
check_dependencies
exit 0
fi
check_dependencies
if [[ "$OPT_IMAGE_PROVIDED" -eq 1 ]]; then
provide_raspbian
else
get_raspbian "$OPT_RASPBIAN_VERSION"
fi
setup_raspbian
provision_raspbian
#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 ${gender[$rand]} (⌐■_■)!"
echo -e "[+] One more step: dd if=../${PWNI_OUTPUT} of=<PATH_TO_SDCARD> bs=4M status=progress"
if [ "${OPT_SPARSE}" -eq 1 ];
then
echo -e "[t] To transfer use: rsync -vaS --progress $(whoami)@$(hostname -f):${THIS_DIR}/../${PWNI_OUTPUT} <DEST>"
echo -e "[t] To burn with bmaptool: bmaptool copy ~/${PWNI_OUTPUT} /dev/<DEVICE>"
fi
# Helpful OSX reminder
echo -e "[t] Mac: use 'diskutil list' to figure out which device to burn to; 'diskutil unmountDisk' to unmount that disk'; then use /dev/rdiskX (note the 'r') for faster transfer"