Compare commits

..

338 Commits

Author SHA1 Message Date
7edd752664 small change
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-19 07:56:06 +01:00
cc550aa236 small change
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-18 15:05:00 +01:00
ff033d41d3 Revert "fallback to older 32bit image"
This reverts commit b33af167d4.
2024-03-18 14:56:59 +01:00
6d0a0d8d5f fallback to older 32bit image
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-18 13:04:19 +01:00
b33af167d4 fallback to older 32bit image
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-18 12:03:20 +01:00
9053762e71 2.8.7.2
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-18 11:59:32 +01:00
26fef7dd99 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	builder/data/64bit/raspberrypi64.yml
2024-03-18 11:58:33 +01:00
5dd17291f7 Fix a lot of stuff
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-18 11:58:22 +01:00
bac79f3465 Update _version.py 2024-03-17 21:17:08 +01:00
bb8dfe0244 Update raspberrypi64.yml 2024-03-17 21:16:25 +01:00
1b16975031 Update workflow
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 09:24:57 +01:00
dd2b559ebc Update workflow
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 09:22:35 +01:00
93ba2a7f79 Update workflow
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 09:20:02 +01:00
dd18072002 Update workflow
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 09:18:31 +01:00
1eafbb841f Update build
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 01:10:56 +01:00
aa817288ea Update Raspios image
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 00:50:17 +01:00
43285eb2c0 Update Raspios image
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 00:47:49 +01:00
4b29476c2f Update Raspios image
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 00:46:09 +01:00
1a8ff930d9 Update nexmon
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-17 00:34:54 +01:00
8a65afdc8f Update nexmon
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-16 10:52:56 +01:00
6fcd1b0e23 Fix displays
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-15 15:50:43 +01:00
e0b0f5d800 Fix displays
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-15 15:07:55 +01:00
2243079bf6 Fix displays
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-15 15:07:15 +01:00
e10eb31ed1 Fix displays
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-15 13:41:27 +01:00
1c8114e444 Merge remote-tracking branch 'origin/master' 2024-03-15 10:00:01 +01:00
91638a151f Fix displays
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-15 09:59:55 +01:00
d4adaabcbd Merge pull request #93
Screen support
2024-03-13 23:03:44 +01:00
006cdb0fe3 Add 2 waveshare displays
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-13 22:41:18 +01:00
29386fb945 Update build to kernel 6.6.20
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-13 21:49:12 +01:00
4b4646d604 Added 2 waveshare diplays:
5.79 inch
5.79b inch

Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-13 21:49:00 +01:00
3fae6ec312 Screen support
Screen support for the following displays:
Adafruit pitft (2,4" and 2,8" tested)
Adafruit tft bonnet
Pimoroni pirate audio
Waveshare OLED/LCD hat
2024-03-13 16:31:49 +01:00
09a82aa0b4 revert pcapng
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-13 07:59:37 +01:00
541865a2eb Merge pull request #92 from jayofelony/dev
Dev
2024-03-13 07:57:37 +01:00
928de2769d Update build
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-13 07:55:53 +01:00
6987840da2 Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	Makefile
#	pwnagotchi/plugins/default/hashie.py
2024-03-07 21:37:27 +01:00
58de15ce2d Update Makefile
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-06 16:55:04 +01:00
b5ea3da619 Update Makefile
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-06 15:23:40 +01:00
6c68d4608f Fix gps plugin
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-06 15:23:30 +01:00
14a727954b Update Makefile and build
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-05 21:48:33 +01:00
aeada2ee6e Fix waveshare2in7_V2.py
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-05 21:48:16 +01:00
ebb8fef3fc Update build
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-05 19:54:47 +01:00
e531288369 Added WeAct 2.9 inch display
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-05 19:54:33 +01:00
2015b56c5d Fix waveshare3in52.py
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-05 19:54:10 +01:00
2497475057 Added WeAct 2.9 inch display
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-05 19:54:01 +01:00
0bdbbc23fd Version 2.8.7
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-05 19:53:35 +01:00
111787544f Merge remote-tracking branch 'origin/master' 2024-03-05 16:31:06 +01:00
efa5d8b197 Update build
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-05 16:31:00 +01:00
9e5fb49d7c Merge pull request #78 from rai68/master
Update view.py - bug fix, my self left a broken debug line in
2024-03-05 06:14:15 +01:00
Rai
cbbd7d5a6d Merge branch 'jayofelony:master' into master 2024-03-05 14:36:29 +10:00
Rai
90c5818123 Update view.py
Signed-off-by: Rai <58925163+rai68@users.noreply.github.com>
2024-03-05 13:23:30 +10:00
eb76ef4c54 Update build
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-04 21:21:48 +01:00
59e42daeb5 Update bash
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-03-04 21:13:33 +01:00
5b7014c68e Change MOTD 2024-03-04 21:01:23 +01:00
42cc3136ee Update wizard script 2024-03-04 20:54:25 +01:00
2a243870f7 Update wizard script 2024-03-04 20:49:38 +01:00
8f043ff5ef Update wizard script 2024-03-04 20:47:52 +01:00
255bbdbc08 Update wizard script 2024-03-04 20:40:16 +01:00
6f57b66cf4 Add display invert to --install 2024-03-04 20:35:09 +01:00
a4c25e9996 Add display invert to --install 2024-03-04 20:28:31 +01:00
9495d55296 Add display invert to --install 2024-03-04 20:25:22 +01:00
69e7503d67 Add display invert to --install 2024-03-04 20:21:41 +01:00
25cb1f2175 Add display invert to --install 2024-03-04 20:11:20 +01:00
54b7ce5d0d Add display invert to --install 2024-03-04 20:08:45 +01:00
1f9afd541d Add display invert to --install 2024-03-04 19:59:48 +01:00
87eae76a58 Add display invert to --install 2024-03-04 16:07:17 +01:00
6691257036 change small font size 2024-03-04 16:00:31 +01:00
2149c5dbdf remove color = black 2024-03-04 15:55:50 +01:00
77af772b4b remove color = black 2024-03-04 15:53:18 +01:00
14e4fc6d47 Add a interactive configuration installer 2024-03-04 15:48:52 +01:00
5be8580a59 Add a interactive configuration installer 2024-03-04 15:46:23 +01:00
f7a599ab8f Add a interactive configuration installer 2024-03-04 15:42:36 +01:00
5f907b236a Add a interactive configuration installer 2024-03-04 15:39:24 +01:00
bc92613700 Add a interactive configuration installer 2024-03-04 15:36:17 +01:00
501ec9ca2b Add a interactive configuration installer 2024-03-04 15:34:39 +01:00
e5e0180f3c Add a interactive configuration installer 2024-03-04 15:32:08 +01:00
ea60808700 Add a interactive configuration installer 2024-03-04 15:26:48 +01:00
a34db250b5 Add a interactive configuration installer 2024-03-04 15:24:45 +01:00
d29aca15a9 Add ui.invert = false to defaults 2024-03-04 15:24:17 +01:00
8531b89771 Add ui.invert = false to defaults 2024-03-04 13:02:33 +01:00
59d510d0e1 Merge pull request #77
Adds invertable BLACK/WHITE to config
2024-03-04 12:56:52 +01:00
913b1a6e1d Update 2.7 inch display 2024-03-04 12:55:12 +01:00
Rai
de2cdaa3c9 Update view.py
Signed-off-by: Rai <58925163+rai68@users.noreply.github.com>
2024-03-04 20:41:19 +10:00
Rai
f2cf34a8b9 Update view.py
Signed-off-by: Rai <58925163+rai68@users.noreply.github.com>
2024-03-04 20:39:55 +10:00
Rai
bbb46128fe Update view.py
Signed-off-by: Rai <58925163+rai68@users.noreply.github.com>
2024-03-04 20:39:20 +10:00
46713b6e73 Update view.py 2024-03-04 19:59:34 +10:00
aa2b09fb21 Update build 2024-03-01 10:19:32 +01:00
9125e43b20 Add display type variants, no new displays 2024-03-01 10:08:03 +01:00
7e4d926b14 Fix setup.py 2024-03-01 10:07:33 +01:00
6417ef5a78 Upgrade pip, setuptools, wheel 2024-03-01 10:07:25 +01:00
46c03063fe Version 2.8.6 2024-02-29 23:05:30 +01:00
d5384d5a81 Moved all reset logging to debug, except for plugin loaded.
Removed the counter from display
2024-02-29 23:01:05 +01:00
e800c66e57 Let auto-update check for armhf/aarch64 (pwngrid/bettercap) 2024-02-29 22:49:21 +01:00
e3a404cb39 Fix waveshare1in54.py 2024-02-29 10:23:15 +01:00
6cb6aaeb81 Merge remote-tracking branch 'origin/master' 2024-02-29 10:22:52 +01:00
5761dac073 Fix pwnagotchi plugins list error if no update has been ran first 2024-02-29 10:22:41 +01:00
3ada0628e1 Merge pull request #74 from Sniffleupagus/patch-1
Automatically remove invalid ai parameters leftover from tensorflow
2024-02-28 18:25:47 +01:00
9fa772c36a Automatically remove invalid ai parameters leftover from tensorflow
Ease transition from old Pwnagotchi running tensor flow to new running torch, but automatically dumping the invalid parameters.

