mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2025-07-01 18:37:27 -04:00
Compare commits
227 Commits
Author | SHA1 | Date | |
---|---|---|---|
a92e66137c | |||
a7e98cf166 | |||
9a1a264a9f | |||
8a0d482fe0 | |||
0cc320d31f | |||
d841d2b649 | |||
966126a986 | |||
d67935fa6a | |||
46d867ce7f | |||
2e16069850 | |||
6e3cbbdd39 | |||
a19bd6a181 | |||
6c03d95724 | |||
60a9da9acc | |||
25aba0d73c | |||
ecde496534 | |||
7ebd4dd7a0 | |||
35f1707436 | |||
60ced12ea5 | |||
6082a0c169 | |||
a72c1b1628 | |||
e37a0bdc62 | |||
262f8bf551 | |||
5311dd9ddc | |||
bd9c44b4a3 | |||
3b01aec872 | |||
3e571bff2d | |||
391941e64a | |||
3fff6182ed | |||
73e0a1fce7 | |||
9ba23d77d1 | |||
8be75627e9 | |||
c2a36aa678 | |||
fdf0a087f6 | |||
c6efa5df08 | |||
62327a711e | |||
bb460a9cc6 | |||
93b2322ab5 | |||
53a8af4711 | |||
ed5decffa0 | |||
147cbfaa07 | |||
ced9b4d5ee | |||
472c3165ed | |||
1578d13d98 | |||
0965e7eb3e | |||
b789c14f14 | |||
0855b44d59 | |||
55c6007d32 | |||
a7cf8a3383 | |||
faa48b2752 | |||
d20619340c | |||
43a07fe969 | |||
bcce22c164 | |||
0264b7a7db | |||
fba5dd0341 | |||
dd7760efdf | |||
f7cd0fb1fc | |||
611a3e7fb5 | |||
599c6211e4 | |||
eb48d29851 | |||
0999b95be0 | |||
ae351e5e9c | |||
fa58136c0e | |||
3d5185f2c1 | |||
b6bb7b9080 | |||
20715351af | |||
1d3c781d12 | |||
bd51b4330f | |||
f216a21132 | |||
5ae357c3dc | |||
ed9afe6856 | |||
25d932fa9b | |||
ebd25d50b0 | |||
27e784a5d7 | |||
c02efb5224 | |||
107d366c82 | |||
488968ba7f | |||
0dd8f72c95 | |||
0e274af5a0 | |||
8627c8800d | |||
53ed6f61c6 | |||
835523241b | |||
418dbf21e3 | |||
9a40567daa | |||
eab331686d | |||
e1d8001fb4 | |||
3cc172a526 | |||
41afe302d9 | |||
5bcca7e89b | |||
4a12436942 | |||
d8b6363d37 | |||
b3d8a44208 | |||
3fb91498cd | |||
7587f38c28 | |||
d7fefa78f0 | |||
1ef3a88679 | |||
291ef39563 | |||
16d80a09e6 | |||
4ffad03c91 | |||
0638832532 | |||
f895b06978 | |||
f410feb2bb | |||
1ffe6c4e3d | |||
dfbfd7f891 | |||
a50695aef2 | |||
829a6962d6 | |||
ce1315b85f | |||
6a2703cc27 | |||
502e856934 | |||
dffcbbf447 | |||
333804c3bb | |||
50b1ceed81 | |||
877b9fbba3 | |||
8724ca546d | |||
961d3a536a | |||
c882d0b67a | |||
12fd081ae0 | |||
e1be0f7674 | |||
396b30f780 | |||
e7d8d632a0 | |||
5a6ec7b4b8 | |||
92cd5d3fdb | |||
99caa7a973 | |||
a94e7eef02 | |||
1cefae55d1 | |||
c5ee1df855 | |||
d142840307 | |||
e558146e28 | |||
11a3330153 | |||
53b2dd8628 | |||
6381f9443b | |||
fa7e87b974 | |||
cca2ff2da4 | |||
78415b3137 | |||
34284aa1bc | |||
56ebb60662 | |||
84f6624844 | |||
3bcbb0ce9a | |||
e01e457992 | |||
1780859889 | |||
fdd98bb37a | |||
86991304a5 | |||
4f62759d6d | |||
7b7ba02aad | |||
7040be2d30 | |||
d0617ccfaf | |||
a0b5078b64 | |||
54c1ffd63c | |||
7530709d0c | |||
a9a6fd424b | |||
8c97301992 | |||
91eaa22188 | |||
31a4af4c21 | |||
dceeaff1fb | |||
c0241dc8df | |||
8f405f4ab2 | |||
bd79e71563 | |||
7f662585aa | |||
d23ff8d47a | |||
04435229fe | |||
42e236bafe | |||
5081b72695 | |||
652740f050 | |||
1b6b12bdf5 | |||
c610335a34 | |||
6c39ed97dd | |||
967f1663c6 | |||
ffe1e90ccd | |||
f2d2bcbfdf | |||
bfc0795fb8 | |||
1a55afd74a | |||
1594e7c129 | |||
a244e70a1c | |||
d35d5d6c3c | |||
7aacf9fb44 | |||
dde6fa4c2a | |||
7dfb2f2ff6 | |||
cf46ab3da9 | |||
6824e541a4 | |||
1c4e8fa750 | |||
a50ec4a65c | |||
5414fdf21d | |||
c9883bb4f9 | |||
045f5853bc | |||
6dfcaf05d5 | |||
e2f8119d2c | |||
d675b3d0dd | |||
30850b6530 | |||
1e9c9bae42 | |||
64241515ad | |||
c9f232dae2 | |||
4f97bcaa83 | |||
7d2a03c79f | |||
f89ba85f73 | |||
57f03f4359 | |||
9bc266f9ff | |||
b0db0285bc | |||
cca3e77d50 | |||
4fe603bf5e | |||
9a9ee70a78 | |||
7fc8838f76 | |||
94b2ff7047 | |||
8edb0fdaa4 | |||
b557768159 | |||
5a6967eb4d | |||
c0c35231cf | |||
88362b3354 | |||
e50cf04967 | |||
85a64a3914 | |||
63d0c20a3e | |||
044639a6d4 | |||
7fc2c6b25f | |||
c5d5d9bb14 | |||
129ae92447 | |||
2560692ee2 | |||
1424e0d510 | |||
2c9eaa436a | |||
0c5c6058a5 | |||
a3fb39d78c | |||
bac62bc4aa | |||
f7a5f2a554 | |||
6921fd14a3 | |||
0dbd611ed5 | |||
18b9093f70 | |||
26913016b9 | |||
0786b6757e | |||
0f4eda8039 |
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1,4 +1,3 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
patreon: pwnagotchi_torch
|
|
||||||
github: jayofelony
|
github: jayofelony
|
||||||
|
72
.github/workflows/publish.yml
vendored
Normal file
72
.github/workflows/publish.yml
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
name: Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version number'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Extract version from file
|
||||||
|
id: get_version
|
||||||
|
run: |
|
||||||
|
VERSION=$(cut -d "'" -f2 < pwnagotchi/_version.py)
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get latest tag
|
||||||
|
uses: actions-ecosystem/action-get-latest-tag@v1
|
||||||
|
id: get-latest-tag
|
||||||
|
|
||||||
|
- name: Set LAST_VERSION as an environment variable
|
||||||
|
run: echo "LAST_VERSION=${{ steps.get-latest-tag.outputs.tag }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Generate release notes
|
||||||
|
id: generate_release_notes
|
||||||
|
run: |
|
||||||
|
COMMITS=$(git log --merges --pretty=format:"* %s" $LAST_VERSION--$VERSION | sed 's/$/\\n/g')
|
||||||
|
CONTRIBUTORS=$(git shortlog -sn $LAST_VERSION--$VERSION | awk '{print "* @" $2}' | sed 's/$/\\n/g')
|
||||||
|
RELEASE_BODY="**Full Changelog**: https://github.com/jayofelony/pwnagotchi/compare/$LAST_VERSION...$VERSION"
|
||||||
|
echo "RELEASE_BODY=$RELEASE_BODY" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install qemu dependencies
|
||||||
|
run: sudo apt update && sudo apt install qemu-user-static qemu-utils xz-utils -y
|
||||||
|
|
||||||
|
- name: Build img file
|
||||||
|
run: ls -la .; pwd; make all
|
||||||
|
|
||||||
|
- name: Transfer 32bit.img to docker and give permissions
|
||||||
|
run: sudo chown runner:docker "pwnagotchi-32bit.img"
|
||||||
|
|
||||||
|
- name: Transfer 64bit.img to docker and give permissions
|
||||||
|
run: sudo chown runner:docker "pwnagotchi-64bit.img"
|
||||||
|
|
||||||
|
- name: PiShrink
|
||||||
|
run: |
|
||||||
|
wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
|
||||||
|
chmod +x pishrink.sh
|
||||||
|
sudo mv pishrink.sh /usr/local/bin
|
||||||
|
find /home/runner/work/ -type f -name "*.img" -exec sudo pishrink.sh -aZ {} \;
|
||||||
|
|
||||||
|
- name: Change name of 32.img.xz to add version
|
||||||
|
run: mv "pwnagotchi-32bit.img.xz" "pwnagotchi-$VERSION-32bit.img.xz"
|
||||||
|
|
||||||
|
- name: Change name of 64.img.xz to add version
|
||||||
|
run: mv "pwnagotchi-64bit.img.xz" "pwnagotchi-$VERSION-64bit.img.xz"
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
prerelease: true
|
||||||
|
tag_name: v${{ env.VERSION }}
|
||||||
|
name: Pwnagotchi v${{ env.VERSION }}
|
||||||
|
files: |
|
||||||
|
pwnagotchi-${{ env.VERSION }}-32bit.img.xz
|
||||||
|
pwnagotchi-${{ env.VERSION }}-64bit.img.xz
|
||||||
|
body: ${{ env.RELEASE_BODY }}
|
21
.idea/deployment.xml
generated
21
.idea/deployment.xml
generated
@ -1,4 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="PublishConfigData" filePermissions="493" folderPermissions="493" remoteFilesAllowedToDisappearOnAutoupload="false" />
|
<component name="PublishConfigData" serverName="pwnagotchi" filePermissions="493" folderPermissions="493" remoteFilesAllowedToDisappearOnAutoupload="false" confirmBeforeUploading="false">
|
||||||
|
<option name="confirmBeforeUploading" value="false" />
|
||||||
|
<serverData>
|
||||||
|
<paths name="pwnagotchi">
|
||||||
|
<serverdata>
|
||||||
|
<mappings>
|
||||||
|
<mapping deploy="/usr/local/lib/python3.11/dist-packages/pwnagotchi" local="$PROJECT_DIR$/pwnagotchi" web="/" />
|
||||||
|
<mapping deploy="/usr/local/bin" local="$PROJECT_DIR$/bin" />
|
||||||
|
<mapping local="" />
|
||||||
|
</mappings>
|
||||||
|
<excludedPaths>
|
||||||
|
<excludedPath local="true" path="$PROJECT_DIR$/venv" />
|
||||||
|
<excludedPath local="true" path="$PROJECT_DIR$/pwnagotchi.egg-info" />
|
||||||
|
<excludedPath local="true" path="$PROJECT_DIR$/dist" />
|
||||||
|
<excludedPath local="true" path="$PROJECT_DIR$/builder/packer-builder-arm" />
|
||||||
|
</excludedPaths>
|
||||||
|
</serverdata>
|
||||||
|
</paths>
|
||||||
|
</serverData>
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@ -3,5 +3,8 @@
|
|||||||
<component name="Black">
|
<component name="Black">
|
||||||
<option name="sdkName" value="Python 3.11 (pwnagotchi)" />
|
<option name="sdkName" value="Python 3.11 (pwnagotchi)" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (pwnagotchi-torch-bookworm)" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
|
||||||
|
<component name="PythonCompatibilityInspectionAdvertiser">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
2
.idea/pwnagotchi.iml
generated
2
.idea/pwnagotchi.iml
generated
@ -4,7 +4,7 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Python 3.10 (pwnagotchi-torch-bookworm)" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PyDocumentationSettings">
|
<component name="PyDocumentationSettings">
|
||||||
|
40
Makefile
40
Makefile
@ -1,4 +1,4 @@
|
|||||||
PACKER_VERSION := 1.10.0
|
PACKER_VERSION := 1.10.1
|
||||||
PWN_HOSTNAME := pwnagotchi
|
PWN_HOSTNAME := pwnagotchi
|
||||||
PWN_VERSION := $(shell cut -d"'" -f2 < pwnagotchi/_version.py)
|
PWN_VERSION := $(shell cut -d"'" -f2 < pwnagotchi/_version.py)
|
||||||
|
|
||||||
@ -25,7 +25,8 @@ ifneq (,$(UNSHARE))
|
|||||||
UNSHARE := $(UNSHARE) --uts
|
UNSHARE := $(UNSHARE) --uts
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: clean image clean
|
# sudo apt-get install qemu-user-static qemu-utils
|
||||||
|
all: clean packer image
|
||||||
|
|
||||||
update_langs:
|
update_langs:
|
||||||
@for lang in pwnagotchi/locale/*/; do\
|
@for lang in pwnagotchi/locale/*/; do\
|
||||||
@ -39,30 +40,21 @@ compile_langs:
|
|||||||
./scripts/language.sh compile $$(basename $$lang); \
|
./scripts/language.sh compile $$(basename $$lang); \
|
||||||
done
|
done
|
||||||
|
|
||||||
PACKER := ~/pwnagotchi/packer
|
packer: clean
|
||||||
PACKER_URL := https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_$(GOARCH).zip
|
curl https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_amd64.zip -o /tmp/packer.zip
|
||||||
$(PACKER):
|
unzip /tmp/packer.zip -d /tmp
|
||||||
mkdir -p $(@D)
|
sudo mv /tmp/packer /usr/bin/packer
|
||||||
curl -L "$(PACKER_URL)" -o $(PACKER).zip
|
|
||||||
unzip $(PACKER).zip -d $(@D)
|
|
||||||
rm $(PACKER).zip
|
|
||||||
chmod +x $@
|
|
||||||
|
|
||||||
SDIST := dist/pwnagotchi-$(PWN_VERSION).tar.gz
|
image: clean packer
|
||||||
$(SDIST): setup.py pwnagotchi
|
cd builder && sudo /usr/bin/packer init combined.json.pkr.hcl && sudo $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" combined.json.pkr.hcl
|
||||||
python3 setup.py sdist
|
|
||||||
|
|
||||||
# Building the image requires packer, but don't rebuild the image just because packer updated.
|
bullseye: clean packer
|
||||||
pwnagotchi: | $(PACKER)
|
cd builder && sudo /usr/bin/packer init data/32bit/raspberrypi32.json.pkr.hcl && sudo $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" data/32bit/raspberrypi32.json.pkr.hcl
|
||||||
|
sudo pishrink -vaZ pwnagotchi-32bit.img
|
||||||
|
|
||||||
# If the packer or ansible files are updated, rebuild the image.
|
bookworm: clean packer
|
||||||
pwnagotchi: $(SDIST) builder/pwnagotchi.json.pkr.hcl builder/raspberrypi64.yml $(shell find builder/data -type f)
|
cd builder && sudo /usr/bin/packer init data/64bit/raspberrypi64.json.pkr.hcl && sudo $(UNSHARE) /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" data/64bit/raspberrypi64.json.pkr.hcl
|
||||||
|
sudo pishrink -vaZ pwnagotchi-64bit.img
|
||||||
cd builder && $(PACKER) init pwnagotchi.json.pkr.hcl && sudo $(UNSHARE) $(PACKER) build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" pwnagotchi.json.pkr.hcl
|
|
||||||
|
|
||||||
.PHONY: image
|
|
||||||
image: pwnagotchi
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
- rm -rf build dist pwnagotchi.egg-info
|
- rm -rf /tmp/packer*
|
||||||
- rm -f $(PACKER)
|
|
||||||
|
27
README.md
27
README.md
@ -1,26 +1,7 @@
|
|||||||
# Pwnagotchi-Torch
|
# Pwnagotchi
|
||||||
<a href="https://github.com/jayofelony/pwnagotchi-bookworm/releases/latest"><img alt="Release" src="https://img.shields.io/github/release/jayofelony/pwnagotchi-bookworm.svg"></a><br/>
|
This is the main source for all forks:
|
||||||
**This fork of [Pwnagotchi](https://www.pwnagotchi.ai) is only for 64-bit Raspberry Pi's. Such as the 02W, 3(b+) and 4(b) ~~and the new Raspberry Pi 5~~!!.**
|
- RPiZeroW (32bit)
|
||||||
|
- RPiZero2W, RPi3, RPi4, RPi5 (64bit)
|
||||||
It seems the Pi 5 is unable to run in monitor mode, will keep you updated on this.
|
|
||||||
|
|
||||||
If you are using an older 32-bit version Raspberry Pi, ZeroWH, use this [fork](https://github.com/jayofelony/pwnagotchi-torch/releases/tag/v2.6.4) and make sure you download the `armhf` version.
|
|
||||||
|
|
||||||
---
|
|
||||||
Download latest image file [here](https://github.com/jayofelony/pwnagotchi-bookworm/releases/tag/v2.6.7), and let it auto-update from here on out.
|
|
||||||
|
|
||||||
**Use RPi imager to flash, please don't flash a new user as this will mess with logs created.**
|
|
||||||
|
|
||||||
SSH credentials are `pi/raspberry`.
|
|
||||||
|
|
||||||
# Donations:
|
|
||||||
I would like to thank
|
|
||||||
- [findingmoist](https://github.com/findingmoist)
|
|
||||||
- [kr4k0n](https://github.com/kr4k0n)
|
|
||||||
|
|
||||||
for donating!
|
|
||||||
|
|
||||||
[Pwnagotchi-Torch](https://www.patreon.com/pwnagotchi_torch)
|
|
||||||
|
|
||||||
[GH Sponsor](https://github.com/sponsors/jayofelony)
|
[GH Sponsor](https://github.com/sponsors/jayofelony)
|
||||||
|
|
||||||
|
@ -18,13 +18,13 @@ from pwnagotchi import fs
|
|||||||
from pwnagotchi.utils import DottedTomlEncoder, parse_version as version_to_tuple
|
from pwnagotchi.utils import DottedTomlEncoder, parse_version as version_to_tuple
|
||||||
|
|
||||||
|
|
||||||
def pwnagotchi_cli():
|
def do_clear(display):
|
||||||
def do_clear(display):
|
|
||||||
logging.info("clearing the display ...")
|
logging.info("clearing the display ...")
|
||||||
display.clear()
|
display.clear()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
def do_manual_mode(agent):
|
|
||||||
|
def do_manual_mode(agent):
|
||||||
logging.info("entering manual mode ...")
|
logging.info("entering manual mode ...")
|
||||||
|
|
||||||
agent.mode = 'manual'
|
agent.mode = 'manual'
|
||||||
@ -45,7 +45,8 @@ def pwnagotchi_cli():
|
|||||||
if grid.is_connected():
|
if grid.is_connected():
|
||||||
plugins.on('internet_available', agent)
|
plugins.on('internet_available', agent)
|
||||||
|
|
||||||
def do_auto_mode(agent):
|
|
||||||
|
def do_auto_mode(agent):
|
||||||
logging.info("entering auto mode ...")
|
logging.info("entering auto mode ...")
|
||||||
|
|
||||||
agent.mode = 'auto'
|
agent.mode = 'auto'
|
||||||
@ -87,15 +88,15 @@ def pwnagotchi_cli():
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if str(e).find("wifi.interface not set") > 0:
|
if str(e).find("wifi.interface not set") > 0:
|
||||||
logging.exception(
|
logging.exception("main loop exception due to unavailable wifi device, likely programmatically disabled (%s)", e)
|
||||||
"main loop exception due to unavailable wifi device, likely programmatically disabled (%s)", e)
|
logging.info("sleeping 60 seconds then advancing to next epoch to allow for cleanup code to trigger")
|
||||||
logging.info(
|
|
||||||
"sleeping 60 seconds then advancing to next epoch to allow for cleanup code to trigger")
|
|
||||||
time.sleep(60)
|
time.sleep(60)
|
||||||
agent.next_epoch()
|
agent.next_epoch()
|
||||||
else:
|
else:
|
||||||
logging.exception("main loop exception (%s)", e)
|
logging.exception("main loop exception (%s)", e)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
def add_parsers(parser):
|
def add_parsers(parser):
|
||||||
"""
|
"""
|
||||||
Adds the plugins and google subcommands
|
Adds the plugins and google subcommands
|
||||||
@ -157,11 +158,14 @@ def pwnagotchi_cli():
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if args.donate:
|
if args.donate:
|
||||||
print("Donations can made @ https://www.patreon.com/pwnagotchi_torch \n\nBut only if you really want to!")
|
print("Donations can made @ \n "
|
||||||
|
"https://www.patreon.com/pwnagotchi_torch \n "
|
||||||
|
"https://github.com/sponsors/jayofelony \n\n"
|
||||||
|
"But only if you really want to!")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if args.check_update:
|
if args.check_update:
|
||||||
resp = requests.get("https://api.github.com/repos/jayofelony/pwnagotchi-bookworm/releases/latest")
|
resp = requests.get("https://api.github.com/repos/jayofelony/pwnagotchi/releases/latest")
|
||||||
latest = resp.json()
|
latest = resp.json()
|
||||||
latest_ver = latest['tag_name'].replace('v', '')
|
latest_ver = latest['tag_name'].replace('v', '')
|
||||||
|
|
||||||
@ -174,12 +178,11 @@ def pwnagotchi_cli():
|
|||||||
if user_input.lower() in ('y', 'yes'):
|
if user_input.lower() in ('y', 'yes'):
|
||||||
if os.path.exists('/root/.auto-update'):
|
if os.path.exists('/root/.auto-update'):
|
||||||
os.system("rm /root/.auto-update && systemctl restart pwnagotchi")
|
os.system("rm /root/.auto-update && systemctl restart pwnagotchi")
|
||||||
os.system("systemctl restart pwnagotchi")
|
|
||||||
print("Okay, give me a couple minutes. Just watch pwnlog while you wait.")
|
|
||||||
elif user_input.lower() in ('n', 'no'):
|
|
||||||
print("Okay, guess not!")
|
|
||||||
else:
|
else:
|
||||||
print("Invalid input.")
|
logging.error("You should make sure auto-update is enabled!")
|
||||||
|
print("Okay, give me a couple minutes. Just watch pwnlog while you wait.")
|
||||||
|
elif user_input.lower() in ('n', 'no'): # using this elif for readability
|
||||||
|
print("Okay, guess not!")
|
||||||
else:
|
else:
|
||||||
print("You are currently on the latest release, v%s." % pwnagotchi.__version__)
|
print("You are currently on the latest release, v%s." % pwnagotchi.__version__)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@ -224,7 +227,3 @@ def pwnagotchi_cli():
|
|||||||
do_manual_mode(agent)
|
do_manual_mode(agent)
|
||||||
else:
|
else:
|
||||||
do_auto_mode(agent)
|
do_auto_mode(agent)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
pwnagotchi_cli()
|
|
||||||
|
173
builder/combined.json.pkr.hcl
Normal file
173
builder/combined.json.pkr.hcl
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
packer {
|
||||||
|
required_plugins {
|
||||||
|
arm = {
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "github.com/cdecoux/builder-arm"
|
||||||
|
}
|
||||||
|
ansible = {
|
||||||
|
source = "github.com/hashicorp/ansible"
|
||||||
|
version = ">= 1.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "pwn_hostname" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "pwn_version" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
source "arm" "rpi64-pwnagotchi" {
|
||||||
|
file_checksum_url = "https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2023-12-11/2023-12-11-raspios-bookworm-arm64-lite.img.xz.sha256"
|
||||||
|
file_urls = ["https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2023-12-11/2023-12-11-raspios-bookworm-arm64-lite.img.xz"]
|
||||||
|
file_checksum_type = "sha256"
|
||||||
|
file_target_extension = "xz"
|
||||||
|
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
||||||
|
image_path = "../pwnagotchi-64bit.img"
|
||||||
|
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
|
||||||
|
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
|
||||||
|
image_build_method = "resize"
|
||||||
|
image_size = "9G"
|
||||||
|
image_type = "dos"
|
||||||
|
image_partitions {
|
||||||
|
name = "boot"
|
||||||
|
type = "c"
|
||||||
|
start_sector = "8192"
|
||||||
|
filesystem = "fat"
|
||||||
|
size = "256M"
|
||||||
|
mountpoint = "/boot/firmware"
|
||||||
|
}
|
||||||
|
image_partitions {
|
||||||
|
name = "root"
|
||||||
|
type = "83"
|
||||||
|
start_sector = "532480"
|
||||||
|
filesystem = "ext4"
|
||||||
|
size = "0"
|
||||||
|
mountpoint = "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source "arm" "rpi32-pwnagotchi" {
|
||||||
|
file_checksum_url = "https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2023-12-06/2023-12-05-raspios-bullseye-armhf-lite.img.xz.sha256"
|
||||||
|
file_urls = ["https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2023-12-06/2023-12-05-raspios-bullseye-armhf-lite.img.xz"]
|
||||||
|
file_checksum_type = "sha256"
|
||||||
|
file_target_extension = "xz"
|
||||||
|
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
||||||
|
image_path = "../pwnagotchi-32bit.img"
|
||||||
|
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
||||||
|
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
||||||
|
image_build_method = "resize"
|
||||||
|
image_size = "9G"
|
||||||
|
image_type = "dos"
|
||||||
|
image_partitions {
|
||||||
|
name = "boot"
|
||||||
|
type = "c"
|
||||||
|
start_sector = "8192"
|
||||||
|
filesystem = "fat"
|
||||||
|
size = "256M"
|
||||||
|
mountpoint = "/boot"
|
||||||
|
}
|
||||||
|
image_partitions {
|
||||||
|
name = "root"
|
||||||
|
type = "83"
|
||||||
|
start_sector = "532480"
|
||||||
|
filesystem = "ext4"
|
||||||
|
size = "0"
|
||||||
|
mountpoint = "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# a build block invokes sources and runs provisioning steps on them. The
|
||||||
|
# documentation for build blocks can be found here:
|
||||||
|
# https://www.packer.io/docs/from-1.5/blocks/build
|
||||||
|
build {
|
||||||
|
name = "Raspberry Pi 64 Pwnagotchi"
|
||||||
|
sources = ["source.arm.rpi64-pwnagotchi"]
|
||||||
|
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/usr/bin/"
|
||||||
|
sources = [
|
||||||
|
"data/64bit/usr/bin/bettercap-launcher",
|
||||||
|
"data/64bit/usr/bin/hdmioff",
|
||||||
|
"data/64bit/usr/bin/hdmion",
|
||||||
|
"data/64bit/usr/bin/monstart",
|
||||||
|
"data/64bit/usr/bin/monstop",
|
||||||
|
"data/64bit/usr/bin/pwnagotchi-launcher",
|
||||||
|
"data/64bit/usr/bin/pwnlib",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["chmod +x /usr/bin/*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/etc/systemd/system/"
|
||||||
|
sources = [
|
||||||
|
"data/64bit/etc/systemd/system/bettercap.service",
|
||||||
|
"data/64bit/etc/systemd/system/pwnagotchi.service",
|
||||||
|
"data/64bit/etc/systemd/system/pwngrid-peer.service",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/etc/update-motd.d/01-motd"
|
||||||
|
source = "data/64bit/etc/update-motd.d/01-motd"
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["chmod +x /etc/update-motd.d/*"]
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["apt-get -y --allow-releaseinfo-change update", "apt-get -y dist-upgrade", "apt-get install -y --no-install-recommends ansible"]
|
||||||
|
}
|
||||||
|
provisioner "ansible-local" {
|
||||||
|
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
||||||
|
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
||||||
|
playbook_file = "data/64bit/raspberrypi64.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build {
|
||||||
|
name = "Raspberry Pi 32 Pwnagotchi"
|
||||||
|
sources = ["source.arm.rpi32-pwnagotchi"]
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/usr/bin/"
|
||||||
|
sources = [
|
||||||
|
"data/32bit/usr/bin/bettercap-launcher",
|
||||||
|
"data/32bit/usr/bin/hdmioff",
|
||||||
|
"data/32bit/usr/bin/hdmion",
|
||||||
|
"data/32bit/usr/bin/monstart",
|
||||||
|
"data/32bit/usr/bin/monstop",
|
||||||
|
"data/32bit/usr/bin/pwnagotchi-launcher",
|
||||||
|
"data/32bit/usr/bin/pwnlib",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["chmod +x /usr/bin/*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/etc/systemd/system/"
|
||||||
|
sources = [
|
||||||
|
"data/32bit/etc/systemd/system/bettercap.service",
|
||||||
|
"data/32bit/etc/systemd/system/pwnagotchi.service",
|
||||||
|
"data/32bit/etc/systemd/system/pwngrid-peer.service",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/etc/update-motd.d/01-motd"
|
||||||
|
source = "data/32bit/etc/update-motd.d/01-motd"
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["chmod +x /etc/update-motd.d/*"]
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["apt-get -y --allow-releaseinfo-change update", "apt-get -y dist-upgrade", "apt-get install -y --no-install-recommends ansible"]
|
||||||
|
}
|
||||||
|
provisioner "ansible-local" {
|
||||||
|
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
||||||
|
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
||||||
|
playbook_dir = "data/32bit/extras/"
|
||||||
|
playbook_file = "data/32bit/raspberrypi32.yml"
|
||||||
|
}
|
||||||
|
}
|
62
builder/data/32bit/etc/dhcpcd.conf
Normal file
62
builder/data/32bit/etc/dhcpcd.conf
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# A sample configuration for dhcpcd.
|
||||||
|
# See dhcpcd.conf(5) for details.
|
||||||
|
|
||||||
|
# Allow users of this group to interact with dhcpcd via the control socket.
|
||||||
|
#controlgroup wheel
|
||||||
|
|
||||||
|
# Inform the DHCP server of our hostname for DDNS.
|
||||||
|
hostname
|
||||||
|
|
||||||
|
# Use the hardware address of the interface for the Client ID.
|
||||||
|
clientid
|
||||||
|
# or
|
||||||
|
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
|
||||||
|
# Some non-RFC compliant DHCP servers do not reply with this set.
|
||||||
|
# In this case, comment out duid and enable clientid above.
|
||||||
|
#duid
|
||||||
|
|
||||||
|
# Persist interface configuration when dhcpcd exits.
|
||||||
|
persistent
|
||||||
|
|
||||||
|
# Rapid commit support.
|
||||||
|
# Safe to enable by default because it requires the equivalent option set
|
||||||
|
# on the server to actually work.
|
||||||
|
option rapid_commit
|
||||||
|
|
||||||
|
# A list of options to request from the DHCP server.
|
||||||
|
option domain_name_servers, domain_name, domain_search, host_name
|
||||||
|
option classless_static_routes
|
||||||
|
# Respect the network MTU. This is applied to DHCP routes.
|
||||||
|
option interface_mtu
|
||||||
|
|
||||||
|
# Most distributions have NTP support.
|
||||||
|
#option ntp_servers
|
||||||
|
|
||||||
|
# A ServerID is required by RFC2131.
|
||||||
|
require dhcp_server_identifier
|
||||||
|
|
||||||
|
# Generate SLAAC address using the Hardware Address of the interface
|
||||||
|
#slaac hwaddr
|
||||||
|
# OR generate Stable Private IPv6 Addresses based from the DUID
|
||||||
|
slaac private
|
||||||
|
|
||||||
|
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
# !! DO NOT EDIT THESE LINES BELOW PLEASE !!
|
||||||
|
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
# static IP configuration:
|
||||||
|
denyinterfaces wlan0
|
||||||
|
|
||||||
|
interface eth0
|
||||||
|
static domain_name_servers=8.8.8.8 1.1.1.1
|
||||||
|
metric 201
|
||||||
|
|
||||||
|
interface usb0
|
||||||
|
static ip_address=10.0.0.2/24
|
||||||
|
static routers=10.0.0.1
|
||||||
|
static domain_name_servers=10.0.0.1 8.8.8.8 1.1.1.1
|
||||||
|
metric 202
|
||||||
|
|
||||||
|
interface bnep0
|
||||||
|
static domain_name_servers=8.8.8.8 1.1.1.1
|
||||||
|
metric 203
|
20
builder/data/32bit/etc/systemd/system/bluetooth.service
Normal file
20
builder/data/32bit/etc/systemd/system/bluetooth.service
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Bluetooth service
|
||||||
|
Documentation=man:bluetoothd(8)
|
||||||
|
ConditionPathIsDirectory=/sys/class/bluetooth
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=dbus
|
||||||
|
BusName=org.bluez
|
||||||
|
ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,a2dp
|
||||||
|
NotifyAccess=main
|
||||||
|
#WatchdogSec=10
|
||||||
|
#Restart=on-failure
|
||||||
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||||
|
LimitNPROC=1
|
||||||
|
ProtectHome=true
|
||||||
|
ProtectSystem=full
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=bluetooth.target
|
||||||
|
Alias=dbus-org.bluez.service
|
@ -0,0 +1,6 @@
|
|||||||
|
[Unit]
|
||||||
|
After=hciuart.service bluetooth.service
|
||||||
|
Before=
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=/bin/sleep 5
|
@ -8,7 +8,7 @@ After=bettercap.service
|
|||||||
Environment=LD_PRELOAD=/usr/local/lib/libpcap.so.1
|
Environment=LD_PRELOAD=/usr/local/lib/libpcap.so.1
|
||||||
Environment=LD_LIBRARY_PATH=/usr/local/lib
|
Environment=LD_LIBRARY_PATH=/usr/local/lib
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=/usr/local/bin/pwngrid -keys /etc/pwnagotchi -peers /root/peers -address 127.0.0.1:8666 -client-token /root/.api-enrollment.json -wait -log /home/pi/logs/pwngrid-peer.log -iface wlan0mon
|
ExecStart=/usr/local/bin/pwngrid -keys /etc/pwnagotchi -peers /root/peers -address 127.0.0.1:8666 -client-token /root/.api-enrollment.json -wait -log /etc/pwnagotchi/log/pwngrid-peer.log -iface wlan0mon
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=30
|
RestartSec=30
|
||||||
|
|
40
builder/data/32bit/extras/nexmon.yml
Normal file
40
builder/data/32bit/extras/nexmon.yml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Install nexmon to fix wireless scanning (takes 2.5G of space)
|
||||||
|
- name: clone nexmon repository
|
||||||
|
git:
|
||||||
|
repo: https://github.com/DrSchottky/nexmon.git
|
||||||
|
dest: /usr/local/src/nexmon
|
||||||
|
|
||||||
|
- name: make firmware
|
||||||
|
shell: "source ./setup_env.sh && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: "make firmware patch ({{ item.name }})"
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/{{ item.patch }}/nexmon/ && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ item.kernel }}"
|
||||||
|
ARCHFLAGS: "{{ item.arch_flags }}"
|
||||||
|
|
||||||
|
- name: "install new firmware ({{ item.name }})"
|
||||||
|
copy:
|
||||||
|
src: "/usr/local/src/nexmon/patches/{{ item.patch }}/nexmon/{{ item.firmware }}"
|
||||||
|
dest: "/usr/lib/firmware/brcm/{{ item.firmware }}"
|
||||||
|
follow: true
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ item.kernel }}"
|
||||||
|
ARCHFLAGS: "{{ item.arch_flags }}"
|
||||||
|
|
||||||
|
- name: backup original driver
|
||||||
|
command: "mv /usr/lib/modules/{{ item.kernel }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz /usr/lib/modules/{{ item.kernel }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz.orig"
|
||||||
|
|
||||||
|
- name: copy modified driver
|
||||||
|
copy:
|
||||||
|
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_6.1.y-nexmon/brcmfmac.ko"
|
||||||
|
dest: "/usr/lib/modules/{{ item.kernel }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
|
||||||
|
|
||||||
|
- name : load brcmfmac drivers
|
||||||
|
command: "/sbin/depmod -a {{ item.kernel }}"
|
94
builder/data/32bit/raspberrypi32.json.pkr.hcl
Normal file
94
builder/data/32bit/raspberrypi32.json.pkr.hcl
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
packer {
|
||||||
|
required_plugins {
|
||||||
|
arm = {
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "github.com/cdecoux/builder-arm"
|
||||||
|
}
|
||||||
|
ansible = {
|
||||||
|
source = "github.com/hashicorp/ansible"
|
||||||
|
version = ">= 1.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "pwn_hostname" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "pwn_version" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
source "arm" "rpi32-pwnagotchi" {
|
||||||
|
file_checksum_url = "https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2023-12-06/2023-12-05-raspios-bullseye-armhf-lite.img.xz.sha256"
|
||||||
|
file_urls = ["https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2023-12-06/2023-12-05-raspios-bullseye-armhf-lite.img.xz"]
|
||||||
|
file_checksum_type = "sha256"
|
||||||
|
file_target_extension = "xz"
|
||||||
|
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
||||||
|
image_path = "../../pwnagotchi-32bit.img"
|
||||||
|
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
||||||
|
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/arm-binfmt-P"
|
||||||
|
image_build_method = "resize"
|
||||||
|
image_size = "9G"
|
||||||
|
image_type = "dos"
|
||||||
|
image_partitions {
|
||||||
|
name = "boot"
|
||||||
|
type = "c"
|
||||||
|
start_sector = "8192"
|
||||||
|
filesystem = "fat"
|
||||||
|
size = "256M"
|
||||||
|
mountpoint = "/boot"
|
||||||
|
}
|
||||||
|
image_partitions {
|
||||||
|
name = "root"
|
||||||
|
type = "83"
|
||||||
|
start_sector = "532480"
|
||||||
|
filesystem = "ext4"
|
||||||
|
size = "0"
|
||||||
|
mountpoint = "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build {
|
||||||
|
name = "Raspberry Pi 32 Pwnagotchi"
|
||||||
|
sources = ["source.arm.rpi32-pwnagotchi"]
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/usr/bin/"
|
||||||
|
sources = [
|
||||||
|
"data/32bit/usr/bin/bettercap-launcher",
|
||||||
|
"data/32bit/usr/bin/hdmioff",
|
||||||
|
"data/32bit/usr/bin/hdmion",
|
||||||
|
"data/32bit/usr/bin/monstart",
|
||||||
|
"data/32bit/usr/bin/monstop",
|
||||||
|
"data/32bit/usr/bin/pwnagotchi-launcher",
|
||||||
|
"data/32bit/usr/bin/pwnlib",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["chmod +x /usr/bin/*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/etc/systemd/system/"
|
||||||
|
sources = [
|
||||||
|
"data/32bit/etc/systemd/system/bettercap.service",
|
||||||
|
"data/32bit/etc/systemd/system/pwnagotchi.service",
|
||||||
|
"data/32bit/etc/systemd/system/pwngrid-peer.service",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
provisioner "file" {
|
||||||
|
destination = "/etc/update-motd.d/01-motd"
|
||||||
|
source = "data/32bit/etc/update-motd.d/01-motd"
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["chmod +x /etc/update-motd.d/*"]
|
||||||
|
}
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["apt-get -y --allow-releaseinfo-change update", "apt-get -y dist-upgrade", "apt-get install -y --no-install-recommends ansible"]
|
||||||
|
}
|
||||||
|
provisioner "ansible-local" {
|
||||||
|
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
||||||
|
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
||||||
|
playbook_dir = "data/32bit/extras/"
|
||||||
|
playbook_file = "data/32bit/raspberrypi32.yml"
|
||||||
|
}
|
||||||
|
}
|
606
builder/data/32bit/raspberrypi32.yml
Normal file
606
builder/data/32bit/raspberrypi32.yml
Normal file
@ -0,0 +1,606 @@
|
|||||||
|
---
|
||||||
|
- hosts:
|
||||||
|
- 127.0.0.1
|
||||||
|
gather_facts: true
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
boards:
|
||||||
|
- {
|
||||||
|
kernel: "6.1.21+",
|
||||||
|
name: "PiZeroW",
|
||||||
|
firmware: "brcmfmac43430-sdio.bin",
|
||||||
|
patch: "bcm43430a1/7_45_41_46",
|
||||||
|
cpu: arm1176,
|
||||||
|
arch_flags: "-arch armv6l"
|
||||||
|
}
|
||||||
|
- {
|
||||||
|
kernel: "6.1.21-v7+",
|
||||||
|
name: "PiZero2W",
|
||||||
|
firmware: "brcmfmac43436-sdio.bin",
|
||||||
|
patch: "bcm43436b0/9_88_4_65",
|
||||||
|
cpu: any, #cortex-a53
|
||||||
|
arch_flags: "-arch armv7l"
|
||||||
|
}
|
||||||
|
- {
|
||||||
|
kernel: "6.1.21-v7l+",
|
||||||
|
name: "Pi4b_32",
|
||||||
|
firmware: "brcmfmac43455-sdio.bin",
|
||||||
|
patch: "bcm43455c0/7_45_206",
|
||||||
|
cpu: any, #cortex-a72
|
||||||
|
arch_flags: "-arch armv7l"
|
||||||
|
}
|
||||||
|
kernel:
|
||||||
|
min: "6.1"
|
||||||
|
full: "6.1.21+"
|
||||||
|
full_2w: "6.1.21-v7+"
|
||||||
|
full_4b: "6.1.21-v7l+"
|
||||||
|
arch: "v6l"
|
||||||
|
pwnagotchi:
|
||||||
|
hostname: "{{ lookup('env', 'PWN_HOSTNAME') | default('pwnagotchi', true) }}"
|
||||||
|
version: "{{ lookup('env', 'PWN_VERSION') | default('pwnagotchi-torch', true) }}"
|
||||||
|
custom_plugin_dir: "/usr/local/share/pwnagotchi/custom-plugins"
|
||||||
|
system:
|
||||||
|
boot_options:
|
||||||
|
- "#### pwnagotchi additions"
|
||||||
|
- "# this pwnagotchi image is 32-bit only no v8+ headers to build nexmon for 64 bit"
|
||||||
|
- "arm_64bit=0"
|
||||||
|
- "# dwc2 for RNDIS. comment out, and remove dwc2 and g_ether from cmdline.txt for X306 usb battery hat"
|
||||||
|
- "dtoverlay=dwc2"
|
||||||
|
- "dtoverlay=spi1-3cs"
|
||||||
|
- "dtparam=i2c1=on"
|
||||||
|
- "dtparam=i2c_arm=on"
|
||||||
|
- "dtparam=spi=on"
|
||||||
|
- "gpu_mem=16"
|
||||||
|
- "#### audio out on pins 18 and 19"
|
||||||
|
- "#dtoverlay=audremap,pins_18_19"
|
||||||
|
- "#### touchscreen on waveshare touch e-paper"
|
||||||
|
- "#dtoverlay=goodix,interrupt=27,reset=22"
|
||||||
|
- "#### for PWM backlighting on pimoroni displayhatmini"
|
||||||
|
- "dtoverlay=pwm-2chan,pin=12,func=4,pin2=13,func2=4"
|
||||||
|
modules:
|
||||||
|
- "i2c-dev"
|
||||||
|
services:
|
||||||
|
enable:
|
||||||
|
- bettercap.service
|
||||||
|
- bluetooth.service
|
||||||
|
- dphys-swapfile.service
|
||||||
|
- fstrim.timer
|
||||||
|
- pwnagotchi.service
|
||||||
|
- pwngrid-peer.service
|
||||||
|
disable:
|
||||||
|
- apt-daily-upgrade.service
|
||||||
|
- apt-daily-upgrade.timer
|
||||||
|
- apt-daily.service
|
||||||
|
- apt-daily.timer
|
||||||
|
- ifup@wlan0.service
|
||||||
|
- triggerhappy.service
|
||||||
|
- wpa_supplicant.service
|
||||||
|
packages:
|
||||||
|
caplets:
|
||||||
|
source: "https://github.com/jayofelony/caplets.git"
|
||||||
|
bettercap:
|
||||||
|
source: "https://github.com/jayofelony/bettercap.git"
|
||||||
|
url: "https://github.com/jayofelony/bettercap/releases/download/2.32.2/bettercap-2.32.2-armhf.zip"
|
||||||
|
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
|
||||||
|
opwngrid:
|
||||||
|
source: "https://github.com/jayofelony/pwngrid.git"
|
||||||
|
url: "https://github.com/jayofelony/pwngrid/releases/download/v1.10.7/pwngrid-1.10.7-armhf.zip"
|
||||||
|
torch:
|
||||||
|
wheel: "torch-2.1.0a0+gitunknown-cp39-cp39-linux_armv6l.whl"
|
||||||
|
url: "https://github.com/Sniffleupagus/Torch4Pizero/releases/download/v1.0.0/torch-2.1.0a0+gitunknown-cp39-cp39-linux_armv6l.whl"
|
||||||
|
torchvision:
|
||||||
|
wheel: "torchvision-0.16.0a0-cp39-cp39-linux_armv6l.whl"
|
||||||
|
url: "https://github.com/Sniffleupagus/Torch4Pizero/releases/download/v1.0.0/torchvision-0.16.0a0-cp39-cp39-linux_armv6l.whl"
|
||||||
|
apt:
|
||||||
|
downgrade:
|
||||||
|
- libpcap-dev_1.9.1-4_armhf.deb
|
||||||
|
- libpcap0.8-dbg_1.9.1-4_armhf.deb
|
||||||
|
- libpcap0.8-dev_1.9.1-4_armhf.deb
|
||||||
|
- libpcap0.8_1.9.1-4_armhf.deb
|
||||||
|
hold:
|
||||||
|
- firmware-atheros
|
||||||
|
- firmware-brcm80211
|
||||||
|
- firmware-libertas
|
||||||
|
- firmware-misc-nonfree
|
||||||
|
- firmware-realtek
|
||||||
|
- libpcap-dev
|
||||||
|
- libpcap0.8
|
||||||
|
- libpcap0.8-dev
|
||||||
|
- libpcap0.8-dbg
|
||||||
|
remove:
|
||||||
|
- avahi-daemon
|
||||||
|
- nfs-common
|
||||||
|
- triggerhappy
|
||||||
|
- wpasupplicant
|
||||||
|
install:
|
||||||
|
- autoconf
|
||||||
|
- bc
|
||||||
|
- bison
|
||||||
|
- bluez
|
||||||
|
- build-essential
|
||||||
|
- curl
|
||||||
|
- dkms
|
||||||
|
- dphys-swapfile
|
||||||
|
- espeak-ng
|
||||||
|
- evtest
|
||||||
|
- fbi
|
||||||
|
- flex
|
||||||
|
- fonts-dejavu
|
||||||
|
- fonts-dejavu-core
|
||||||
|
- fonts-dejavu-extra
|
||||||
|
- fonts-freefont-ttf
|
||||||
|
- g++
|
||||||
|
- gawk
|
||||||
|
- gcc-arm-none-eabi
|
||||||
|
- git
|
||||||
|
- libatlas-base-dev
|
||||||
|
- libavcodec58
|
||||||
|
- libavformat58
|
||||||
|
- libblas-dev
|
||||||
|
- libbluetooth-dev
|
||||||
|
- libbz2-dev
|
||||||
|
- libc-ares-dev
|
||||||
|
- libc6-dev
|
||||||
|
- libcpuinfo-dev
|
||||||
|
- libdbus-1-dev
|
||||||
|
- libdbus-glib-1-dev
|
||||||
|
- libeigen3-dev
|
||||||
|
- libelf-dev
|
||||||
|
- libffi-dev
|
||||||
|
- libfl-dev
|
||||||
|
- libfuse-dev
|
||||||
|
- libgdbm-dev
|
||||||
|
- libgl1-mesa-glx
|
||||||
|
- libgmp3-dev
|
||||||
|
- libgstreamer1.0-0
|
||||||
|
- libhdf5-dev
|
||||||
|
- liblapack-dev
|
||||||
|
- libncursesw5-dev
|
||||||
|
- libnetfilter-queue-dev
|
||||||
|
- libopenblas-dev
|
||||||
|
- libopenjp2-7
|
||||||
|
- libopenmpi-dev
|
||||||
|
- libopenmpi3
|
||||||
|
- libpcap-dev
|
||||||
|
- libprotobuf-dev
|
||||||
|
- libraspberrypi-bin
|
||||||
|
- libraspberrypi-dev
|
||||||
|
- libraspberrypi-doc
|
||||||
|
- libraspberrypi0
|
||||||
|
- libsleef-dev
|
||||||
|
- libsqlite3-dev
|
||||||
|
- libssl-dev
|
||||||
|
- libswscale5
|
||||||
|
- libtiff5
|
||||||
|
- libtool
|
||||||
|
- libts-bin
|
||||||
|
- libusb-1.0-0-dev
|
||||||
|
- lsof
|
||||||
|
- make
|
||||||
|
- python3-flask
|
||||||
|
- python3-flask-cors
|
||||||
|
- python3-flaskext.wtf
|
||||||
|
- python3-pil
|
||||||
|
- python3-pip
|
||||||
|
- python3-protobuf
|
||||||
|
- python3-smbus
|
||||||
|
- qpdf
|
||||||
|
- raspberrypi-kernel-headers
|
||||||
|
- rsync
|
||||||
|
- screen
|
||||||
|
- tcpdump
|
||||||
|
- texinfo
|
||||||
|
- time
|
||||||
|
- tk-dev
|
||||||
|
- unzip
|
||||||
|
- vim
|
||||||
|
- wget
|
||||||
|
- wl
|
||||||
|
- xxd
|
||||||
|
- zlib1g-dev
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create pi user
|
||||||
|
copy:
|
||||||
|
dest: /boot/userconf
|
||||||
|
content: |
|
||||||
|
pi:$6$3jNr0GA9KIyt4hmM$efeVIopdMQ8DGgEPCWWlbx3mJJNAYci1lEXGdlky0xPyjqwKNbwTL5SrCcpb4144C4IvzWjn7Iv.QjqmU7iyT/
|
||||||
|
|
||||||
|
- name: change hostname
|
||||||
|
lineinfile:
|
||||||
|
dest: /etc/hostname
|
||||||
|
regexp: '^raspberrypi'
|
||||||
|
line: "{{pwnagotchi.hostname}}"
|
||||||
|
state: present
|
||||||
|
when: lookup('file', '/etc/hostname') == "raspberrypi"
|
||||||
|
register: hostname
|
||||||
|
|
||||||
|
- name: add hostname to /etc/hosts
|
||||||
|
lineinfile:
|
||||||
|
dest: /etc/hosts
|
||||||
|
regexp: '^127\.0\.1\.1[ \t]+raspberrypi'
|
||||||
|
line: "127.0.1.1\t{{pwnagotchi.hostname}}"
|
||||||
|
state: present
|
||||||
|
when: hostname.changed
|
||||||
|
|
||||||
|
- name: Create custom plugin directory
|
||||||
|
file:
|
||||||
|
path: '{{ pwnagotchi.custom_plugin_dir }}'
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: update apt package cache
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: install packages
|
||||||
|
apt:
|
||||||
|
name: "{{ packages.apt.install }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: update pip3, setuptools, wheel
|
||||||
|
shell: "python3 -m pip install --upgrade pip setuptools wheel"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
#
|
||||||
|
# libpcap v1.9 - build from source
|
||||||
|
#
|
||||||
|
###########################################
|
||||||
|
|
||||||
|
# check for presence, then it can re-run in later parts if needed
|
||||||
|
# use the "make" built in
|
||||||
|
|
||||||
|
# install libpcap before bettercap and pwngrid, so they use it
|
||||||
|
- name: clone libpcap v1.9 from github
|
||||||
|
git:
|
||||||
|
repo: 'https://github.com/the-tcpdump-group/libpcap.git'
|
||||||
|
dest: /usr/local/src/libpcap
|
||||||
|
version: libpcap-1.9
|
||||||
|
|
||||||
|
- name: build and install libpcap into /usr/local/lib
|
||||||
|
shell: "./configure && make && make install"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/libpcap
|
||||||
|
|
||||||
|
- name: remove libpcap build folder
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/libpcap
|
||||||
|
|
||||||
|
- name: create symlink /usr/local/lib/libpcap.so.1.9.1
|
||||||
|
file:
|
||||||
|
src: /usr/local/lib/libpcap.so.1.9.1
|
||||||
|
dest: /usr/local/lib/libpcap.so.0.8
|
||||||
|
state: link
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
# Install nexmon to fix wireless scanning (takes 2.5G of space)
|
||||||
|
###############################################################
|
||||||
|
|
||||||
|
# Install nexmon for all boards
|
||||||
|
- name: build and install nexmon as needed
|
||||||
|
include_tasks: nexmon.yml
|
||||||
|
loop: "{{ boards }}"
|
||||||
|
|
||||||
|
# some pizero2w have the pizeroW wifi chip
|
||||||
|
# could this be a link instead of a copy? and force, only if not a link?
|
||||||
|
- name: copy 43430-sdio as 43436s-sdio for the special 43430/1 /2
|
||||||
|
copy:
|
||||||
|
src: /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin
|
||||||
|
dest: /usr/lib/firmware/brcm/brcmfmac43436s-sdio.bin
|
||||||
|
follow: true
|
||||||
|
|
||||||
|
# delete blob files that make nexmon sad
|
||||||
|
- name: Delete the firmware blob files to avoid some nexmon crashing
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: '{{ item }}'
|
||||||
|
loop:
|
||||||
|
- /usr/lib/firmware/brcm/brcmfmac43430-sdio.clm_blob
|
||||||
|
- /usr/lib/firmware/brcm/brcmfmac43430-sdio.raspberrypi,model-zero-w.clm_blob
|
||||||
|
- /usr/lib/firmware/brcm/brcmfmac43430b0-sdio.raspberrypi,model-zero-2-w.clm_blob
|
||||||
|
- /usr/lib/firmware/brcm/brcmfmac43436-sdio.raspberrypi,model-zero-2-w.clm_blob
|
||||||
|
- /usr/lib/firmware/brcm/brcmfmac43430-sdio.raspberrypi,3-model-b.clm_blob
|
||||||
|
|
||||||
|
# To shrink the final image, remove the nexmon directory (takes 2.5G of space) post build and installation
|
||||||
|
- name: Delete nexmon content & directory
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: clone pwnagotchi repository
|
||||||
|
git:
|
||||||
|
repo: https://github.com/jayofelony/pwnagotchi.git
|
||||||
|
dest: /usr/local/src/pwnagotchi
|
||||||
|
register: pwnagotchigit
|
||||||
|
|
||||||
|
# is this even necessary? Can't we just link from /home/pi/pwnagotchi to /usr/local/{bin,lib,etc}
|
||||||
|
# then just git update in the home dir and encourage hacking?
|
||||||
|
# make owned by pi.pi, and custom plugins.
|
||||||
|
- name: build pwnagotchi wheel
|
||||||
|
command: "python3 setup.py sdist bdist_wheel"
|
||||||
|
args:
|
||||||
|
chdir: /usr/local/src/pwnagotchi
|
||||||
|
when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version)
|
||||||
|
|
||||||
|
- name: download torch whl
|
||||||
|
get_url:
|
||||||
|
url: "{{ packages.torch.url }}"
|
||||||
|
dest: /usr/local/src/
|
||||||
|
|
||||||
|
- name: download torchvision whl
|
||||||
|
get_url:
|
||||||
|
url: "{{ packages.torchvision.url }}"
|
||||||
|
dest: /usr/local/src/
|
||||||
|
|
||||||
|
- name: install 32-bit pwnagotchi wheel and dependencies with 32-bit torch wheels
|
||||||
|
pip:
|
||||||
|
name:
|
||||||
|
- "{{ lookup('fileglob', '/usr/local/src/pwnagotchi/dist/pwnagotchi*.whl') }}"
|
||||||
|
- "{{ packages.torch.url }}"
|
||||||
|
- "{{ packages.torchvision.url }}"
|
||||||
|
extra_args: "--no-cache-dir"
|
||||||
|
environment:
|
||||||
|
QEMU_CPU: arm1176
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version)
|
||||||
|
|
||||||
|
- name: create /usr/local/share/pwnagotchi/ folder
|
||||||
|
file:
|
||||||
|
path: /usr/local/share/pwnagotchi/
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: remove pwnagotchi folder
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/pwnagotchi
|
||||||
|
|
||||||
|
- name: remove torch whl
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: "{{ lookup('fileglob', '/usr/local/src/torch*.whl') }}"
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
#
|
||||||
|
# pwngrid, bettercap
|
||||||
|
#
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
- name: Install go-1.21
|
||||||
|
unarchive:
|
||||||
|
src: https://go.dev/dl/go1.21.6.linux-armv6l.tar.gz
|
||||||
|
dest: /usr/local
|
||||||
|
remote_src: yes
|
||||||
|
register: golang
|
||||||
|
|
||||||
|
- name: Update .bashrc for go-1.21
|
||||||
|
blockinfile:
|
||||||
|
dest: /home/pi/.bashrc
|
||||||
|
state: present
|
||||||
|
block: |
|
||||||
|
export GOPATH=$HOME/go
|
||||||
|
export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin
|
||||||
|
when: golang.changed
|
||||||
|
|
||||||
|
- name: download pwngrid
|
||||||
|
unarchive:
|
||||||
|
remote_src: yes
|
||||||
|
src: "{{ packages.opwngrid.url }}"
|
||||||
|
dest: /usr/local/bin/
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: download and install bettercap
|
||||||
|
unarchive:
|
||||||
|
src: "{{ packages.bettercap.url }}"
|
||||||
|
dest: /usr/local/bin
|
||||||
|
remote_src: yes
|
||||||
|
exclude:
|
||||||
|
- README.md
|
||||||
|
- LICENSE.md
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: clone bettercap caplets
|
||||||
|
git:
|
||||||
|
repo: "{{ packages.caplets.source }}"
|
||||||
|
dest: /tmp/caplets
|
||||||
|
register: capletsgit
|
||||||
|
|
||||||
|
- name: install bettercap caplets
|
||||||
|
make:
|
||||||
|
chdir: /tmp/caplets
|
||||||
|
target: install
|
||||||
|
when: capletsgit.changed
|
||||||
|
|
||||||
|
- name: download and install bettercap ui
|
||||||
|
unarchive:
|
||||||
|
src: "{{ packages.bettercap.ui }}"
|
||||||
|
dest: /usr/local/share/bettercap/
|
||||||
|
remote_src: yes
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
# to always have the bettercap webui available (because why not?)
|
||||||
|
- name: copy pwnagotchi-manual over pwnagotchi-auto caplet
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: /usr/local/share/bettercap/caplets/pwnagotchi-manual.cap
|
||||||
|
dest: /usr/local/share/bettercap/caplets/pwnagotchi-auto.cap
|
||||||
|
force: true
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: create /etc/pwnagotchi folder
|
||||||
|
file:
|
||||||
|
path: /etc/pwnagotchi
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: create log folder
|
||||||
|
file:
|
||||||
|
path: /home/pi/logs
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: check if user configuration exists
|
||||||
|
stat:
|
||||||
|
path: /etc/pwnagotchi/config.toml
|
||||||
|
register: user_config
|
||||||
|
|
||||||
|
- name: create /etc/pwnagotchi/config.toml
|
||||||
|
copy:
|
||||||
|
dest: /etc/pwnagotchi/config.toml
|
||||||
|
content: |
|
||||||
|
# Add your configuration overrides on this file any configuration changes done to default.toml will be lost!
|
||||||
|
# Example:
|
||||||
|
# ui.display.enabled = true
|
||||||
|
# ui.display.type = "waveshare_2"
|
||||||
|
when: not user_config.stat.exists
|
||||||
|
|
||||||
|
- name: Delete motd 10-uname
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /etc/update-motd.d/10-uname
|
||||||
|
|
||||||
|
- name: enable ssh on boot
|
||||||
|
file:
|
||||||
|
path: /boot/ssh
|
||||||
|
state: touch
|
||||||
|
|
||||||
|
- name: adjust /boot/config.txt
|
||||||
|
lineinfile:
|
||||||
|
dest: /boot/config.txt
|
||||||
|
insertafter: EOF
|
||||||
|
line: '{{ item }}'
|
||||||
|
with_items: "{{system.boot_options}}"
|
||||||
|
|
||||||
|
- name: adjust /etc/modules
|
||||||
|
lineinfile:
|
||||||
|
dest: /etc/modules
|
||||||
|
insertafter: EOF
|
||||||
|
line: '{{ item }}'
|
||||||
|
with_items: "{{system.modules}}"
|
||||||
|
|
||||||
|
- name: change root partition
|
||||||
|
replace:
|
||||||
|
dest: /boot/cmdline.txt
|
||||||
|
backup: no
|
||||||
|
regexp: "root=PARTUUID=[a-zA-Z0-9\\-]+"
|
||||||
|
replace: "root=/dev/mmcblk0p2"
|
||||||
|
|
||||||
|
- name: configure /boot/cmdline.txt
|
||||||
|
lineinfile:
|
||||||
|
path: /boot/cmdline.txt
|
||||||
|
backrefs: True
|
||||||
|
state: present
|
||||||
|
backup: no
|
||||||
|
regexp: '(.*)$'
|
||||||
|
line: '\1 modules-load=dwc2,g_ether'
|
||||||
|
|
||||||
|
- name: Add pwnlog alias
|
||||||
|
lineinfile:
|
||||||
|
dest: /home/pi/.bashrc
|
||||||
|
line: "\nalias pwnlog='tail -f -n300 /etc/pwnagotchi/log/pwn*.log | sed --unbuffered \"s/,[[:digit:]]\\{3\\}\\]//g\" | cut -d \" \" -f 2-'"
|
||||||
|
insertafter: EOF
|
||||||
|
|
||||||
|
- name: Add pwnver alias
|
||||||
|
lineinfile:
|
||||||
|
dest: /home/pi/.bashrc
|
||||||
|
line: "\nalias pwnver='python3 -c \"import pwnagotchi as p; print(p.__version__)\"'"
|
||||||
|
insertafter: EOF
|
||||||
|
|
||||||
|
- name: Add pwnkill alias to restart pwnagotchi with a signal
|
||||||
|
lineinfile:
|
||||||
|
dest: /home/pi/.bashrc
|
||||||
|
line: "\nalias pwnkill='sudo killall -USR1 pwnagotchi'"
|
||||||
|
insertafter: EOF
|
||||||
|
|
||||||
|
- name: add firmware packages to hold
|
||||||
|
dpkg_selections:
|
||||||
|
name: "{{ item }}"
|
||||||
|
selection: hold
|
||||||
|
with_items: "{{ packages.apt.hold }}"
|
||||||
|
|
||||||
|
- name: disable unnecessary services
|
||||||
|
systemd:
|
||||||
|
name: "{{ item }}"
|
||||||
|
state: stopped
|
||||||
|
enabled: no
|
||||||
|
with_items: "{{ services.disable }}"
|
||||||
|
|
||||||
|
- name: enable services
|
||||||
|
systemd:
|
||||||
|
name: "{{ item }}"
|
||||||
|
enabled: true
|
||||||
|
state: stopped
|
||||||
|
with_items: "{{ services.enable }}"
|
||||||
|
|
||||||
|
#- name: remove golang build libraries
|
||||||
|
# file:
|
||||||
|
# state: absent
|
||||||
|
# path: /root/go
|
||||||
|
|
||||||
|
#- name: remove golang
|
||||||
|
# file:
|
||||||
|
# state: absent
|
||||||
|
# path: /usr/local/go
|
||||||
|
|
||||||
|
- name: make /root readable, becauase that's where all the files are
|
||||||
|
file:
|
||||||
|
path: /root
|
||||||
|
mode: '755'
|
||||||
|
|
||||||
|
- name: fix permissions on /home/pi
|
||||||
|
file:
|
||||||
|
path: /home/pi
|
||||||
|
owner: pi
|
||||||
|
group: pi
|
||||||
|
recurse: true
|
||||||
|
|
||||||
|
- name: remove unnecessary apt packages
|
||||||
|
apt:
|
||||||
|
name: "{{ packages.apt.remove }}"
|
||||||
|
state: absent
|
||||||
|
purge: yes
|
||||||
|
|
||||||
|
- name: remove dependencies that are no longer required
|
||||||
|
apt:
|
||||||
|
autoremove: yes
|
||||||
|
|
||||||
|
- name: clean apt cache
|
||||||
|
apt:
|
||||||
|
autoclean: true
|
||||||
|
|
||||||
|
- name: remove golang build libraries
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /root/go
|
||||||
|
|
||||||
|
- name: remove pre-collected packages zip
|
||||||
|
file:
|
||||||
|
path: /root/go_pkgs.tgz
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: remove golang
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/go
|
||||||
|
|
||||||
|
- name: remove /root/.cache (pip cache)
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /root/.cache
|
||||||
|
|
||||||
|
- name: remove ssh keys
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: "{{ item }}"
|
||||||
|
with_fileglob:
|
||||||
|
- "/etc/ssh/ssh_host*_key*"
|
||||||
|
|
||||||
|
- name: regenerate ssh keys
|
||||||
|
shell: "dpkg-reconfigure openssh-server"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: reload systemd services
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
@ -18,7 +18,7 @@ if ! check_brcm; then
|
|||||||
sleep 10
|
sleep 10
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# start mon0
|
# start wlan0mon
|
||||||
start_monitor_interface
|
start_monitor_interface
|
||||||
|
|
||||||
if is_auto_mode_no_delete; then
|
if is_auto_mode_no_delete; then
|
149
builder/data/32bit/usr/bin/decryption-webserver
Executable file
149
builder/data/32bit/usr/bin/decryption-webserver
Executable file
@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||||
|
from urllib.parse import parse_qsl
|
||||||
|
|
||||||
|
|
||||||
|
_HTML_FORM_TEMPLATE = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Decryption</title>
|
||||||
|
<style>
|
||||||
|
body {{ text-align: center; padding: 150px; }}
|
||||||
|
h1 {{ font-size: 50px; }}
|
||||||
|
body {{ font: 20px Helvetica, sans-serif; color: #333; }}
|
||||||
|
article {{ display: block; text-align: center; width: 650px; margin: 0 auto;}}
|
||||||
|
input {{
|
||||||
|
padding: 12px 20px;
|
||||||
|
margin: 8px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}}
|
||||||
|
input[type=password] {{
|
||||||
|
width: 75%;
|
||||||
|
font-size: 24px;
|
||||||
|
}}
|
||||||
|
input[type=submit] {{
|
||||||
|
cursor: pointer;
|
||||||
|
width: 75%;
|
||||||
|
}}
|
||||||
|
input[type=submit]:hover {{
|
||||||
|
background-color: #d9d9d9;
|
||||||
|
}}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<article>
|
||||||
|
<h1>Decryption</h1>
|
||||||
|
<p>Some of your files are encrypted.</p>
|
||||||
|
<p>Please provide the decryption password.</p>
|
||||||
|
<div>
|
||||||
|
<form action="/set-password" method="POST">
|
||||||
|
{password_fields}
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
POST_RESPONSE = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<style>
|
||||||
|
/* Center the loader */
|
||||||
|
#loader {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
z-index: 1;
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
margin: -75px 0 0 -75px;
|
||||||
|
border: 16px solid #f3f3f3;
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top: 16px solid #3498db;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
-webkit-animation: spin 2s linear infinite;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% { -webkit-transform: rotate(0deg); }
|
||||||
|
100% { -webkit-transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#myDiv {
|
||||||
|
display: none;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function checkPwnagotchi() {
|
||||||
|
var target = 'http://' + document.location.hostname + ':8080/';
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', target);
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
if (xhr.readyState == 4) {
|
||||||
|
if (xhr.status == 200 || xhr.status == 401) {
|
||||||
|
window.location.replace(target);
|
||||||
|
}else{
|
||||||
|
setTimeout(checkPwnagotchi, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(checkPwnagotchi, 1000);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body style="margin:0;">
|
||||||
|
|
||||||
|
<div id="loader"></div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
HTML_FORM = None
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(HTML_FORM.encode())
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
content_length = int(self.headers['Content-Length'])
|
||||||
|
body = self.rfile.read(content_length)
|
||||||
|
for mapping, password in parse_qsl(body.decode('UTF-8')):
|
||||||
|
with open('/tmp/.pwnagotchi-secret-{}'.format(mapping), 'wt') as pwfile:
|
||||||
|
pwfile.write(password)
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(POST_RESPONSE.encode())
|
||||||
|
|
||||||
|
|
||||||
|
with open('/root/.pwnagotchi-crypted') as crypted_file:
|
||||||
|
mappings = [line.split()[0] for line in crypted_file.readlines()]
|
||||||
|
fields = ''.join(['<label for="{m}">Passphrase for {m}:</label>\n<input type="password" id="{m}" name="{m}" value=""><br>'.format(m=m)
|
||||||
|
for m in mappings])
|
||||||
|
HTML_FORM = _HTML_FORM_TEMPLATE.format(password_fields=fields)
|
||||||
|
|
||||||
|
httpd = HTTPServer(('0.0.0.0', 80), SimpleHTTPRequestHandler)
|
||||||
|
httpd.serve_forever()
|
184
builder/data/32bit/usr/bin/pwnlib
Executable file
184
builder/data/32bit/usr/bin/pwnlib
Executable file
@ -0,0 +1,184 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# check if brcm is stuck
|
||||||
|
check_brcm() {
|
||||||
|
if [[ "$(journalctl -n10 -k --since -5m | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 5 ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# reload mod
|
||||||
|
reload_brcm() {
|
||||||
|
if ! modprobe -r brcmfmac; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
if ! modprobe brcmfmac; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
iw dev wlan0 set power_save off
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# starts mon0
|
||||||
|
start_monitor_interface() {
|
||||||
|
rfkill unblock all
|
||||||
|
ifconfig wlan0 up
|
||||||
|
iw dev wlan0 set power_save off
|
||||||
|
iw phy "$(iw phy | head -1 | cut -d" " -f2)" interface add wlan0mon type monitor
|
||||||
|
rfkill unblock all
|
||||||
|
ifconfig wlan0 down
|
||||||
|
ifconfig wlan0mon up
|
||||||
|
iw dev wlan0mon set power_save off
|
||||||
|
}
|
||||||
|
|
||||||
|
# stops mon0
|
||||||
|
stop_monitor_interface() {
|
||||||
|
ifconfig wlan0mon down && iw dev wlan0mon del
|
||||||
|
reload_brcm
|
||||||
|
ifconfig wlan0 up
|
||||||
|
}
|
||||||
|
|
||||||
|
# returns 0 if the specificed network interface is up
|
||||||
|
is_interface_up() {
|
||||||
|
if grep -qi 'up' /sys/class/net/"$1"/operstate; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# returns 0 if conditions for AUTO mode are met
|
||||||
|
is_auto_mode() {
|
||||||
|
# check override file first
|
||||||
|
if [ -f /root/.pwnagotchi-manual ]; then
|
||||||
|
# remove the override file if found
|
||||||
|
rm -rf /root/.pwnagotchi-manual
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check override file first
|
||||||
|
if [ -f /root/.pwnagotchi-auto ]; then
|
||||||
|
# remove the override file if found
|
||||||
|
rm -rf /root/.pwnagotchi-auto
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if usb0 is up, we're in MANU
|
||||||
|
if is_interface_up usb0; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if eth0 is up (for other boards), we're in MANU
|
||||||
|
if is_interface_up eth0; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# no override, but none of the interfaces is up -> AUTO
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# returns 0 if conditions for AUTO mode are met
|
||||||
|
is_auto_mode_no_delete() {
|
||||||
|
# check override file first
|
||||||
|
if [ -f /root/.pwnagotchi-manual ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check override file first
|
||||||
|
if [ -f /root/.pwnagotchi-auto ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if usb0 is up, we're in MANU
|
||||||
|
if is_interface_up usb0; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if eth0 is up (for other boards), we're in MANU
|
||||||
|
if is_interface_up eth0; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# no override, but none of the interfaces is up -> AUTO
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# check if we need to decrypt something
|
||||||
|
is_crypted_mode() {
|
||||||
|
if [ -f /root/.pwnagotchi-crypted ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# decryption loop
|
||||||
|
is_decrypted() {
|
||||||
|
while read -r mapping container mount; do
|
||||||
|
# mapping = name the device or file will be mapped to
|
||||||
|
# container = the luks encrypted device or file
|
||||||
|
# mount = the mountpoint
|
||||||
|
|
||||||
|
# fail if not mounted
|
||||||
|
if ! mountpoint -q "$mount" >/dev/null 2>&1; then
|
||||||
|
if [ -f /tmp/.pwnagotchi-secret-"$mapping" ]; then
|
||||||
|
</tmp/.pwnagotchi-secret-"$mapping" read -r SECRET
|
||||||
|
if ! test -b /dev/disk/by-id/dm-uuid-*"$(cryptsetup luksUUID "$container" | tr -d -)"*; then
|
||||||
|
if echo -n "$SECRET" | cryptsetup luksOpen -d- "$container" "$mapping" >/dev/null 2>&1; then
|
||||||
|
echo "Container decrypted!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if mount /dev/mapper/"$mapping" "$mount" >/dev/null 2>&1; then
|
||||||
|
echo "Mounted /dev/mapper/$mapping to $mount"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! ip -4 addr show wlan0 | grep inet >/dev/null 2>&1; then
|
||||||
|
>/dev/null 2>&1 ip addr add 192.168.0.10/24 dev wlan0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! pgrep -f decryption-webserver >/dev/null 2>&1; then
|
||||||
|
>/dev/null 2>&1 decryption-webserver &
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! pgrep wpa_supplicant >/dev/null 2>&1; then
|
||||||
|
>/tmp/wpa_supplicant.conf cat <<EOF
|
||||||
|
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
|
||||||
|
update_config=1
|
||||||
|
ap_scan=2
|
||||||
|
|
||||||
|
network={
|
||||||
|
ssid="DECRYPT-ME"
|
||||||
|
mode=2
|
||||||
|
key_mgmt=WPA-PSK
|
||||||
|
psk="pwnagotchi"
|
||||||
|
frequency=2437
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
>/dev/null 2>&1 wpa_supplicant -u -s -O -D nl80211 -i wlan0 -c /tmp/wpa_supplicant.conf &
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! pgrep dnsmasq >/dev/null 2>&1; then
|
||||||
|
>/dev/null 2>&1 dnsmasq -k -p 53 -h -O "6,192.168.0.10" -A "/#/192.168.0.10" -i wlan0 -K -F 192.168.0.50,192.168.0.60,255.255.255.0,24h &
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done </root/.pwnagotchi-crypted
|
||||||
|
|
||||||
|
# overwrite passwords
|
||||||
|
python3 -c 'print("A"*4096)' | tee /tmp/.pwnagotchi-secret-* >/dev/null
|
||||||
|
# delete
|
||||||
|
rm /tmp/.pwnagotchi-secret-*
|
||||||
|
sync # flush
|
||||||
|
|
||||||
|
pkill wpa_supplicant
|
||||||
|
pkill dnsmasq
|
||||||
|
pid="$(pgrep -f "decryption-webserver")"
|
||||||
|
[[ -n "$pid" ]] && kill "$pid"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
_show_complete()
|
||||||
|
{
|
||||||
|
local cur opts node_names all_options opt_line
|
||||||
|
all_options="
|
||||||
|
pwnagotchi -h --help -C --config -U --user-config --manual --skip-session --clear --debug --version --print-config --check-update --donate {plugins,google}
|
||||||
|
pwnagotchi plugins -h --help {list,install,enable,disable,uninstall,update,upgrade}
|
||||||
|
pwnagotchi plugins list -i --installed -h --help
|
||||||
|
pwnagotchi plugins install -h --help
|
||||||
|
pwnagotchi plugins uninstall -h --help
|
||||||
|
pwnagotchi plugins enable -h --help
|
||||||
|
pwnagotchi plugins disable -h --help
|
||||||
|
pwnagotchi plugins update -h --help
|
||||||
|
pwnagotchi plugins upgrade -h --help
|
||||||
|
pwnagotchi google -h --help {login,refresh}
|
||||||
|
pwnagotchi google login -h --help
|
||||||
|
pwnagotchi google refresh -h --help
|
||||||
|
"
|
||||||
|
COMPREPLY=()
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
# shellcheck disable=SC2124
|
||||||
|
cmd="${COMP_WORDS[@]:0:${#COMP_WORDS[@]}-1}"
|
||||||
|
opt_line="$(grep -m1 "$cmd" <<<"$all_options")"
|
||||||
|
if [[ ${cur} == -* ]] ; then
|
||||||
|
opts="$(echo "$opt_line" | tr ' ' '\n' | awk '/^ *-/{gsub("[^a-zA-Z0-9-]","",$1);print $1}')"
|
||||||
|
# shellcheck disable=SC2207
|
||||||
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
opts="$(echo $opt_line | grep -Po '{\K[^}]+' | tr ',' '\n')"
|
||||||
|
# shellcheck disable=SC2207
|
||||||
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -F _show_complete pwnagotchi
|
26
builder/data/64bit/etc/dphys-swapfile
Normal file
26
builder/data/64bit/etc/dphys-swapfile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# /etc/dphys-swapfile - user settings for dphys-swapfile package
|
||||||
|
# author Neil Franklin, last modification 2010.05.05
|
||||||
|
# copyright ETH Zuerich Physics Departement
|
||||||
|
# use under either modified/non-advertising BSD or GPL license
|
||||||
|
|
||||||
|
# this file is sourced with . so full normal sh syntax applies
|
||||||
|
|
||||||
|
# the default settings are added as commented out CONF_*=* lines
|
||||||
|
|
||||||
|
|
||||||
|
# where we want the swapfile to be, this is the default
|
||||||
|
#CONF_SWAPFILE=/var/swap
|
||||||
|
|
||||||
|
# set size to absolute value, leaving empty (default) then uses computed value
|
||||||
|
# you most likely don't want this, unless you have an special disk situation
|
||||||
|
CONF_SWAPSIZE=2048
|
||||||
|
|
||||||
|
# set size to computed value, this times RAM size, dynamically adapts,
|
||||||
|
# guarantees that there is enough swap without wasting disk space on excess
|
||||||
|
#CONF_SWAPFACTOR=2
|
||||||
|
|
||||||
|
# restrict size (computed and absolute!) to maximally this limit
|
||||||
|
# can be set to empty for no limit, but beware of filled partitions!
|
||||||
|
# this is/was a (outdated?) 32bit kernel limit (in MBytes), do not overrun it
|
||||||
|
# but is also sensible on 64bit to prevent filling /var or even / partition
|
||||||
|
#CONF_MAXSWAP=2048
|
13
builder/data/64bit/etc/systemd/system/bettercap.service
Normal file
13
builder/data/64bit/etc/systemd/system/bettercap.service
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=bettercap api.rest service.
|
||||||
|
Documentation=https://bettercap.org
|
||||||
|
Wants=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/bin/bettercap-launcher
|
||||||
|
Restart=always
|
||||||
|
RestartSec=30
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
20
builder/data/64bit/etc/systemd/system/bluetooth.service
Normal file
20
builder/data/64bit/etc/systemd/system/bluetooth.service
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Bluetooth service
|
||||||
|
Documentation=man:bluetoothd(8)
|
||||||
|
ConditionPathIsDirectory=/sys/class/bluetooth
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=dbus
|
||||||
|
BusName=org.bluez
|
||||||
|
ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,a2dp
|
||||||
|
NotifyAccess=main
|
||||||
|
#WatchdogSec=10
|
||||||
|
#Restart=on-failure
|
||||||
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||||
|
LimitNPROC=1
|
||||||
|
ProtectHome=true
|
||||||
|
ProtectSystem=full
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=bluetooth.target
|
||||||
|
Alias=dbus-org.bluez.service
|
20
builder/data/64bit/etc/systemd/system/pwnagotchi.service
Normal file
20
builder/data/64bit/etc/systemd/system/pwnagotchi.service
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=pwnagotchi Deep Reinforcement Learning instrumenting bettercap for WiFI pwning.
|
||||||
|
Documentation=https://pwnagotchi.org
|
||||||
|
Wants=network.target
|
||||||
|
After=pwngrid-peer.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=~
|
||||||
|
ExecStart=/usr/bin/pwnagotchi-launcher
|
||||||
|
ExecStopPost=/usr/bin/bash -c "if egrep -qi 'personality.clear_on_exit[ =]*true' /etc/pwnagotchi/config.toml ; then /usr/local/bin/pwnagotchi --clear; fi"
|
||||||
|
Restart=always
|
||||||
|
RestartSec=30
|
||||||
|
TasksMax=infinity
|
||||||
|
LimitNPROC=infinity
|
||||||
|
StandardOutput=null
|
||||||
|
StandardError=null
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
16
builder/data/64bit/etc/systemd/system/pwngrid-peer.service
Normal file
16
builder/data/64bit/etc/systemd/system/pwngrid-peer.service
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=pwngrid peer service.
|
||||||
|
Documentation=https://pwnagotchi.ai
|
||||||
|
Wants=network.target
|
||||||
|
After=bettercap.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=LD_PRELOAD=/usr/local/lib/libpcap.so.1
|
||||||
|
Environment=LD_LIBRARY_PATH=/usr/local/lib
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/bin/pwngrid -keys /etc/pwnagotchi -peers /root/peers -address 127.0.0.1:8666 -client-token /root/.api-enrollment.json -wait -log /etc/pwnagotchi/log/pwngrid-peer.log -iface wlan0mon
|
||||||
|
Restart=always
|
||||||
|
RestartSec=30
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
33
builder/data/64bit/etc/update-motd.d/01-motd
Executable file
33
builder/data/64bit/etc/update-motd.d/01-motd
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
_hostname=$(hostname)
|
||||||
|
_version=$(cut -d"'" -f2 < /usr/local/lib/python3.11/dist-packages/pwnagotchi/_version.py)
|
||||||
|
echo
|
||||||
|
echo "(☉_☉ ) $_hostname"
|
||||||
|
echo
|
||||||
|
echo " Hi! I'm a pwnagotchi $_version, please take good care of me!"
|
||||||
|
echo " Here are some basic things you need to know to raise me properly!"
|
||||||
|
echo
|
||||||
|
echo " If you want to change my configuration, use /etc/pwnagotchi/config.toml"
|
||||||
|
echo " All plugin config files are located in /etc/pwnagotchi/conf.d/"
|
||||||
|
echo " Read the readme if you want to use gdrivesync plugin!!"
|
||||||
|
echo
|
||||||
|
echo " All the configuration options can be found on /etc/pwnagotchi/default.toml,"
|
||||||
|
echo " but don't change this file because I will recreate it every time I'm restarted!"
|
||||||
|
echo
|
||||||
|
echo " I use oPwnGrid as my main API, you can check stats at https://opwngrid.xyz"
|
||||||
|
echo
|
||||||
|
echo " I'm managed by systemd. Here are some basic commands."
|
||||||
|
echo
|
||||||
|
echo " If you want to know what I'm doing, you can check my logs with the command"
|
||||||
|
echo " - pwnlog"
|
||||||
|
echo " - sudo pwnagotchi --version, to check the current version"
|
||||||
|
echo " - sudo pwnagotchi --donate, to see how you can donate to this project"
|
||||||
|
echo " - sudo pwnagotchi --check-update, to see if there is a new version available"
|
||||||
|
echo
|
||||||
|
echo " If you want to know if I'm running, you can use"
|
||||||
|
echo " sudo systemctl status pwnagotchi"
|
||||||
|
echo
|
||||||
|
echo " You can restart me using"
|
||||||
|
echo " pwnkill"
|
||||||
|
echo
|
||||||
|
echo " You can learn more about me at https://pwnagotchi.org/"
|
@ -1,14 +1,12 @@
|
|||||||
# This is not working quite yet
|
|
||||||
# https://github.com/mkaczanowski/packer-builder-arm/pull/172
|
|
||||||
packer {
|
packer {
|
||||||
required_plugins {
|
required_plugins {
|
||||||
#arm = {
|
arm = {
|
||||||
# version = "~> 1"
|
version = "1.0.0"
|
||||||
# source = "github.com/cdecoux/builder-arm"
|
source = "github.com/cdecoux/builder-arm"
|
||||||
#}
|
}
|
||||||
ansible = {
|
ansible = {
|
||||||
source = "github.com/hashicorp/ansible"
|
source = "github.com/hashicorp/ansible"
|
||||||
version = "~> 1"
|
version = ">= 1.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,9 +25,9 @@ source "arm" "rpi64-pwnagotchi" {
|
|||||||
file_checksum_type = "sha256"
|
file_checksum_type = "sha256"
|
||||||
file_target_extension = "xz"
|
file_target_extension = "xz"
|
||||||
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"]
|
||||||
image_path = "../../../pwnagotchi-rpi-bookworm-${var.pwn_version}-arm64.img"
|
image_path = "../../../pwnagotchi-64bit.img"
|
||||||
qemu_binary_source_path = "/usr/bin/qemu-aarch64-static"
|
qemu_binary_source_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
|
||||||
qemu_binary_destination_path = "/usr/bin/qemu-aarch64-static"
|
qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P"
|
||||||
image_build_method = "resize"
|
image_build_method = "resize"
|
||||||
image_size = "9G"
|
image_size = "9G"
|
||||||
image_type = "dos"
|
image_type = "dos"
|
||||||
@ -51,6 +49,8 @@ source "arm" "rpi64-pwnagotchi" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# a build block invokes sources and runs provisioning steps on them. The
|
# a build block invokes sources and runs provisioning steps on them. The
|
||||||
# documentation for build blocks can be found here:
|
# documentation for build blocks can be found here:
|
||||||
# https://www.packer.io/docs/from-1.5/blocks/build
|
# https://www.packer.io/docs/from-1.5/blocks/build
|
||||||
@ -61,13 +61,13 @@ build {
|
|||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
destination = "/usr/bin/"
|
destination = "/usr/bin/"
|
||||||
sources = [
|
sources = [
|
||||||
"data/usr/bin/bettercap-launcher",
|
"data/64bit/usr/bin/bettercap-launcher",
|
||||||
"data/usr/bin/hdmioff",
|
"data/64bit/usr/bin/hdmioff",
|
||||||
"data/usr/bin/hdmion",
|
"data/64bit/usr/bin/hdmion",
|
||||||
"data/usr/bin/monstart",
|
"data/64bit/usr/bin/monstart",
|
||||||
"data/usr/bin/monstop",
|
"data/64bit/usr/bin/monstop",
|
||||||
"data/usr/bin/pwnagotchi-launcher",
|
"data/64bit/usr/bin/pwnagotchi-launcher",
|
||||||
"data/usr/bin/pwnlib",
|
"data/64bit/usr/bin/pwnlib",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
provisioner "shell" {
|
provisioner "shell" {
|
||||||
@ -77,15 +77,14 @@ build {
|
|||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
destination = "/etc/systemd/system/"
|
destination = "/etc/systemd/system/"
|
||||||
sources = [
|
sources = [
|
||||||
"data/etc/systemd/system/bettercap.service",
|
"data/64bit/etc/systemd/system/bettercap.service",
|
||||||
"data/etc/systemd/system/pwnagotchi.service",
|
"data/64bit/etc/systemd/system/pwnagotchi.service",
|
||||||
"data/etc/systemd/system/pwngrid-peer.service",
|
"data/64bit/etc/systemd/system/pwngrid-peer.service",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
destination = "/etc/update-motd.d/01-motd"
|
destination = "/etc/update-motd.d/01-motd"
|
||||||
source = "data/etc/update-motd.d/01-motd"
|
source = "data/64bit/etc/update-motd.d/01-motd"
|
||||||
}
|
}
|
||||||
provisioner "shell" {
|
provisioner "shell" {
|
||||||
inline = ["chmod +x /etc/update-motd.d/*"]
|
inline = ["chmod +x /etc/update-motd.d/*"]
|
||||||
@ -96,6 +95,6 @@ build {
|
|||||||
provisioner "ansible-local" {
|
provisioner "ansible-local" {
|
||||||
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook"
|
||||||
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
extra_arguments = ["--extra-vars \"ansible_python_interpreter=/usr/bin/python3\""]
|
||||||
playbook_file = "raspberrypi64.yml"
|
playbook_file = "data/64bit/raspberrypi64.yml"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,10 +6,11 @@
|
|||||||
vars:
|
vars:
|
||||||
kernel:
|
kernel:
|
||||||
min: "6.1"
|
min: "6.1"
|
||||||
full: "6.1.0-rpi7-rpi-v8"
|
full: "6.1.0-rpi8-rpi-v8"
|
||||||
|
full_pi5: "6.1.0-rpi8-rpi-2712"
|
||||||
pwnagotchi:
|
pwnagotchi:
|
||||||
hostname: "{{ lookup('env', 'PWN_HOSTNAME') | default('pwnagotchi', true) }}"
|
hostname: "{{ lookup('env', 'PWN_HOSTNAME') | default('pwnagotchi', true) }}"
|
||||||
version: "{{ lookup('env', 'PWN_VERSION') | default('pwnagotchi-torch', true) }}"
|
version: "{{ lookup('env', 'PWN_VERSION') | default('pwnagotchi', true) }}"
|
||||||
system:
|
system:
|
||||||
boot_options:
|
boot_options:
|
||||||
- "dtoverlay=dwc2"
|
- "dtoverlay=dwc2"
|
||||||
@ -23,7 +24,6 @@
|
|||||||
services:
|
services:
|
||||||
enable:
|
enable:
|
||||||
- bettercap.service
|
- bettercap.service
|
||||||
- dphys-swapfile.service
|
|
||||||
- fstrim.timer
|
- fstrim.timer
|
||||||
- pwnagotchi.service
|
- pwnagotchi.service
|
||||||
- pwngrid-peer.service
|
- pwngrid-peer.service
|
||||||
@ -32,18 +32,14 @@
|
|||||||
- apt-daily-upgrade.timer
|
- apt-daily-upgrade.timer
|
||||||
- apt-daily.service
|
- apt-daily.service
|
||||||
- apt-daily.timer
|
- apt-daily.timer
|
||||||
- avahi-daemon.service
|
|
||||||
- avahi-daemon.socket
|
|
||||||
- bluetooth.service
|
- bluetooth.service
|
||||||
- ifup@wlan0.service
|
- ifup@wlan0.service
|
||||||
- triggerhappy.service
|
|
||||||
- wpa_supplicant.service
|
|
||||||
packages:
|
packages:
|
||||||
caplets:
|
caplets:
|
||||||
source: "https://github.com/jayofelony/caplets.git"
|
source: "https://github.com/jayofelony/caplets.git"
|
||||||
bettercap:
|
bettercap:
|
||||||
source: "https://github.com/jayofelony/bettercap.git"
|
source: "https://github.com/jayofelony/bettercap.git"
|
||||||
url: "https://github.com/jayofelony/bettercap/releases/download/2.32.2/bettercap-2.32.2.zip"
|
url: "https://github.com/jayofelony/bettercap/releases/download/2.32.4/bettercap-2.32.4.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:
|
||||||
source: "https://github.com/jayofelony/pwngrid.git"
|
source: "https://github.com/jayofelony/pwngrid.git"
|
||||||
@ -55,12 +51,20 @@
|
|||||||
- libpcap0.8-dev_1.9.1-4_arm64.deb
|
- libpcap0.8-dev_1.9.1-4_arm64.deb
|
||||||
- libpcap0.8_1.9.1-4_arm64.deb
|
- libpcap0.8_1.9.1-4_arm64.deb
|
||||||
hold:
|
hold:
|
||||||
|
- firmware-atheros
|
||||||
|
- firmware-brcm80211
|
||||||
|
- firmware-libertas
|
||||||
|
- firmware-misc-nonfree
|
||||||
|
- firmware-realtek
|
||||||
- libpcap-dev
|
- libpcap-dev
|
||||||
- libpcap0.8
|
- libpcap0.8
|
||||||
- libpcap0.8-dev
|
|
||||||
- libpcap0.8-dbg
|
- libpcap0.8-dbg
|
||||||
|
- libpcap0.8-dev
|
||||||
remove:
|
remove:
|
||||||
- avahi-daemon
|
- avahi-daemon
|
||||||
|
- dhpys-swapfile
|
||||||
|
- libcurl-ocaml-dev
|
||||||
|
- libssl-ocaml-dev
|
||||||
- nfs-common
|
- nfs-common
|
||||||
- triggerhappy
|
- triggerhappy
|
||||||
- wpasupplicant
|
- wpasupplicant
|
||||||
@ -75,6 +79,11 @@
|
|||||||
- dkms
|
- dkms
|
||||||
- dphys-swapfile
|
- dphys-swapfile
|
||||||
- fbi
|
- fbi
|
||||||
|
- firmware-atheros
|
||||||
|
- firmware-brcm80211
|
||||||
|
- firmware-libertas
|
||||||
|
- firmware-misc-nonfree
|
||||||
|
- firmware-realtek
|
||||||
- flex
|
- flex
|
||||||
- fonts-dejavu
|
- fonts-dejavu
|
||||||
- fonts-dejavu-core
|
- fonts-dejavu-core
|
||||||
@ -84,6 +93,7 @@
|
|||||||
- gawk
|
- gawk
|
||||||
- gcc-arm-none-eabi
|
- gcc-arm-none-eabi
|
||||||
- git
|
- git
|
||||||
|
- hcxtools
|
||||||
- libatlas-base-dev
|
- libatlas-base-dev
|
||||||
- libavcodec59
|
- libavcodec59
|
||||||
- libavformat59
|
- libavformat59
|
||||||
@ -93,6 +103,7 @@
|
|||||||
- libc-ares-dev
|
- libc-ares-dev
|
||||||
- libc6-dev
|
- libc6-dev
|
||||||
- libcap-dev
|
- libcap-dev
|
||||||
|
- libcurl-ocaml-dev
|
||||||
- libdbus-1-dev
|
- libdbus-1-dev
|
||||||
- libdbus-glib-1-dev
|
- libdbus-glib-1-dev
|
||||||
- libeigen3-dev
|
- libeigen3-dev
|
||||||
@ -119,34 +130,30 @@
|
|||||||
- libraspberrypi0
|
- libraspberrypi0
|
||||||
- libsqlite3-dev
|
- libsqlite3-dev
|
||||||
- libssl-dev
|
- libssl-dev
|
||||||
|
- libssl-ocaml-dev
|
||||||
- libswscale5
|
- libswscale5
|
||||||
- libtiff6
|
- libtiff6
|
||||||
- libtool
|
- libtool
|
||||||
- libusb-1.0-0-dev
|
- libusb-1.0-0-dev
|
||||||
- lsof
|
- lsof
|
||||||
- make
|
- make
|
||||||
- python3-yaml
|
|
||||||
- python3-dbus
|
- python3-dbus
|
||||||
- python3-flask
|
- python3-flask
|
||||||
- python3-flask-cors
|
- python3-flask-cors
|
||||||
- python3-flaskext.wtf
|
- python3-flaskext.wtf
|
||||||
- python3-gast
|
- python3-gast
|
||||||
- python3-pil
|
- python3-pil
|
||||||
|
- python3-pip
|
||||||
- python3-pycryptodome
|
- python3-pycryptodome
|
||||||
- python3-requests
|
- python3-requests
|
||||||
- python3-scapy
|
- python3-scapy
|
||||||
|
- python3-setuptools
|
||||||
|
- python3-smbus
|
||||||
- python3-smbus2
|
- python3-smbus2
|
||||||
- python3-spidev
|
- python3-spidev
|
||||||
- python3-tweepy
|
- python3-tweepy
|
||||||
- python3-werkzeug
|
- python3-werkzeug
|
||||||
- firmware-atheros
|
- python3-yaml
|
||||||
- firmware-brcm80211
|
|
||||||
- firmware-libertas
|
|
||||||
- firmware-misc-nonfree
|
|
||||||
- firmware-realtek
|
|
||||||
- python3-pip
|
|
||||||
- python3-setuptools
|
|
||||||
- python3-smbus
|
|
||||||
- qpdf
|
- qpdf
|
||||||
- raspberrypi-kernel-headers
|
- raspberrypi-kernel-headers
|
||||||
- rsync
|
- rsync
|
||||||
@ -163,15 +170,51 @@
|
|||||||
- zlib1g-dev
|
- zlib1g-dev
|
||||||
environment:
|
environment:
|
||||||
ARCHFLAGS: "-arch aarch64"
|
ARCHFLAGS: "-arch aarch64"
|
||||||
QEMU_UNAME: "{{ kernel.full }}"
|
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
# First we install packages
|
||||||
|
- name: install packages
|
||||||
|
apt:
|
||||||
|
name: "{{ packages.apt.install }}"
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
install_recommends: false
|
||||||
|
|
||||||
|
# Now we set up /boot/firmware
|
||||||
- name: Create pi user
|
- name: Create pi user
|
||||||
copy:
|
copy:
|
||||||
dest: /boot/firmware/userconf
|
dest: /boot/firmware/userconf
|
||||||
content: |
|
content: |
|
||||||
pi:$6$3jNr0GA9KIyt4hmM$efeVIopdMQ8DGgEPCWWlbx3mJJNAYci1lEXGdlky0xPyjqwKNbwTL5SrCcpb4144C4IvzWjn7Iv.QjqmU7iyT/
|
pi:$6$3jNr0GA9KIyt4hmM$efeVIopdMQ8DGgEPCWWlbx3mJJNAYci1lEXGdlky0xPyjqwKNbwTL5SrCcpb4144C4IvzWjn7Iv.QjqmU7iyT/
|
||||||
|
|
||||||
|
- name: enable ssh on boot
|
||||||
|
file:
|
||||||
|
path: /boot/firmware/ssh
|
||||||
|
state: touch
|
||||||
|
|
||||||
|
- name: adjust /boot/firmware/config.txt
|
||||||
|
lineinfile:
|
||||||
|
dest: /boot/firmware/config.txt
|
||||||
|
insertafter: EOF
|
||||||
|
line: '{{ item }}'
|
||||||
|
with_items: "{{ system.boot_options }}"
|
||||||
|
|
||||||
|
- name: change root partition
|
||||||
|
replace:
|
||||||
|
dest: /boot/firmware/cmdline.txt
|
||||||
|
backup: no
|
||||||
|
regexp: "root=PARTUUID=[a-zA-Z0-9\\-]+"
|
||||||
|
replace: "root=/dev/mmcblk0p2"
|
||||||
|
|
||||||
|
- name: configure /boot/firmware/cmdline.txt
|
||||||
|
lineinfile:
|
||||||
|
path: /boot/firmware/cmdline.txt
|
||||||
|
backrefs: True
|
||||||
|
state: present
|
||||||
|
backup: no
|
||||||
|
regexp: '(.*)$'
|
||||||
|
line: '\1 modules-load=dwc2,g_ether'
|
||||||
|
|
||||||
- name: change hostname
|
- name: change hostname
|
||||||
lineinfile:
|
lineinfile:
|
||||||
dest: /etc/hostname
|
dest: /etc/hostname
|
||||||
@ -189,6 +232,7 @@
|
|||||||
state: present
|
state: present
|
||||||
when: hostname.changed
|
when: hostname.changed
|
||||||
|
|
||||||
|
# Now we disable sap and a2dp, we don't use them on rpi
|
||||||
- name: disable sap plugin for bluetooth.service
|
- name: disable sap plugin for bluetooth.service
|
||||||
lineinfile:
|
lineinfile:
|
||||||
dest: /lib/systemd/system/bluetooth.service
|
dest: /lib/systemd/system/bluetooth.service
|
||||||
@ -196,19 +240,6 @@
|
|||||||
line: 'ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,a2dp'
|
line: 'ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,a2dp'
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: configure dphys-swapfile
|
|
||||||
lineinfile:
|
|
||||||
path: /etc/dphys-swapfile
|
|
||||||
regexp: "^CONF_SWAPSIZE=.*$"
|
|
||||||
line: "CONF_SWAPSIZE=2048"
|
|
||||||
|
|
||||||
- name: install packages
|
|
||||||
apt:
|
|
||||||
name: "{{ packages.apt.install }}"
|
|
||||||
state: present
|
|
||||||
update_cache: yes
|
|
||||||
install_recommends: false
|
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
#
|
#
|
||||||
# libpcap v1.9 - build from source
|
# libpcap v1.9 - build from source
|
||||||
@ -242,35 +273,116 @@
|
|||||||
dest: /usr/local/lib/libpcap.so.0.8
|
dest: /usr/local/lib/libpcap.so.0.8
|
||||||
state: link
|
state: link
|
||||||
|
|
||||||
# Install nexmon to fix wireless scanning (takes 2.5G of space)
|
# install latest hcxtools
|
||||||
|
|
||||||
|
- name: clone hcxtools
|
||||||
|
git:
|
||||||
|
repo: https://github.com/ZerBea/hcxtools.git
|
||||||
|
dest: /usr/local/src/hcxtools
|
||||||
|
|
||||||
|
- name: install hcxtools
|
||||||
|
shell: "make && make install"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/hcxtools
|
||||||
|
|
||||||
|
- name: remove hcxtools directory
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/hcxtools
|
||||||
|
|
||||||
- name: clone nexmon repository
|
- name: clone nexmon repository
|
||||||
git:
|
git:
|
||||||
repo: https://github.com/DrSchottky/nexmon.git
|
repo: https://github.com/DrSchottky/nexmon.git
|
||||||
dest: /usr/local/src/nexmon
|
dest: /usr/local/src/nexmon
|
||||||
|
|
||||||
- name: make firmware
|
# FIRST WE BUILD DRIVER FOR RPi5
|
||||||
|
|
||||||
|
- name: make firmware, RPi5
|
||||||
shell: "source ./setup_env.sh && make"
|
shell: "source ./setup_env.sh && make"
|
||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
chdir: /usr/local/src/nexmon/
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full_pi5 }}"
|
||||||
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
- name: make firmware patch (bcm43455c0)
|
- name: make firmware patch (bcm43455c0), RPi5
|
||||||
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make"
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make"
|
||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
chdir: /usr/local/src/nexmon/
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full_pi5 }}"
|
||||||
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
- name: install new firmware (bcm43455c0)
|
- name: copy modified driver, RPi5
|
||||||
|
copy:
|
||||||
|
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
|
||||||
|
dest: "/usr/lib/modules/{{ kernel.full_pi5 }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full_pi5 }}"
|
||||||
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
|
- name: Delete the modified driver, RPi5
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: '/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko'
|
||||||
|
|
||||||
|
- name: backup original driver, RPi5
|
||||||
|
command: "mv /usr/lib/modules/{{ kernel.full_pi5 }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz /usr/lib/modules/{{ kernel.full_pi5 }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz.orig"
|
||||||
|
|
||||||
|
- name: load brcmfmac drivers
|
||||||
|
command: "/sbin/depmod {{ kernel.full_pi5 }}"
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full_pi5 }}"
|
||||||
|
|
||||||
|
- name: Delete nexmon content & directory
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
# NOW WE BUILD DRIVERS FOR RPi4, RPizero2w and RPi3
|
||||||
|
|
||||||
|
- name: clone nexmon repository
|
||||||
|
git:
|
||||||
|
repo: https://github.com/DrSchottky/nexmon.git
|
||||||
|
dest: /usr/local/src/nexmon
|
||||||
|
|
||||||
|
- name: make firmware, RPi4
|
||||||
|
shell: "source ./setup_env.sh && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
|
- name: make firmware patch (bcm43455c0), RPi4
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
|
- name: install new firmware (bcm43455c0), RPi4 RPi5
|
||||||
copy:
|
copy:
|
||||||
src: /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/brcmfmac43455-sdio.bin
|
src: /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/brcmfmac43455-sdio.bin
|
||||||
dest: /usr/lib/firmware/brcm/brcmfmac43455-sdio.bin
|
dest: /usr/lib/firmware/brcm/brcmfmac43455-sdio.bin
|
||||||
follow: true
|
follow: true
|
||||||
|
|
||||||
|
# NOW WE BUILD DRIVERS FOR RPiZero2W, RPi 3
|
||||||
|
|
||||||
- name: make firmware patch (bcm43436b0)
|
- name: make firmware patch (bcm43436b0)
|
||||||
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make"
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make"
|
||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
chdir: /usr/local/src/nexmon/
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
- name: install new firmware (bcm43436b0)
|
- name: install new firmware (bcm43436b0)
|
||||||
copy:
|
copy:
|
||||||
@ -283,6 +395,17 @@
|
|||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
chdir: /usr/local/src/nexmon/
|
chdir: /usr/local/src/nexmon/
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
|
- name: copy modified driver, RPi4
|
||||||
|
copy:
|
||||||
|
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
|
||||||
|
dest: "/usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
|
||||||
|
environment:
|
||||||
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
ARCHFLAGS: "-arch aarch64"
|
||||||
|
|
||||||
- name: install new firmware (bcm43430a1)
|
- name: install new firmware (bcm43430a1)
|
||||||
copy:
|
copy:
|
||||||
@ -313,13 +436,10 @@
|
|||||||
- name: backup original driver
|
- name: backup original driver
|
||||||
command: "mv /usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz /usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz.orig"
|
command: "mv /usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz /usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz.orig"
|
||||||
|
|
||||||
- name: copy modified driver
|
- name: load brcmfmac drivers
|
||||||
copy:
|
command: "/sbin/depmod {{ kernel.full }}"
|
||||||
src: "/usr/local/src/nexmon/patches/driver/brcmfmac_{{ kernel.min }}.y-nexmon/brcmfmac.ko"
|
environment:
|
||||||
dest: "/usr/lib/modules/{{ kernel.full }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
|
QEMU_UNAME: "{{ kernel.full }}"
|
||||||
|
|
||||||
- name : load brcmfmac drivers
|
|
||||||
command: "/sbin/depmod -a"
|
|
||||||
|
|
||||||
# To shrink the final image, remove the nexmon directory (takes 2.5G of space) post build and installation
|
# To shrink the final image, remove the nexmon directory (takes 2.5G of space) post build and installation
|
||||||
- name: Delete nexmon content & directory
|
- name: Delete nexmon content & directory
|
||||||
@ -339,7 +459,7 @@
|
|||||||
|
|
||||||
- name: clone pwnagotchi repository
|
- name: clone pwnagotchi repository
|
||||||
git:
|
git:
|
||||||
repo: https://github.com/jayofelony/pwnagotchi-bookworm.git
|
repo: https://github.com/jayofelony/pwnagotchi.git
|
||||||
dest: /usr/local/src/pwnagotchi
|
dest: /usr/local/src/pwnagotchi
|
||||||
|
|
||||||
- name: build pwnagotchi wheel
|
- name: build pwnagotchi wheel
|
||||||
@ -394,7 +514,7 @@
|
|||||||
repo: "{{ packages.bettercap.source }}"
|
repo: "{{ packages.bettercap.source }}"
|
||||||
dest: /usr/local/src/bettercap
|
dest: /usr/local/src/bettercap
|
||||||
|
|
||||||
- name: install bettercap 2.32.2
|
- name: install bettercap 2.32.4
|
||||||
shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && go mod tidy && make && make install"
|
shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && go mod tidy && make && make install"
|
||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
@ -447,11 +567,6 @@
|
|||||||
path: /etc/pwnagotchi
|
path: /etc/pwnagotchi
|
||||||
state: directory
|
state: directory
|
||||||
|
|
||||||
- name: create log folder
|
|
||||||
file:
|
|
||||||
path: /home/pi/logs
|
|
||||||
state: directory
|
|
||||||
|
|
||||||
- name: check if user configuration exists
|
- name: check if user configuration exists
|
||||||
stat:
|
stat:
|
||||||
path: /etc/pwnagotchi/config.toml
|
path: /etc/pwnagotchi/config.toml
|
||||||
@ -477,45 +592,10 @@
|
|||||||
state: absent
|
state: absent
|
||||||
path: /etc/update-motd.d/10-uname
|
path: /etc/update-motd.d/10-uname
|
||||||
|
|
||||||
- name: enable ssh on boot
|
|
||||||
file:
|
|
||||||
path: /boot/firmware/ssh
|
|
||||||
state: touch
|
|
||||||
|
|
||||||
- name: adjust /boot/config.txt
|
|
||||||
lineinfile:
|
|
||||||
dest: /boot/firmware/config.txt
|
|
||||||
insertafter: EOF
|
|
||||||
line: '{{ item }}'
|
|
||||||
with_items: "{{ system.boot_options }}"
|
|
||||||
|
|
||||||
- name: adjust /etc/modules
|
|
||||||
lineinfile:
|
|
||||||
dest: /etc/modules
|
|
||||||
insertafter: EOF
|
|
||||||
line: '{{ item }}'
|
|
||||||
with_items: "{{ system.modules }}"
|
|
||||||
|
|
||||||
- name: change root partition
|
|
||||||
replace:
|
|
||||||
dest: /boot/firmware/cmdline.txt
|
|
||||||
backup: no
|
|
||||||
regexp: "root=PARTUUID=[a-zA-Z0-9\\-]+"
|
|
||||||
replace: "root=/dev/mmcblk0p2"
|
|
||||||
|
|
||||||
- name: configure /boot/cmdline.txt
|
|
||||||
lineinfile:
|
|
||||||
path: /boot/cmdline.txt
|
|
||||||
backrefs: True
|
|
||||||
state: present
|
|
||||||
backup: no
|
|
||||||
regexp: '(.*)$'
|
|
||||||
line: '\1 modules-load=dwc2,g_ether'
|
|
||||||
|
|
||||||
- name: Add pwnlog alias
|
- name: Add pwnlog alias
|
||||||
lineinfile:
|
lineinfile:
|
||||||
dest: /home/pi/.bashrc
|
dest: /home/pi/.bashrc
|
||||||
line: "\nalias pwnlog='tail -f -n300 /home/pi/logs/pwn*.log | sed --unbuffered \"s/,[[:digit:]]\\{3\\}\\]//g\" | cut -d \" \" -f 2-'"
|
line: "\nalias pwnlog='tail -f -n300 /etc/pwnagotchi/log/pwn*.log | sed --unbuffered \"s/,[[:digit:]]\\{3\\}\\]//g\" | cut -d \" \" -f 2-'"
|
||||||
insertafter: EOF
|
insertafter: EOF
|
||||||
|
|
||||||
- name: Add pwnver alias
|
- name: Add pwnver alias
|
||||||
@ -563,18 +643,6 @@
|
|||||||
group: pi
|
group: pi
|
||||||
recurse: true
|
recurse: true
|
||||||
|
|
||||||
- name: remove unnecessary apt packages
|
|
||||||
apt:
|
|
||||||
name: "{{ packages.apt.remove }}"
|
|
||||||
state: absent
|
|
||||||
purge: yes
|
|
||||||
register: removed
|
|
||||||
|
|
||||||
- name: clean apt cache
|
|
||||||
apt:
|
|
||||||
autoclean: true
|
|
||||||
when: removed.changed
|
|
||||||
|
|
||||||
- name: remove pre-collected packages zip
|
- name: remove pre-collected packages zip
|
||||||
file:
|
file:
|
||||||
path: /root/go_pkgs.tgz
|
path: /root/go_pkgs.tgz
|
||||||
@ -595,11 +663,6 @@
|
|||||||
state: absent
|
state: absent
|
||||||
path: /root/.cache/pip
|
path: /root/.cache/pip
|
||||||
|
|
||||||
- name: remove dependencies that are no longer required
|
|
||||||
apt:
|
|
||||||
autoremove: yes
|
|
||||||
when: removed.changed
|
|
||||||
|
|
||||||
- name: remove ssh keys
|
- name: remove ssh keys
|
||||||
file:
|
file:
|
||||||
state: absent
|
state: absent
|
||||||
@ -612,6 +675,24 @@
|
|||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
|
|
||||||
|
# Now we remove packages
|
||||||
|
- name: remove unnecessary apt packages
|
||||||
|
apt:
|
||||||
|
name: "{{ packages.apt.remove }}"
|
||||||
|
state: absent
|
||||||
|
purge: yes
|
||||||
|
register: removed
|
||||||
|
|
||||||
|
- name: remove dependencies that are no longer required
|
||||||
|
apt:
|
||||||
|
autoremove: yes
|
||||||
|
when: removed.changed
|
||||||
|
|
||||||
|
- name: clean apt cache
|
||||||
|
apt:
|
||||||
|
autoclean: true
|
||||||
|
when: removed.changed
|
||||||
|
|
||||||
handlers:
|
handlers:
|
||||||
- name: reload systemd services
|
- name: reload systemd services
|
||||||
systemd:
|
systemd:
|
0
builder/data/64bit/root/client_secrets.json
Normal file
0
builder/data/64bit/root/client_secrets.json
Normal file
15
builder/data/64bit/root/settings.yaml
Normal file
15
builder/data/64bit/root/settings.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
client_config_backend: file
|
||||||
|
client_config_file: /root/client_secrets.json
|
||||||
|
client_config:
|
||||||
|
client_id: <YOUR CLIENT ID>
|
||||||
|
client_secret: <YOUR CLIENT SECRET>
|
||||||
|
|
||||||
|
save_credentials: True
|
||||||
|
save_credentials_backend: file
|
||||||
|
save_credentials_file: /root/credentials.json
|
||||||
|
|
||||||
|
get_refresh_token: True
|
||||||
|
|
||||||
|
oauth_scope:
|
||||||
|
- https://www.googleapis.com/auth/drive
|
||||||
|
- https://www.googleapis.com/auth/drive.install
|
19
builder/data/64bit/usr/bin/bettercap-launcher
Executable file
19
builder/data/64bit/usr/bin/bettercap-launcher
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source /usr/bin/pwnlib
|
||||||
|
|
||||||
|
# we need to decrypt something
|
||||||
|
if is_crypted_mode; then
|
||||||
|
while ! is_decrypted; do
|
||||||
|
echo "Waiting for decryption..."
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# start mon0
|
||||||
|
start_monitor_interface
|
||||||
|
|
||||||
|
if is_auto_mode_no_delete; then
|
||||||
|
/usr/local/bin/bettercap -no-colors -caplet pwnagotchi-auto -iface wlan0mon
|
||||||
|
else
|
||||||
|
/usr/local/bin/bettercap -no-colors -caplet pwnagotchi-manual -iface wlan0mon
|
||||||
|
fi
|
2
builder/data/64bit/usr/bin/hdmioff
Executable file
2
builder/data/64bit/usr/bin/hdmioff
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
sudo /usr/bin/tvservice -o
|
2
builder/data/64bit/usr/bin/hdmion
Executable file
2
builder/data/64bit/usr/bin/hdmion
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
sudo /usr/bin/tvservice -p
|
3
builder/data/64bit/usr/bin/monstart
Executable file
3
builder/data/64bit/usr/bin/monstart
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source /usr/bin/pwnlib
|
||||||
|
start_monitor_interface
|
3
builder/data/64bit/usr/bin/monstop
Executable file
3
builder/data/64bit/usr/bin/monstop
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source /usr/bin/pwnlib
|
||||||
|
stop_monitor_interface
|
16
builder/data/64bit/usr/bin/pwnagotchi-launcher
Executable file
16
builder/data/64bit/usr/bin/pwnagotchi-launcher
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source /usr/bin/pwnlib
|
||||||
|
|
||||||
|
# we need to decrypt something
|
||||||
|
if is_crypted_mode; then
|
||||||
|
while ! is_decrypted; do
|
||||||
|
echo "Waiting for decryption..."
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_auto_mode; then
|
||||||
|
/usr/local/bin/pwnagotchi
|
||||||
|
else
|
||||||
|
/usr/local/bin/pwnagotchi --manual
|
||||||
|
fi
|
@ -13,14 +13,6 @@ blink_led() {
|
|||||||
sleep 0.3
|
sleep 0.3
|
||||||
}
|
}
|
||||||
|
|
||||||
# check if brcm is stuck
|
|
||||||
check_brcm() {
|
|
||||||
if [[ "$(journalctl -n10 -k --since -5m | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 5 ]]; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# reload mod
|
# reload mod
|
||||||
reload_brcm() {
|
reload_brcm() {
|
||||||
if ! modprobe -r brcmfmac; then
|
if ! modprobe -r brcmfmac; then
|
||||||
@ -39,8 +31,10 @@ reload_brcm() {
|
|||||||
start_monitor_interface() {
|
start_monitor_interface() {
|
||||||
rfkill unblock all
|
rfkill unblock all
|
||||||
ifconfig wlan0 up
|
ifconfig wlan0 up
|
||||||
|
sleep 3
|
||||||
iw dev wlan0 set power_save off
|
iw dev wlan0 set power_save off
|
||||||
iw phy "$(iw phy | head -1 | cut -d" " -f2)" interface add wlan0mon type monitor
|
iw phy "$(iw phy | head -1 | cut -d" " -f2)" interface add wlan0mon type monitor
|
||||||
|
sleep 2
|
||||||
rfkill unblock all
|
rfkill unblock all
|
||||||
ifconfig wlan0 down
|
ifconfig wlan0 down
|
||||||
ifconfig wlan0mon up
|
ifconfig wlan0mon up
|
||||||
@ -54,7 +48,7 @@ stop_monitor_interface() {
|
|||||||
ifconfig wlan0 up
|
ifconfig wlan0 up
|
||||||
}
|
}
|
||||||
|
|
||||||
# returns 0 if the specificed network interface is up
|
# returns 0 if the specified network interface is up
|
||||||
is_interface_up() {
|
is_interface_up() {
|
||||||
if grep -qi 'up' /sys/class/net/"$1"/operstate; then
|
if grep -qi 'up' /sys/class/net/"$1"/operstate; then
|
||||||
return 0
|
return 0
|
@ -1 +1 @@
|
|||||||
__version__ = '2.7.1'
|
__version__ = '2.8.5'
|
||||||
|
@ -21,17 +21,17 @@ RECOVERY_DATA_FILE = '/root/.pwnagotchi-recovery'
|
|||||||
|
|
||||||
class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
||||||
def __init__(self, view, config, keypair):
|
def __init__(self, view, config, keypair):
|
||||||
Client.__init__(self, config['bettercap']['hostname'],
|
Client.__init__(self,
|
||||||
config['bettercap']['scheme'],
|
"127.0.0.1" if "hostname" not in config['bettercap'] else config['bettercap']['hostname'],
|
||||||
config['bettercap']['port'],
|
"http" if "scheme" not in config['bettercap'] else config['bettercap']['scheme'],
|
||||||
config['bettercap']['username'],
|
8081 if "port" not in config['bettercap'] else config['bettercap']['port'],
|
||||||
config['bettercap']['password'])
|
"pwnagotchi" if "username" not in config['bettercap'] else config['bettercap']['username'],
|
||||||
|
"pwnagotchi" if "password" not in config['bettercap'] else config['bettercap']['password'])
|
||||||
Automata.__init__(self, config, view)
|
Automata.__init__(self, config, view)
|
||||||
AsyncAdvertiser.__init__(self, config, view, keypair)
|
AsyncAdvertiser.__init__(self, config, view, keypair)
|
||||||
AsyncTrainer.__init__(self, config)
|
AsyncTrainer.__init__(self, config)
|
||||||
|
|
||||||
self._started_at = time.time()
|
self._started_at = time.time()
|
||||||
self._filter = None if not config['main']['filter'] else re.compile(config['main']['filter'])
|
|
||||||
self._current_channel = 0
|
self._current_channel = 0
|
||||||
self._tot_aps = 0
|
self._tot_aps = 0
|
||||||
self._aps_on_channel = 0
|
self._aps_on_channel = 0
|
||||||
@ -164,11 +164,6 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
|||||||
|
|
||||||
self.wait_for(recon_time, sleeping=False)
|
self.wait_for(recon_time, sleeping=False)
|
||||||
|
|
||||||
def _filter_included(self, ap):
|
|
||||||
return self._filter is None or \
|
|
||||||
self._filter.match(ap['hostname']) is not None or \
|
|
||||||
self._filter.match(ap['mac']) is not None
|
|
||||||
|
|
||||||
def set_access_points(self, aps):
|
def set_access_points(self, aps):
|
||||||
self._access_points = aps
|
self._access_points = aps
|
||||||
plugins.on('wifi_update', self, aps)
|
plugins.on('wifi_update', self, aps)
|
||||||
@ -184,12 +179,9 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
|||||||
for ap in s['wifi']['aps']:
|
for ap in s['wifi']['aps']:
|
||||||
if ap['encryption'] == '' or ap['encryption'] == 'OPEN':
|
if ap['encryption'] == '' or ap['encryption'] == 'OPEN':
|
||||||
continue
|
continue
|
||||||
elif ap['hostname'] in whitelist or ap['mac'][:8].lower() in whitelist:
|
elif ap['hostname'] in whitelist or ap['mac'][:13].lower() in whitelist or ap['mac'].lower() in whitelist:
|
||||||
continue
|
continue
|
||||||
elif ap['hostname'] not in whitelist \
|
else:
|
||||||
and ap['mac'].lower() not in whitelist \
|
|
||||||
and ap['mac'][:8].lower() not in whitelist:
|
|
||||||
if self._filter_included(ap):
|
|
||||||
aps.append(ap)
|
aps.append(ap)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("Error while getting access points (%s)", e)
|
logging.exception("Error while getting access points (%s)", e)
|
||||||
@ -277,6 +269,10 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
|||||||
self._save_recovery_data()
|
self._save_recovery_data()
|
||||||
pwnagotchi.reboot()
|
pwnagotchi.reboot()
|
||||||
|
|
||||||
|
def _restart(self):
|
||||||
|
self._save_recovery_data()
|
||||||
|
pwnagotchi.restart("AUTO")
|
||||||
|
|
||||||
def _save_recovery_data(self):
|
def _save_recovery_data(self):
|
||||||
logging.warning("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:
|
with open(RECOVERY_DATA_FILE, 'w') as fp:
|
||||||
@ -429,7 +425,6 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
|
|||||||
if self.is_stale():
|
if self.is_stale():
|
||||||
logging.debug("recon is stale, skipping assoc(%s)", ap['mac'])
|
logging.debug("recon is stale, skipping assoc(%s)", ap['mac'])
|
||||||
return
|
return
|
||||||
|
|
||||||
if throttle == -1 and "throttle_a" in self._config['personality']:
|
if throttle == -1 and "throttle_a" in self._config['personality']:
|
||||||
throttle = self._config['personality']['throttle_a']
|
throttle = self._config['personality']['throttle_a']
|
||||||
|
|
||||||
|
@ -59,7 +59,8 @@ def load(config, agent, epoch, from_disk=True):
|
|||||||
|
|
||||||
return a2c
|
return a2c
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("[AI] error while starting AI (%s)", e)
|
logging.info("[AI] Error while starting AI")
|
||||||
|
logging.debug("[AI] error while starting AI (%s)", e)
|
||||||
logging.info("[AI] Deleting brain and restarting.")
|
logging.info("[AI] Deleting brain and restarting.")
|
||||||
os.system("rm /root/brain.nn && service pwnagotchi restart")
|
os.system("rm /root/brain.nn && service pwnagotchi restart")
|
||||||
|
|
||||||
|
@ -138,6 +138,6 @@ class Automata(object):
|
|||||||
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
|
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
|
||||||
|
|
||||||
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']:
|
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']:
|
||||||
logging.critical("%d epochs without visible access points -> rebooting ...", self._epoch.blind_for)
|
logging.critical("%d epochs without visible access points -> restarting ...", self._epoch.blind_for)
|
||||||
self._reboot()
|
self._restart()
|
||||||
self._epoch.blind_for = 0
|
self._epoch.blind_for = 0
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
main.name = "pwnagotchi"
|
main.name = "pwnagotchi"
|
||||||
main.lang = "en"
|
main.lang = "en"
|
||||||
|
main.whitelist = [
|
||||||
|
"EXAMPLE_NETWORK",
|
||||||
|
"ANOTHER_EXAMPLE_NETWORK",
|
||||||
|
"fo:od:ba:be:fo:od",
|
||||||
|
"fo:od:ba"
|
||||||
|
]
|
||||||
main.confd = "/etc/pwnagotchi/conf.d/"
|
main.confd = "/etc/pwnagotchi/conf.d/"
|
||||||
main.custom_plugin_repos = [
|
main.custom_plugin_repos = [
|
||||||
"https://github.com/jayofelony/pwnagotchi-torch-plugins/archive/master.zip",
|
"https://github.com/jayofelony/pwnagotchi-torch-plugins/archive/master.zip",
|
||||||
@ -55,9 +61,6 @@ main.plugins.gps.device = "/dev/ttyUSB0" # for GPSD: "localhost:2947"
|
|||||||
|
|
||||||
main.plugins.grid.enabled = true
|
main.plugins.grid.enabled = true
|
||||||
main.plugins.grid.report = true
|
main.plugins.grid.report = true
|
||||||
main.plugins.grid.exclude = [
|
|
||||||
"YourHomeNetworkHere"
|
|
||||||
]
|
|
||||||
|
|
||||||
main.plugins.logtail.enabled = false
|
main.plugins.logtail.enabled = false
|
||||||
main.plugins.logtail.max-lines = 10000
|
main.plugins.logtail.max-lines = 10000
|
||||||
@ -73,10 +76,6 @@ main.plugins.onlinehashcrack.enabled = false
|
|||||||
main.plugins.onlinehashcrack.email = ""
|
main.plugins.onlinehashcrack.email = ""
|
||||||
main.plugins.onlinehashcrack.dashboard = ""
|
main.plugins.onlinehashcrack.dashboard = ""
|
||||||
main.plugins.onlinehashcrack.single_files = false
|
main.plugins.onlinehashcrack.single_files = false
|
||||||
main.plugins.onlinehashcrack.whitelist = []
|
|
||||||
|
|
||||||
main.plugins.paw-gps.enabled = false
|
|
||||||
main.plugins.paw-gps.ip = "192.168.44.1:8080"
|
|
||||||
|
|
||||||
main.plugins.pisugar2.enabled = false
|
main.plugins.pisugar2.enabled = false
|
||||||
main.plugins.pisugar2.shutdown = 5
|
main.plugins.pisugar2.shutdown = 5
|
||||||
@ -100,29 +99,22 @@ main.plugins.webgpsmap.enabled = false
|
|||||||
|
|
||||||
main.plugins.wigle.enabled = false
|
main.plugins.wigle.enabled = false
|
||||||
main.plugins.wigle.api_key = ""
|
main.plugins.wigle.api_key = ""
|
||||||
main.plugins.wigle.whitelist = []
|
main.plugins.wigle.donate = false
|
||||||
main.plugins.wigle.donate = true
|
|
||||||
|
|
||||||
main.plugins.wpa-sec.enabled = false
|
main.plugins.wpa-sec.enabled = false
|
||||||
main.plugins.wpa-sec.api_key = ""
|
main.plugins.wpa-sec.api_key = ""
|
||||||
main.plugins.wpa-sec.api_url = "https://wpa-sec.stanev.org"
|
main.plugins.wpa-sec.api_url = "https://wpa-sec.stanev.org"
|
||||||
main.plugins.wpa-sec.download_results = false
|
main.plugins.wpa-sec.download_results = false
|
||||||
main.plugins.wpa-sec.whitelist = []
|
|
||||||
|
|
||||||
main.iface = "wlan0mon"
|
main.iface = "wlan0mon"
|
||||||
main.mon_start_cmd = "/usr/bin/monstart"
|
main.mon_start_cmd = "/usr/bin/monstart"
|
||||||
main.mon_stop_cmd = "/usr/bin/monstop"
|
main.mon_stop_cmd = "/usr/bin/monstop"
|
||||||
main.mon_max_blind_epochs = 50
|
main.mon_max_blind_epochs = 50
|
||||||
main.no_restart = false
|
main.no_restart = false
|
||||||
main.whitelist = [
|
|
||||||
"EXAMPLE_NETWORK",
|
|
||||||
"ANOTHER_EXAMPLE_NETWORK",
|
|
||||||
"fo:od:ba:be:fo:od",
|
|
||||||
"fo:od:ba"
|
|
||||||
]
|
|
||||||
main.filter = ""
|
main.filter = ""
|
||||||
|
|
||||||
main.log.path = "/home/pi/logs/pwnagotchi.log"
|
main.log.path = "/etc/pwnagotchi/log/pwnagotchi.log"
|
||||||
main.log.rotation.enabled = true
|
main.log.rotation.enabled = true
|
||||||
main.log.rotation.size = "10M"
|
main.log.rotation.size = "10M"
|
||||||
|
|
||||||
@ -160,6 +152,8 @@ personality.bond_encounters_factor = 20000
|
|||||||
personality.throttle_a = 0.4
|
personality.throttle_a = 0.4
|
||||||
personality.throttle_d = 0.9
|
personality.throttle_d = 0.9
|
||||||
|
|
||||||
|
personality.clear_on_exit = true # clear display when shutting down cleanly
|
||||||
|
|
||||||
ui.fps = 0.0
|
ui.fps = 0.0
|
||||||
ui.font.name = "DejaVuSansMono" # for japanese: fonts-japanese-gothic
|
ui.font.name = "DejaVuSansMono" # for japanese: fonts-japanese-gothic
|
||||||
ui.font.size_offset = 0 # will be added to the font size
|
ui.font.size_offset = 0 # will be added to the font size
|
||||||
@ -189,6 +183,9 @@ ui.faces.debug = "(#__#)"
|
|||||||
ui.faces.upload = "(1__0)"
|
ui.faces.upload = "(1__0)"
|
||||||
ui.faces.upload1 = "(1__1)"
|
ui.faces.upload1 = "(1__1)"
|
||||||
ui.faces.upload2 = "(0__1)"
|
ui.faces.upload2 = "(0__1)"
|
||||||
|
ui.faces.png = false
|
||||||
|
ui.faces.position_x = 0
|
||||||
|
ui.faces.position_y = 34
|
||||||
|
|
||||||
ui.web.enabled = true
|
ui.web.enabled = true
|
||||||
ui.web.address = "::" # listening on both ipv4 and ipv6 - switch to 0.0.0.0 to listen on just ipv4
|
ui.web.address = "::" # listening on both ipv4 and ipv6 - switch to 0.0.0.0 to listen on just ipv4
|
||||||
@ -202,11 +199,6 @@ ui.display.enabled = false
|
|||||||
ui.display.rotation = 180
|
ui.display.rotation = 180
|
||||||
ui.display.type = "waveshare_4"
|
ui.display.type = "waveshare_4"
|
||||||
|
|
||||||
bettercap.scheme = "http"
|
|
||||||
bettercap.hostname = "localhost"
|
|
||||||
bettercap.port = 8081
|
|
||||||
bettercap.username = "pwnagotchi"
|
|
||||||
bettercap.password = "pwnagotchi"
|
|
||||||
bettercap.handshakes = "/root/handshakes"
|
bettercap.handshakes = "/root/handshakes"
|
||||||
bettercap.silence = [
|
bettercap.silence = [
|
||||||
"ble.device.new",
|
"ble.device.new",
|
||||||
@ -225,7 +217,7 @@ bettercap.silence = [
|
|||||||
|
|
||||||
fs.memory.enabled = true
|
fs.memory.enabled = true
|
||||||
fs.memory.mounts.log.enabled = true
|
fs.memory.mounts.log.enabled = true
|
||||||
fs.memory.mounts.log.mount = "/home/pi/logs"
|
fs.memory.mounts.log.mount = "/etc/pwnagotchi/log/"
|
||||||
fs.memory.mounts.log.size = "50M"
|
fs.memory.mounts.log.size = "50M"
|
||||||
fs.memory.mounts.log.sync = 60
|
fs.memory.mounts.log.sync = 60
|
||||||
fs.memory.mounts.log.zram = true
|
fs.memory.mounts.log.zram = true
|
||||||
|
@ -89,7 +89,7 @@ def update_data(last_session):
|
|||||||
'uname': subprocess.getoutput("uname -a"),
|
'uname': subprocess.getoutput("uname -a"),
|
||||||
'brain': brain,
|
'brain': brain,
|
||||||
'version': pwnagotchi.__version__,
|
'version': pwnagotchi.__version__,
|
||||||
'build': "Pwnagotchi-Torch by Jayofelony",
|
'build': "Pwnagotchi by Jayofelony",
|
||||||
'plugins': enabled,
|
'plugins': enabled,
|
||||||
'language': language,
|
'language': language,
|
||||||
'bettercap': subprocess.getoutput("bettercap -version").split(".\n\n")[1],
|
'bettercap': subprocess.getoutput("bettercap -version").split(".\n\n")[1],
|
||||||
|
Binary file not shown.
@ -1,14 +1,13 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
# Pwnagotchi display English to Esperanto.
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR MADE THIS IN YEAR 2024.
|
||||||
#
|
#
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-11-16 21:10+0100\n"
|
"POT-Creation-Date: 2024-01-25 23:40+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -18,218 +17,219 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
msgid "ZzzzZZzzzzZzzz"
|
msgid "ZzzzZZzzzzZzzz"
|
||||||
msgstr ""
|
msgstr "ZzzzZZzzzzZzzz"
|
||||||
|
|
||||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||||
msgstr ""
|
msgstr "Sal, mi estas Pwnagotchi! Komencante…"
|
||||||
|
|
||||||
msgid "New day, new hunt, new pwns!"
|
msgid "New day, new hunt, new pwns!"
|
||||||
msgstr ""
|
msgstr "Nova tago, nova ĉaso, nova wifi!"
|
||||||
|
|
||||||
msgid "Hack the Planet!"
|
msgid "Hack the Planet!"
|
||||||
msgstr ""
|
msgstr "Eniru la elektronikon!"
|
||||||
|
|
||||||
msgid "AI ready."
|
msgid "AI ready."
|
||||||
msgstr ""
|
msgstr "Mi pretas."
|
||||||
|
|
||||||
msgid "The neural network is ready."
|
msgid "The neural network is ready."
|
||||||
msgstr ""
|
msgstr "La elektronika reto estas preta."
|
||||||
|
|
||||||
msgid "Generating keys, do not turn off ..."
|
msgid "Generating keys, do not turn off ..."
|
||||||
msgstr ""
|
msgstr "Mi generas ŝlosilojn, ne malŝaltu min!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||||
msgstr ""
|
msgstr "Hej, kanalo {channel} disponeblas! Via alirpunkto dankos vin"
|
||||||
|
|
||||||
msgid "Reading last session logs ..."
|
msgid "Reading last session logs ..."
|
||||||
msgstr ""
|
msgstr "Legante protokolojn de antaŭa sesio…"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Read {lines_so_far} log lines so far ..."
|
msgid "Read {lines_so_far} log lines so far ..."
|
||||||
msgstr ""
|
msgstr "legi {lines_so_far} liniojn ĝis nun…"
|
||||||
|
|
||||||
msgid "I'm bored ..."
|
msgid "I'm bored ..."
|
||||||
msgstr ""
|
msgstr "Mi enuas…"
|
||||||
|
|
||||||
msgid "Let's go for a walk!"
|
msgid "Let's go for a walk!"
|
||||||
msgstr ""
|
msgstr "Ni iru promeni!"
|
||||||
|
|
||||||
msgid "This is the best day of my life!"
|
msgid "This is the best day of my life!"
|
||||||
msgstr ""
|
msgstr "Plej bona tago de mia vivo!"
|
||||||
|
|
||||||
msgid "Shitty day :/"
|
msgid "Shitty day :/"
|
||||||
msgstr ""
|
msgstr "Terura tago :/"
|
||||||
|
|
||||||
msgid "I'm extremely bored ..."
|
msgid "I'm extremely bored ..."
|
||||||
msgstr ""
|
msgstr "mi estas tre enuigita…"
|
||||||
|
|
||||||
msgid "I'm very sad ..."
|
msgid "I'm very sad ..."
|
||||||
msgstr ""
|
msgstr "Mi estas tre malĝoja…"
|
||||||
|
|
||||||
msgid "I'm sad"
|
msgid "I'm sad"
|
||||||
msgstr ""
|
msgstr "Mi estas malfeliĉa"
|
||||||
|
|
||||||
msgid "Leave me alone ..."
|
msgid "Leave me alone ..."
|
||||||
msgstr ""
|
msgstr "Lasu min sola…"
|
||||||
|
|
||||||
msgid "I'm mad at you!"
|
msgid "I'm mad at you!"
|
||||||
msgstr ""
|
msgstr "Mi koleras kontraŭ vi!"
|
||||||
|
|
||||||
msgid "I'm living the life!"
|
msgid "I'm living the life!"
|
||||||
msgstr ""
|
msgstr "Mi ĝuas la vivon!"
|
||||||
|
|
||||||
msgid "I pwn therefore I am."
|
msgid "I pwn therefore I am."
|
||||||
msgstr ""
|
msgstr "Mi eniras tial mi estas."
|
||||||
|
|
||||||
msgid "So many networks!!!"
|
msgid "So many networks!!!"
|
||||||
msgstr ""
|
msgstr "Tiom da ludiloj!"
|
||||||
|
|
||||||
msgid "I'm having so much fun!"
|
msgid "I'm having so much fun!"
|
||||||
msgstr ""
|
msgstr "Mi tre amuzas!"
|
||||||
|
|
||||||
msgid "My crime is that of curiosity ..."
|
msgid "My crime is that of curiosity ..."
|
||||||
msgstr ""
|
msgstr "Scivolemo estas mia krimo…"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hello {name}! Nice to meet you."
|
msgid "Hello {name}! Nice to meet you."
|
||||||
msgstr ""
|
msgstr "Sal {name}! Mi ĝojas renkonti vin."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Yo {name}! Sup?"
|
msgid "Yo {name}! Sup?"
|
||||||
msgstr ""
|
msgstr "Hej {name}! Sal?"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hey {name} how are you doing?"
|
msgid "Hey {name} how are you doing?"
|
||||||
msgstr ""
|
msgstr "Sal {name}! Kiel vi fartas?"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Unit {name} is nearby!"
|
msgid "Unit {name} is nearby!"
|
||||||
msgstr ""
|
msgstr "Iu estas proksime! Ĝia nomo estas {name}."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Uhm ... goodbye {name}"
|
msgid "Uhm ... goodbye {name}"
|
||||||
msgstr ""
|
msgstr "Adiaŭ {name}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} is gone ..."
|
msgid "{name} is gone ..."
|
||||||
msgstr ""
|
msgstr "{name} malaperis…"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Whoops ... {name} is gone."
|
msgid "Whoops ... {name} is gone."
|
||||||
msgstr ""
|
msgstr "Hups… {name} malaperis…"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} missed!"
|
msgid "{name} missed!"
|
||||||
msgstr ""
|
msgstr "{name} mankis!"
|
||||||
|
|
||||||
msgid "Missed!"
|
msgid "Missed!"
|
||||||
msgstr ""
|
msgstr "Maltrafis!"
|
||||||
|
|
||||||
msgid "Good friends are a blessing!"
|
msgid "Good friends are a blessing!"
|
||||||
msgstr ""
|
msgstr "Bonaj amikoj estas beno!"
|
||||||
|
|
||||||
msgid "I love my friends!"
|
msgid "I love my friends!"
|
||||||
msgstr ""
|
msgstr "Mi amas miajn amikojn!"
|
||||||
|
|
||||||
msgid "Nobody wants to play with me ..."
|
msgid "Nobody wants to play with me ..."
|
||||||
msgstr ""
|
msgstr "Neniu volas ludi kun mi..."
|
||||||
|
|
||||||
msgid "I feel so alone ..."
|
msgid "I feel so alone ..."
|
||||||
msgstr ""
|
msgstr "Mi estas tiel sola..."
|
||||||
|
|
||||||
msgid "Where's everybody?!"
|
msgid "Where's everybody?!"
|
||||||
msgstr ""
|
msgstr "KIE ĈIUJ ESTAS?!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Napping for {secs}s ..."
|
msgid "Napping for {secs}s ..."
|
||||||
msgstr ""
|
msgstr "Dormeto por {sec}j…"
|
||||||
|
|
||||||
msgid "Zzzzz"
|
msgid "Zzzzz"
|
||||||
msgstr ""
|
msgstr "Zzzzz"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "ZzzZzzz ({secs}s)"
|
msgid "ZzzZzzz ({secs}s)"
|
||||||
msgstr ""
|
msgstr "ZzzZzzz ({sec}j)"
|
||||||
|
|
||||||
msgid "Good night."
|
msgid "Good night."
|
||||||
msgstr ""
|
msgstr "Bonan nokton"
|
||||||
|
|
||||||
msgid "Zzz"
|
msgid "Zzz"
|
||||||
msgstr ""
|
msgstr "Zzz"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Waiting for {secs}s ..."
|
msgid "Waiting for {secs}s ..."
|
||||||
msgstr ""
|
msgstr "Atendas {sec}j…"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Looking around ({secs}s)"
|
msgid "Looking around ({secs}s)"
|
||||||
msgstr ""
|
msgstr "Ĉirkaŭrigardante ({sec}j)"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hey {what} let's be friends!"
|
msgid "Hey {what} let's be friends!"
|
||||||
msgstr ""
|
msgstr "Hej {what}, ni estu amikoj!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Associating to {what}"
|
msgid "Associating to {what}"
|
||||||
msgstr ""
|
msgstr "asociante al {what}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Yo {what}!"
|
msgid "Yo {what}!"
|
||||||
msgstr ""
|
msgstr "Hej {what}!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Just decided that {mac} needs no WiFi!"
|
msgid "Just decided that {mac} needs no WiFi!"
|
||||||
msgstr ""
|
msgstr "Ĵus decidis, ke {mac} ne bezonas konekton!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Deauthenticating {mac}"
|
msgid "Deauthenticating {mac}"
|
||||||
msgstr ""
|
msgstr "Malaŭtentigi {mac}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Kickbanning {mac}!"
|
msgid "Kickbanning {mac}!"
|
||||||
msgstr ""
|
msgstr "Forigante {mac}!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Cool, we got {num} new handshake{plural}!"
|
msgid "Cool, we got {num} new handshake{plural}!"
|
||||||
msgstr ""
|
msgstr "Mirinda, ni havas {num} novajn manpremojn!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "You have {count} new message{plural}!"
|
msgid "You have {count} new message{plural}!"
|
||||||
msgstr ""
|
msgstr "Vi nun havas {num} novajn mesaĝojn"
|
||||||
|
|
||||||
msgid "Oops, something went wrong ... Rebooting ..."
|
msgid "Oops, something went wrong ... Rebooting ..."
|
||||||
msgstr ""
|
msgstr "Lo okazis... Rekomencante…"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Uploading data to {to} ..."
|
msgid "Uploading data to {to} ..."
|
||||||
msgstr ""
|
msgstr "alŝuti datumojn al {to}…"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Downloading from {name} ..."
|
msgid "Downloading from {name} ..."
|
||||||
msgstr ""
|
msgstr "Elŝutu de {name}…"
|
||||||
|
|
||||||
#, python-brace-format
|
#, fuzzy, python-brace-format
|
||||||
msgid "Kicked {num} stations\n"
|
msgid "Kicked {num} stations\n"
|
||||||
msgstr ""
|
msgstr "Forigita de {num} stacioj"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
msgid "Made >999 new friends\n"
|
msgid "Made >999 new friends\n"
|
||||||
msgstr ""
|
msgstr "Faris pli ol 999 novajn amikojn!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, fuzzy, python-brace-format
|
||||||
msgid "Made {num} new friends\n"
|
msgid "Made {num} new friends\n"
|
||||||
msgstr ""
|
msgstr "faris (nombro) novajn amikojn"
|
||||||
|
|
||||||
#, python-brace-format
|
#, fuzzy, python-brace-format
|
||||||
msgid "Got {num} handshakes\n"
|
msgid "Got {num} handshakes\n"
|
||||||
msgstr ""
|
msgstr "Ricevis {num} novajn manpremojn"
|
||||||
|
|
||||||
msgid "Met 1 peer"
|
msgid "Met 1 peer"
|
||||||
msgstr ""
|
msgstr "Renkontita unu kolego"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Met {num} peers"
|
msgid "Met {num} peers"
|
||||||
msgstr ""
|
msgstr "renkontitajn {num} kolegojn"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -237,21 +237,24 @@ msgid ""
|
|||||||
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
|
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
|
||||||
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
"#pwnlog #pwnlife #hacktheplanet #skynet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Mi pwning dum {duration} kaj piedbatis {deauthed} klientojn!Mi ankaŭ "
|
||||||
|
"renkontis {associated} novajn amikojn kaj manĝis {handshakes} manpremojn!"
|
||||||
|
"#pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
|
||||||
|
|
||||||
msgid "hours"
|
msgid "hours"
|
||||||
msgstr ""
|
msgstr "horror"
|
||||||
|
|
||||||
msgid "minutes"
|
msgid "minutes"
|
||||||
msgstr ""
|
msgstr "minutoj"
|
||||||
|
|
||||||
msgid "seconds"
|
msgid "seconds"
|
||||||
msgstr ""
|
msgstr "sekundoj"
|
||||||
|
|
||||||
msgid "hour"
|
msgid "hour"
|
||||||
msgstr ""
|
msgstr "horo"
|
||||||
|
|
||||||
msgid "minute"
|
msgid "minute"
|
||||||
msgstr ""
|
msgstr "minuto"
|
||||||
|
|
||||||
msgid "second"
|
msgid "second"
|
||||||
msgstr ""
|
msgstr "dua"
|
||||||
|
Binary file not shown.
@ -36,18 +36,18 @@ msgid "The neural network is ready."
|
|||||||
msgstr "La red neuronal está lista."
|
msgstr "La red neuronal está lista."
|
||||||
|
|
||||||
msgid "Generating keys, do not turn off ..."
|
msgid "Generating keys, do not turn off ..."
|
||||||
msgstr ""
|
msgstr "Generando llaves, no me apagues ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||||
msgstr "¡Oye, el canal {channel} está libre! Tu AP lo agradecerá."
|
msgstr "¡Oye, el canal {channel} está libre! Tu AP lo agradecerá."
|
||||||
|
|
||||||
msgid "Reading last session logs ..."
|
msgid "Reading last session logs ..."
|
||||||
msgstr ""
|
msgstr "Leyendo los logs de la última sesión ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Read {lines_so_far} log lines so far ..."
|
msgid "Read {lines_so_far} log lines so far ..."
|
||||||
msgstr ""
|
msgstr "Leyendo {lines_so_far} líneas de log hasta ahora ..."
|
||||||
|
|
||||||
msgid "I'm bored ..."
|
msgid "I'm bored ..."
|
||||||
msgstr "Estoy aburrido ..."
|
msgstr "Estoy aburrido ..."
|
||||||
@ -74,7 +74,7 @@ msgid "Leave me alone ..."
|
|||||||
msgstr "Me siento tan solo ..."
|
msgstr "Me siento tan solo ..."
|
||||||
|
|
||||||
msgid "I'm mad at you!"
|
msgid "I'm mad at you!"
|
||||||
msgstr ""
|
msgstr "Toy re enojado con vos!"
|
||||||
|
|
||||||
msgid "I'm living the life!"
|
msgid "I'm living the life!"
|
||||||
msgstr "¡Estoy viviendo la vida!"
|
msgstr "¡Estoy viviendo la vida!"
|
||||||
@ -97,11 +97,11 @@ msgstr "¡Hola {name}! Encantado de conocerte."
|
|||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Yo {name}! Sup?"
|
msgid "Yo {name}! Sup?"
|
||||||
msgstr ""
|
msgstr "Que onda {name}!?"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hey {name} how are you doing?"
|
msgid "Hey {name} how are you doing?"
|
||||||
msgstr ""
|
msgstr "Eh!, ¿Que haces {name}?"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Unit {name} is nearby!"
|
msgid "Unit {name} is nearby!"
|
||||||
@ -127,10 +127,10 @@ msgid "Missed!"
|
|||||||
msgstr "¡Perdido!"
|
msgstr "¡Perdido!"
|
||||||
|
|
||||||
msgid "Good friends are a blessing!"
|
msgid "Good friends are a blessing!"
|
||||||
msgstr ""
|
msgstr "Lxs buenxs amigxs son una masa!"
|
||||||
|
|
||||||
msgid "I love my friends!"
|
msgid "I love my friends!"
|
||||||
msgstr ""
|
msgstr "¡Amo a mis amigxs!"
|
||||||
|
|
||||||
msgid "Nobody wants to play with me ..."
|
msgid "Nobody wants to play with me ..."
|
||||||
msgstr "Nadie quiere jugar conmigo ..."
|
msgstr "Nadie quiere jugar conmigo ..."
|
||||||
@ -143,7 +143,7 @@ msgstr "¡¿Dónde está todo el mundo?!"
|
|||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Napping for {secs}s ..."
|
msgid "Napping for {secs}s ..."
|
||||||
msgstr "Descansando durante {secs}s ..."
|
msgstr "Descansando por {secs}s ..."
|
||||||
|
|
||||||
msgid "Zzzzz"
|
msgid "Zzzzz"
|
||||||
msgstr "Zzzzz"
|
msgstr "Zzzzz"
|
||||||
@ -203,7 +203,7 @@ msgstr "Oops, algo salió mal ... Reiniciando ..."
|
|||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Uploading data to {to} ..."
|
msgid "Uploading data to {to} ..."
|
||||||
msgstr ""
|
msgstr "Subiendo data a {to} ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Downloading from {name} ..."
|
msgid "Downloading from {name} ..."
|
||||||
|
Binary file not shown.
@ -16,7 +16,7 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
msgid "ZzzzZZzzzzZzzz"
|
msgid "ZzzzZZzzzzZzzz"
|
||||||
msgstr ""
|
msgstr "ZzzzZZzzzzZzzz"
|
||||||
|
|
||||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||||
msgstr "Ciao! Piacere Pwnagotchi! Caricamento ..."
|
msgstr "Ciao! Piacere Pwnagotchi! Caricamento ..."
|
||||||
@ -25,7 +25,7 @@ msgid "New day, new hunt, new pwns!"
|
|||||||
msgstr "Nuovo giorno...nuovi handshakes!!!"
|
msgstr "Nuovo giorno...nuovi handshakes!!!"
|
||||||
|
|
||||||
msgid "Hack the Planet!"
|
msgid "Hack the Planet!"
|
||||||
msgstr ""
|
msgstr "Hack il Pianeta"
|
||||||
|
|
||||||
msgid "AI ready."
|
msgid "AI ready."
|
||||||
msgstr "IA pronta."
|
msgstr "IA pronta."
|
||||||
@ -34,18 +34,18 @@ msgid "The neural network is ready."
|
|||||||
msgstr "La rete neurale è pronta."
|
msgstr "La rete neurale è pronta."
|
||||||
|
|
||||||
msgid "Generating keys, do not turn off ..."
|
msgid "Generating keys, do not turn off ..."
|
||||||
msgstr ""
|
msgstr "Generazione di chiavi, non spegnere"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||||
msgstr "Hey, il canale {channel} è libero! Il tuo AP ringrazia."
|
msgstr "Hey, il canale {channel} è libero! Il tuo AP ringrazia."
|
||||||
|
|
||||||
msgid "Reading last session logs ..."
|
msgid "Reading last session logs ..."
|
||||||
msgstr ""
|
msgstr "Lettura dei log dell'ultima sessione ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Read {lines_so_far} log lines so far ..."
|
msgid "Read {lines_so_far} log lines so far ..."
|
||||||
msgstr ""
|
msgstr "Leggi le righe di log {lines_so_far} finora ..."
|
||||||
|
|
||||||
msgid "I'm bored ..."
|
msgid "I'm bored ..."
|
||||||
msgstr "Che noia ..."
|
msgstr "Che noia ..."
|
||||||
@ -54,7 +54,7 @@ msgid "Let's go for a walk!"
|
|||||||
msgstr "Andiamo a fare una passeggiata!"
|
msgstr "Andiamo a fare una passeggiata!"
|
||||||
|
|
||||||
msgid "This is the best day of my life!"
|
msgid "This is the best day of my life!"
|
||||||
msgstr "Questo è il più bel giorno della mia vita!!!!"
|
msgstr "Questo e il miglior giorno della mia vita!!!!"
|
||||||
|
|
||||||
msgid "Shitty day :/"
|
msgid "Shitty day :/"
|
||||||
msgstr "Giorno di merda :/"
|
msgstr "Giorno di merda :/"
|
||||||
@ -72,22 +72,22 @@ msgid "Leave me alone ..."
|
|||||||
msgstr "Mi sento così solo..."
|
msgstr "Mi sento così solo..."
|
||||||
|
|
||||||
msgid "I'm mad at you!"
|
msgid "I'm mad at you!"
|
||||||
msgstr ""
|
msgstr "sono arabiata con te"
|
||||||
|
|
||||||
msgid "I'm living the life!"
|
msgid "I'm living the life!"
|
||||||
msgstr "Mi sento vivo!"
|
msgstr "sono viva la vita!"
|
||||||
|
|
||||||
msgid "I pwn therefore I am."
|
msgid "I pwn therefore I am."
|
||||||
msgstr "Pwn ergo sum."
|
msgstr "Pwn ergo sum."
|
||||||
|
|
||||||
msgid "So many networks!!!"
|
msgid "So many networks!!!"
|
||||||
msgstr "Qui è pieno di reti!"
|
msgstr "Qui pieno di reti!"
|
||||||
|
|
||||||
msgid "I'm having so much fun!"
|
msgid "I'm having so much fun!"
|
||||||
msgstr "Mi sto divertendo tantissimo!"
|
msgstr "Mi sto divertendo tantissimo!"
|
||||||
|
|
||||||
msgid "My crime is that of curiosity ..."
|
msgid "My crime is that of curiosity ..."
|
||||||
msgstr ""
|
msgstr "Il mio crimine ? quello della curiosit?"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hello {name}! Nice to meet you."
|
msgid "Hello {name}! Nice to meet you."
|
||||||
@ -95,15 +95,15 @@ msgstr "Ciao {name}! E' un piacere."
|
|||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Yo {name}! Sup?"
|
msgid "Yo {name}! Sup?"
|
||||||
msgstr ""
|
msgstr "Yo {name} Come va"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Hey {name} how are you doing?"
|
msgid "Hey {name} how are you doing?"
|
||||||
msgstr ""
|
msgstr "Ehi {name} come stai?"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Unit {name} is nearby!"
|
msgid "Unit {name} is nearby!"
|
||||||
msgstr "L'Unità {name} è vicina!"
|
msgstr "L'Unit {name} e vicina!"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Uhm ... goodbye {name}"
|
msgid "Uhm ... goodbye {name}"
|
||||||
@ -111,30 +111,30 @@ msgstr "Uhm ... addio {name}, mi mancherai..."
|
|||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} is gone ..."
|
msgid "{name} is gone ..."
|
||||||
msgstr "{name} se n'è andato ..."
|
msgstr "{name} se andato ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Whoops ... {name} is gone."
|
msgid "Whoops ... {name} is gone."
|
||||||
msgstr "Whoops ...{name} se n'è andato."
|
msgstr "Whoops ...{name} se andato."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "{name} missed!"
|
msgid "{name} missed!"
|
||||||
msgstr "{name} è scomparso..."
|
msgstr "{name} scomparso..."
|
||||||
|
|
||||||
msgid "Missed!"
|
msgid "Missed!"
|
||||||
msgstr "Ehi! Dove sei andato!?"
|
msgstr "Ehi! Dove sei andato!?"
|
||||||
|
|
||||||
msgid "Good friends are a blessing!"
|
msgid "Good friends are a blessing!"
|
||||||
msgstr ""
|
msgstr "Buoni amici sono una benedizione"
|
||||||
|
|
||||||
msgid "I love my friends!"
|
msgid "I love my friends!"
|
||||||
msgstr ""
|
msgstr "Amo i miei amici"
|
||||||
|
|
||||||
msgid "Nobody wants to play with me ..."
|
msgid "Nobody wants to play with me ..."
|
||||||
msgstr "Nessuno vuole giocare con me..."
|
msgstr "Nessuno vuole giocare con me..."
|
||||||
|
|
||||||
msgid "I feel so alone ..."
|
msgid "I feel so alone ..."
|
||||||
msgstr "Mi sento così solo..."
|
msgstr "Mi sento cos solo..."
|
||||||
|
|
||||||
msgid "Where's everybody?!"
|
msgid "Where's everybody?!"
|
||||||
msgstr "Dove sono tutti?!"
|
msgstr "Dove sono tutti?!"
|
||||||
@ -144,17 +144,17 @@ msgid "Napping for {secs}s ..."
|
|||||||
msgstr "Schiaccio un pisolino per {secs}s ..."
|
msgstr "Schiaccio un pisolino per {secs}s ..."
|
||||||
|
|
||||||
msgid "Zzzzz"
|
msgid "Zzzzz"
|
||||||
msgstr ""
|
msgstr "Zzzzz"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "ZzzZzzz ({secs}s)"
|
msgid "ZzzZzzz ({secs}s)"
|
||||||
msgstr ""
|
msgstr "ZzzZzzz ({secs}s)"
|
||||||
|
|
||||||
msgid "Good night."
|
msgid "Good night."
|
||||||
msgstr ""
|
msgstr "Buona notte"
|
||||||
|
|
||||||
msgid "Zzz"
|
msgid "Zzz"
|
||||||
msgstr ""
|
msgstr "Zzz"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Waiting for {secs}s ..."
|
msgid "Waiting for {secs}s ..."
|
||||||
@ -182,7 +182,7 @@ msgstr "Ho appena deciso che {mac} non necessita di WiFi!"
|
|||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Deauthenticating {mac}"
|
msgid "Deauthenticating {mac}"
|
||||||
msgstr ""
|
msgstr "Annullamento dell'autenticazione {mac}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Kickbanning {mac}!"
|
msgid "Kickbanning {mac}!"
|
||||||
@ -201,11 +201,11 @@ msgstr "Ops, qualcosa è andato storto ... Riavvio ..."
|
|||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Uploading data to {to} ..."
|
msgid "Uploading data to {to} ..."
|
||||||
msgstr ""
|
msgstr "Caricamento dei dati in {to}"
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Downloading from {name} ..."
|
msgid "Downloading from {name} ..."
|
||||||
msgstr ""
|
msgstr "Scaricamento da {name} ..."
|
||||||
|
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Kicked {num} stations\n"
|
msgid "Kicked {num} stations\n"
|
||||||
|
Binary file not shown.
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: Portuguese (Brazil)\n"
|
"Language: Portuguese (Brazil)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=CHARSET\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
msgid "ZzzzZZzzzzZzzz"
|
msgid "ZzzzZZzzzzZzzz"
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-11-17 15:46+0100\n"
|
"POT-Creation-Date: 2024-02-16 15:26-0300\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -28,7 +28,7 @@ def check(version, repo, native=True):
|
|||||||
resp = requests.get("https://api.github.com/repos/%s/releases/latest" % repo)
|
resp = requests.get("https://api.github.com/repos/%s/releases/latest" % repo)
|
||||||
latest = resp.json()
|
latest = resp.json()
|
||||||
info['available'] = latest_ver = latest['tag_name'].replace('v', '')
|
info['available'] = latest_ver = latest['tag_name'].replace('v', '')
|
||||||
is_arm64 = info['arch'].startswith('aarch')
|
is_armhf = info['arch'].startswith('arm')
|
||||||
|
|
||||||
local = version_to_tuple(info['current'])
|
local = version_to_tuple(info['current'])
|
||||||
remote = version_to_tuple(latest_ver)
|
remote = version_to_tuple(latest_ver)
|
||||||
@ -36,12 +36,12 @@ def check(version, repo, native=True):
|
|||||||
if not native:
|
if not native:
|
||||||
info['url'] = "https://github.com/%s/archive/%s.zip" % (repo, latest['tag_name'])
|
info['url'] = "https://github.com/%s/archive/%s.zip" % (repo, latest['tag_name'])
|
||||||
else:
|
else:
|
||||||
if is_arm64:
|
if is_armhf:
|
||||||
# check if this release is compatible with aarch64
|
# check if this release is compatible with armhf
|
||||||
for asset in latest['assets']:
|
for asset in latest['assets']:
|
||||||
download_url = asset['browser_download_url']
|
download_url = asset['browser_download_url']
|
||||||
if (download_url.endswith('.zip') and
|
if (download_url.endswith('.zip') and
|
||||||
(info['arch'] in download_url or (is_arm64 and 'aarch64' in download_url))):
|
(info['arch'] in download_url or (is_armhf and 'armhf' in download_url))):
|
||||||
info['url'] = download_url
|
info['url'] = download_url
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ def install(display, update):
|
|||||||
source_path = "%s-%s" % (source_path, update['available'])
|
source_path = "%s-%s" % (source_path, update['available'])
|
||||||
|
|
||||||
# setup.py is going to install data files for us
|
# setup.py is going to install data files for us
|
||||||
os.system("cd %s && pip3 install . --no-cache-dir --break-system-packages" % source_path)
|
os.system("cd %s && pip3 install . --break-system-packages" % source_path)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ class AutoUpdate(plugins.Plugin):
|
|||||||
to_check = [
|
to_check = [
|
||||||
('jayofelony/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
|
('jayofelony/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
|
||||||
('jayofelony/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
|
('jayofelony/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
|
||||||
('jayofelony/pwnagotchi-bookworm', pwnagotchi.__version__, False, 'pwnagotchi')
|
('jayofelony/pwnagotchi', pwnagotchi.__version__, False, 'pwnagotchi')
|
||||||
]
|
]
|
||||||
|
|
||||||
for repo, local_version, is_native, svc_name in to_check:
|
for repo, local_version, is_native, svc_name in to_check:
|
||||||
@ -212,7 +212,7 @@ class AutoUpdate(plugins.Plugin):
|
|||||||
if install(display, update):
|
if install(display, update):
|
||||||
num_installed += 1
|
num_installed += 1
|
||||||
else:
|
else:
|
||||||
prev_status = '%d new update%c available!' % (num_updates, 's' if num_updates > 1 else '')
|
prev_status = '%d new update%s available!' % (num_updates, 's' if num_updates > 1 else '')
|
||||||
|
|
||||||
logging.info("[update] done")
|
logging.info("[update] done")
|
||||||
|
|
||||||
|
@ -11,6 +11,10 @@ from pwnagotchi import plugins
|
|||||||
import pwnagotchi.ui.faces as faces
|
import pwnagotchi.ui.faces as faces
|
||||||
from pwnagotchi.bettercap import Client
|
from pwnagotchi.bettercap import Client
|
||||||
|
|
||||||
|
from pwnagotchi.ui.components import Text
|
||||||
|
from pwnagotchi.ui.view import BLACK
|
||||||
|
import pwnagotchi.ui.fonts as fonts
|
||||||
|
|
||||||
|
|
||||||
class FixServices(plugins.Plugin):
|
class FixServices(plugins.Plugin):
|
||||||
__author__ = 'jayofelony'
|
__author__ = 'jayofelony'
|
||||||
@ -21,12 +25,6 @@ class FixServices(plugins.Plugin):
|
|||||||
__help__ = """
|
__help__ = """
|
||||||
Reload brcmfmac module when blindbug is detected, instead of rebooting. Adapted from WATCHDOG.
|
Reload brcmfmac module when blindbug is detected, instead of rebooting. Adapted from WATCHDOG.
|
||||||
"""
|
"""
|
||||||
__dependencies__ = {
|
|
||||||
'pip': ['scapy']
|
|
||||||
}
|
|
||||||
__defaults__ = {
|
|
||||||
'enabled': True,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.options = dict()
|
self.options = dict()
|
||||||
@ -37,12 +35,14 @@ class FixServices(plugins.Plugin):
|
|||||||
self.isReloadingMon = False
|
self.isReloadingMon = False
|
||||||
self.connection = None
|
self.connection = None
|
||||||
self.LASTTRY = 0
|
self.LASTTRY = 0
|
||||||
|
self._status = "--"
|
||||||
self._count = 0
|
self._count = 0
|
||||||
|
|
||||||
def on_loaded(self):
|
def on_loaded(self):
|
||||||
"""
|
"""
|
||||||
Gets called when the plugin gets loaded
|
Gets called when the plugin gets loaded
|
||||||
"""
|
"""
|
||||||
|
self._status = "ld"
|
||||||
logging.info("[Fix_Services] plugin loaded.")
|
logging.info("[Fix_Services] plugin loaded.")
|
||||||
|
|
||||||
def on_ready(self, agent):
|
def on_ready(self, agent):
|
||||||
@ -53,8 +53,10 @@ class FixServices(plugins.Plugin):
|
|||||||
logging.info("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
|
logging.info("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
|
||||||
if ",UP," in str(cmd_output):
|
if ",UP," in str(cmd_output):
|
||||||
logging.info("wlan0mon is up.")
|
logging.info("wlan0mon is up.")
|
||||||
|
self._status = "up"
|
||||||
|
|
||||||
if len(self.pattern.findall(last_lines)) >= 3:
|
if len(self.pattern.findall(last_lines)) >= 3:
|
||||||
|
self._status = "XX"
|
||||||
if hasattr(agent, 'view'):
|
if hasattr(agent, 'view'):
|
||||||
display = agent.view()
|
display = agent.view()
|
||||||
display.set('status', 'Blind-Bug detected. Restarting.')
|
display.set('status', 'Blind-Bug detected. Restarting.')
|
||||||
@ -67,10 +69,12 @@ class FixServices(plugins.Plugin):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
logging.info("[Fix_Services] Logs look good!")
|
logging.info("[Fix_Services] Logs look good!")
|
||||||
|
self._status = ""
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logging.error("[Fix_Services ip link show wlan0mon]: %s" % repr(err))
|
logging.error("[Fix_Services ip link show wlan0mon]: %s" % repr(err))
|
||||||
try:
|
try:
|
||||||
|
self._status = "xx"
|
||||||
self._tryTurningItOffAndOnAgain(agent)
|
self._tryTurningItOffAndOnAgain(agent)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logging.error("[Fix_Services OffNOn]: %s" % repr(err))
|
logging.error("[Fix_Services OffNOn]: %s" % repr(err))
|
||||||
@ -105,7 +109,7 @@ class FixServices(plugins.Plugin):
|
|||||||
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'],
|
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'],
|
||||||
stdout=subprocess.PIPE).stdout))[-10:])
|
stdout=subprocess.PIPE).stdout))[-10:])
|
||||||
other_other_last_lines = ''.join(
|
other_other_last_lines = ''.join(
|
||||||
list(TextIOWrapper(subprocess.Popen(['tail', '-n10', '/home/pi/logs/pwnagotchi.log'],
|
list(TextIOWrapper(subprocess.Popen(['tail', '-n10', '/var/log/pwnagotchi.log'],
|
||||||
stdout=subprocess.PIPE).stdout))[-10:])
|
stdout=subprocess.PIPE).stdout))[-10:])
|
||||||
# don't check if we ran a reset recently
|
# don't check if we ran a reset recently
|
||||||
logging.debug("[Fix_Services]**** epoch")
|
logging.debug("[Fix_Services]**** epoch")
|
||||||
@ -143,6 +147,7 @@ class FixServices(plugins.Plugin):
|
|||||||
logging.info("[Fix_Services] wifi.recon flip: success!")
|
logging.info("[Fix_Services] wifi.recon flip: success!")
|
||||||
if display:
|
if display:
|
||||||
display.update(force=True, new_data={"status": "Wifi recon flipped!",
|
display.update(force=True, new_data={"status": "Wifi recon flipped!",
|
||||||
|
"brcmfmac_status": self._status,
|
||||||
"face": faces.COOL})
|
"face": faces.COOL})
|
||||||
else:
|
else:
|
||||||
print("Wifi recon flipped\nthat was easy!")
|
print("Wifi recon flipped\nthat was easy!")
|
||||||
@ -212,11 +217,12 @@ class FixServices(plugins.Plugin):
|
|||||||
self.isReloadingMon = True
|
self.isReloadingMon = True
|
||||||
self.LASTTRY = time.time()
|
self.LASTTRY = time.time()
|
||||||
|
|
||||||
|
self._status = "BL"
|
||||||
if hasattr(connection, 'view'):
|
if hasattr(connection, 'view'):
|
||||||
display = connection.view()
|
display = connection.view()
|
||||||
if display:
|
if display:
|
||||||
display.update(force=True, new_data={"status": "I'm blind! Try turning it off and on again",
|
display.update(force=True, new_data={"status": "I'm blind! Try turning it off and on again",
|
||||||
"face": faces.BORED})
|
"brcmfmac_status": self._status, "face": faces.BORED})
|
||||||
else:
|
else:
|
||||||
display = None
|
display = None
|
||||||
|
|
||||||
@ -259,6 +265,7 @@ class FixServices(plugins.Plugin):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
cmd_output = subprocess.check_output("monstop", shell=True)
|
cmd_output = subprocess.check_output("monstop", shell=True)
|
||||||
|
self._status = "dn"
|
||||||
self.logPrintView("info", "[Fix_Services] wlan0mon down and deleted: %s" % cmd_output,
|
self.logPrintView("info", "[Fix_Services] wlan0mon down and deleted: %s" % cmd_output,
|
||||||
display, {"status": "wlan0mon d-d-d-down!", "face": faces.BORED})
|
display, {"status": "wlan0mon d-d-d-down!", "face": faces.BORED})
|
||||||
except Exception as nope:
|
except Exception as nope:
|
||||||
@ -271,14 +278,14 @@ class FixServices(plugins.Plugin):
|
|||||||
#
|
#
|
||||||
# Future: while "not fixed yet": blah blah blah. if "max_attemts", then reboot like the old days
|
# Future: while "not fixed yet": blah blah blah. if "max_attemts", then reboot like the old days
|
||||||
#
|
#
|
||||||
tries = 0
|
tries = 1
|
||||||
while tries < 3:
|
while tries < 3:
|
||||||
try:
|
try:
|
||||||
# unload the module
|
# unload the module
|
||||||
cmd_output = subprocess.check_output("sudo modprobe -r brcmfmac", shell=True)
|
cmd_output = subprocess.check_output("sudo modprobe -r brcmfmac", shell=True)
|
||||||
self.logPrintView("info", "[Fix_Services] unloaded brcmfmac", display,
|
self.logPrintView("info", "[Fix_Services] unloaded brcmfmac", display,
|
||||||
{"status": "Turning it off #%s" % tries, "face": faces.SMART})
|
{"status": "Turning it off #%s" % tries, "face": faces.SMART})
|
||||||
time.sleep(1 + tries)
|
self._status = "ul"
|
||||||
|
|
||||||
# reload the module
|
# reload the module
|
||||||
try:
|
try:
|
||||||
@ -286,21 +293,21 @@ class FixServices(plugins.Plugin):
|
|||||||
cmd_output = subprocess.check_output("sudo modprobe brcmfmac", shell=True)
|
cmd_output = subprocess.check_output("sudo modprobe brcmfmac", shell=True)
|
||||||
|
|
||||||
self.logPrintView("info", "[Fix_Services] reloaded brcmfmac")
|
self.logPrintView("info", "[Fix_Services] reloaded brcmfmac")
|
||||||
time.sleep(10 + 4 * tries) # give it some time for wlan device to stabilize, or whatever
|
self._status = "rl"
|
||||||
|
|
||||||
# success! now make the mon0
|
# success! now make the mon0
|
||||||
try:
|
try:
|
||||||
cmd_output = subprocess.check_output("monstart", shell=True)
|
cmd_output = subprocess.check_output("monstart", shell=True)
|
||||||
self.logPrintView("info", "[Fix_Services interface add wlan0mon] worked #%s: %s"
|
self.logPrintView("info", "[Fix_Services interface add wlan0mon worked #%s: %s"
|
||||||
% (tries, cmd_output))
|
% (tries, cmd_output))
|
||||||
time.sleep(tries + 5)
|
self._status = "up"
|
||||||
try:
|
try:
|
||||||
# try accessing mon0 in bettercap
|
# try accessing mon0 in bettercap
|
||||||
result = connection.run("set wifi.interface wlan0mon")
|
result = connection.run("set wifi.interface wlan0mon")
|
||||||
if "success" in result:
|
if "success" in result:
|
||||||
logging.info("[Fix_Services set wifi.interface wlan0mon] worked!")
|
logging.info("[Fix_Services set wifi.interface wlan0mon worked!")
|
||||||
|
self._status = ""
|
||||||
self._count = self._count + 1
|
self._count = self._count + 1
|
||||||
time.sleep(1)
|
|
||||||
# stop looping and get back to recon
|
# stop looping and get back to recon
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
@ -337,6 +344,7 @@ class FixServices(plugins.Plugin):
|
|||||||
if tries < 3:
|
if tries < 3:
|
||||||
if display:
|
if display:
|
||||||
display.update(force=True, new_data={"status": "And back on again...",
|
display.update(force=True, new_data={"status": "And back on again...",
|
||||||
|
"brcmfmac_status": self._status,
|
||||||
"face": faces.INTENSE})
|
"face": faces.INTENSE})
|
||||||
else:
|
else:
|
||||||
print("And back on again...")
|
print("And back on again...")
|
||||||
@ -352,8 +360,10 @@ class FixServices(plugins.Plugin):
|
|||||||
result = connection.run("wifi.clear; wifi.recon on")
|
result = connection.run("wifi.clear; wifi.recon on")
|
||||||
|
|
||||||
if "success" in result: # and result["success"] is True:
|
if "success" in result: # and result["success"] is True:
|
||||||
|
self._status = ""
|
||||||
if display:
|
if display:
|
||||||
display.update(force=True, new_data={"status": "I can see again! (probably)",
|
display.update(force=True, new_data={"status": "I can see again! (probably)",
|
||||||
|
"brcmfmac_status": self._status,
|
||||||
"face": faces.HAPPY})
|
"face": faces.HAPPY})
|
||||||
else:
|
else:
|
||||||
print("I can see again")
|
print("I can see again")
|
||||||
@ -368,9 +378,31 @@ class FixServices(plugins.Plugin):
|
|||||||
logging.error("[Fix_Services wifi.recon on] %s" % repr(err))
|
logging.error("[Fix_Services wifi.recon on] %s" % repr(err))
|
||||||
pwnagotchi.reboot()
|
pwnagotchi.reboot()
|
||||||
|
|
||||||
|
# called to setup the ui elements
|
||||||
|
def on_ui_setup(self, ui):
|
||||||
|
with ui._lock:
|
||||||
|
# add custom UI elements
|
||||||
|
if "position" in self.options:
|
||||||
|
pos = self.options['position'].split(',')
|
||||||
|
pos = [int(x.strip()) for x in pos]
|
||||||
|
else:
|
||||||
|
pos = (ui.width() / 2 + 35, ui.height() - 11)
|
||||||
|
|
||||||
|
logging.info("Got here")
|
||||||
|
ui.add_element('brcmfmac_status', Text(color=BLACK, value='--', position=pos, font=fonts.Small))
|
||||||
|
|
||||||
|
# called when the ui is updated
|
||||||
|
def on_ui_update(self, ui):
|
||||||
|
# update those elements
|
||||||
|
if self._status:
|
||||||
|
ui.set('brcmfmac_status', "wlan0mon %s" % self._status)
|
||||||
|
else:
|
||||||
|
ui.set('brcmfmac_status', "rst#%s" % self._count)
|
||||||
|
|
||||||
def on_unload(self, ui):
|
def on_unload(self, ui):
|
||||||
with ui._lock:
|
with ui._lock:
|
||||||
try:
|
try:
|
||||||
|
ui.remove_element('brcmfmac_status')
|
||||||
logging.info("[Fix_Services] unloaded")
|
logging.info("[Fix_Services] unloaded")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logging.info("[Fix_Services] unload err %s " % repr(err))
|
logging.info("[Fix_Services] unload err %s " % repr(err))
|
||||||
|
@ -14,19 +14,15 @@ import zipfile
|
|||||||
|
|
||||||
class GdriveSync(plugins.Plugin):
|
class GdriveSync(plugins.Plugin):
|
||||||
__author__ = '@jayofelony'
|
__author__ = '@jayofelony'
|
||||||
__version__ = '1.0'
|
__version__ = '1.2'
|
||||||
__license__ = 'GPL3'
|
__license__ = 'GPL3'
|
||||||
__description__ = 'A plugin to backup various pwnagotchi files and folders to Google Drive. Once every hour from loading plugin.'
|
__description__ = 'A plugin to backup various pwnagotchi files and folders to Google Drive. Once every hour from loading plugin.'
|
||||||
__dependencies__ = {
|
|
||||||
'pip': ['pydrive2']
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.options = dict()
|
self.options = dict()
|
||||||
self.lock = Lock()
|
self.lock = Lock()
|
||||||
self.internet = False
|
self.internet = False
|
||||||
self.ready = False
|
self.ready = False
|
||||||
self.drive = None
|
|
||||||
self.status = StatusFile('/root/.gdrive-backup')
|
self.status = StatusFile('/root/.gdrive-backup')
|
||||||
self.backup = True
|
self.backup = True
|
||||||
self.backupfiles = [
|
self.backupfiles = [
|
||||||
@ -38,12 +34,11 @@ class GdriveSync(plugins.Plugin):
|
|||||||
'/etc/pwnagotchi'
|
'/etc/pwnagotchi'
|
||||||
]
|
]
|
||||||
|
|
||||||
def on_loaded(self, agent):
|
def on_loaded(self):
|
||||||
"""
|
"""
|
||||||
Called when the plugin is loaded
|
Called when the plugin is loaded
|
||||||
"""
|
"""
|
||||||
# client_secrets.json needs to be not empty
|
# client_secrets.json needs to be not empty
|
||||||
display = agent.view()
|
|
||||||
if os.stat("/root/client_secrets.json").st_size == 0:
|
if os.stat("/root/client_secrets.json").st_size == 0:
|
||||||
logging.error("[gDriveSync] /root/client_secrets.json is empty. Please RTFM!")
|
logging.error("[gDriveSync] /root/client_secrets.json is empty. Please RTFM!")
|
||||||
return
|
return
|
||||||
@ -78,25 +73,24 @@ class GdriveSync(plugins.Plugin):
|
|||||||
# logging.warning(f"[gDriveSync] No files found in the folder with ID {root_file_list} and {pwnagotchi_file_list}")
|
# logging.warning(f"[gDriveSync] No files found in the folder with ID {root_file_list} and {pwnagotchi_file_list}")
|
||||||
if self.options['backupfiles'] is not None:
|
if self.options['backupfiles'] is not None:
|
||||||
self.backupfiles = self.backupfiles + self.options['backupfiles']
|
self.backupfiles = self.backupfiles + self.options['backupfiles']
|
||||||
self.backup_files(self.backupfiles, '/backup')
|
self.backup_files(self.backupfiles, '/home/pi/backup')
|
||||||
|
|
||||||
# Create a zip archive of the /backup folder
|
# Create a zip archive of the /backup folder
|
||||||
zip_file_path = os.path.join('/home/pi', 'backup.zip')
|
zip_file_path = os.path.join('/home/pi', 'backup.zip')
|
||||||
with zipfile.ZipFile(zip_file_path, 'w') as zip_ref:
|
with zipfile.ZipFile(zip_file_path, 'w') as zip_ref:
|
||||||
for root, dirs, files in os.walk('/backup'):
|
for root, dirs, files in os.walk('/home/pi/backup'):
|
||||||
for file in files:
|
for file in files:
|
||||||
file_path = os.path.join(root, file)
|
file_path = os.path.join(root, file)
|
||||||
arcname = os.path.relpath(file_path, '/backup')
|
arcname = os.path.relpath(file_path, '/home/pi/backup')
|
||||||
zip_ref.write(file_path, arcname=arcname)
|
zip_ref.write(file_path, arcname=arcname)
|
||||||
|
|
||||||
# Upload the zip archive to Google Drive
|
# Upload the zip archive to Google Drive
|
||||||
self.upload_to_gdrive(zip_file_path, self.get_folder_id_by_name(self.drive, self.options['backup_folder']))
|
self.upload_to_gdrive(zip_file_path, self.get_folder_id_by_name(self.drive, self.options['backup_folder']))
|
||||||
display.on_uploading("Google Drive")
|
|
||||||
self.backup = True
|
self.backup = True
|
||||||
self.status.update()
|
self.status.update()
|
||||||
|
|
||||||
# Specify the local backup path
|
# Specify the local backup path
|
||||||
local_backup_path = '/'
|
local_backup_path = '/home/pi/'
|
||||||
|
|
||||||
# Download the zip archive from Google Drive
|
# Download the zip archive from Google Drive
|
||||||
zip_file_id = self.get_latest_backup_file_id(self.options['backup_folder'])
|
zip_file_id = self.get_latest_backup_file_id(self.options['backup_folder'])
|
||||||
@ -104,7 +98,6 @@ class GdriveSync(plugins.Plugin):
|
|||||||
zip_file = self.drive.CreateFile({'id': zip_file_id})
|
zip_file = self.drive.CreateFile({'id': zip_file_id})
|
||||||
zip_file.GetContentFile(os.path.join(local_backup_path, 'backup.zip'))
|
zip_file.GetContentFile(os.path.join(local_backup_path, 'backup.zip'))
|
||||||
|
|
||||||
display.on_downloading("Google Drive")
|
|
||||||
logging.info("[gDriveSync] Downloaded backup.zip from Google Drive")
|
logging.info("[gDriveSync] Downloaded backup.zip from Google Drive")
|
||||||
|
|
||||||
# Extract the zip archive to the root directory
|
# Extract the zip archive to the root directory
|
||||||
@ -112,9 +105,12 @@ class GdriveSync(plugins.Plugin):
|
|||||||
zip_ref.extractall('/')
|
zip_ref.extractall('/')
|
||||||
|
|
||||||
self.status.update()
|
self.status.update()
|
||||||
os.remove("/backup")
|
shutil.rmtree("/home/pi/backup")
|
||||||
# Reboot so we can start opwngrid with the backup id
|
os.remove("/home/pi/backup.zip")
|
||||||
pwnagotchi.reboot()
|
self.ready = True
|
||||||
|
logging.info("[gdrivesync] loaded")
|
||||||
|
# Restart so we can start opwngrid with the backup id
|
||||||
|
pwnagotchi.restart("AUTO")
|
||||||
|
|
||||||
# all set, gdriveSync is ready to run
|
# all set, gdriveSync is ready to run
|
||||||
self.ready = True
|
self.ready = True
|
||||||
@ -186,15 +182,15 @@ class GdriveSync(plugins.Plugin):
|
|||||||
logging.info("[gdrivesync] new handshake captured, backing up to gdrive")
|
logging.info("[gdrivesync] new handshake captured, backing up to gdrive")
|
||||||
if self.options['backupfiles'] is not None:
|
if self.options['backupfiles'] is not None:
|
||||||
self.backupfiles = self.backupfiles + self.options['backupfiles']
|
self.backupfiles = self.backupfiles + self.options['backupfiles']
|
||||||
self.backup_files(self.backupfiles, '/backup')
|
self.backup_files(self.backupfiles, '/home/pi/backup')
|
||||||
|
|
||||||
# Create a zip archive of the /backup folder
|
# Create a zip archive of the /backup folder
|
||||||
zip_file_path = os.path.join('/home/pi', 'backup.zip')
|
zip_file_path = os.path.join('/home/pi', 'backup.zip')
|
||||||
with zipfile.ZipFile(zip_file_path, 'w') as zip_ref:
|
with zipfile.ZipFile(zip_file_path, 'w') as zip_ref:
|
||||||
for root, dirs, files in os.walk('/backup'):
|
for root, dirs, files in os.walk('/home/pi/backup'):
|
||||||
for file in files:
|
for file in files:
|
||||||
file_path = os.path.join(root, file)
|
file_path = os.path.join(root, file)
|
||||||
arcname = os.path.relpath(file_path, '/backup')
|
arcname = os.path.relpath(file_path, '/home/pi/backup')
|
||||||
zip_ref.write(file_path, arcname=arcname)
|
zip_ref.write(file_path, arcname=arcname)
|
||||||
|
|
||||||
# Upload the zip archive to Google Drive
|
# Upload the zip archive to Google Drive
|
||||||
@ -203,7 +199,7 @@ class GdriveSync(plugins.Plugin):
|
|||||||
|
|
||||||
# Cleanup the local zip file
|
# Cleanup the local zip file
|
||||||
os.remove(zip_file_path)
|
os.remove(zip_file_path)
|
||||||
os.remove("/backup")
|
shutil.rmtree("/home/pi/backup")
|
||||||
self.status.update()
|
self.status.update()
|
||||||
display = agent.view()
|
display = agent.view()
|
||||||
display.update(force=True, new_data={'Backing up to gdrive ...'})
|
display.update(force=True, new_data={'Backing up to gdrive ...'})
|
||||||
|
@ -20,6 +20,7 @@ class GPS(plugins.Plugin):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.running = False
|
self.running = False
|
||||||
self.coordinates = None
|
self.coordinates = None
|
||||||
|
self.options = dict()
|
||||||
|
|
||||||
def on_loaded(self):
|
def on_loaded(self):
|
||||||
logging.info(f"gps plugin loaded for {self.options['device']}")
|
logging.info(f"gps plugin loaded for {self.options['device']}")
|
||||||
|
@ -58,8 +58,9 @@ class Grid(plugins.Plugin):
|
|||||||
self.total_messages = 0
|
self.total_messages = 0
|
||||||
self.lock = Lock()
|
self.lock = Lock()
|
||||||
|
|
||||||
def is_excluded(self, what):
|
def is_excluded(self, what, agent):
|
||||||
for skip in self.options['exclude']:
|
config = agent.config()
|
||||||
|
for skip in config['main']['whitelist']:
|
||||||
skip = skip.lower()
|
skip = skip.lower()
|
||||||
what = what.lower()
|
what = what.lower()
|
||||||
if skip in what or skip.replace(':', '') in what:
|
if skip in what or skip.replace(':', '') in what:
|
||||||
@ -87,6 +88,7 @@ class Grid(plugins.Plugin):
|
|||||||
|
|
||||||
def check_handshakes(self, agent):
|
def check_handshakes(self, agent):
|
||||||
logging.debug("checking pcaps")
|
logging.debug("checking pcaps")
|
||||||
|
config = agent.config()
|
||||||
|
|
||||||
pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap"))
|
pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap"))
|
||||||
num_networks = len(pcap_files)
|
num_networks = len(pcap_files)
|
||||||
@ -98,19 +100,19 @@ class Grid(plugins.Plugin):
|
|||||||
if self.options['report']:
|
if self.options['report']:
|
||||||
logging.info("grid: %d new networks to report" % num_new)
|
logging.info("grid: %d new networks to report" % num_new)
|
||||||
logging.debug("self.options: %s" % self.options)
|
logging.debug("self.options: %s" % self.options)
|
||||||
logging.debug(" exclude: %s" % self.options['exclude'])
|
logging.debug(" exclude: %s" % config['main']['whitelist'])
|
||||||
|
|
||||||
for pcap_file in pcap_files:
|
for pcap_file in pcap_files:
|
||||||
net_id = os.path.basename(pcap_file).replace('.pcap', '')
|
net_id = os.path.basename(pcap_file).replace('.pcap', '')
|
||||||
if net_id not in reported:
|
if net_id not in reported:
|
||||||
if self.is_excluded(net_id):
|
if self.is_excluded(net_id, agent):
|
||||||
logging.debug("skipping %s due to exclusion filter" % pcap_file)
|
logging.debug("skipping %s due to exclusion filter" % pcap_file)
|
||||||
self.set_reported(reported, net_id)
|
self.set_reported(reported, net_id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
essid, bssid = parse_pcap(pcap_file)
|
essid, bssid = parse_pcap(pcap_file)
|
||||||
if bssid:
|
if bssid:
|
||||||
if self.is_excluded(essid) or self.is_excluded(bssid):
|
if self.is_excluded(essid, agent) or self.is_excluded(bssid, agent):
|
||||||
logging.debug("not reporting %s due to exclusion filter" % pcap_file)
|
logging.debug("not reporting %s due to exclusion filter" % pcap_file)
|
||||||
self.set_reported(reported, net_id)
|
self.set_reported(reported, net_id)
|
||||||
else:
|
else:
|
||||||
|
@ -144,6 +144,9 @@ class MemTemp(plugins.Plugin):
|
|||||||
elif ui.is_waveshare2in7():
|
elif ui.is_waveshare2in7():
|
||||||
h_pos = (192, 138)
|
h_pos = (192, 138)
|
||||||
v_pos = (211, 122)
|
v_pos = (211, 122)
|
||||||
|
elif ui.is_waveshare1in54V2():
|
||||||
|
h_pos = (53, 77)
|
||||||
|
v_pos = (154, 65)
|
||||||
else:
|
else:
|
||||||
h_pos = (155, 76)
|
h_pos = (155, 76)
|
||||||
v_pos = (175, 61)
|
v_pos = (175, 61)
|
||||||
|
@ -24,6 +24,7 @@ class NetPos(plugins.Plugin):
|
|||||||
self.skip = list()
|
self.skip = list()
|
||||||
self.ready = False
|
self.ready = False
|
||||||
self.lock = threading.Lock()
|
self.lock = threading.Lock()
|
||||||
|
self.options = dict()
|
||||||
|
|
||||||
def on_loaded(self):
|
def on_loaded(self):
|
||||||
if 'api_key' not in self.options or ('api_key' in self.options and not self.options['api_key']):
|
if 'api_key' not in self.options or ('api_key' in self.options and not self.options['api_key']):
|
||||||
|
@ -25,6 +25,7 @@ class OnlineHashCrack(plugins.Plugin):
|
|||||||
self.report = StatusFile('/root/.ohc_uploads', data_format='json')
|
self.report = StatusFile('/root/.ohc_uploads', data_format='json')
|
||||||
self.skip = list()
|
self.skip = list()
|
||||||
self.lock = Lock()
|
self.lock = Lock()
|
||||||
|
self.options = dict()
|
||||||
|
|
||||||
def on_loaded(self):
|
def on_loaded(self):
|
||||||
"""
|
"""
|
||||||
@ -34,13 +35,9 @@ class OnlineHashCrack(plugins.Plugin):
|
|||||||
logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com")
|
logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com")
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'whitelist' not in self.options:
|
|
||||||
self.options['whitelist'] = list()
|
|
||||||
|
|
||||||
self.ready = True
|
self.ready = True
|
||||||
logging.info("OHC: OnlineHashCrack plugin loaded.")
|
logging.info("OHC: OnlineHashCrack plugin loaded.")
|
||||||
|
|
||||||
|
|
||||||
def _upload_to_ohc(self, path, timeout=30):
|
def _upload_to_ohc(self, path, timeout=30):
|
||||||
"""
|
"""
|
||||||
Uploads the file to onlinehashcrack.com
|
Uploads the file to onlinehashcrack.com
|
||||||
@ -78,7 +75,6 @@ class OnlineHashCrack(plugins.Plugin):
|
|||||||
except OSError as os_e:
|
except OSError as os_e:
|
||||||
raise os_e
|
raise os_e
|
||||||
|
|
||||||
|
|
||||||
def on_webhook(self, path, request):
|
def on_webhook(self, path, request):
|
||||||
import requests
|
import requests
|
||||||
from flask import redirect
|
from flask import redirect
|
||||||
@ -87,7 +83,6 @@ class OnlineHashCrack(plugins.Plugin):
|
|||||||
r = s.post('https://www.onlinehashcrack.com/dashboard', data={'emailTasks': self.options['email'], 'submit': ''})
|
r = s.post('https://www.onlinehashcrack.com/dashboard', data={'emailTasks': self.options['email'], 'submit': ''})
|
||||||
return redirect(r.url, code=302)
|
return redirect(r.url, code=302)
|
||||||
|
|
||||||
|
|
||||||
def on_internet_available(self, agent):
|
def on_internet_available(self, agent):
|
||||||
"""
|
"""
|
||||||
Called in manual mode when there's internet connectivity
|
Called in manual mode when there's internet connectivity
|
||||||
@ -105,7 +100,7 @@ class OnlineHashCrack(plugins.Plugin):
|
|||||||
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if
|
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if
|
||||||
filename.endswith('.pcap')]
|
filename.endswith('.pcap')]
|
||||||
# pull out whitelisted APs
|
# pull out whitelisted APs
|
||||||
handshake_paths = remove_whitelisted(handshake_paths, self.options['whitelist'])
|
handshake_paths = remove_whitelisted(handshake_paths, config['main']['whitelist'])
|
||||||
handshake_new = set(handshake_paths) - set(reported) - set(self.skip)
|
handshake_new = set(handshake_paths) - set(reported) - set(self.skip)
|
||||||
if handshake_new:
|
if handshake_new:
|
||||||
logging.info("OHC: Internet connectivity detected. Uploading new handshakes to onlinehashcrack.com")
|
logging.info("OHC: Internet connectivity detected. Uploading new handshakes to onlinehashcrack.com")
|
||||||
|
@ -15,6 +15,9 @@ class PawGPS(plugins.Plugin):
|
|||||||
__license__ = 'GPL3'
|
__license__ = 'GPL3'
|
||||||
__description__ = 'Saves GPS coordinates whenever an handshake is captured. The GPS data is get from PAW on android.'
|
__description__ = 'Saves GPS coordinates whenever an handshake is captured. The GPS data is get from PAW on android.'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.options = dict()
|
||||||
|
|
||||||
def on_loaded(self):
|
def on_loaded(self):
|
||||||
logging.info("[paw-gps] plugin loaded")
|
logging.info("[paw-gps] plugin loaded")
|
||||||
if 'ip' not in self.options or ('ip' in self.options and self.options['ip'] is None) or (len('ip' in self.options and self.options['ip']) is 0):
|
if 'ip' not in self.options or ('ip' in self.options and self.options['ip'] is None) or (len('ip' in self.options and self.options['ip']) is 0):
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
# Based on UPS Lite v1.1 from https://github.com/xenDE
|
# Based on UPS Lite v1.1 from https://github.com/xenDE
|
||||||
|
# Made specifically to address the problems caused by the hardware changes in 1.3. Oh yeah I also removed the auto-shutdown feature because it's kind of broken.
|
||||||
#
|
#
|
||||||
# functions for get UPS status - needs enable "i2c" in raspi-config
|
# To setup, see page six of this manual to see how to enable i2c:
|
||||||
|
# https://github.com/linshuqin329/UPS-Lite/blob/master/UPS-Lite_V1.3_CW2015/Instructions%20for%20UPS-Lite%20V1.3.pdf
|
||||||
#
|
#
|
||||||
# https://github.com/linshuqin329/UPS-Lite
|
# Follow page seven, install the dependencies (python-smbus) and copy this script over for later use:
|
||||||
|
# https://github.com/linshuqin329/UPS-Lite/blob/master/UPS-Lite_V1.3_CW2015/UPS_Lite_V1.3_CW2015.py
|
||||||
#
|
#
|
||||||
# For Raspberry Pi Zero Ups Power Expansion Board with Integrated Serial Port S3U4
|
# Now, install this plugin by copying this to the 'available-plugins' folder in your pwnagotchi, install and enable the plugin with the commands:
|
||||||
# https://www.ebay.de/itm/For-Raspberry-Pi-Zero-Ups-Power-Expansion-Board-with-Integrated-Serial-Port-S3U4/323873804310
|
# sudo pwnagotchi plugins install upslite_plugin_1_3
|
||||||
# https://www.aliexpress.com/item/32888533624.html
|
# sudo pwnagotchi plugins enable upslite_plugin_1_3
|
||||||
#
|
#
|
||||||
# To display external power supply status you need to bridge the necessary pins on the UPS-Lite board. See instructions in the UPS-Lite repo.
|
# Now restart raspberry pi. Once back up ensure upslite_plugin_1_3 plugin is turned on in the WebUI. If there is still '0%' on your battery meter
|
||||||
|
# run the script we saved earlier and ensure that the pwnagotchi is plugged in both at the battery and the raspberry pi. The script should start trying to
|
||||||
|
# read the battery, and should be successful once there's a USB cable running power to the battery supply.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
@ -20,6 +26,11 @@ import pwnagotchi.ui.fonts as fonts
|
|||||||
from pwnagotchi.ui.components import LabeledValue
|
from pwnagotchi.ui.components import LabeledValue
|
||||||
from pwnagotchi.ui.view import BLACK
|
from pwnagotchi.ui.view import BLACK
|
||||||
|
|
||||||
|
CW2015_ADDRESS = 0X62
|
||||||
|
CW2015_REG_VCELL = 0X02
|
||||||
|
CW2015_REG_SOC = 0X04
|
||||||
|
CW2015_REG_MODE = 0X0A
|
||||||
|
|
||||||
|
|
||||||
# TODO: add enable switch in config.yml an cleanup all to the best place
|
# TODO: add enable switch in config.yml an cleanup all to the best place
|
||||||
class UPS:
|
class UPS:
|
||||||
@ -31,8 +42,7 @@ class UPS:
|
|||||||
|
|
||||||
def voltage(self):
|
def voltage(self):
|
||||||
try:
|
try:
|
||||||
address = 0x36
|
read = self._bus.read_word_data(CW2015_ADDRESS, CW2015_REG_VCELL)
|
||||||
read = self._bus.read_word_data(address, 2)
|
|
||||||
swapped = struct.unpack("<H", struct.pack(">H", read))[0]
|
swapped = struct.unpack("<H", struct.pack(">H", read))[0]
|
||||||
return swapped * 1.25 / 1000 / 16
|
return swapped * 1.25 / 1000 / 16
|
||||||
except:
|
except:
|
||||||
@ -41,7 +51,7 @@ class UPS:
|
|||||||
def capacity(self):
|
def capacity(self):
|
||||||
try:
|
try:
|
||||||
address = 0x36
|
address = 0x36
|
||||||
read = self._bus.read_word_data(address, 4)
|
read = self._bus.read_word_data(CW2015_ADDRESS, CW2015_REG_SOC)
|
||||||
swapped = struct.unpack("<H", struct.pack(">H", read))[0]
|
swapped = struct.unpack("<H", struct.pack(">H", read))[0]
|
||||||
return swapped / 256
|
return swapped / 256
|
||||||
except:
|
except:
|
||||||
@ -57,10 +67,10 @@ class UPS:
|
|||||||
|
|
||||||
|
|
||||||
class UPSLite(plugins.Plugin):
|
class UPSLite(plugins.Plugin):
|
||||||
__author__ = 'evilsocket@gmail.com'
|
__author__ = 'marbasec'
|
||||||
__version__ = '1.0.0'
|
__version__ = '1.3.0'
|
||||||
__license__ = 'GPL3'
|
__license__ = 'GPL3'
|
||||||
__description__ = 'A plugin that will add a voltage indicator for the UPS Lite v1.1'
|
__description__ = 'A plugin that will add a voltage indicator for the UPS Lite v1.3'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.ups = None
|
self.ups = None
|
||||||
@ -69,7 +79,7 @@ class UPSLite(plugins.Plugin):
|
|||||||
self.ups = UPS()
|
self.ups = UPS()
|
||||||
|
|
||||||
def on_ui_setup(self, ui):
|
def on_ui_setup(self, ui):
|
||||||
ui.add_element('ups', LabeledValue(color=BLACK, label='UPS', value='0%/0V', position=(ui.width() / 2 + 15, 0),
|
ui.add_element('ups', LabeledValue(color=BLACK, label='UPS', value='0%', position=(ui.width() / 2 + 15, 0),
|
||||||
label_font=fonts.Bold, text_font=fonts.Medium))
|
label_font=fonts.Bold, text_font=fonts.Medium))
|
||||||
|
|
||||||
def on_unload(self, ui):
|
def on_unload(self, ui):
|
||||||
@ -80,7 +90,3 @@ class UPSLite(plugins.Plugin):
|
|||||||
capacity = self.ups.capacity()
|
capacity = self.ups.capacity()
|
||||||
charging = self.ups.charging()
|
charging = self.ups.charging()
|
||||||
ui.set('ups', "%2i%s" % (capacity, charging))
|
ui.set('ups', "%2i%s" % (capacity, charging))
|
||||||
if capacity <= self.options['shutdown']:
|
|
||||||
logging.info('[ups_lite] Empty battery (<= %s%%): shuting down' % self.options['shutdown'])
|
|
||||||
ui.update(force=True, new_data={'status': 'Battery exhausted, bye ...'})
|
|
||||||
pwnagotchi.shutdown()
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
import pwnagotchi.plugins as plugins
|
import pwnagotchi.plugins as plugins
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import datetime
|
|
||||||
from flask import Response
|
from flask import Response
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from dateutil.parser import parse
|
from dateutil.parser import parse
|
||||||
@ -22,6 +23,7 @@ from dateutil.parser import parse
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
class Webgpsmap(plugins.Plugin):
|
class Webgpsmap(plugins.Plugin):
|
||||||
__author__ = 'https://github.com/xenDE and https://github.com/dadav'
|
__author__ = 'https://github.com/xenDE and https://github.com/dadav'
|
||||||
__version__ = '1.4.0'
|
__version__ = '1.4.0'
|
||||||
@ -103,7 +105,7 @@ class Webgpsmap(plugins.Plugin):
|
|||||||
response_status = 200
|
response_status = 200
|
||||||
response_mimetype = "application/xhtml+xml"
|
response_mimetype = "application/xhtml+xml"
|
||||||
response_header_contenttype = 'text/html'
|
response_header_contenttype = 'text/html'
|
||||||
response_header_contentdisposition = 'attachment; filename=webgpsmap.html';
|
response_header_contentdisposition = 'attachment; filename=webgpsmap.html'
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logging.error(f"[webgpsmap] on_webhook offlinemap: error: {error}")
|
logging.error(f"[webgpsmap] on_webhook offlinemap: error: {error}")
|
||||||
return
|
return
|
||||||
@ -149,7 +151,6 @@ class Webgpsmap(plugins.Plugin):
|
|||||||
def _get_pos_from_file(self, path):
|
def _get_pos_from_file(self, path):
|
||||||
return PositionFile(path)
|
return PositionFile(path)
|
||||||
|
|
||||||
|
|
||||||
def load_gps_from_dir(self, gpsdir, newest_only=False):
|
def load_gps_from_dir(self, gpsdir, newest_only=False):
|
||||||
"""
|
"""
|
||||||
Parses the gps-data from disk
|
Parses the gps-data from disk
|
||||||
@ -160,13 +161,9 @@ class Webgpsmap(plugins.Plugin):
|
|||||||
|
|
||||||
logging.info(f"[webgpsmap] scanning {handshake_dir}")
|
logging.info(f"[webgpsmap] scanning {handshake_dir}")
|
||||||
|
|
||||||
|
|
||||||
all_files = os.listdir(handshake_dir)
|
all_files = os.listdir(handshake_dir)
|
||||||
#print(all_files)
|
# print(all_files)
|
||||||
all_pcap_files = [os.path.join(handshake_dir, filename)
|
all_pcap_files = [os.path.join(handshake_dir, filename) for filename in all_files if filename.endswith('.pcap')]
|
||||||
for filename in all_files
|
|
||||||
if filename.endswith('.pcap')
|
|
||||||
]
|
|
||||||
all_geo_or_gps_files = []
|
all_geo_or_gps_files = []
|
||||||
for filename_pcap in all_pcap_files:
|
for filename_pcap in all_pcap_files:
|
||||||
filename_base = filename_pcap[:-5] # remove ".pcap"
|
filename_base = filename_pcap[:-5] # remove ".pcap"
|
||||||
@ -300,7 +297,6 @@ class PositionFile:
|
|||||||
return parsed_ssid.groups()[0]
|
return parsed_ssid.groups()[0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def json(self):
|
def json(self):
|
||||||
"""
|
"""
|
||||||
returns the parsed json
|
returns the parsed json
|
||||||
|
@ -3,6 +3,7 @@ import logging
|
|||||||
import json
|
import json
|
||||||
import csv
|
import csv
|
||||||
import requests
|
import requests
|
||||||
|
import pwnagotchi
|
||||||
|
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -24,7 +25,11 @@ def _extract_gps_data(path):
|
|||||||
with open(path, 'r') as json_file:
|
with open(path, 'r') as json_file:
|
||||||
tempJson = json.load(json_file)
|
tempJson = json.load(json_file)
|
||||||
d = datetime.utcfromtimestamp(int(tempJson["ts"]))
|
d = datetime.utcfromtimestamp(int(tempJson["ts"]))
|
||||||
return {"Latitude": tempJson["location"]["lat"], "Longitude": tempJson["location"]["lng"], "Altitude": 10, "Updated": d.strftime('%Y-%m-%dT%H:%M:%S.%f')}
|
return {"Latitude": tempJson["location"]["lat"],
|
||||||
|
"Longitude": tempJson["location"]["lng"],
|
||||||
|
"Altitude": 10,
|
||||||
|
"Accuracy": tempJson["accuracy"],
|
||||||
|
"Updated": d.strftime('%Y-%m-%dT%H:%M:%S.%f')}
|
||||||
else:
|
else:
|
||||||
with open(path, 'r') as json_file:
|
with open(path, 'r') as json_file:
|
||||||
return json.load(json_file)
|
return json.load(json_file)
|
||||||
@ -38,7 +43,7 @@ def _format_auth(data):
|
|||||||
out = ""
|
out = ""
|
||||||
for auth in data:
|
for auth in data:
|
||||||
out = f"{out}[{auth}]"
|
out = f"{out}[{auth}]"
|
||||||
return out
|
return [f"{auth}" for auth in data]
|
||||||
|
|
||||||
|
|
||||||
def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
|
def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
|
||||||
@ -47,10 +52,10 @@ def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
|
|||||||
"""
|
"""
|
||||||
dummy = StringIO()
|
dummy = StringIO()
|
||||||
# write kismet header
|
# write kismet header
|
||||||
|
dummy.write(f"WigleWifi-1.6,appRelease={plugin_version},model=pwnagotchi,release={__pwnagotchi_version__},"
|
||||||
|
f"device={pwnagotchi.name()},display=kismet,board=RaspberryPi,brand=pwnagotchi,star=Sol,body=3,subBody=0\n")
|
||||||
dummy.write(
|
dummy.write(
|
||||||
"WigleWifi-1.4,appRelease={},model=pwnagotchi,release={},device=pwnagotchi,display=kismet,board=kismet,brand=pwnagotchi\n".format(plugin_version, __pwnagotchi_version__))
|
"MAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type\n")
|
||||||
dummy.write(
|
|
||||||
"MAC,SSID,AuthMode,FirstSeen,Channel,RSSI,CurrentLatitude,CurrentLongitude,AltitudeMeters,AccuracyMeters,Type")
|
|
||||||
|
|
||||||
writer = csv.writer(dummy, delimiter=",", quoting=csv.QUOTE_NONE, escapechar="\\")
|
writer = csv.writer(dummy, delimiter=",", quoting=csv.QUOTE_NONE, escapechar="\\")
|
||||||
writer.writerow([
|
writer.writerow([
|
||||||
@ -64,7 +69,7 @@ def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
|
|||||||
gps_data['Latitude'],
|
gps_data['Latitude'],
|
||||||
gps_data['Longitude'],
|
gps_data['Longitude'],
|
||||||
gps_data['Altitude'],
|
gps_data['Altitude'],
|
||||||
0, # accuracy?
|
gps_data['Accuracy'],
|
||||||
'WIFI'])
|
'WIFI'])
|
||||||
return dummy.getvalue()
|
return dummy.getvalue()
|
||||||
|
|
||||||
@ -84,7 +89,7 @@ def _send_to_wigle(lines, api_key, donate=True, timeout=30):
|
|||||||
headers = {'Authorization': f"Basic {api_key}",
|
headers = {'Authorization': f"Basic {api_key}",
|
||||||
'Accept': 'application/json'}
|
'Accept': 'application/json'}
|
||||||
data = {'donate': 'on' if donate else 'false'}
|
data = {'donate': 'on' if donate else 'false'}
|
||||||
payload = {'file': dummy, 'type': 'text/csv'}
|
payload = {'file': (pwnagotchi.name() + ".csv", dummy, 'multipart/form-data', {'Expires': '0'})}
|
||||||
try:
|
try:
|
||||||
res = requests.post('https://api.wigle.net/api/v2/file/upload',
|
res = requests.post('https://api.wigle.net/api/v2/file/upload',
|
||||||
data=data,
|
data=data,
|
||||||
@ -99,34 +104,32 @@ def _send_to_wigle(lines, api_key, donate=True, timeout=30):
|
|||||||
|
|
||||||
|
|
||||||
class Wigle(plugins.Plugin):
|
class Wigle(plugins.Plugin):
|
||||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
__author__ = "Dadav and updated by Jayofelony"
|
||||||
__version__ = '2.0.0'
|
__version__ = "3.0.1"
|
||||||
__license__ = 'GPL3'
|
__license__ = "GPL3"
|
||||||
__description__ = 'This plugin automatically uploads collected wifis to wigle.net'
|
__description__ = "This plugin automatically uploads collected WiFi to wigle.net"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.ready = False
|
self.ready = False
|
||||||
self.report = StatusFile('/root/.wigle_uploads', data_format='json')
|
self.report = StatusFile('/root/.wigle_uploads', data_format='json')
|
||||||
self.skip = list()
|
self.skip = list()
|
||||||
self.lock = Lock()
|
self.lock = Lock()
|
||||||
|
self.options = dict()
|
||||||
|
|
||||||
def on_loaded(self):
|
def on_loaded(self):
|
||||||
if 'api_key' not in self.options or ('api_key' in self.options and self.options['api_key'] is None):
|
if 'api_key' not in self.options or ('api_key' in self.options and self.options['api_key'] is None):
|
||||||
logging.debug("WIGLE: api_key isn't set. Can't upload to wigle.net")
|
logging.debug("WIGLE: api_key isn't set. Can't upload to wigle.net")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not 'whitelist' in self.options:
|
if 'donate' not in self.options:
|
||||||
self.options['whitelist'] = list()
|
self.options['donate'] = False
|
||||||
|
|
||||||
if not 'donate' in self.options:
|
|
||||||
self.options['donate'] = True
|
|
||||||
|
|
||||||
self.ready = True
|
self.ready = True
|
||||||
logging.info("WIGLE: ready")
|
logging.info("WIGLE: ready")
|
||||||
|
|
||||||
def on_internet_available(self, agent):
|
def on_internet_available(self, agent):
|
||||||
"""
|
"""
|
||||||
Called in manual mode when there's internet connectivity
|
Called when there's internet connectivity
|
||||||
"""
|
"""
|
||||||
if not self.ready or self.lock.locked():
|
if not self.ready or self.lock.locked():
|
||||||
return
|
return
|
||||||
@ -140,9 +143,9 @@ class Wigle(plugins.Plugin):
|
|||||||
all_files = os.listdir(handshake_dir)
|
all_files = os.listdir(handshake_dir)
|
||||||
all_gps_files = [os.path.join(handshake_dir, filename)
|
all_gps_files = [os.path.join(handshake_dir, filename)
|
||||||
for filename in all_files
|
for filename in all_files
|
||||||
if filename.endswith('.gps.json') or filename.endswith('.paw-gps.json') or filename.endswith('.geo.json')]
|
if filename.endswith('.gps.json') or filename.endswith('.geo.json')]
|
||||||
|
|
||||||
all_gps_files = remove_whitelisted(all_gps_files, self.options['whitelist'])
|
all_gps_files = remove_whitelisted(all_gps_files, config['main']['whitelist'])
|
||||||
new_gps_files = set(all_gps_files) - set(reported) - set(self.skip)
|
new_gps_files = set(all_gps_files) - set(reported) - set(self.skip)
|
||||||
if new_gps_files:
|
if new_gps_files:
|
||||||
logging.info("WIGLE: Internet connectivity detected. Uploading new handshakes to wigle.net")
|
logging.info("WIGLE: Internet connectivity detected. Uploading new handshakes to wigle.net")
|
||||||
@ -151,8 +154,6 @@ class Wigle(plugins.Plugin):
|
|||||||
for gps_file in new_gps_files:
|
for gps_file in new_gps_files:
|
||||||
if gps_file.endswith('.gps.json'):
|
if gps_file.endswith('.gps.json'):
|
||||||
pcap_filename = gps_file.replace('.gps.json', '.pcap')
|
pcap_filename = gps_file.replace('.gps.json', '.pcap')
|
||||||
if gps_file.endswith('.paw-gps.json'):
|
|
||||||
pcap_filename = gps_file.replace('.paw-gps.json', '.pcap')
|
|
||||||
if gps_file.endswith('.geo.json'):
|
if gps_file.endswith('.geo.json'):
|
||||||
pcap_filename = gps_file.replace('.geo.json', '.pcap')
|
pcap_filename = gps_file.replace('.geo.json', '.pcap')
|
||||||
if not os.path.exists(pcap_filename):
|
if not os.path.exists(pcap_filename):
|
||||||
|
@ -76,9 +76,6 @@ class WpaSec(plugins.Plugin):
|
|||||||
logging.error("WPA_SEC: API-URL isn't set. Can't upload, no endpoint configured.")
|
logging.error("WPA_SEC: API-URL isn't set. Can't upload, no endpoint configured.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'whitelist' not in self.options:
|
|
||||||
self.options['whitelist'] = list()
|
|
||||||
|
|
||||||
self.ready = True
|
self.ready = True
|
||||||
logging.info("WPA_SEC: plugin loaded")
|
logging.info("WPA_SEC: plugin loaded")
|
||||||
|
|
||||||
@ -101,9 +98,8 @@ class WpaSec(plugins.Plugin):
|
|||||||
reported = self.report.data_field_or('reported', default=list())
|
reported = self.report.data_field_or('reported', default=list())
|
||||||
handshake_dir = config['bettercap']['handshakes']
|
handshake_dir = config['bettercap']['handshakes']
|
||||||
handshake_filenames = os.listdir(handshake_dir)
|
handshake_filenames = os.listdir(handshake_dir)
|
||||||
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if
|
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if filename.endswith('.pcap')]
|
||||||
filename.endswith('.pcap')]
|
handshake_paths = remove_whitelisted(handshake_paths, config['main']['whitelist'])
|
||||||
handshake_paths = remove_whitelisted(handshake_paths, self.options['whitelist'])
|
|
||||||
handshake_new = set(handshake_paths) - set(reported) - set(self.skip)
|
handshake_new = set(handshake_paths) - set(reported) - set(self.skip)
|
||||||
|
|
||||||
if handshake_new:
|
if handshake_new:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from PIL import Image
|
from PIL import Image, ImageOps
|
||||||
from textwrap import TextWrapper
|
from textwrap import TextWrapper
|
||||||
|
|
||||||
|
|
||||||
@ -40,21 +40,37 @@ class FilledRect(Widget):
|
|||||||
|
|
||||||
|
|
||||||
class Text(Widget):
|
class Text(Widget):
|
||||||
def __init__(self, value="", position=(0, 0), font=None, color=0, wrap=False, max_length=0):
|
def __init__(self, value="", position=(0, 0), font=None, color=0, wrap=False, max_length=0, png=False):
|
||||||
super().__init__(position, color)
|
super().__init__(position, color)
|
||||||
self.value = value
|
self.value = value
|
||||||
self.font = font
|
self.font = font
|
||||||
self.wrap = wrap
|
self.wrap = wrap
|
||||||
self.max_length = max_length
|
self.max_length = max_length
|
||||||
self.wrapper = TextWrapper(width=self.max_length, replace_whitespace=False) if wrap else None
|
self.wrapper = TextWrapper(width=self.max_length, replace_whitespace=False) if wrap else None
|
||||||
|
self.png = png
|
||||||
|
|
||||||
def draw(self, canvas, drawer):
|
def draw(self, canvas, drawer):
|
||||||
if self.value is not None:
|
if self.value is not None:
|
||||||
|
if not self.png:
|
||||||
if self.wrap:
|
if self.wrap:
|
||||||
text = '\n'.join(self.wrapper.wrap(self.value))
|
text = '\n'.join(self.wrapper.wrap(self.value))
|
||||||
else:
|
else:
|
||||||
text = self.value
|
text = self.value
|
||||||
drawer.text(self.xy, text, font=self.font, fill=self.color)
|
drawer.text(self.xy, text, font=self.font, fill=self.color)
|
||||||
|
else:
|
||||||
|
self.image = Image.open(self.value)
|
||||||
|
self.image = self.image.convert('RGBA')
|
||||||
|
self.pixels = self.image.load()
|
||||||
|
for y in range(self.image.size[1]):
|
||||||
|
for x in range(self.image.size[0]):
|
||||||
|
if self.pixels[x,y][3] < 255: # check alpha
|
||||||
|
self.pixels[x,y] = (255, 255, 255, 255)
|
||||||
|
if self.color == 255:
|
||||||
|
self._image = ImageOps.colorize(self.image.convert('L'), black = "white", white = "black")
|
||||||
|
else:
|
||||||
|
self._image = self.image
|
||||||
|
self.image = self._image.convert('1')
|
||||||
|
canvas.paste(self.image, self.xy)
|
||||||
|
|
||||||
|
|
||||||
class LabeledValue(Widget):
|
class LabeledValue(Widget):
|
||||||
|
@ -103,8 +103,8 @@ class Display(View):
|
|||||||
def is_waveshare2in13d(self):
|
def is_waveshare2in13d(self):
|
||||||
return self._implementation.name == 'waveshare2in13d'
|
return self._implementation.name == 'waveshare2in13d'
|
||||||
|
|
||||||
def is_waveshare2in23g(self):
|
def is_waveshare2in13g(self):
|
||||||
return self._implementation.name == 'waveshare2in23g'
|
return self._implementation.name == 'waveshare2in13g'
|
||||||
|
|
||||||
def is_waveshare2in36g(self):
|
def is_waveshare2in36g(self):
|
||||||
return self._implementation.name == 'waveshare2in36g'
|
return self._implementation.name == 'waveshare2in36g'
|
||||||
@ -112,6 +112,9 @@ class Display(View):
|
|||||||
def is_waveshare2in66(self):
|
def is_waveshare2in66(self):
|
||||||
return self._implementation.name == 'waveshare2in66'
|
return self._implementation.name == 'waveshare2in66'
|
||||||
|
|
||||||
|
def is_waveshare2in66b(self):
|
||||||
|
return self._implementation.name == 'waveshare2in66b'
|
||||||
|
|
||||||
def is_waveshare2in66g(self):
|
def is_waveshare2in66g(self):
|
||||||
return self._implementation.name == 'waveshare2in66g'
|
return self._implementation.name == 'waveshare2in66g'
|
||||||
|
|
||||||
|
@ -23,7 +23,9 @@ DEBUG = '(#__#)'
|
|||||||
UPLOAD = '(1__0)'
|
UPLOAD = '(1__0)'
|
||||||
UPLOAD1 = '(1__1)'
|
UPLOAD1 = '(1__1)'
|
||||||
UPLOAD2 = '(0__1)'
|
UPLOAD2 = '(0__1)'
|
||||||
|
PNG = False
|
||||||
|
POSITION_X = 0
|
||||||
|
POSITION_Y = 40
|
||||||
|
|
||||||
def load_from_config(config):
|
def load_from_config(config):
|
||||||
for face_name, face_value in config.items():
|
for face_name, face_value in config.items():
|
||||||
|
@ -16,6 +16,7 @@ from pwnagotchi.ui.hw.waveshare1in44lcd import Waveshare144lcd
|
|||||||
from pwnagotchi.ui.hw.waveshare1in54b import Waveshare154inchb
|
from pwnagotchi.ui.hw.waveshare1in54b import Waveshare154inchb
|
||||||
from pwnagotchi.ui.hw.waveshare2in13bc import Waveshare213bc
|
from pwnagotchi.ui.hw.waveshare2in13bc import Waveshare213bc
|
||||||
from pwnagotchi.ui.hw.waveshare2in13d import Waveshare213d
|
from pwnagotchi.ui.hw.waveshare2in13d import Waveshare213d
|
||||||
|
from pwnagotchi.ui.hw.waveshare2in13g import Waveshare2in13g
|
||||||
from pwnagotchi.ui.hw.waveshare2in13b_V4 import Waveshare213bV4
|
from pwnagotchi.ui.hw.waveshare2in13b_V4 import Waveshare213bV4
|
||||||
from pwnagotchi.ui.hw.waveshare3in5lcd import Waveshare35lcd
|
from pwnagotchi.ui.hw.waveshare3in5lcd import Waveshare35lcd
|
||||||
from pwnagotchi.ui.hw.spotpear24in import Spotpear24inch
|
from pwnagotchi.ui.hw.spotpear24in import Spotpear24inch
|
||||||
@ -33,9 +34,10 @@ from pwnagotchi.ui.hw.waveshare2in9b_V4 import Waveshare29bV4
|
|||||||
from pwnagotchi.ui.hw.waveshare2in9bc import Waveshare2in9bc
|
from pwnagotchi.ui.hw.waveshare2in9bc import Waveshare2in9bc
|
||||||
from pwnagotchi.ui.hw.waveshare2in9d import Waveshare2in9d
|
from pwnagotchi.ui.hw.waveshare2in9d import Waveshare2in9d
|
||||||
from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare2in13bV3
|
from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare2in13bV3
|
||||||
from pwnagotchi.ui.hw.waveshare2in23g import Waveshare2in23g
|
|
||||||
from pwnagotchi.ui.hw.waveshare2in36g import Waveshare2in36g
|
from pwnagotchi.ui.hw.waveshare2in36g import Waveshare2in36g
|
||||||
from pwnagotchi.ui.hw.waveshare2in66 import Waveshare2in66
|
from pwnagotchi.ui.hw.waveshare2in66 import Waveshare2in66
|
||||||
|
from pwnagotchi.ui.hw.waveshare2in66b import Waveshare2in66b
|
||||||
|
from pwnagotchi.ui.hw.waveshare2in66g import Waveshare2in66g
|
||||||
from pwnagotchi.ui.hw.waveshare3in0g import Waveshare3in0g
|
from pwnagotchi.ui.hw.waveshare3in0g import Waveshare3in0g
|
||||||
from pwnagotchi.ui.hw.waveshare3in7 import Waveshare3in7
|
from pwnagotchi.ui.hw.waveshare3in7 import Waveshare3in7
|
||||||
from pwnagotchi.ui.hw.waveshare3in52 import Waveshare3in52
|
from pwnagotchi.ui.hw.waveshare3in52 import Waveshare3in52
|
||||||
@ -82,6 +84,21 @@ def display_for(config):
|
|||||||
elif config['ui']['display']['type'] == 'dfrobot_2':
|
elif config['ui']['display']['type'] == 'dfrobot_2':
|
||||||
return DFRobotV2(config)
|
return DFRobotV2(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare144lcd':
|
||||||
|
return Waveshare144lcd(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare35lcd':
|
||||||
|
return Waveshare35lcd(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'spotpear24inch':
|
||||||
|
return Spotpear24inch(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'displayhatmini':
|
||||||
|
return DisplayHatMini(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare1in02':
|
||||||
|
return Waveshare1in02(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare1in54':
|
elif config['ui']['display']['type'] == 'waveshare1in54':
|
||||||
return Waveshare154(config)
|
return Waveshare154(config)
|
||||||
|
|
||||||
@ -94,12 +111,36 @@ def display_for(config):
|
|||||||
elif config['ui']['display']['type'] == 'waveshare1in54b_v2':
|
elif config['ui']['display']['type'] == 'waveshare1in54b_v2':
|
||||||
return Waveshare154bV2(config)
|
return Waveshare154bV2(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare1in54c':
|
||||||
|
return Waveshare1in54c(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare1in64g':
|
||||||
|
return Waveshare1in64g(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in7':
|
||||||
|
return Waveshare27inch(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in7_v2':
|
||||||
|
return Waveshare27inchV2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in7b':
|
elif config['ui']['display']['type'] == 'waveshare2in7b':
|
||||||
return Waveshare27b(config)
|
return Waveshare27b(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in7b_v2':
|
elif config['ui']['display']['type'] == 'waveshare2in7b_v2':
|
||||||
return Waveshare27bV2(config)
|
return Waveshare27bV2(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in9':
|
||||||
|
return Waveshare29inch(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in9bc':
|
||||||
|
return Waveshare2in9bc(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in9d':
|
||||||
|
return Waveshare2in9d(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in9_v2':
|
||||||
|
return Waveshare29inchV2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in9b_v3':
|
elif config['ui']['display']['type'] == 'waveshare2in9b_v3':
|
||||||
return Waveshare29bV3(config)
|
return Waveshare29bV3(config)
|
||||||
|
|
||||||
@ -118,137 +159,101 @@ def display_for(config):
|
|||||||
elif config['ui']['display']['type'] == 'waveshare_4':
|
elif config['ui']['display']['type'] == 'waveshare_4':
|
||||||
return WaveshareV4(config)
|
return WaveshareV4(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in7':
|
|
||||||
return Waveshare27inch(config)
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in7_v2':
|
|
||||||
return Waveshare27inchV2(config)
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in9':
|
|
||||||
return Waveshare29inch(config)
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in9_v2':
|
|
||||||
return Waveshare29inchV2(config)
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare144lcd':
|
|
||||||
return Waveshare144lcd(config)
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare1in54b':
|
|
||||||
return Waveshare154inchb(config)
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in13bc':
|
elif config['ui']['display']['type'] == 'waveshare2in13bc':
|
||||||
return Waveshare213bc(config)
|
return Waveshare213bc(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in13d':
|
elif config['ui']['display']['type'] == 'waveshare2in13d':
|
||||||
return Waveshare213d(config)
|
return Waveshare213d(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in13b_v3':
|
||||||
|
return Waveshare2in13bV3(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in13b_v4':
|
elif config['ui']['display']['type'] == 'waveshare2in13b_v4':
|
||||||
return Waveshare213bV4(config)
|
return Waveshare213bV4(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare35lcd':
|
elif config['ui']['display']['type'] == 'waveshare2in13g':
|
||||||
return Waveshare35lcd(config)
|
return Waveshare2in13g(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'spotpear24inch':
|
|
||||||
return Spotpear24inch(config)
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'displayhatmini':
|
|
||||||
return DisplayHatMini(config)
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare1in54c':
|
|
||||||
return Waveshare1in54c
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare1in64g':
|
|
||||||
return Waveshare1in64g
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare1in02':
|
|
||||||
return Waveshare1in02
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in9bc':
|
|
||||||
return Waveshare2in9bc
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in9d':
|
|
||||||
return Waveshare2in9d
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in13b_v3':
|
|
||||||
return Waveshare2in13bV3
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in23g':
|
|
||||||
return Waveshare2in23g
|
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in36g':
|
elif config['ui']['display']['type'] == 'waveshare2in36g':
|
||||||
return Waveshare2in36g
|
return Waveshare2in36g(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare2in66':
|
elif config['ui']['display']['type'] == 'waveshare2in66':
|
||||||
return Waveshare2in66
|
return Waveshare2in66(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in66b':
|
||||||
|
return Waveshare2in66b(config)
|
||||||
|
|
||||||
|
elif config['ui']['display']['type'] == 'waveshare2in66g':
|
||||||
|
return Waveshare2in66g(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare3in0g':
|
elif config['ui']['display']['type'] == 'waveshare3in0g':
|
||||||
return Waveshare3in0g
|
return Waveshare3in0g(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare3in7':
|
elif config['ui']['display']['type'] == 'waveshare3in7':
|
||||||
return Waveshare3in7
|
return Waveshare3in7(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare3in52':
|
elif config['ui']['display']['type'] == 'waveshare3in52':
|
||||||
return Waveshare3in52
|
return Waveshare3in52(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare4in01f':
|
elif config['ui']['display']['type'] == 'waveshare4in01f':
|
||||||
return Waveshare4in01f
|
return Waveshare4in01f(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare4in2':
|
elif config['ui']['display']['type'] == 'waveshare4in2':
|
||||||
return Waveshare4in2
|
return Waveshare4in2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare4in2_v2':
|
elif config['ui']['display']['type'] == 'waveshare4in2_v2':
|
||||||
return Waveshare4in2V2
|
return Waveshare4in2V2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare4in2b_v2':
|
elif config['ui']['display']['type'] == 'waveshare4in2b_v2':
|
||||||
return Waveshare4in2bV2
|
return Waveshare4in2bV2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare4in2bc':
|
elif config['ui']['display']['type'] == 'waveshare4in2bc':
|
||||||
return Waveshare4in2bc
|
return Waveshare4in2bc(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare4in26':
|
elif config['ui']['display']['type'] == 'waveshare4in26':
|
||||||
return Waveshare4in26
|
return Waveshare4in26(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare4in37g':
|
elif config['ui']['display']['type'] == 'waveshare4in37g':
|
||||||
return Waveshare4in37g
|
return Waveshare4in37g(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare5in65f':
|
elif config['ui']['display']['type'] == 'waveshare5in65f':
|
||||||
return Waveshare5in65f
|
return Waveshare5in65f(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare5in83':
|
elif config['ui']['display']['type'] == 'waveshare5in83':
|
||||||
return Waveshare5in83
|
return Waveshare5in83(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare5in83_v2':
|
elif config['ui']['display']['type'] == 'waveshare5in83_v2':
|
||||||
return Waveshare5in83V2
|
return Waveshare5in83V2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare5in83b_v2':
|
elif config['ui']['display']['type'] == 'waveshare5in83b_v2':
|
||||||
return Waveshare5in83bV2
|
return Waveshare5in83bV2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare5in83bc':
|
elif config['ui']['display']['type'] == 'waveshare5in83bc':
|
||||||
return Waveshare5in83bc
|
return Waveshare5in83bc(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare7in3f':
|
elif config['ui']['display']['type'] == 'waveshare7in3f':
|
||||||
return Waveshare7in3f
|
return Waveshare7in3f(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare7in3g':
|
elif config['ui']['display']['type'] == 'waveshare7in3g':
|
||||||
return Waveshare7in3g
|
return Waveshare7in3g(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare7in5':
|
elif config['ui']['display']['type'] == 'waveshare7in5':
|
||||||
return Waveshare7in5
|
return Waveshare7in5(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare7in5_HD':
|
elif config['ui']['display']['type'] == 'waveshare7in5_HD':
|
||||||
return Waveshare7in5HD
|
return Waveshare7in5HD(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare7in5_v2':
|
elif config['ui']['display']['type'] == 'waveshare7in5_v2':
|
||||||
return Waveshare7in5V2
|
return Waveshare7in5V2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare7in5b_HD':
|
elif config['ui']['display']['type'] == 'waveshare7in5b_HD':
|
||||||
return Waveshare7in5bHD
|
return Waveshare7in5bHD(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare7in5b_v2':
|
elif config['ui']['display']['type'] == 'waveshare7in5b_v2':
|
||||||
return Waveshare7in5bV2
|
return Waveshare7in5bV2(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare7in5bc':
|
elif config['ui']['display']['type'] == 'waveshare7in5bc':
|
||||||
return Waveshare7in5bc
|
return Waveshare7in5bc(config)
|
||||||
|
|
||||||
elif config['ui']['display']['type'] == 'waveshare13in3k':
|
elif config['ui']['display']['type'] == 'waveshare13in3k':
|
||||||
return Waveshare13in3k
|
return Waveshare13in3k(config)
|
||||||
|
@ -3,6 +3,7 @@ import pwnagotchi.ui.fonts as fonts
|
|||||||
|
|
||||||
class DisplayImpl(object):
|
class DisplayImpl(object):
|
||||||
def __init__(self, config, name):
|
def __init__(self, config, name):
|
||||||
|
self._display = None
|
||||||
if fonts.Medium is None:
|
if fonts.Medium is None:
|
||||||
fonts.init(config)
|
fonts.init(config)
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -3,10 +3,10 @@ import logging
|
|||||||
import pwnagotchi.ui.fonts as fonts
|
import pwnagotchi.ui.fonts as fonts
|
||||||
from pwnagotchi.ui.hw.base import DisplayImpl
|
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||||
|
|
||||||
|
|
||||||
class DFRobotV1(DisplayImpl):
|
class DFRobotV1(DisplayImpl):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
|
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
|
||||||
self._display = None
|
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
fonts.setup(10, 9, 10, 35, 25, 9)
|
fonts.setup(10, 9, 10, 35, 25, 9)
|
||||||
|
@ -3,10 +3,10 @@ import logging
|
|||||||
import pwnagotchi.ui.fonts as fonts
|
import pwnagotchi.ui.fonts as fonts
|
||||||
from pwnagotchi.ui.hw.base import DisplayImpl
|
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||||
|
|
||||||
|
|
||||||
class DFRobotV1(DisplayImpl):
|
class DFRobotV1(DisplayImpl):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
|
super(DFRobotV1, self).__init__(config, 'dfrobot_1')
|
||||||
self._display = None
|
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
fonts.setup(10, 9, 10, 35, 25, 9)
|
fonts.setup(10, 9, 10, 35, 25, 9)
|
||||||
|
@ -3,10 +3,10 @@ import logging
|
|||||||
import pwnagotchi.ui.fonts as fonts
|
import pwnagotchi.ui.fonts as fonts
|
||||||
from pwnagotchi.ui.hw.base import DisplayImpl
|
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||||
|
|
||||||
|
|
||||||
class DFRobotV2(DisplayImpl):
|
class DFRobotV2(DisplayImpl):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
|
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
|
||||||
self._display = None
|
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
fonts.setup(10, 9, 10, 35, 25, 9)
|
fonts.setup(10, 9, 10, 35, 25, 9)
|
||||||
|
@ -3,10 +3,10 @@ import logging
|
|||||||
import pwnagotchi.ui.fonts as fonts
|
import pwnagotchi.ui.fonts as fonts
|
||||||
from pwnagotchi.ui.hw.base import DisplayImpl
|
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||||
|
|
||||||
|
|
||||||
class DFRobotV2(DisplayImpl):
|
class DFRobotV2(DisplayImpl):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
|
super(DFRobotV2, self).__init__(config, 'dfrobot_2')
|
||||||
self._display = None
|
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
fonts.setup(10, 9, 10, 35, 25, 9)
|
fonts.setup(10, 9, 10, 35, 25, 9)
|
||||||
|
@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
|
|||||||
class DisplayHatMini(DisplayImpl):
|
class DisplayHatMini(DisplayImpl):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(DisplayHatMini, self).__init__(config, 'displayhatmini')
|
super(DisplayHatMini, self).__init__(config, 'displayhatmini')
|
||||||
self._display = None
|
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
fonts.setup(12, 10, 12, 70, 25, 9)
|
fonts.setup(12, 10, 12, 70, 25, 9)
|
||||||
|
@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
|
|||||||
class Inky(DisplayImpl):
|
class Inky(DisplayImpl):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(Inky, self).__init__(config, 'inky')
|
super(Inky, self).__init__(config, 'inky')
|
||||||
self._display = None
|
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
fonts.setup(10, 8, 10, 28, 25, 9)
|
fonts.setup(10, 8, 10, 28, 25, 9)
|
||||||
|
@ -7,7 +7,6 @@ from pwnagotchi.ui.hw.base import DisplayImpl
|
|||||||
class LcdHat(DisplayImpl):
|
class LcdHat(DisplayImpl):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(LcdHat, self).__init__(config, 'lcdhat')
|
super(LcdHat, self).__init__(config, 'lcdhat')
|
||||||
self._display = None
|
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
fonts.setup(10, 9, 10, 35, 25, 9)
|
fonts.setup(10, 9, 10, 35, 25, 9)
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user