Signed-off-by: Sniffleupagus <129890632+Sniffleupagus@users.noreply.github.com>
2024-02-28 09:58:41 -05:00
a92e66137c Fix build 2024-02-27 11:59:22 +01:00
a7e98cf166 Fix build 2024-02-27 10:24:44 +01:00
9a1a264a9f Fix waveshare1in54.py 2024-02-27 10:21:29 +01:00
8a0d482fe0 Make pwnlog point to correct log location 2024-02-27 10:19:30 +01:00
0cc320d31f Fix waveshare1in54.py 2024-02-27 10:12:38 +01:00
d841d2b649 Update build 2024-02-27 10:11:00 +01:00
966126a986 Update build 2024-02-27 10:10:06 +01:00
d67935fa6a Update build 2024-02-26 21:27:10 +01:00
46d867ce7f Update build 2024-02-26 21:20:56 +01:00
2e16069850 Update workflow 2024-02-26 20:36:16 +01:00
6e3cbbdd39 Update Makefile 2024-02-26 20:15:55 +01:00
a19bd6a181 Update setup.py 2024-02-26 19:38:54 +01:00
6c03d95724 Update build 2024-02-26 19:34:14 +01:00
60a9da9acc Update workflow 2024-02-26 13:09:15 +01:00
25aba0d73c Update workflow 2024-02-26 13:04:00 +01:00
ecde496534 Update workflow 2024-02-26 11:49:39 +01:00
7ebd4dd7a0 Update workflow 2024-02-26 10:48:21 +01:00
35f1707436 Update workflow 2024-02-26 08:58:06 +01:00
60ced12ea5 Update workflow 2024-02-26 08:56:37 +01:00
6082a0c169 Update workflow 2024-02-26 08:55:05 +01:00
a72c1b1628 Update workflow 2024-02-26 08:54:05 +01:00
e37a0bdc62 Update workflow 2024-02-26 08:52:17 +01:00
262f8bf551 Update workflow 2024-02-26 08:48:30 +01:00
5311dd9ddc Update workflow 2024-02-25 21:54:39 +01:00
bd9c44b4a3 Update workflow 2024-02-25 20:50:08 +01:00
3b01aec872 Update workflow 2024-02-25 20:33:09 +01:00
3e571bff2d Update workflow 2024-02-25 14:29:23 +01:00
391941e64a Update workflow 2024-02-25 14:28:09 +01:00
3fff6182ed Update workflow 2024-02-25 14:23:16 +01:00
73e0a1fce7 Update auto-update.py 2024-02-25 13:42:12 +01:00
9ba23d77d1 Update Makefile
Remove bananagotchi files
2024-02-25 13:35:23 +01:00
8be75627e9 Update build 2024-02-25 12:58:40 +01:00
c2a36aa678 Update README.md 2024-02-25 12:29:11 +01:00
fdf0a087f6 Update workflow 2024-02-25 12:23:56 +01:00
c6efa5df08 Update workflow 2024-02-25 12:11:47 +01:00
62327a711e Update workflow 2024-02-25 12:11:20 +01:00
bb460a9cc6 Update workflow 2024-02-25 12:07:11 +01:00
93b2322ab5 Update workflow 2024-02-25 12:05:14 +01:00
53a8af4711 Update workflow 2024-02-25 12:04:16 +01:00
ed5decffa0 Version 2.8.5 2024-02-25 12:00:29 +01:00
147cbfaa07 Version 2.8.5 2024-02-25 11:56:44 +01:00
ced9b4d5ee Update requirements.txt 2024-02-25 11:55:46 +01:00
472c3165ed Update workflow publisher 2024-02-25 11:50:56 +01:00
1578d13d98 Fix builder 2024-02-25 11:46:30 +01:00
0965e7eb3e Update image filename
Add pishrink to Makefile
2024-02-25 11:25:22 +01:00
b789c14f14 Change image filename, 32bit/64bit
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-25 11:18:19 +01:00
0855b44d59 Update everyting!
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-25 11:17:05 +01:00
55c6007d32 Update everyting!
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-25 11:10:59 +01:00
a7cf8a3383 Delete pwnagotchi/ui/hw/libs directory
Signed-off-by: Jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-25 10:45:28 +01:00
faa48b2752 Change repo's
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-25 10:42:47 +01:00
d20619340c Edit build
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-25 10:10:07 +01:00
43a07fe969 Edit Makefile
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-25 10:07:02 +01:00
bcce22c164 Edit Makefile
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-25 10:06:35 +01:00
0264b7a7db Merge remote-tracking branch 'origin/master' 2024-02-24 11:08:19 +01:00
fba5dd0341 Correct layout for waveshare3in52.py
Signed-off-by: jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-24 11:08:00 +01:00
dd7760efdf Merge pull request #56 from Sniffleupagus/DummyDisplay
Added DummyDisplay for arbitrary screen size when headless
2024-02-20 20:49:04 +01:00
f7cd0fb1fc Initialize as "DummyDisplay", not "inky"
Signed-off-by: Sniffleupagus <129890632+Sniffleupagus@users.noreply.github.com>
2024-02-20 11:18:15 -05:00
611a3e7fb5 fix for waveshare3in7.py 2024-02-15 20:51:55 +01:00
599c6211e4 version 2.8.4 2024-02-15 20:48:27 +01:00
eb48d29851 fix on 38 displays 2024-02-15 20:46:48 +01:00
0999b95be0 update build 2024-02-15 09:55:01 +01:00
ae351e5e9c update waveshare3in0g.py 2024-02-15 09:54:49 +01:00
fa58136c0e update waveshare3in7.py 2024-02-15 09:34:45 +01:00
3d5185f2c1 update waveshare3in7.py 2024-02-15 09:30:03 +01:00
b6bb7b9080 update waveshare3in7.py 2024-02-15 09:26:33 +01:00
20715351af revert back to drschottky 2024-02-14 08:53:54 +01:00
1d3c781d12 version 2.8.3 2024-02-13 23:25:55 +01:00
bd51b4330f version 2.8.3 2024-02-13 23:15:05 +01:00
f216a21132 update 2024-02-13 23:13:49 +01:00
5ae357c3dc Merge remote-tracking branch 'origin/master' 2024-02-13 23:11:10 +01:00
ed9afe6856 Revert "Changed from dphys-swapfile to zram-tools"
This reverts commit 26913016b9.
2024-02-13 23:10:53 +01:00
25d932fa9b Revert "zramswap"
This reverts commit 0dbd611ed5.
2024-02-13 23:10:52 +01:00
ebd25d50b0 Update README.md 2024-02-09 23:13:26 +01:00
0585fe75fe update 2024-02-09 13:14:10 +01:00
27e784a5d7 update 2024-02-09 13:12:40 +01:00
c02efb5224 update Makefile 2024-02-09 13:11:02 +01:00
a7634a2b4a update Makefile 2024-02-09 13:01:47 +01:00
ca4feb895e Revert "Revert "Testing pcapng fileformat""
This reverts commit 0e274af5a0.
2024-02-08 22:51:57 +01:00
107d366c82 update Makefile 2024-02-08 21:40:28 +01:00
488968ba7f Revert "update Makefile"
This reverts commit 9a40567d
2024-02-08 20:18:58 +01:00
0dd8f72c95 Merge pull request #58 from jayofelony/dev
dev
2024-02-08 20:07:20 +01:00
0e274af5a0 Revert "Testing pcapng fileformat"
This reverts commit 7040be2d30.
2024-02-08 20:06:33 +01:00
8627c8800d Merge pull request #57 from jayofelony/dev
Dev
2024-02-08 07:53:53 +01:00
53ed6f61c6 Merge branch 'master' into dev
Signed-off-by: Jayofelony <oudshoorn.jeroen@gmail.com>
2024-02-08 07:53:45 +01:00
835523241b update build 2024-02-08 07:51:19 +01:00
418dbf21e3 Added DummyDisplay for arbitrary screen size when headless 2024-02-07 15:16:26 -08:00
9a40567daa update Makefile 2024-02-06 22:12:05 +01:00
eab331686d Merge pull request #54 from crs-k/dev
Add PiShrink step to the workflow (#1)
2024-02-06 22:10:12 +01:00
e1d8001fb4 Add PiShrink step to the workflow (#1)
* Add PiShrink step to the workflow

* Add environment variables for Raspberry Pi 64-bit builder

* Update Makefile command to include debug information

* Add source distribution target to Makefile

* Remove unnecessary provisioner command

* Add armhf architecture support

* Remove armhf architecture provisioning

* Refactor Makefile to remove unnecessary files

* Update Makefile command in publish.yml

* Update pwngrid URL in raspberrypi64.yml

* Add permissions to publish workflow

* Remove unnecessary permissions in publish.yml
2024-02-06 12:53:45 -05:00
3cc172a526 update Makefile 2024-02-06 09:06:54 +01:00
41afe302d9 update Makefile 2024-02-06 09:05:42 +01:00
5bcca7e89b update README.md 2024-02-06 08:52:16 +01:00
4a12436942 add architecture armhf 2024-02-06 08:41:28 +01:00
d8b6363d37 Merge pull request #51
Waveshare 3.52 in e-ink update
2024-02-06 08:36:21 +01:00
b3d8a44208 Update waveshare3in52.py
Signed-off-by: Chris Kerins <clkerins@gmail.com>
2024-02-05 20:14:18 -05:00
ck
3fb91498cd Enable Makefile execution and remove disk image creation 2024-02-05 17:52:51 -05:00
ck
7587f38c28 Update disk.img path in publish.yml 2024-02-05 17:46:20 -05:00
ck
d7fefa78f0 Commented out make step and added code to create .img file 2024-02-05 17:40:38 -05:00
ck
1ef3a88679 Update distDir path in publish.yml 2024-02-05 17:34:23 -05:00
291ef39563 Update README.md to show support for Pi 5 2024-02-05 22:10:53 +01:00
16d80a09e6 Update README.md to show support for Pi 5 2024-02-05 22:10:34 +01:00
ck
4ffad03c91 Update distDir path in publish.yml 2024-02-05 15:44:50 -05:00
ck
0638832532 Update mountpoint for boot partition 2024-02-05 13:42:59 -05:00
ck
f895b06978 Update qemu binary paths for arm64 2024-02-05 13:19:56 -05:00
ck
f410feb2bb Add check for qemu-aarch64 in binfmt_misc 2024-02-05 13:09:36 -05:00
ck
1ffe6c4e3d Remove Makefile2 and update build process 2024-02-05 12:34:34 -05:00
ck
dfbfd7f891 Update pwngrid to version 1.11.1 2024-02-05 12:34:09 -05:00
ck
a50695aef2 Update publish workflow and add Makefile2 2024-02-05 12:18:04 -05:00
ck
829a6962d6 Update binfmt-support and add checks for qemu-user-static package, binfmt-support service, and binfmt_misc filesystem 2024-02-05 12:17:41 -05:00
ck
ce1315b85f Add binfmt_misc registration for qemu-aarch64 2024-02-05 12:08:07 -05:00
ck
6a2703cc27 Update QEMU in publish.yml 2024-02-05 11:34:03 -05:00
ck
502e856934 Update QEMU and restart binfmt-support 2024-02-05 11:22:39 -05:00
dffcbbf447 Revert "Revert "Testing pcapng fileformat""
This reverts commit d142840307.
2024-02-05 17:16:13 +01:00
ck
333804c3bb Remove unnecessary build configuration for Raspberry Pi 32 Pwnagotchi 2024-02-05 11:10:29 -05:00
ck
50b1ceed81 Remove unnecessary file from pwnagotchi build process 2024-02-05 11:01:49 -05:00
ck
877b9fbba3 Update Makefile and builder/pwnagotchi.json.pkr.hcl 2024-02-05 10:57:33 -05:00
ck
8724ca546d Update packer builder-arm source URL 2024-02-05 10:51:18 -05:00
961d3a536a Merge pull request #2 from crs-k/waveshare-352-support
Waveshare 352 support
2024-02-05 10:38:39 -05:00
ck
c882d0b67a Update arm plugin source in pwnagotchi.json.pkr.hcl 2024-02-05 10:29:01 -05:00
ck
12fd081ae0 Update required_plugins in pwnagotchi.json.pkr.hcl 2024-02-05 10:09:57 -05:00
ck
e1be0f7674 Remove unnecessary clean-up step in Makefile 2024-02-05 10:01:12 -05:00
396b30f780 Merge pull request #1 from crs-k:waveshare-352-support
Add publish workflow and update display layout
2024-02-05 09:31:24 -05:00
ck
e7d8d632a0 Add publish workflow and update display layout 2024-02-05 09:30:49 -05:00
5a6ec7b4b8 Next version will be 2.8.2 2024-02-04 18:28:09 +01:00
92cd5d3fdb Merge pull request #47 from jayofelony/dev
removed blind bug check from fix_services.py
2024-02-04 18:09:33 +01:00
99caa7a973 removed blind bug check from fix_services.py 2024-02-04 18:08:31 +01:00
a94e7eef02 Merge pull request #46 from jayofelony/dev
Dev to master
2024-02-04 18:04:44 +01:00
1cefae55d1 moved the majority of logging to debug 2024-02-04 17:48:22 +01:00
c5ee1df855 unused function 2024-02-04 17:44:05 +01:00
d142840307 Revert "Testing pcapng fileformat"
This reverts commit 7040be2d30.
2024-02-04 17:42:56 +01:00
e558146e28 moves the majority of logging to debug 2024-02-04 17:42:40 +01:00
11a3330153 small fix 2024-02-04 17:42:22 +01:00
53b2dd8628 update build for latest kernel 2024-02-04 17:42:10 +01:00
6381f9443b remove blind bug, as its not a blind bug anymore. 2024-02-04 17:41:57 +01:00
fa7e87b974 remove blind bug, as its not a blind bug anymore.
delayed hopping channels by .2 seconds to give firmware time to get ready for hopping.
2024-02-04 17:41:41 +01:00
cca2ff2da4 Merge pull request #45 from wpa-2/patch-1
MOTD updated
2024-02-03 17:09:03 +01:00
78415b3137 Update 01-motd
Maybe a good idea to point people to the new wiki instead. 


Signed-off-by: wpa-2 <9049886+wpa-2@users.noreply.github.com>
2024-02-03 15:13:44 +00:00
34284aa1bc Change to seemoo-lab nexmon 2024-02-01 13:50:51 +01:00
56ebb60662 Change to seemoo-lab nexmon 2024-02-01 13:26:20 +01:00
84f6624844 Change to seemoo-lab nexmon 2024-02-01 13:04:06 +01:00
3bcbb0ce9a Version 2.8.1 2024-01-29 22:52:16 +01:00
e01e457992 Remove bettercap client settings, so you cannot mess it up. 2024-01-29 22:24:20 +01:00
1780859889 Merge pull request #37 from Ravioli5/patch-1
Update 01-motd
2024-01-29 16:15:12 +01:00
fdd98bb37a Update 01-motd
-fixed grammar (added a word)

Signed-off-by: Ravioli5 <157115073+Ravioli5@users.noreply.github.com>
2024-01-29 13:33:47 +05:30
86991304a5 Merge remote-tracking branch 'origin/dev' into dev 2024-01-28 22:12:20 +01:00
4f62759d6d Revert grid name 2024-01-28 22:12:06 +01:00
7b7ba02aad Changed setup.py 2024-01-28 22:12:06 +01:00
7040be2d30 Testing pcapng fileformat 2024-01-28 22:12:05 +01:00
d0617ccfaf Revert grid name 2024-01-28 22:08:17 +01:00
a0b5078b64 Changed setup.py 2024-01-28 22:05:14 +01:00
54c1ffd63c Updated wiglewifi version to 1.6 2024-01-28 22:02:57 +01:00
7530709d0c Updated wiglewifi version to 1.6 2024-01-28 21:46:50 +01:00
a9a6fd424b Small changes/fixes for debugging 2024-01-28 21:46:22 +01:00
8c97301992 Readability changes for webgpsmap.py 2024-01-28 21:45:53 +01:00
91eaa22188 Fix for waveshare2in13b_V4.py implementation 2024-01-28 21:44:19 +01:00
31a4af4c21 sudo pwnagotchi plugins update
`sudo pwnagotchi plugins list`

Do not work, somehow I forgot to remove a test I did.
2024-01-28 21:44:04 +01:00
dceeaff1fb Next update will be 2.8.0 2024-01-28 21:43:17 +01:00
c0241dc8df Update README.md 2024-01-27 16:11:59 +01:00
8f405f4ab2 Merge pull request #35 from Kal-Toh/patch-1
Update README.md
2024-01-27 16:11:19 +01:00
bd79e71563 Update README.md
This is a small change to address questions I had about the installation process.

Signed-off-by: Rory <104321806+Kal-Toh@users.noreply.github.com>
2024-01-27 14:03:40 +00:00
7f662585aa Merge pull request #34 from findingmoist/master
Update 01-motd
2024-01-27 10:03:24 +01:00
d23ff8d47a Update 01-motd
* Changed face so it shows
* updated python3 version so $_version shows the update number

Signed-off-by: findingmoist <128169791+findingmoist@users.noreply.github.com>
2024-01-26 18:56:40 -05:00
04435229fe Update build for RPi5 2024-01-26 15:28:04 +01:00
42e236bafe Update build for RPi5 2024-01-26 10:45:18 +01:00
5081b72695 Merge remote-tracking branch 'origin/master' 2024-01-25 23:48:49 +01:00
652740f050 Version 2.7.9
Add Esperanzo language
Updated Pt-Br language
Updated Italian language
2024-01-25 23:48:41 +01:00
1b6b12bdf5 Add Esperanzo language
Updated Pt-Br language
Updated Italian language
2024-01-25 23:48:06 +01:00
c610335a34 Add Esperanzo language
Edited Pt-Br language
2024-01-25 22:23:01 +01:00
6c39ed97dd Update build for Pi 5 users
Version 2.7.8
2024-01-25 21:38:04 +01:00
967f1663c6 Update build for Pi 5 users
Version 2.7.8
2024-01-25 17:51:15 +01:00
ffe1e90ccd Update build for Pi 5 users
Version 2.7.8
2024-01-25 17:49:17 +01:00
f2d2bcbfdf Update build for Pi 5 users
Version 2.7.8
2024-01-25 17:30:15 +01:00
bfc0795fb8 Update build for Pi 5 users
Version 2.7.8
2024-01-25 16:31:35 +01:00
1a55afd74a Update build for Pi 5 users
Version 2.7.8
2024-01-25 15:16:33 +01:00
1594e7c129 Update build for Pi 5 users
Version 2.7.8
2024-01-24 15:51:09 +01:00
a244e70a1c Update build for Pi 5 users
Version 2.7.8
2024-01-24 11:00:32 +01:00
d35d5d6c3c Update build for Pi 5 users
Version 2.7.8
2024-01-24 10:51:02 +01:00
7aacf9fb44 Update build for Pi 5 users
Version 2.7.8
2024-01-24 10:24:01 +01:00
dde6fa4c2a Update build for Pi 5 users 2024-01-24 01:47:23 +01:00
7dfb2f2ff6 Update build for Pi 5 users 2024-01-23 14:56:34 +01:00
cf46ab3da9 Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 14:47:06 +01:00
6824e541a4 Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 14:40:41 +01:00
1c4e8fa750 Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 14:36:46 +01:00
a50ec4a65c Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 14:35:12 +01:00
5414fdf21d Removed hashie interval and deprecated functions of hcxpcapngtool. 2024-01-23 13:29:31 +01:00
c9883bb4f9 Add hcxtools to apt_packages.txt 2024-01-23 12:27:59 +01:00
045f5853bc Test 2024-01-23 12:26:33 +01:00
6dfcaf05d5 Hashie enabled by default 2024-01-23 12:26:00 +01:00
e2f8119d2c Install apt-packages while installing pwnagotchi, if needed 2024-01-23 12:22:30 +01:00
d675b3d0dd Added hcxtools as installed package. 2024-01-23 11:46:50 +01:00
30850b6530 Added hcxtools as installed package. 2024-01-23 11:42:47 +01:00
1e9c9bae42 Added hcxtools as installed package. 2024-01-23 11:38:14 +01:00
64241515ad Added hashie to default plugins, to convert pcaps to a crackable format from the start. 2024-01-23 11:37:34 +01:00
c9f232dae2 Added hashie to default plugins, to convert pcaps to a crackable format from the start. 2024-01-23 11:37:23 +01:00
4f97bcaa83 Moved aircrackonly to default plugins, is also enabled by default. To immediately delete empty handshakes. 2024-01-23 11:25:04 +01:00
7d2a03c79f Changing behaviour when mon_max_blind_epochs is hit, from full reboot to simple restart to save uptime. 2024-01-23 11:13:23 +01:00
f89ba85f73 Couple updated displays from Waveshare, not 213g.
166c012cde
2024-01-23 10:59:25 +01:00
57f03f4359 Removed paw-gps.py, as it is no longer supported. 2024-01-22 23:56:13 +01:00
9bc266f9ff Make wigle, wpa-sec, onlinehashcrack and grid plugins check against main.whitelist instead of their own whitelist. Possibly reduces possibility of errors in config.
https://github.com/jayofelony/pwnagotchi-bookworm/issues/24
2024-01-22 23:29:43 +01:00
b0db0285bc Version 2.7.7 2024-01-22 23:12:59 +01:00
cca3e77d50 Version 2.7.6 2024-01-22 14:25:16 +01:00
4fe603bf5e Small edit to net-pos.py 2024-01-22 12:35:21 +01:00
9a9ee70a78 Fixed wigle plugin 2024-01-22 12:06:20 +01:00
7fc8838f76 2.7.5 2024-01-21 11:43:58 +01:00
94b2ff7047 2.7.5 2024-01-21 11:40:27 +01:00
8edb0fdaa4 2.7.5 2024-01-21 11:33:22 +01:00
b557768159 Fix gdrivesync.py 2024-01-21 11:32:39 +01:00
5a6967eb4d Fix gdrivesync.py 2024-01-21 11:14:17 +01:00
c0c35231cf Fix gdrivesync.py 2024-01-21 11:13:51 +01:00
88362b3354 Version 2.7.4 2024-01-21 00:00:45 +01:00
e50cf04967 Moved self._display = None to base.py for easier debugging display files.
Fixed waveshare2in13g.py
2024-01-20 23:54:32 +01:00
85a64a3914 Merge pull request #23 from Opalinus/master
Repair broken Waveshare213g #22
2024-01-20 23:27:02 +01:00
63d0c20a3e Repair broken Waveshare213g 2024-01-20 20:16:01 +01:00
044639a6d4 Fix 2.7V2 display 2024-01-20 10:23:50 +01:00
7fc2c6b25f Update README.md 2024-01-19 12:25:08 +01:00
c5d5d9bb14 Changed Makefile 2024-01-19 09:04:08 +01:00
129ae92447 Version 2.7.3 2024-01-19 08:51:56 +01:00
2560692ee2 Fixed a mistake on display loading 2024-01-19 08:50:16 +01:00
1424e0d510 Added display waveshare2in66b 2024-01-19 08:43:00 +01:00
2c9eaa436a Added display waveshare2in13g 2024-01-19 08:34:41 +01:00
0c5c6058a5 Added display waveshare2in13g 2024-01-19 07:28:31 +01:00
a3fb39d78c Update README.md 2024-01-18 23:36:25 +01:00
bac62bc4aa Fix for pwnlib 2024-01-17 23:17:48 +01:00
f7a5f2a554 Update build 2024-01-17 21:55:27 +01:00
6921fd14a3 Update Makefile 2024-01-17 20:46:03 +01:00
0dbd611ed5 zramswap 2024-01-17 20:42:28 +01:00
18b9093f70 Version 2.7.2 2024-01-17 20:11:38 +01:00
26913016b9 Changed from dphys-swapfile to zram-tools
Fix on auto-update.py
2024-01-17 19:55:07 +01:00
0786b6757e Changed from dphys-swapfile to zram-tools
Fix on auto-update.py
2024-01-17 19:53:36 +01:00
0f4eda8039 Changed from ext4 to f2fs
Changed from dphys-swapfile to zram-tools
Fix on auto-update.py
2024-01-17 19:51:38 +01:00
1672a35f09 Changed MAC check for whitelist upto last 2 characters. 2024-01-17 18:28:53 +01:00
80e7e6c550 Changed MAC check for whitelist upto last 2 characters. 2024-01-17 18:26:45 +01:00
ca274036ab Version 2.7.1 2024-01-17 18:23:15 +01:00
649e8a4222 Small fixes 2024-01-17 18:22:57 +01:00
63f0a761c1 Added a skip for hostnames/mac addresses on whitelist 2024-01-17 18:22:42 +01:00
8a64918b55 Added Hebrew language 2024-01-16 10:45:47 +01:00
c27cc0ac24 Added 38 waveshare displays or so
Layouts may not be correct, but I have no way of testing that.
2024-01-15 22:46:18 +01:00
c9bdce0ea3 Add Pt-Br language 2024-01-15 20:45:37 +01:00
6422371346 Version 2.7.0 2024-01-15 14:55:26 +01:00
3c5a95e0b8 Version 2.7.0 2024-01-15 14:55:15 +01:00
18217119fc Version 2.6.9 2024-01-14 09:41:39 +01:00
237 changed files with 8682 additions and 5534 deletions

1
.github/FUNDING.yml vendored
View File

@ -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
View 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@v2
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
View File

@ -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
View File

@ -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
View File

@ -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">

View File

@ -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,24 @@ 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 export LC_ALL=en_GB.UTF-8
python3 setup.py sdist 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
# Building the image requires packer, but don't rebuild the image just because packer updated. bullseye: clean packer
pwnagotchi: | $(PACKER) export LC_ALL=en_GB.UTF-8
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) export LC_ALL=en_GB.UTF-8
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
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 sudo pishrink -vaZ pwnagotchi-64bit.img
.PHONY: image
image: pwnagotchi
clean: clean:
- rm -rf build dist pwnagotchi.egg-info - rm -rf /tmp/packer*
- rm -f $(PACKER)

View File

@ -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)

View File

@ -7,6 +7,7 @@ import sys
import toml import toml
import requests import requests
import os import os
import re
import pwnagotchi import pwnagotchi
from pwnagotchi import utils from pwnagotchi import utils
@ -59,6 +60,7 @@ def pwnagotchi_cli():
channels = agent.get_access_points_by_channel() channels = agent.get_access_points_by_channel()
# for each channel # for each channel
for ch, aps in channels: for ch, aps in channels:
time.sleep(0.2)
agent.set_channel(ch) agent.set_channel(ch)
if not agent.is_stale() and agent.any_activity(): if not agent.is_stale() and agent.any_activity():
@ -87,10 +89,8 @@ 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:
@ -132,6 +132,8 @@ def pwnagotchi_cli():
help="Print the configuration.") help="Print the configuration.")
# Jayofelony added these # Jayofelony added these
parser.add_argument('--wizard', dest="wizard", action="store_true", default=False,
help="Interactive installation of your personal configuration.")
parser.add_argument('--check-update', dest="check_update", action="store_true", default=False, parser.add_argument('--check-update', dest="check_update", action="store_true", default=False,
help="Check for updates on Pwnagotchi. And tells current version.") help="Check for updates on Pwnagotchi. And tells current version.")
parser.add_argument('--donate', dest="donate", action="store_true", default=False, parser.add_argument('--donate', dest="donate", action="store_true", default=False,
@ -156,23 +158,134 @@ def pwnagotchi_cli():
print(pwnagotchi.__version__) print(pwnagotchi.__version__)
sys.exit(0) sys.exit(0)
if args.wizard:
def is_valid_hostname(hostname):
if len(hostname) > 255:
return False
if hostname[-1] == ".":
hostname = hostname[:-1] # strip exactly one dot from the right, if present
allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
return all(allowed.match(x) for x in hostname.split("."))
pwn_restore = input("Do you want to restore the previous configuration?\n\n"
"[Y/N]: ")
if pwn_restore in ('y', 'yes'):
os.system("cp -f /etc/pwnagotchi/config.toml.bak /etc/pwnagotchi/config.toml")
print("Your previous configuration is restored, and I will restart in 5 seconds.")
time.sleep(5)
os.system("service pwnagotchi restart")
else:
pwn_check = input("This will create a new configuration file and overwrite your current backup, are you sure?\n\n"
"[Y/N]: ")
if pwn_check.lower() in ('y', 'yes'):
os.system("mv -f /etc/pwnagotchi/config.toml /etc/pwnagotchi/config.toml.bak")
with open("/etc/pwnagotchi/config.toml", "a+") as f:
f.write("# Do not edit this file if you do not know what you are doing!!!\n\n")
# Set pwnagotchi name
print("Welcome to the interactive installation of your personal Pwnagotchi configuration!\n"
"My name is Jayofelony, how may I call you?\n\n")
pwn_name = input("Pwnagotchi name (no spaces): ")
if pwn_name == "":
pwn_name = "Pwnagotchi"
print("I shall go by Pwnagotchi from now on!")
pwn_name = f"main.name = \"{pwn_name}\"\n"
f.write(pwn_name)
else:
if is_valid_hostname(pwn_name):
print(f"I shall go by {pwn_name} from now on!")
pwn_name = f"main.name = \"{pwn_name}\"\n"
f.write(pwn_name)
else:
print("You have chosen an invalid name. Please start over.")
exit()
pwn_whitelist = input("How many networks do you want to whitelist? "
"We will also ask a MAC for each network?\n"
"Each SSID and BSSID count as 1 network. \n\n"
"Be sure to use digits as your answer.\n\n"
"Amount of networks: ")
if int(pwn_whitelist) > 0:
f.write("main.whitelist = [\n")
for x in range(int(pwn_whitelist)):
ssid = input("SSID (Name): ")
bssid = input("BSSID (MAC): ")
f.write(f"\t\"{ssid}\",\n")
f.write(f"\t\"{bssid}\",\n")
f.write("]\n")
# set bluetooth tether
pwn_bluetooth = input("Do you want to enable BT-Tether?\n\n"
"[Y/N] ")
if pwn_bluetooth.lower() in ('y', 'yes'):
f.write("main.plugins.bt-tether.enabled = true\n\n")
pwn_bluetooth_device = input("What device do you use? Android or iOS?\n\n"
"Device: ")
if pwn_bluetooth_device.lower() == "android":
f.write("main.plugins.bt-tether.devices.android-phone.enabled = true\n")
pwn_bluetooth_mac = input("What is the bluetooth MAC of your device?\n\n"
"MAC: ")
if pwn_bluetooth_mac != "":
f.write(f"main.plugins.bt-tether.devices.android-phone.mac = \"{pwn_bluetooth_mac}\"\n")
elif pwn_bluetooth_device.lower() == "ios":
f.write("main.plugins.bt-tether.devices.ios-phone.enabled = true\n")
pwn_bluetooth_mac = input("What is the bluetooth MAC of your device?\n\n"
"MAC: ")
if pwn_bluetooth_mac != "":
f.write(f"main.plugins.bt-tether.devices.ios-phone.mac = \"{pwn_bluetooth_mac}\"\n")
# set up display settings
pwn_display_enabled = input("Do you want to enable a display?\n\n"
"[Y/N]: ")
if pwn_display_enabled.lower() in ('y', 'yes'):
f.write("ui.display.enabled = true\n")
pwn_display_type = input("What display do you use?\n\n"
"Be sure to check for the correct display type @ \n"
"https://github.com/jayofelony/pwnagotchi/blob/master/pwnagotchi/utils.py#L240-L431\n\n"
"Display type: ")
if pwn_display_type != "":
f.write(f"ui.display.type = \"{pwn_display_type}\"\n")
pwn_display_invert = input("Do you want to invert the display colors?\n"
"N = Black background\n"
"Y = White background\n\n"
"[Y/N]: ")
if pwn_display_invert.lower() in ('y', 'yes'):
f.write("ui.invert = true\n")
f.close()
if pwn_bluetooth.lower() in ('y', 'yes'):
if pwn_bluetooth_device.lower == "android":
print("To visit the webui when connected with your phone, visit: http://192.168.44.44:8080\n"
"Your configuration is done, and I will restart in 5 seconds.")
elif pwn_bluetooth_device.lower == "ios":
print("To visit the webui when connected with your phone, visit: http://172.20.10.6:8080\n"
"Your configuration is done, and I will restart in 5 seconds.")
else:
print("Your configuration is done, and I will restart in 5 seconds.")
time.sleep(5)
os.system("service pwnagotchi restart")
else:
print("Ok, doing nothing.")
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', '')
local = version_to_tuple(pwnagotchi.__version__) local = version_to_tuple(pwnagotchi.__version__)
remote = version_to_tuple(latest_ver) remote = version_to_tuple(latest_ver)
if remote > local: if remote > local:
user_input = input("There is a new version available! Update from v%s to v%s?\n[y(es)/n(o)]" user_input = input("There is a new version available! Update from v%s to v%s?\n[Y/N] "
% (pwnagotchi.__version__, latest_ver)) % (pwnagotchi.__version__, latest_ver))
# input validation # input validation
if user_input.lower() in ('y', 'yes'): if user_input.lower() in ('y', 'yes'):
os.system("rm /root/.auto-update && systemctl restart pwnagotchi") if os.path.exists('/root/.auto-update'):
os.system("rm /root/.auto-update && systemctl restart pwnagotchi")
else:
logging.error("You should make sure auto-update is enabled!")
print("Okay, give me a couple minutes. Just watch pwnlog while you wait.") 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 elif user_input.lower() in ('n', 'no'): # using this elif for readability
print("Okay, guess not!") print("Okay, guess not!")
@ -221,6 +334,5 @@ def pwnagotchi_cli():
else: else:
do_auto_mode(agent) do_auto_mode(agent)
if __name__ == '__main__': if __name__ == '__main__':
pwnagotchi_cli() pwnagotchi_cli()

View 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.com/raspios_lite_arm64/images/raspios_lite_arm64-2024-03-15/2024-03-15-raspios-bookworm-arm64-lite.img.xz.sha256"
file_urls = ["https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2024-03-15/2024-03-15-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-2024-03-12/2024-03-12-raspios-bullseye-armhf-lite.img.xz.sha256"
file_urls = ["https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2024-03-12/2024-03-12-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"
}
}

View File

@ -0,0 +1,63 @@
# For more options and information see
# http://rptl.io/configtxt
# Some settings may impact device functionality. See link above for details
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
# Additional overlays and parameters are documented
# /boot/overlays/README
# Automatically load overlays for detected cameras
camera_auto_detect=1
# Automatically load overlays for detected DSI displays
display_auto_detect=1
# Automatically load initramfs files, if found
auto_initramfs=1
# Enable DRM VC4 V3D driver
dtoverlay=vc4-kms-v3d
max_framebuffers=2
# Don't have the firmware create an initial video= setting in cmdline.txt.
# Use the kernel's default instead.
disable_fw_kms_setup=1
# Run in 64-bit mode
arm_64bit=0
# Disable compensation for displays with overscan
disable_overscan=1
# Run as fast as firmware / board allows
arm_boost=1
[cm4]
# Enable host mode on the 2711 built-in XHCI USB controller.
# This line should be removed if the legacy DWC2 controller is required
# (e.g. for USB device mode) or if USB support is not required.
otg_mode=1
[all]
dtoverlay=dwc2
dtparam=i2c1=on
dtparam=i2c_arm=on
dtparam=spi=on
gpu_mem=1
dtoverlay=dwc2
[pi0]
dtoverlay=spi1-3cs
[pi3]
dtoverlay=spi1-3cs
[pi4]
dtoverlay=spi1-3cs

View 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

View File

@ -0,0 +1,6 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.
i2c-dev

View File

@ -0,0 +1,16 @@
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
timedatectl set-ntp true
exit 0

View 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

View File

@ -0,0 +1,6 @@
[Unit]
After=hciuart.service bluetooth.service
Before=
[Service]
ExecStartPre=/bin/sleep 5

View File

@ -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

View 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 }}"

View 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-2024-03-12/2024-03-12-raspios-bullseye-armhf-lite.img.xz.sha256"
file_urls = ["https://downloads.raspberrypi.com/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2024-03-12/2024-03-12-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"
}
}

View File

@ -0,0 +1,565 @@
---
- 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"
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
- ntp
- 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: remove current rc.local
file:
path: /etc/rc.local
state: absent
- 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
alias custom='cd /usr/local/share/pwnagotchi/custom-plugins/'
alias config='sudo nano /etc/pwnagotchi/config.toml'
alias pwnlog='tail -f -n300 /etc/pwnagotchi/log/pwn*.log | sed --unbuffered "s/,[[:digit:]]\\{3\\}\\]//g" | cut -d " " -f 2-'
alias pwnver='python3 -c "import pwnagotchi as p; print(p.__version__)"'
alias pwnkill='sudo killall -USR1 pwnagotchi'
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_4"
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: 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 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

View File

@ -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

View 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()

View File

@ -11,6 +11,7 @@ fi
if is_auto_mode; then if is_auto_mode; then
/usr/local/bin/pwnagotchi /usr/local/bin/pwnagotchi
systemctl restart bettercap
else else
/usr/local/bin/pwnagotchi --manual /usr/local/bin/pwnagotchi --manual
fi fi

View File

@ -1,18 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# well ... it blinks the led
blink_led() {
# shellcheck disable=SC2034
for i in $(seq 1 "$1"); do
echo 0 >/sys/class/leds/led0/brightness
sleep 0.3
echo 1 >/sys/class/leds/led0/brightness
sleep 0.3
done
echo 0 >/sys/class/leds/led0/brightness
sleep 0.3
}
# check if brcm is stuck # check if brcm is stuck
check_brcm() { check_brcm() {
if [[ "$(journalctl -n10 -k --since -5m | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 5 ]]; then if [[ "$(journalctl -n10 -k --since -5m | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 5 ]]; then
@ -39,10 +26,8 @@ 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

View File

@ -0,0 +1,65 @@
# For more options and information see
# http://rptl.io/configtxt
# Some settings may impact device functionality. See link above for details
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
# Additional overlays and parameters are documented
# /boot/firmware/overlays/README
# Automatically load overlays for detected cameras
camera_auto_detect=1
# Automatically load overlays for detected DSI displays
display_auto_detect=1
# Automatically load initramfs files, if found
auto_initramfs=1
# Enable DRM VC4 V3D driver
dtoverlay=vc4-kms-v3d
max_framebuffers=2
# Don't have the firmware create an initial video= setting in cmdline.txt.
# Use the kernel's default instead.
disable_fw_kms_setup=1
# Run in 64-bit mode
arm_64bit=1
# Disable compensation for displays with overscan
disable_overscan=1
# Run as fast as firmware / board allows
arm_boost=1
[cm4]
# Enable host mode on the 2711 built-in XHCI USB controller.
# This line should be removed if the legacy DWC2 controller is required
# (e.g. for USB device mode) or if USB support is not required.
otg_mode=1
[all]
dtparam=i2c1=on
dtparam=i2c_arm=on
dtparam=spi=on
gpu_mem=1
dtoverlay=dwc2
[pi0]
dtoverlay=spi0-0cs
[pi3]
dtoverlay=spi0-0cs
[pi4]
dtoverlay=spi0-0cs
[pi5]
dtoverlay=spi0-0cs

View File

@ -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 --wizard --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

View 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

View File

@ -0,0 +1,6 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.
i2c-dev

View File

@ -5,4 +5,4 @@ iface usb0 inet static
network 10.0.0.0 network 10.0.0.0
broadcast 10.0.0.255 broadcast 10.0.0.255
gateway 10.0.0.1 gateway 10.0.0.1
metric 101 metric 101

View File

@ -0,0 +1,16 @@
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
timedatectl set-ntp true
exit 0

View 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

View 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

View 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

View 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

View File

@ -0,0 +1,34 @@
#!/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 --wizard, to help set up a config.toml"
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/"

View File

@ -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"
} }
} }
} }
@ -22,14 +20,14 @@ variable "pwn_version" {
} }
source "arm" "rpi64-pwnagotchi" { 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_checksum_url = "https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2024-03-15/2024-03-15-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_urls = ["https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2024-03-15/2024-03-15-raspios-bookworm-arm64-lite.img.xz"]
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"
} }
} }

View File

@ -5,25 +5,15 @@
become: true become: true
vars: vars:
kernel: kernel:
min: "6.1" min: "6.6"
full: "6.1.0-rpi7-rpi-v8" full: "6.6.20+rpt-rpi-v8"
full_pi5: "6.6.20+rpt-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:
boot_options:
- "dtoverlay=dwc2"
- "dtoverlay=spi1-3cs"
- "dtparam=i2c1=on"
- "dtparam=i2c_arm=on"
- "dtparam=spi=on"
- "gpu_mem=16"
modules:
- "i2c-dev"
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 +22,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 +41,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 +69,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 +83,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 +93,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 +120,31 @@
- 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 - ntp
- 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 +161,55 @@
- 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
- name: update pip3, setuptools, wheel
shell: "python3 -m pip install --upgrade pip setuptools wheel --break-system-packages"
args:
executable: /bin/bash
chdir: /usr/local/src
# 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: remove current rc.local
file:
path: /etc/rc.local
state: absent
- 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 +227,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 +235,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 +268,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 +390,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 +431,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 +454,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
@ -371,6 +486,11 @@
block: | block: |
export GOPATH=$HOME/go export GOPATH=$HOME/go
export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin
alias custom='cd /usr/local/share/pwnagotchi/custom-plugins/'
alias config='sudo nano /etc/pwnagotchi/config.toml'
alias pwnlog='tail -f -n300 /etc/pwnagotchi/log/pwn*.log | sed --unbuffered "s/,[[:digit:]]\\{3\\}\\]//g" | cut -d " " -f 2-'
alias pwnver='python3 -c "import pwnagotchi as p; print(p.__version__)"'
alias pwnkill='sudo killall -USR1 pwnagotchi'
when: golang.changed when: golang.changed
- name: download pwngrid - name: download pwngrid
@ -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
@ -464,7 +579,7 @@
# Add your configuration overrides on this file any configuration changes done to default.toml will be lost! # Add your configuration overrides on this file any configuration changes done to default.toml will be lost!
# Example: # Example:
# ui.display.enabled = true # ui.display.enabled = true
# ui.display.type = "waveshare_2" # ui.display.type = "waveshare_4"
when: not user_config.stat.exists when: not user_config.stat.exists
- name: Delete motd - name: Delete motd
@ -477,59 +592,6 @@
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
lineinfile:
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-'"
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 - name: add firmware packages to hold
dpkg_selections: dpkg_selections:
name: "{{ item }}" name: "{{ item }}"
@ -563,18 +625,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 +645,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 +657,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:

View 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

View 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

View File

@ -0,0 +1,2 @@
#!/usr/bin/env bash
sudo /usr/bin/tvservice -o

View File

@ -0,0 +1,2 @@
#!/usr/bin/env bash
sudo /usr/bin/tvservice -p

View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
source /usr/bin/pwnlib
start_monitor_interface

View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
source /usr/bin/pwnlib
stop_monitor_interface

View File

@ -0,0 +1,17 @@
#!/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
systemctl restart bettercap
else
/usr/local/bin/pwnagotchi --manual
fi

178
builder/data/64bit/usr/bin/pwnlib Executable file
View File

@ -0,0 +1,178 @@
#!/usr/bin/env bash
# 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
sleep 3
iw dev wlan0 set power_save off
iw phy "$(iw phy | head -1 | cut -d" " -f2)" interface add wlan0mon type monitor
sleep 2
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 specified 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
}

View File

@ -1 +1 @@
__version__ = '2.6.8' __version__ = '2.8.7.2'

View File

@ -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,13 +179,12 @@ 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'] not in whitelist \ elif ap['hostname'] in whitelist or ap['mac'][:13].lower() in whitelist or ap['mac'].lower() in whitelist:
and ap['mac'].lower() not in whitelist \ continue
and ap['mac'][:8].lower() not in whitelist: else:
if self._filter_included(ap): aps.append(ap)
aps.append(ap)
except Exception as e: except Exception as e:
logging.exception("Error while getting acces points (%s)", e) logging.exception("Error while getting access points (%s)", e)
aps.sort(key=lambda ap: ap['channel']) aps.sort(key=lambda ap: ap['channel'])
return self.set_access_points(aps) return self.set_access_points(aps)
@ -275,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:
@ -427,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']

View File

@ -23,6 +23,12 @@ def load(config, agent, epoch, from_disk=True):
from stable_baselines3 import A2C from stable_baselines3 import A2C
logging.debug("[AI] A2C imported in %.2fs" % (time.time() - start)) logging.debug("[AI] A2C imported in %.2fs" % (time.time() - start))
# remove invalid ai.parameters leftover from tensor_flow, if present
for key in [ 'alpha', 'epsilon', 'lr_schedule' ]:
if key in config['params']:
logging.info("Removing legacy ai parameter %s" % key);
del config['params'][key]
start = time.time() start = time.time()
from stable_baselines3.a2c import MlpPolicy from stable_baselines3.a2c import MlpPolicy
logging.debug("[AI] MlpPolicy imported in %.2fs" % (time.time() - start)) logging.debug("[AI] MlpPolicy imported in %.2fs" % (time.time() - start))
@ -59,7 +65,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")

View File

@ -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

View File

@ -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",
@ -26,7 +32,7 @@ main.plugins.bt-tether.devices.android-phone.netmask = 24
main.plugins.bt-tether.devices.android-phone.interval = 1 main.plugins.bt-tether.devices.android-phone.interval = 1
main.plugins.bt-tether.devices.android-phone.scantime = 10 main.plugins.bt-tether.devices.android-phone.scantime = 10
main.plugins.bt-tether.devices.android-phone.max_tries = 10 main.plugins.bt-tether.devices.android-phone.max_tries = 10
main.plugins.bt-tether.devices.android-phone.share_internet = false main.plugins.bt-tether.devices.android-phone.share_internet = true
main.plugins.bt-tether.devices.android-phone.priority = 1 main.plugins.bt-tether.devices.android-phone.priority = 1
main.plugins.bt-tether.devices.ios-phone.enabled = false main.plugins.bt-tether.devices.ios-phone.enabled = false
@ -37,7 +43,7 @@ main.plugins.bt-tether.devices.ios-phone.netmask = 24
main.plugins.bt-tether.devices.ios-phone.interval = 5 main.plugins.bt-tether.devices.ios-phone.interval = 5
main.plugins.bt-tether.devices.ios-phone.scantime = 20 main.plugins.bt-tether.devices.ios-phone.scantime = 20
main.plugins.bt-tether.devices.ios-phone.max_tries = 0 main.plugins.bt-tether.devices.ios-phone.max_tries = 0
main.plugins.bt-tether.devices.ios-phone.share_internet = false main.plugins.bt-tether.devices.ios-phone.share_internet = true
main.plugins.bt-tether.devices.ios-phone.priority = 999 main.plugins.bt-tether.devices.ios-phone.priority = 999
main.plugins.fix_services.enabled = true main.plugins.fix_services.enabled = true
@ -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,10 @@ 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.invert = false # false = black background, true = white background
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 +185,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 +201,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 +219,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

View File

@ -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],

View File

@ -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"

View File

@ -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} ..."

View File

@ -10,7 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-16 21:51+0100\n" "POT-Creation-Date: 2023-11-16 21:51+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: neo0oen \n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: Hebrew\n" "Language: Hebrew\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -18,240 +18,242 @@ 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 "שלום, אני פוונגוטצ'י! מתחיל . . ."
msgid "New day, new hunt, new pwns!" msgid "New day, new hunt, new pwns!"
msgstr "" msgstr "יום חדש, ציד חדש, ניצחונות חדשים !"
msgid "Hack the Planet!" msgid "Hack the Planet!"
msgstr "" msgstr "פרוץ לכדור הארץ !"
msgid "AI ready." msgid "AI ready."
msgstr "" msgstr "הבינה המלאחות'ית מוכנה"
msgid "The neural network is ready." msgid "The neural network is ready."
msgstr "" msgstr "הרשת הניורולוגית העצבית מוכנה."
msgid "Generating keys, do not turn off ..." msgid "Generating keys, do not turn off ..."
msgstr "" msgstr "יוצר מפתחות, בבקשה אל תכבה אותי"
#, 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 "היי , הערוץ {channel}פנוי ,נקודת הגישה שלך אומרת תודה "
msgid "Reading last session logs ..." msgid "Reading last session logs ..."
msgstr "" msgstr ". . . קורא לוגים מאז ההפעלה האחרונה"
#, 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 "קראתי {lines_so_far} שורות מהלוג עד עכשיו . . ."
msgid "I'm bored ..." msgid "I'm bored ..."
msgstr "" msgstr "אני משועמם . . ."
msgid "Let's go for a walk!" msgid "Let's go for a walk!"
msgstr "" msgstr "בוא ניצא לטיול! "
msgid "This is the best day of my life!" msgid "This is the best day of my life!"
msgstr "" msgstr "זה היום הכי טוב בחיי!"
msgid "Shitty day :/" msgid "Shitty day :/"
msgstr "" msgstr "יום מחורבן :/"
msgid "I'm extremely bored ..." msgid "I'm extremely bored ..."
msgstr "" msgstr "אני משועמם בטירוף . . ."
msgid "I'm very sad ..." msgid "I'm very sad ..."
msgstr "" msgstr "אני עצוב נורא . . ."
msgid "I'm sad" msgid "I'm sad"
msgstr "" msgstr "אני עצוב"
msgid "Leave me alone ..." msgid "Leave me alone ..."
msgstr "" msgstr "עזוב אותי בשקט . . ."
msgid "I'm mad at you!" msgid "I'm mad at you!"
msgstr "" msgstr "אני כועס עלייך!"
msgid "I'm living the life!" msgid "I'm living the life!"
msgstr "" msgstr "אני חי את החיים!"
msgid "I pwn therefore I am." msgid "I pwn therefore I am."
msgstr "" msgstr "אני שולט לכן אני כאן."
msgid "So many networks!!!" msgid "So many networks!!!"
msgstr "" msgstr "כל כך הרבה רשתות! ! !"
msgid "I'm having so much fun!" msgid "I'm having so much fun!"
msgstr "" msgstr "אני כל כך נהנה ועושה הרבה כיף!"
msgid "My crime is that of curiosity ..." msgid "My crime is that of curiosity ..."
msgstr "" msgstr "הפשע שלי הוא הסקרנות . . ."
#, python-brace-format #, python-brace-format
msgid "Hello {name}! Nice to meet you." msgid "Hello {name}! Nice to meet you."
msgstr "" msgstr "שלום {name}! נעים להכיר אותך."
#, python-brace-format #, python-brace-format
msgid "Yo {name}! Sup?" msgid "Yo {name}! Sup?"
msgstr "" msgstr "יו {name}! מה קורה?"
#, python-brace-format #, python-brace-format
msgid "Hey {name} how are you doing?" msgid "Hey {name} how are you doing?"
msgstr "" msgstr "היי {name} איך אתה מסתדר?"
#, python-brace-format #, python-brace-format
msgid "Unit {name} is nearby!" msgid "Unit {name} is nearby!"
msgstr "" msgstr "יחידה {name} בקרבת מקום!"
#, python-brace-format #, python-brace-format
msgid "Uhm ... goodbye {name}" msgid "Uhm ... goodbye {name}"
msgstr "" msgstr "אוף ... להתראות {name}"
#, python-brace-format #, python-brace-format
msgid "{name} is gone ..." msgid "{name} is gone ..."
msgstr "" msgstr "{name} נעלם ..."
#, python-brace-format #, python-brace-format
msgid "Whoops ... {name} is gone." msgid "Whoops ... {name} is gone."
msgstr "" msgstr "אופס ... {name} נעלם ."
#, python-brace-format #, python-brace-format
msgid "{name} missed!" msgid "{name} missed!"
msgstr "" msgstr "{name} התפספס!"
msgid "Missed!" msgid "Missed!"
msgstr "" msgstr "התפספס!"
msgid "Good friends are a blessing!" msgid "Good friends are a blessing!"
msgstr "" msgstr "חברים טובים זאת ברכה!"
msgid "I love my friends!" msgid "I love my friends!"
msgstr "" msgstr "אני אוהב את החברים שלי!"
msgid "Nobody wants to play with me ..." msgid "Nobody wants to play with me ..."
msgstr "" msgstr "אף אחד לא רוצה לשחק אית . . ."
msgid "I feel so alone ..." msgid "I feel so alone ..."
msgstr "" msgstr "אני מרגיש כל כך לבד . . ."
msgid "Where's everybody?!" msgid "Where's everybody?!"
msgstr "" msgstr "לאיפה כולם נעלמו?!"
#, python-brace-format #, python-brace-format
msgid "Napping for {secs}s ..." msgid "Napping for {secs}s ..."
msgstr "" msgstr "מנמנם למשך {secs}שניות ..."
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 "לילה טוב"
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 "מחכה ל {secs}שניות ..."
#, python-brace-format #, python-brace-format
msgid "Looking around ({secs}s)" msgid "Looking around ({secs}s)"
msgstr "" msgstr "מסתכל מסביב ({secs}שניות)"
#, python-brace-format #, python-brace-format
msgid "Hey {what} let's be friends!" msgid "Hey {what} let's be friends!"
msgstr "" msgstr "היי {what} בוא נהיה חברים!"
#, python-brace-format #, python-brace-format
msgid "Associating to {what}" msgid "Associating to {what}"
msgstr "" msgstr "מקשר את עצמי אל {what}"
#, python-brace-format #, python-brace-format
msgid "Yo {what}!" msgid "Yo {what}!"
msgstr "" msgstr "יו יו {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 "בדיוק החלטתי ש {mac} לא צריך חיבור אלחוטי"
#, python-brace-format #, python-brace-format
msgid "Deauthenticating {mac}" msgid "Deauthenticating {mac}"
msgstr "" msgstr "מסכל את האימות של {mac}"
#, python-brace-format #, python-brace-format
msgid "Kickbanning {mac}!" msgid "Kickbanning {mac}!"
msgstr "" msgstr "מוציא איסור על/מעיף {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 "מגניב!, הצלחנו להשיג {num} לחיצות ידיים חדשות{plural}!"
#, python-brace-format #, python-brace-format
msgid "You have {count} new message{plural}!" msgid "You have {count} new message{plural}!"
msgstr "" msgstr "יש לך {count} הודעות חדשות{plural}!"
msgid "Oops, something went wrong ... Rebooting ..." msgid "Oops, something went wrong ... Rebooting ..."
msgstr "" msgstr "אופס!, משהו לא קרה כשורה ... מאתחל ..."
#, python-brace-format #, python-brace-format
msgid "Uploading data to {to} ..." msgid "Uploading data to {to} ..."
msgstr "" msgstr "מעלה נתונים ל {to} ..."
#, python-brace-format #, python-brace-format
msgid "Downloading from {name} ..." msgid "Downloading from {name} ..."
msgstr "" msgstr "מוריד נתונים מ {name} ..."
#, python-brace-format #, python-brace-format
msgid "Kicked {num} stations\n" msgid "Kicked {num} stations\n"
msgstr "" msgstr "העפתי {num} תחנות\n"
msgid "Made >999 new friends\n" msgid "Made >999 new friends\n"
msgstr "" msgstr "הכרתי >999 חברים חדשים\n"
#, python-brace-format #, python-brace-format
msgid "Made {num} new friends\n" msgid "Made {num} new friends\n"
msgstr "" msgstr "הכרתי {num} חברים חדשים\n"
#, python-brace-format #, python-brace-format
msgid "Got {num} handshakes\n" msgid "Got {num} handshakes\n"
msgstr "" msgstr "השגתי {num} לחיצות ידיים\n"
msgid "Met 1 peer" msgid "Met 1 peer"
msgstr "" msgstr "פגשתי שותף 1 "
#, python-brace-format #, python-brace-format
msgid "Met {num} peers" msgid "Met {num} peers"
msgstr "" msgstr "פגשתי {num} שותפים"
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met " "I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{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 "אני שלטתי במשך {duration} והצלחתי להעיף {deauthed} משתמשים! בדרך גם פגשתי "
"{associated} חברים חדשים ואכלתי {handshakes} לחיצות ידיים #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours" msgid "hours"
msgstr "" msgstr "שעות"
msgid "minutes" msgid "minutes"
msgstr "" msgstr "דקות"
msgid "seconds" msgid "seconds"
msgstr "" msgstr "שניות"
msgid "hour" msgid "hour"
msgstr "" msgstr "שעה"
msgid "minute" msgid "minute"
msgstr "" msgstr "דקה"
msgid "second" msgid "second"
msgstr "" msgstr "שניה"

View File

@ -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"
@ -255,4 +255,4 @@ msgid "minute"
msgstr "minuto" msgstr "minuto"
msgid "second" msgid "second"
msgstr "secondo" msgstr "secondo"

Binary file not shown.

View File

@ -10,98 +10,98 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-17 15:46+0100\n" "POT-Creation-Date: 2023-11-17 15:46+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: Foxy <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \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"
msgstr "" msgstr "ZzzzZZzzzzZzzz"
msgid "Hi, I'm Pwnagotchi! Starting ..." msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "" msgstr "Olá, Eu sou Pwnagotchi! Iniciando ..."
msgid "New day, new hunt, new pwns!" msgid "New day, new hunt, new pwns!"
msgstr "" msgstr "Um novo dia, Uma nova caça e novos pwns!"
msgid "Hack the Planet!" msgid "Hack the Planet!"
msgstr "" msgstr "Burle o Planeta!"
msgid "AI ready." msgid "AI ready."
msgstr "" msgstr "IA pronta."
msgid "The neural network is ready." msgid "The neural network is ready."
msgstr "" msgstr "A rede neural está pronta."
msgid "Generating keys, do not turn off ..." msgid "Generating keys, do not turn off ..."
msgstr "" msgstr "Criando chaves, não desligue o sistema ..."
#, 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 "Ei, canal {channel} está livre! Seu AP vai agradecer."
msgid "Reading last session logs ..." msgid "Reading last session logs ..."
msgstr "" msgstr "Lendo os logs da ultima sessão"
#, 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 "Leia {lines_so_far} linha de logs até agora ..."
msgid "I'm bored ..." msgid "I'm bored ..."
msgstr "" msgstr "Eu estou entediado ..."
msgid "Let's go for a walk!" msgid "Let's go for a walk!"
msgstr "" msgstr "Vamos ir numa caminhada!"
msgid "This is the best day of my life!" msgid "This is the best day of my life!"
msgstr "" msgstr "Esse é o melhor dia da minha vida!"
msgid "Shitty day :/" msgid "Shitty day :/"
msgstr "" msgstr "Dia ruim :/"
msgid "I'm extremely bored ..." msgid "I'm extremely bored ..."
msgstr "" msgstr "Eu estou extremamente entediado ..."
msgid "I'm very sad ..." msgid "I'm very sad ..."
msgstr "" msgstr "Eu estou muito triste ..."
msgid "I'm sad" msgid "I'm sad"
msgstr "" msgstr "Eu estou triste"
msgid "Leave me alone ..." msgid "Leave me alone ..."
msgstr "" msgstr "Me deixe em paz ..."
msgid "I'm mad at you!" msgid "I'm mad at you!"
msgstr "" msgstr "Eu estou bravo com você!"
msgid "I'm living the life!" msgid "I'm living the life!"
msgstr "" msgstr "Eu estou vivendo a vida!"
msgid "I pwn therefore I am." msgid "I pwn therefore I am."
msgstr "" msgstr "Eu pwn então Eu sou."
msgid "So many networks!!!" msgid "So many networks!!!"
msgstr "" msgstr "Tantas redes!!!"
msgid "I'm having so much fun!" msgid "I'm having so much fun!"
msgstr "" msgstr "Eu estou tendo muita diversão"
msgid "My crime is that of curiosity ..." msgid "My crime is that of curiosity ..."
msgstr "" msgstr "Meu crime é de curiosidade ..."
#, python-brace-format #, python-brace-format
msgid "Hello {name}! Nice to meet you." msgid "Hello {name}! Nice to meet you."
msgstr "" msgstr "Olá {name}! É bom em conhecê-lo"
#, python-brace-format #, python-brace-format
msgid "Yo {name}! Sup?" msgid "Yo {name}! Sup?"
msgstr "" msgstr "Ei {name}! Como vai?"
#, python-brace-format #, python-brace-format
msgid "Hey {name} how are you doing?" msgid "Hey {name} how are you doing?"
msgstr "" msgstr "Ei {name} como você está indo?"
#, python-brace-format #, python-brace-format
msgid "Unit {name} is nearby!" msgid "Unit {name} is nearby!"
@ -121,115 +121,115 @@ msgstr ""
#, python-brace-format #, python-brace-format
msgid "{name} missed!" msgid "{name} missed!"
msgstr "" msgstr "{name} errou!"
msgid "Missed!" msgid "Missed!"
msgstr "" msgstr "Errei!"
msgid "Good friends are a blessing!" msgid "Good friends are a blessing!"
msgstr "" msgstr "Bom amigos são uma bensão!"
msgid "I love my friends!" msgid "I love my friends!"
msgstr "" msgstr "Eu amo meus amigos!"
msgid "Nobody wants to play with me ..." msgid "Nobody wants to play with me ..."
msgstr "" msgstr "Ninguém quer brincar comigo ..."
msgid "I feel so alone ..." msgid "I feel so alone ..."
msgstr "" msgstr "Estou me sentindo sozinho"
msgid "Where's everybody?!" msgid "Where's everybody?!"
msgstr "" msgstr "Onde está todo mundo?!"
#, python-brace-format #, python-brace-format
msgid "Napping for {secs}s ..." msgid "Napping for {secs}s ..."
msgstr "" msgstr "Tirando uma soneca por {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 "Boa noite."
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 "Esperando por {secs}s ..."
#, python-brace-format #, python-brace-format
msgid "Looking around ({secs}s)" msgid "Looking around ({secs}s)"
msgstr "" msgstr "Olhando por volta ({secs}s)"
#, python-brace-format #, python-brace-format
msgid "Hey {what} let's be friends!" msgid "Hey {what} let's be friends!"
msgstr "" msgstr "Ei {what} vamos ser amigos!"
#, python-brace-format #, python-brace-format
msgid "Associating to {what}" msgid "Associating to {what}"
msgstr "" msgstr "Associando para {what}"
#, python-brace-format #, python-brace-format
msgid "Yo {what}!" msgid "Yo {what}!"
msgstr "" msgstr "Ei {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 "Apenas decidindo que {mac} não precisa de WiFi!"
#, python-brace-format #, python-brace-format
msgid "Deauthenticating {mac}" msgid "Deauthenticating {mac}"
msgstr "" msgstr "Desautenticando {mac}"
#, python-brace-format #, python-brace-format
msgid "Kickbanning {mac}!" msgid "Kickbanning {mac}!"
msgstr "" msgstr "Banindo {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 "Legal, conseguimos {num} novos handshake{plural}!"
#, python-brace-format #, python-brace-format
msgid "You have {count} new message{plural}!" msgid "You have {count} new message{plural}!"
msgstr "" msgstr "Você tem {count} novas messagem{plural}!"
msgid "Oops, something went wrong ... Rebooting ..." msgid "Oops, something went wrong ... Rebooting ..."
msgstr "" msgstr "Oops, algo deu errado ... Reiniciando ..."
#, python-brace-format #, python-brace-format
msgid "Uploading data to {to} ..." msgid "Uploading data to {to} ..."
msgstr "" msgstr "Enviando dados para {to} ..."
#, python-brace-format #, python-brace-format
msgid "Downloading from {name} ..." msgid "Downloading from {name} ..."
msgstr "" msgstr "Instalando para {name} ..."
#, python-brace-format #, python-brace-format
msgid "Kicked {num} stations\n" msgid "Kicked {num} stations\n"
msgstr "" msgstr "Expulsei {num} estações\n"
msgid "Made >999 new friends\n" msgid "Made >999 new friends\n"
msgstr "" msgstr "Fiz >999 novos amigos\n"
#, python-brace-format #, python-brace-format
msgid "Made {num} new friends\n" msgid "Made {num} new friends\n"
msgstr "" msgstr "Fiz {num} novos amigos\n"
#, python-brace-format #, python-brace-format
msgid "Got {num} handshakes\n" msgid "Got {num} handshakes\n"
msgstr "" msgstr "Peguei {num} handshakes\n"
msgid "Met 1 peer" msgid "Met 1 peer"
msgstr "" msgstr "Encontrei 1 pessoa"
#, python-brace-format #, python-brace-format
msgid "Met {num} peers" msgid "Met {num} peers"
msgstr "" msgstr "Encontrei {num} pessoas"
#, 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 ""
"Estou navegando há {duration} e expulsei {deauthed} clientes! Também conheci "
"{associamos} novos amigos e comi {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours" msgid "hours"
msgstr "" msgstr "horas"
msgid "minutes" msgid "minutes"
msgstr "" msgstr "minutos"
msgid "seconds" msgid "seconds"
msgstr "" msgstr "segundos"
msgid "hour" msgid "hour"
msgstr "" msgstr "hora"
msgid "minute" msgid "minute"
msgstr "" msgstr "minuto"
msgid "second" msgid "second"
msgstr "" msgstr "segundo"

View File

@ -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"

View File

@ -199,6 +199,9 @@ def list_plugins(args, config, pattern='*'):
available_not_installed = set(available.keys()) - set(installed.keys()) available_not_installed = set(available.keys()) - set(installed.keys())
max_len_list = available_and_installed if args.installed else available_not_installed max_len_list = available_and_installed if args.installed else available_not_installed
if not max_len_list:
print('Maybe try: sudo pwnagotchi plugins update')
return 1
max_len = max(map(len, max_len_list)) max_len = max(map(len, max_len_list))
header = line.format(name='Plugin', width=max_len, version='Version', enabled='Active', status='Status') header = line.format(name='Plugin', width=max_len, version='Version', enabled='Active', status='Status')
line_length = max(max_len, len('Plugin')) + len(header) - len('Plugin') - 12 # lol line_length = max(max_len, len('Plugin')) + len(header) - len('Plugin') - 12 # lol
@ -239,7 +242,7 @@ def list_plugins(args, config, pattern='*'):
print('-' * line_length) print('-' * line_length)
if not found: if not found:
logging.info('Maybe try: pwnagotchi plugins update') print('Maybe try: sudo pwnagotchi plugins update')
return 1 return 1
return 0 return 0

View File

@ -28,7 +28,8 @@ 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')
is_aarch = info['arch'].startswith('aarch')
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 +37,20 @@ 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
break
elif is_aarch:
# check if this release is compatible with arm64/aarch64
for asset in latest['assets']:
download_url = asset['browser_download_url']
if (download_url.endswith('.zip') and
(info['arch'] in download_url or (is_aarch and 'aarch' in download_url))):
info['url'] = download_url info['url'] = download_url
break break
@ -130,7 +139,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 +198,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 +221,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")

View File

@ -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,7 +35,6 @@ class FixServices(plugins.Plugin):
self.isReloadingMon = False self.isReloadingMon = False
self.connection = None self.connection = None
self.LASTTRY = 0 self.LASTTRY = 0
self._count = 0
def on_loaded(self): def on_loaded(self):
""" """
@ -50,23 +47,23 @@ class FixServices(plugins.Plugin):
stdout=subprocess.PIPE).stdout))[-10:]) stdout=subprocess.PIPE).stdout))[-10:])
try: try:
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True) cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
logging.info("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output)) logging.debug("[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.debug("wlan0mon is up.")
if len(self.pattern.findall(last_lines)) >= 3: if len(self.pattern.findall(last_lines)) >= 3:
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.')
display.update(force=True) display.update(force=True)
logging.info('[Fix_Services] Blind-Bug detected. Restarting.') logging.debug('[Fix_Services] Blind-Bug detected. Restarting.')
try: try:
self._tryTurningItOffAndOnAgain(agent) self._tryTurningItOffAndOnAgain(agent)
except Exception as err: except Exception as err:
logging.warning("[Fix_Services turnOffAndOn] %s" % repr(err)) logging.warning("[Fix_Services turnOffAndOn] %s" % repr(err))
else: else:
logging.info("[Fix_Services] Logs look good!") logging.debug("[Fix_Services] Logs look good!")
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))
@ -80,12 +77,12 @@ class FixServices(plugins.Plugin):
# apparently this only gets messages from bettercap going to syslog, not from syslog # apparently this only gets messages from bettercap going to syslog, not from syslog
def on_bcap_sys_log(self, agent, event): def on_bcap_sys_log(self, agent, event):
if re.search('wifi error while hopping to channel', event['data']['Message']): if re.search('wifi error while hopping to channel', event['data']['Message']):
logging.info("[Fix_Services]SYSLOG MATCH: %s" % event['data']['Message']) logging.debug("[Fix_Services]SYSLOG MATCH: %s" % event['data']['Message'])
logging.info("[Fix_Services]**** restarting wifi.recon") logging.debug("[Fix_Services]**** restarting wifi.recon")
try: try:
result = agent.run("wifi.recon off; wifi.recon on") result = agent.run("wifi.recon off; wifi.recon on")
if result["success"]: if result["success"]:
logging.info("[Fix_Services] wifi.recon flip: success!") logging.debug("[Fix_Services] wifi.recon flip: success!")
if hasattr(agent, 'view'): if hasattr(agent, 'view'):
display = agent.view() display = agent.view()
if display: if display:
@ -117,12 +114,12 @@ class FixServices(plugins.Plugin):
# Look for pattern 1 # Look for pattern 1
if len(self.pattern.findall(last_lines)) >= 3: if len(self.pattern.findall(last_lines)) >= 3:
logging.info("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines) logging.debug("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
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.')
display.update(force=True) display.update(force=True)
logging.info('[Fix_Services] Blind-Bug detected. Restarting.') logging.debug('[Fix_Services] Blind-Bug detected. Restarting.')
try: try:
self._tryTurningItOffAndOnAgain(agent) self._tryTurningItOffAndOnAgain(agent)
except Exception as err: except Exception as err:
@ -130,17 +127,17 @@ class FixServices(plugins.Plugin):
# Look for pattern 2 # Look for pattern 2
elif len(self.pattern2.findall(other_last_lines)) >= 5: elif len(self.pattern2.findall(other_last_lines)) >= 5:
logging.info("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines) logging.debug("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
if hasattr(agent, 'view'): if hasattr(agent, 'view'):
display = agent.view() display = agent.view()
display.set('status', 'Wifi channel stuck. Restarting recon.') display.set('status', 'Wifi channel stuck. Restarting recon.')
display.update(force=True) display.update(force=True)
logging.info('[Fix_Services] Wifi channel stuck. Restarting recon.') logging.debug('[Fix_Services] Wifi channel stuck. Restarting recon.')
try: try:
result = agent.run("wifi.recon off; wifi.recon on") result = agent.run("wifi.recon off; wifi.recon on")
if result["success"]: if result["success"]:
logging.info("[Fix_Services] wifi.recon flip: success!") logging.debug("[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!",
"face": faces.COOL}) "face": faces.COOL})
@ -154,7 +151,7 @@ class FixServices(plugins.Plugin):
# Look for pattern 3 # Look for pattern 3
elif len(self.pattern3.findall(other_last_lines)) >= 1: elif len(self.pattern3.findall(other_last_lines)) >= 1:
logging.info("[Fix_Services] Firmware has halted or crashed. Restarting wlan0mon.") logging.debug("[Fix_Services] Firmware has halted or crashed. Restarting wlan0mon.")
if hasattr(agent, 'view'): if hasattr(agent, 'view'):
display = agent.view() display = agent.view()
display.set('status', 'Firmware has halted or crashed. Restarting wlan0mon.') display.set('status', 'Firmware has halted or crashed. Restarting wlan0mon.')
@ -162,13 +159,13 @@ class FixServices(plugins.Plugin):
try: try:
# Run the monstart command to restart wlan0mon # Run the monstart command to restart wlan0mon
cmd_output = subprocess.check_output("monstart", shell=True) cmd_output = subprocess.check_output("monstart", shell=True)
logging.info("[Fix_Services monstart]: %s" % repr(cmd_output)) logging.debug("[Fix_Services monstart]: %s" % repr(cmd_output))
except Exception as err: except Exception as err:
logging.error("[Fix_Services monstart]: %s" % repr(err)) logging.error("[Fix_Services monstart]: %s" % repr(err))
# Look for pattern 4 # Look for pattern 4
elif len(self.pattern4.findall(other_other_last_lines)) >= 3: elif len(self.pattern4.findall(other_other_last_lines)) >= 3:
logging.info("[Fix_Services] wlan0 is down!") logging.debug("[Fix_Services] wlan0 is down!")
if hasattr(agent, 'view'): if hasattr(agent, 'view'):
display = agent.view() display = agent.view()
display.set('status', 'Restarting wlan0 now!') display.set('status', 'Restarting wlan0 now!')
@ -176,7 +173,7 @@ class FixServices(plugins.Plugin):
try: try:
# Run the monstart command to restart wlan0mon # Run the monstart command to restart wlan0mon
cmd_output = subprocess.check_output("monstart", shell=True) cmd_output = subprocess.check_output("monstart", shell=True)
logging.info("[Fix_Services monstart]: %s" % repr(cmd_output)) logging.debug("[Fix_Services monstart]: %s" % repr(cmd_output))
except Exception as err: except Exception as err:
logging.error("[Fix_Services monstart]: %s" % repr(err)) logging.error("[Fix_Services monstart]: %s" % repr(err))
@ -192,7 +189,7 @@ class FixServices(plugins.Plugin):
elif level == "debug": elif level == "debug":
logging.debug(message) logging.debug(message)
else: else:
logging.info(message) logging.debug(message)
if ui: if ui:
ui.update(force=force, new_data=displayData) ui.update(force=force, new_data=displayData)
@ -207,7 +204,7 @@ class FixServices(plugins.Plugin):
# avoid overlapping restarts, but allow it if it's been a while # avoid overlapping restarts, but allow it if it's been a while
# (in case the last attempt failed before resetting "isReloadingMon") # (in case the last attempt failed before resetting "isReloadingMon")
if self.isReloadingMon and (time.time() - self.LASTTRY) < 180: if self.isReloadingMon and (time.time() - self.LASTTRY) < 180:
logging.info("[Fix_Services] Duplicate attempt ignored") logging.debug("[Fix_Services] Duplicate attempt ignored")
else: else:
self.isReloadingMon = True self.isReloadingMon = True
self.LASTTRY = time.time() self.LASTTRY = time.time()
@ -232,9 +229,9 @@ class FixServices(plugins.Plugin):
# is it up? # is it up?
try: try:
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True) cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
logging.info("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output)) logging.debug("[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. Skip reset?") logging.debug("wlan0mon is up. Skip reset?")
# not reliable, so don't skip just yet # not reliable, so don't skip just yet
# print("wlan0mon is up. Skipping reset.") # print("wlan0mon is up. Skipping reset.")
# self.isReloadingMon = False # self.isReloadingMon = False
@ -255,7 +252,7 @@ class FixServices(plugins.Plugin):
except Exception as err: except Exception as err:
logging.error("[Fix_Services wifi.recon off] error %s" % (repr(err))) logging.error("[Fix_Services wifi.recon off] error %s" % (repr(err)))
logging.info("[Fix_Services] recon paused. Now trying wlan0mon reload") logging.debug("[Fix_Services] recon paused. Now trying wlan0mon reload")
try: try:
cmd_output = subprocess.check_output("monstop", shell=True) cmd_output = subprocess.check_output("monstop", shell=True)
@ -271,14 +268,13 @@ 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)
# reload the module # reload the module
try: try:
@ -286,28 +282,24 @@ 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
# 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)
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.debug("[Fix_Services set wifi.interface wlan0mon worked!")
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:
logging.info( logging.debug(
"[Fix_Services set wifi.interfaceface wlan0mon] failed? %s" % repr(result)) "[Fix_Services set wifi.interfaceface wlan0mon] failed? %s" % repr(result))
except Exception as err: except Exception as err:
logging.info( logging.debug(
"[Fix_Services set wifi.interface wlan0mon] except: %s" % repr(err)) "[Fix_Services set wifi.interface wlan0mon] except: %s" % repr(err))
except Exception as cerr: # except Exception as cerr: #
if not display: if not display:
@ -326,11 +318,11 @@ class FixServices(plugins.Plugin):
tries = tries + 1 tries = tries + 1
if tries < 3: if tries < 3:
logging.info("[Fix_Services] wlan0mon didn't make it. trying again") logging.debug("[Fix_Services] wlan0mon didn't make it. trying again")
if not display: if not display:
print(" wlan0mon didn't make it. trying again") print(" wlan0mon didn't make it. trying again")
else: else:
logging.info("[Fix_Services] wlan0mon loading failed, no choice but to reboot ..") logging.debug("[Fix_Services] wlan0mon loading failed, no choice but to reboot ..")
pwnagotchi.reboot() pwnagotchi.reboot()
# exited the loop, so hopefully it loaded # exited the loop, so hopefully it loaded
@ -340,14 +332,14 @@ class FixServices(plugins.Plugin):
"face": faces.INTENSE}) "face": faces.INTENSE})
else: else:
print("And back on again...") print("And back on again...")
logging.info("[Fix_Services] wlan0mon back up") logging.debug("[Fix_Services] wlan0mon back up")
else: else:
self.LASTTRY = time.time() self.LASTTRY = time.time()
time.sleep(8 + tries * 2) # give it a bit before restarting recon in bettercap time.sleep(8 + tries * 2) # give it a bit before restarting recon in bettercap
self.isReloadingMon = False self.isReloadingMon = False
logging.info("[Fix_Services] re-enable recon") logging.debug("[Fix_Services] re-enable recon")
try: try:
result = connection.run("wifi.clear; wifi.recon on") result = connection.run("wifi.clear; wifi.recon on")
@ -357,7 +349,7 @@ class FixServices(plugins.Plugin):
"face": faces.HAPPY}) "face": faces.HAPPY})
else: else:
print("I can see again") print("I can see again")
logging.info("[Fix_Services] wifi.recon on") logging.debug("[Fix_Services] wifi.recon on")
self.LASTTRY = time.time() + 120 # 2-minute pause until next time. self.LASTTRY = time.time() + 120 # 2-minute pause until next time.
else: else:
logging.error("[Fix_Services] wifi.recon did not start up") logging.error("[Fix_Services] wifi.recon did not start up")
@ -368,13 +360,24 @@ 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()
def on_unload(self, ui): # called to setup the ui elements
def on_ui_setup(self, ui):
with ui._lock: with ui._lock:
try: # add custom UI elements
logging.info("[Fix_Services] unloaded") if "position" in self.options:
except Exception as err: pos = self.options['position'].split(',')
logging.info("[Fix_Services] unload err %s " % repr(err)) pos = [int(x.strip()) for x in pos]
pass else:
pos = (ui.width() / 2 + 35, ui.height() - 11)
logging.debug("Got here")
# called when the ui is updated
def on_ui_update(self, ui):
return
def on_unload(self, ui):
return
# run from command line to brute force a reload # run from command line to brute force a reload

View File

@ -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 ...'})

View File

@ -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']}")
@ -97,7 +98,7 @@ class GPS(plugins.Plugin):
lat_pos = (127, 74) lat_pos = (127, 74)
lon_pos = (122, 84) lon_pos = (122, 84)
alt_pos = (127, 94) alt_pos = (127, 94)
elif ui.is_waveshare27inch(): elif ui.is_waveshare2in7():
lat_pos = (6, 120) lat_pos = (6, 120)
lon_pos = (1, 135) lon_pos = (1, 135)
alt_pos = (6, 150) alt_pos = (6, 150)

View File

@ -5,7 +5,6 @@ import glob
import re import re
import pwnagotchi.grid as grid import pwnagotchi.grid as grid
import pwnagotchi.plugins
import pwnagotchi.plugins as plugins import pwnagotchi.plugins as plugins
from pwnagotchi.utils import StatusFile, WifiInfo, extract_from_pcap from pwnagotchi.utils import StatusFile, WifiInfo, extract_from_pcap
from threading import Lock from threading import Lock
@ -58,8 +57,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:
@ -86,7 +86,8 @@ class Grid(plugins.Plugin):
agent.view().on_unread_messages(self.unread_messages, self.total_messages) agent.view().on_unread_messages(self.unread_messages, self.total_messages)
def check_handshakes(self, agent): def check_handshakes(self, agent):
logging.debug("checking pcaps") logging.debug("checking pcap's")
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 +99,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:

View File

@ -141,9 +141,12 @@ class MemTemp(plugins.Plugin):
elif ui.is_inky(): elif ui.is_inky():
h_pos = (140, 68) h_pos = (140, 68)
v_pos = (160, 54) v_pos = (160, 54)
elif ui.is_waveshare27inch(): 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)

View File

@ -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']):

View File

@ -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")
@ -147,6 +142,6 @@ class OnlineHashCrack(plugins.Plugin):
for row in csv.DictReader(cracked_list): for row in csv.DictReader(cracked_list):
if row['password']: if row['password']:
filename = re.sub(r'[^a-zA-Z0-9]', '', row['ESSID']) + '_' + row['BSSID'].replace(':','') filename = re.sub(r'[^a-zA-Z0-9]', '', row['ESSID']) + '_' + row['BSSID'].replace(':','')
if os.path.exists( os.path.join(handshake_dir, filename+'.pcap') ): if os.path.exists( os.path.join(handshake_dir, filename+'.pcap')):
with open(os.path.join(handshake_dir, filename+'.pcap.cracked'), 'w') as f: with open(os.path.join(handshake_dir, filename+'.pcap.cracked'), 'w') as f:
f.write(row['password']) f.write(row['password'])

View File

@ -1,39 +0,0 @@
import logging
import requests
import pwnagotchi.plugins as plugins
'''
You need an bluetooth connection to your android phone which is running PAW server with the GPS "hack" from Systemik and edited by shaynemk
GUIDE HERE: https://community.pwnagotchi.ai/t/setting-up-paw-gps-on-android
'''
class PawGPS(plugins.Plugin):
__author__ = 'leont'
__version__ = '1.0.1'
__name__ = 'pawgps'
__license__ = 'GPL3'
__description__ = 'Saves GPS coordinates whenever an handshake is captured. The GPS data is get from PAW on android.'
def on_loaded(self):
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):
logging.info("[paw-gps] no IP Address defined in the config file, will uses paw server default (192.168.44.1:8080)")
def on_handshake(self, agent, filename, access_point, client_station):
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)):
ip = "192.168.44.1:8080"
else:
ip = self.options['ip']
try:
gps = requests.get('http://' + ip + '/gps.xhtml')
try:
gps_filename = filename.replace('.pcap', '.paw-gps.json')
logging.info("[paw-gps] saving GPS data to %s" % (gps_filename))
with open(gps_filename, 'w+t') as f:
f.write(gps.text)
except Exception as error:
logging.error(f"[paw-gps] encountered error while saving gps data: {error}")
except Exception as error:
logging.error(f"[paw-gps] encountered error while getting gps data: {error}")

View File

@ -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()

View File

@ -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
@ -13,7 +14,7 @@ from dateutil.parser import parse
the plugin does the following: the plugin does the following:
- search for *.pcap files in your /handshakes/ dir - search for *.pcap files in your /handshakes/ dir
- for every found .pcap file it looks for a .geo.json or .gps.json or .paw-gps.json file with - for every found .pcap file it looks for a .geo.json or .gps.json or file with
latitude+longitude data inside and shows this position on the map latitude+longitude data inside and shows this position on the map
- if also an .cracked file with a plaintext password inside exist, it reads the content and shows the - if also an .cracked file with a plaintext password inside exist, it reads the content and shows the
position as green instead of red and the password inside the infopox of the position position as green instead of red and the password inside the infopox of the position
@ -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'
@ -85,7 +87,8 @@ class Webgpsmap(plugins.Plugin):
# returns all positions # returns all positions
try: try:
self.ALREADY_SENT = list() self.ALREADY_SENT = list()
response_data = bytes(json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])), "utf-8") response_data = bytes(
json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])), "utf-8")
response_status = 200 response_status = 200
response_mimetype = "application/json" response_mimetype = "application/json"
response_header_contenttype = 'application/json' response_header_contenttype = 'application/json'
@ -98,12 +101,13 @@ class Webgpsmap(plugins.Plugin):
self.ALREADY_SENT = list() self.ALREADY_SENT = list()
json_data = json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])) json_data = json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes']))
html_data = self.get_html() html_data = self.get_html()
html_data = html_data.replace('var positions = [];', 'var positions = ' + json_data + ';positionsLoaded=true;drawPositions();') html_data = html_data.replace('var positions = [];',
'var positions = ' + json_data + ';positionsLoaded=true;drawPositions();')
response_data = bytes(html_data, "utf-8") response_data = bytes(html_data, "utf-8")
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 +153,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 +163,10 @@ 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
for filename in all_files filename.endswith('.pcap')]
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"
@ -183,22 +183,18 @@ class Webgpsmap(plugins.Plugin):
if check_for in all_files: if check_for in all_files:
filename_position = str(os.path.join(handshake_dir, check_for)) filename_position = str(os.path.join(handshake_dir, check_for))
logging.debug("[webgpsmap] search for .paw-gps.json")
check_for = os.path.basename(filename_base) + ".paw-gps.json"
if check_for in all_files:
filename_position = str(os.path.join(handshake_dir, check_for))
logging.debug(f"[webgpsmap] end search for position data files and use {filename_position}") logging.debug(f"[webgpsmap] end search for position data files and use {filename_position}")
if filename_position is not None: if filename_position is not None:
all_geo_or_gps_files.append(filename_position) all_geo_or_gps_files.append(filename_position)
# all_geo_or_gps_files = set(all_geo_or_gps_files) - set(SKIP) # remove skipped networks? No! # all_geo_or_gps_files = set(all_geo_or_gps_files) - set(SKIP) # remove skipped networks? No!
if newest_only: if newest_only:
all_geo_or_gps_files = set(all_geo_or_gps_files) - set(self.ALREADY_SENT) all_geo_or_gps_files = set(all_geo_or_gps_files) - set(self.ALREADY_SENT)
logging.info(f"[webgpsmap] Found {len(all_geo_or_gps_files)} position-data files from {len(all_pcap_files)} handshakes. Fetching positions ...") logging.info(
f"[webgpsmap] Found {len(all_geo_or_gps_files)} position-data files from {len(all_pcap_files)} handshakes. Fetching positions ...")
for pos_file in all_geo_or_gps_files: for pos_file in all_geo_or_gps_files:
try: try:
@ -216,9 +212,7 @@ class Webgpsmap(plugins.Plugin):
pos_type = 'gps' pos_type = 'gps'
elif pos.type() == PositionFile.GEO: elif pos.type() == PositionFile.GEO:
pos_type = 'geo' pos_type = 'geo'
elif pos.type() == PositionFile.PAWGPS: gps_data[ssid + "_" + mac] = {
pos_type = 'paw'
gps_data[ssid+"_"+mac] = {
'ssid': ssid, 'ssid': ssid,
'mac': mac, 'mac': mac,
'type': pos_type, 'type': pos_type,
@ -227,7 +221,7 @@ class Webgpsmap(plugins.Plugin):
'acc': pos.accuracy(), 'acc': pos.accuracy(),
'ts_first': pos.timestamp_first(), 'ts_first': pos.timestamp_first(),
'ts_last': pos.timestamp_last(), 'ts_last': pos.timestamp_last(),
} }
# get ap password if exist # get ap password if exist
check_for = os.path.basename(pos_file).split(".")[0] + ".pcap.cracked" check_for = os.path.basename(pos_file).split(".")[0] + ".pcap.cracked"
@ -268,7 +262,6 @@ class PositionFile:
""" """
GPS = 1 GPS = 1
GEO = 2 GEO = 2
PAWGPS = 3
def __init__(self, path): def __init__(self, path):
self._file = path self._file = path
@ -285,7 +278,7 @@ class PositionFile:
""" """
Returns the mac from filename Returns the mac from filename
""" """
parsed_mac = re.search(r'.*_?([a-zA-Z0-9]{12})\.(?:gps|geo|paw-gps)\.json', self._filename) parsed_mac = re.search(r'.*_?([a-zA-Z0-9]{12})\.(?:gps|geo)\.json', self._filename)
if parsed_mac: if parsed_mac:
mac = parsed_mac.groups()[0] mac = parsed_mac.groups()[0]
return mac return mac
@ -295,12 +288,11 @@ class PositionFile:
""" """
Returns the ssid from filename Returns the ssid from filename
""" """
parsed_ssid = re.search(r'(.+)_[a-zA-Z0-9]{12}\.(?:gps|geo|paw-gps)\.json', self._filename) parsed_ssid = re.search(r'(.+)_[a-zA-Z0-9]{12}\.(?:gps|geo)\.json', self._filename)
if parsed_ssid: if parsed_ssid:
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
@ -358,8 +350,6 @@ class PositionFile:
return PositionFile.GPS return PositionFile.GPS
if self._file.endswith('.geo.json'): if self._file.endswith('.geo.json'):
return PositionFile.GEO return PositionFile.GEO
if self._file.endswith('.paw-gps.json'):
return PositionFile.PAWGPS
return None return None
def lat(self): def lat(self):
@ -406,9 +396,7 @@ class PositionFile:
def accuracy(self): def accuracy(self):
if self.type() == PositionFile.GPS: if self.type() == PositionFile.GPS:
return 50.0 # a default return 50.0 # a default
if self.type() == PositionFile.PAWGPS:
return 50.0 # a default
if self.type() == PositionFile.GEO: if self.type() == PositionFile.GEO:
try: try:
return self._json['accuracy'] return self._json['accuracy']

View File

@ -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):

View File

@ -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:

View File

@ -1 +0,0 @@

View File

@ -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 self.wrap: if not self.png:
text = '\n'.join(self.wrapper.wrap(self.value)) if self.wrap:
text = '\n'.join(self.wrapper.wrap(self.value))
else:
text = self.value
drawer.text(self.xy, text, font=self.font, fill=self.color)
else: else:
text = self.value self.image = Image.open(self.value)
drawer.text(self.xy, text, font=self.font, fill=self.color) 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):

View File

@ -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,9 +112,15 @@ 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'
def is_weact2in9(self):
return self._implementation.name == 'weact2in9'
def is_waveshare3in0g(self): def is_waveshare3in0g(self):
return self._implementation.name == 'waveshare3in0g' return self._implementation.name == 'waveshare3in0g'
@ -148,6 +154,12 @@ class Display(View):
def is_waveshare5in65f(self): def is_waveshare5in65f(self):
return self._implementation.name == 'waveshare5in65f' return self._implementation.name == 'waveshare5in65f'
def is_waveshare5in79(self):
return self._implementation.name == 'waveshare5in79'
def is_waveshare5in79b(self):
return self._implementation.name == 'waveshare5in79b'
def is_waveshare5in83(self): def is_waveshare5in83(self):
return self._implementation.name == 'waveshare5in83' return self._implementation.name == 'waveshare5in83'
@ -205,6 +217,18 @@ class Display(View):
def is_displayhatmini(self): def is_displayhatmini(self):
return self._implementation.name == 'displayhatmini' return self._implementation.name == 'displayhatmini'
def is_pirateaudio(self):
return self._implementation.name == 'pirateaudio'
def is_pitft(self):
return self._implementation.name == 'pitft'
def is_tftbonnet(self):
return self._implementation.name == 'tftbonnet'
def is_waveshareoledlcd(self):
return self._implementation.name == 'waveshareoledlcd'
def is_waveshare35lcd(self): def is_waveshare35lcd(self):
return self._implementation.name == 'waveshare35lcd' return self._implementation.name == 'waveshare35lcd'

View File

@ -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():

View File

@ -16,50 +16,58 @@ 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
from pwnagotchi.ui.hw.displayhatmini import DisplayHatMini from pwnagotchi.ui.hw.displayhatmini import DisplayHatMini
# from pwnagotchi.ui.hw.waveshare1in02 import Waveshare102 from pwnagotchi.ui.hw.pirateaudio import PirateAudio
from pwnagotchi.ui.hw.pitft import Pitft
from pwnagotchi.ui.hw.tftbonnet import TftBonnet
from pwnagotchi.ui.hw.waveshareoledlcd import Waveshareoledlcd
from pwnagotchi.ui.hw.waveshare1in02 import Waveshare1in02
from pwnagotchi.ui.hw.waveshare1in54 import Waveshare154 from pwnagotchi.ui.hw.waveshare1in54 import Waveshare154
from pwnagotchi.ui.hw.waveshare1in54_V2 import Waveshare154V2 from pwnagotchi.ui.hw.waveshare1in54_V2 import Waveshare154V2
from pwnagotchi.ui.hw.waveshare1in54b_V2 import Waveshare154bV2 from pwnagotchi.ui.hw.waveshare1in54b_V2 import Waveshare154bV2
# from pwnagotchi.ui.hw.waveshare1in54c import Waveshare154c from pwnagotchi.ui.hw.waveshare1in54c import Waveshare1in54c
# from pwnagotchi.ui.hw.waveshare1in64g import Waveshare164g from pwnagotchi.ui.hw.waveshare1in64g import Waveshare1in64g
from pwnagotchi.ui.hw.waveshare2in7b import Waveshare27b from pwnagotchi.ui.hw.waveshare2in7b import Waveshare27b
from pwnagotchi.ui.hw.waveshare2in7b_V2 import Waveshare27bV2 from pwnagotchi.ui.hw.waveshare2in7b_V2 import Waveshare27bV2
from pwnagotchi.ui.hw.waveshare2in9b_V3 import Waveshare29bV3 from pwnagotchi.ui.hw.waveshare2in9b_V3 import Waveshare29bV3
from pwnagotchi.ui.hw.waveshare2in9b_V4 import Waveshare29bV4 from pwnagotchi.ui.hw.waveshare2in9b_V4 import Waveshare29bV4
# from pwnagotchi.ui.hw.waveshare2in9bc import Waveshare29bc from pwnagotchi.ui.hw.waveshare2in9bc import Waveshare2in9bc
# from pwnagotchi.ui.hw.waveshare2in9d import Waveshare29d from pwnagotchi.ui.hw.waveshare2in9d import Waveshare2in9d
from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare213bV3 from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare2in13bV3
# from pwnagotchi.ui.hw.waveshare2in23g import Waveshare223g from pwnagotchi.ui.hw.waveshare2in36g import Waveshare2in36g
# from pwnagotchi.ui.hw.waveshare2in36g import Waveshare236g from pwnagotchi.ui.hw.waveshare2in66 import Waveshare2in66
# from pwnagotchi.ui.hw.waveshare2in66 import Waveshare266 from pwnagotchi.ui.hw.waveshare2in66b import Waveshare2in66b
# from pwnagotchi.ui.hw.waveshare3in0g import Waveshare30g from pwnagotchi.ui.hw.waveshare2in66g import Waveshare2in66g
# from pwnagotchi.ui.hw.waveshare3in7 import Waveshare37 from pwnagotchi.ui.hw.waveshare3in0g import Waveshare3in0g
# from pwnagotchi.ui.hw.waveshare3in52 import Waveshare352 from pwnagotchi.ui.hw.waveshare3in7 import Waveshare3in7
# from pwnagotchi.ui.hw.waveshare4in01f import Waveshare401f from pwnagotchi.ui.hw.waveshare3in52 import Waveshare3in52
# from pwnagotchi.ui.hw.waveshare4in2 import Waveshare42inch from pwnagotchi.ui.hw.waveshare4in01f import Waveshare4in01f
# from pwnagotchi.ui.hw.waveshare4in2_V2 import Waveshare42V2 from pwnagotchi.ui.hw.waveshare4in2 import Waveshare4in2
# from pwnagotchi.ui.hw.waveshare4in2b_V2 import Waveshare42bV2 from pwnagotchi.ui.hw.waveshare4in2_V2 import Waveshare4in2V2
# from pwnagotchi.ui.hw.waveshare4in2bc import Waveshare42bc from pwnagotchi.ui.hw.waveshare4in2b_V2 import Waveshare4in2bV2
# from pwnagotchi.ui.hw.waveshare4in26 import Waveshare426 from pwnagotchi.ui.hw.waveshare4in2bc import Waveshare4in2bc
# from pwnagotchi.ui.hw.waveshare4in37g import Waveshare437g from pwnagotchi.ui.hw.waveshare4in26 import Waveshare4in26
# from pwnagotchi.ui.hw.waveshare5in65f import Waveshare565f from pwnagotchi.ui.hw.waveshare4in37g import Waveshare4in37g
# from pwnagotchi.ui.hw.waveshare5in83 import Waveshare583 from pwnagotchi.ui.hw.waveshare5in65f import Waveshare5in65f
# from pwnagotchi.ui.hw.waveshare5in83_V2 import Waveshare583V2 from pwnagotchi.ui.hw.waveshare5in79 import Waveshare5in79
# from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare583bV2 from pwnagotchi.ui.hw.waveshare5in79b import Waveshare5in79b
# from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare583bc from pwnagotchi.ui.hw.waveshare5in83 import Waveshare5in83
# from pwnagotchi.ui.hw.waveshare7in3f import Waveshare73f from pwnagotchi.ui.hw.waveshare5in83_V2 import Waveshare5in83V2
# from pwnagotchi.ui.hw.waveshare7in3g import Waveshare73g from pwnagotchi.ui.hw.waveshare5in83b_V2 import Waveshare5in83bV2
# from pwnagotchi.ui.hw.waveshare7in5 import Waveshare75 from pwnagotchi.ui.hw.waveshare5in83bc import Waveshare5in83bc
# from pwnagotchi.ui.hw.waveshare7in5_HD import Waveshare75HD from pwnagotchi.ui.hw.waveshare7in3f import Waveshare7in3f
# from pwnagotchi.ui.hw.waveshare7in5_V2 import Waveshare75V2 from pwnagotchi.ui.hw.waveshare7in3g import Waveshare7in3g
# from pwnagotchi.ui.hw.waveshare7in5b_HD import Waveshare75bHD from pwnagotchi.ui.hw.waveshare7in5 import Waveshare7in5
# from pwnagotchi.ui.hw.waveshare7in5b_V2 import Waveshare75bV2 from pwnagotchi.ui.hw.waveshare7in5_HD import Waveshare7in5HD
# from pwnagotchi.ui.hw.waveshare7in5bc import Waveshare75bc from pwnagotchi.ui.hw.waveshare7in5_V2 import Waveshare7in5V2
# from pwnagotchi.ui.hw.waveshare13in3k import Waveshare133k from pwnagotchi.ui.hw.waveshare7in5b_HD import Waveshare7in5bHD
from pwnagotchi.ui.hw.waveshare7in5b_V2 import Waveshare7in5bV2
from pwnagotchi.ui.hw.waveshare7in5bc import Waveshare7in5bc
from pwnagotchi.ui.hw.waveshare13in3k import Waveshare13in3k
def display_for(config): def display_for(config):
@ -82,6 +90,33 @@ 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'] == 'pirateaudio':
return PirateAudio(config)
elif config['ui']['display']['type'] == 'pitft':
return Pitft(config)
elif config['ui']['display']['type'] == 'tftbonnet':
return TftBonnet(config)
elif config['ui']['display']['type'] == 'waveshareoledlcd':
return Waveshareoledlcd(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 +129,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 +177,107 @@ 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
elif config['ui']['display']['type'] == 'waveshare1in64g':
return
elif config['ui']['display']['type'] == 'waveshare1in02':
return
elif config['ui']['display']['type'] == 'waveshare2in9bc':
return
elif config['ui']['display']['type'] == 'waveshare2in9d':
return
elif config['ui']['display']['type'] == 'waveshare2in13b_v3':
return
elif config['ui']['display']['type'] == 'waveshare2in23g':
return
elif config['ui']['display']['type'] == 'waveshare2in36g': elif config['ui']['display']['type'] == 'waveshare2in36g':
return return Waveshare2in36g(config)
elif config['ui']['display']['type'] == 'waveshare2in66': elif config['ui']['display']['type'] == 'waveshare2in66':
return 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 return Waveshare3in0g(config)
elif config['ui']['display']['type'] == 'waveshare3in7': elif config['ui']['display']['type'] == 'waveshare3in7':
return return Waveshare3in7(config)
elif config['ui']['display']['type'] == 'waveshare3in52': elif config['ui']['display']['type'] == 'waveshare3in52':
return return Waveshare3in52(config)
elif config['ui']['display']['type'] == 'waveshare4in01f': elif config['ui']['display']['type'] == 'waveshare4in01f':
return return Waveshare4in01f(config)
elif config['ui']['display']['type'] == 'waveshare4in2': elif config['ui']['display']['type'] == 'waveshare4in2':
return return Waveshare4in2(config)
elif config['ui']['display']['type'] == 'waveshare4in2_v2': elif config['ui']['display']['type'] == 'waveshare4in2_v2':
return return Waveshare4in2V2(config)
elif config['ui']['display']['type'] == 'waveshare4in2b_v2': elif config['ui']['display']['type'] == 'waveshare4in2b_v2':
return return Waveshare4in2bV2(config)
elif config['ui']['display']['type'] == 'waveshare4in2bc': elif config['ui']['display']['type'] == 'waveshare4in2bc':
return return Waveshare4in2bc(config)
elif config['ui']['display']['type'] == 'waveshare4in26': elif config['ui']['display']['type'] == 'waveshare4in26':
return return Waveshare4in26(config)
elif config['ui']['display']['type'] == 'waveshare4in37g': elif config['ui']['display']['type'] == 'waveshare4in37g':
return return Waveshare4in37g(config)
elif config['ui']['display']['type'] == 'waveshare5in65f': elif config['ui']['display']['type'] == 'waveshare5in65f':
return return Waveshare5in65f(config)
elif config['ui']['display']['type'] == 'waveshare5in79':
return Waveshare5in79(config)
elif config['ui']['display']['type'] == 'waveshare5in79b':
return Waveshare5in79b(config)
elif config['ui']['display']['type'] == 'waveshare5in83': elif config['ui']['display']['type'] == 'waveshare5in83':
return return Waveshare5in83(config)
elif config['ui']['display']['type'] == 'waveshare5in83_v2': elif config['ui']['display']['type'] == 'waveshare5in83_v2':
return return Waveshare5in83V2(config)
elif config['ui']['display']['type'] == 'waveshare5in83b_v2': elif config['ui']['display']['type'] == 'waveshare5in83b_v2':
return return Waveshare5in83bV2(config)
elif config['ui']['display']['type'] == 'waveshare5in83bc': elif config['ui']['display']['type'] == 'waveshare5in83bc':
return return Waveshare5in83bc(config)
elif config['ui']['display']['type'] == 'waveshare7in3f': elif config['ui']['display']['type'] == 'waveshare7in3f':
return return Waveshare7in3f(config)
elif config['ui']['display']['type'] == 'waveshare7in3g': elif config['ui']['display']['type'] == 'waveshare7in3g':
return return Waveshare7in3g(config)
elif config['ui']['display']['type'] == 'waveshare7in5': elif config['ui']['display']['type'] == 'waveshare7in5':
return return Waveshare7in5(config)
elif config['ui']['display']['type'] == 'waveshare7in5_HD': elif config['ui']['display']['type'] == 'waveshare7in5_HD':
return return Waveshare7in5HD(config)
elif config['ui']['display']['type'] == 'waveshare7in5_v2': elif config['ui']['display']['type'] == 'waveshare7in5_v2':
return return Waveshare7in5V2(config)
elif config['ui']['display']['type'] == 'waveshare7in5b_HD': elif config['ui']['display']['type'] == 'waveshare7in5b_HD':
return return Waveshare7in5bHD(config)
elif config['ui']['display']['type'] == 'waveshare7in5b_v2': elif config['ui']['display']['type'] == 'waveshare7in5b_v2':
return return Waveshare7in5bV2(config)
elif config['ui']['display']['type'] == 'waveshare7in5bc': elif config['ui']['display']['type'] == 'waveshare7in5bc':
return return Waveshare7in5bc(config)
elif config['ui']['display']['type'] == 'waveshare13in3k': elif config['ui']['display']['type'] == 'waveshare13in3k':
return return Waveshare13in3k(config)

View File

@ -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

View File

@ -3,41 +3,41 @@ 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)
self._layout['width'] = 250 self._layout['width'] = 250
self._layout['height'] = 122 self._layout['height'] = 122
self._layout['face'] = (0, 40) self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20) self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0) self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0) self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0) self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14] self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108] self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92) self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94) self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109) self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109) self._layout['mode'] = (225, 109)
self._layout['status'] = { self._layout['status'] = {
'pos': (125, 20), 'pos': (125, 20),
'font': fonts.status_font(fonts.Medium), 'font': fonts.status_font(fonts.Medium),
'max': 20 'max': 20
} }
return self._layout return self._layout
def initialize(self): def initialize(self):
logging.info("initializing dfrobot1 display") logging.info("initializing dfrobot1 display")
from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot
self._display = DFRobot() self._display = DFRobot()
def render(self, canvas): def render(self, canvas):
buf = self._display.getbuffer(canvas) buf = self._display.getbuffer(canvas)
self._display.display(buf) self._display.display(buf)
def clear(self): def clear(self):
self._display.Clear(0xFF) self._display.Clear(0xFF)

View File

@ -3,41 +3,41 @@ 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)
self._layout['width'] = 250 self._layout['width'] = 250
self._layout['height'] = 122 self._layout['height'] = 122
self._layout['face'] = (0, 40) self._layout['face'] = (0, 40)
self._layout['name'] = (5, 20) self._layout['name'] = (5, 20)
self._layout['channel'] = (0, 0) self._layout['channel'] = (0, 0)
self._layout['aps'] = (28, 0) self._layout['aps'] = (28, 0)
self._layout['uptime'] = (185, 0) self._layout['uptime'] = (185, 0)
self._layout['line1'] = [0, 14, 250, 14] self._layout['line1'] = [0, 14, 250, 14]
self._layout['line2'] = [0, 108, 250, 108] self._layout['line2'] = [0, 108, 250, 108]
self._layout['friend_face'] = (0, 92) self._layout['friend_face'] = (0, 92)
self._layout['friend_name'] = (40, 94) self._layout['friend_name'] = (40, 94)
self._layout['shakes'] = (0, 109) self._layout['shakes'] = (0, 109)
self._layout['mode'] = (225, 109) self._layout['mode'] = (225, 109)
self._layout['status'] = { self._layout['status'] = {
'pos': (125, 20), 'pos': (125, 20),
'font': fonts.status_font(fonts.Medium), 'font': fonts.status_font(fonts.Medium),
'max': 20 'max': 20
} }
return self._layout return self._layout
def initialize(self): def initialize(self):
logging.info("initializing dfrobot1 display") logging.info("initializing dfrobot1 display")
from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot from pwnagotchi.ui.hw.libs.dfrobot.v1.dfrobot import DFRobot
self._display = DFRobot() self._display = DFRobot()
def render(self, canvas): def render(self, canvas):
buf = self._display.getbuffer(canvas) buf = self._display.getbuffer(canvas)
self._display.display(buf) self._display.display(buf)
def clear(self): def clear(self):
self._display.Clear(0xFF) self._display.Clear(0xFF)

Some files were not shown because too many files have changed in this diff Show More