Showing preview only (3,647K chars total). Download the full file or copy to clipboard to get everything.
Repository: evilsocket/pwnagotchi
Branch: master
Commit: 9f963e25e0c0
Files: 306
Total size: 3.4 MB
Directory structure:
gitextract_zo4q6okm/
├── .DEREK.yml
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature_request.md
│ │ └── other.md
│ ├── ISSUE_TEMPLATE.md
│ └── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .travis.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── MANIFEST.in
├── Makefile
├── README.md
├── bin/
│ └── pwnagotchi
├── builder/
│ ├── data/
│ │ ├── etc/
│ │ │ ├── bash_completion.d/
│ │ │ │ └── pwnagotchi_completion.sh
│ │ │ ├── network/
│ │ │ │ └── interfaces.d/
│ │ │ │ ├── eth0-cfg
│ │ │ │ ├── lo-cfg
│ │ │ │ ├── usb0-cfg
│ │ │ │ └── wlan0-cfg
│ │ │ └── systemd/
│ │ │ └── system/
│ │ │ ├── bettercap.service
│ │ │ ├── pwnagotchi.service
│ │ │ └── pwngrid-peer.service
│ │ └── usr/
│ │ └── bin/
│ │ ├── bettercap-launcher
│ │ ├── decryption-webserver
│ │ ├── hdmioff
│ │ ├── hdmion
│ │ ├── monstart
│ │ ├── monstop
│ │ ├── pwnagotchi-launcher
│ │ └── pwnlib
│ ├── pwnagotchi.json
│ └── pwnagotchi.yml
├── pwnagotchi/
│ ├── __init__.py
│ ├── _version.py
│ ├── agent.py
│ ├── ai/
│ │ ├── __init__.py
│ │ ├── epoch.py
│ │ ├── featurizer.py
│ │ ├── gym.py
│ │ ├── parameter.py
│ │ ├── reward.py
│ │ ├── train.py
│ │ └── utils.py
│ ├── automata.py
│ ├── bettercap.py
│ ├── defaults.toml
│ ├── fs/
│ │ └── __init__.py
│ ├── grid.py
│ ├── identity.py
│ ├── locale/
│ │ ├── af/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── bg/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── ch/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── cs/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── de/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── dk/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── el/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── es/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── fr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── ga/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── hr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── hu/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── it/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── jp/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── mk/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── nl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── no/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── pl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── pt/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── pt-BR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── ro/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── ru/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── se/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── sk/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── spa/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── tr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── tw/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ ├── ua/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── voice.mo
│ │ │ └── voice.po
│ │ └── voice.pot
│ ├── log.py
│ ├── mesh/
│ │ ├── __init__.py
│ │ ├── peer.py
│ │ ├── utils.py
│ │ └── wifi.py
│ ├── plugins/
│ │ ├── __init__.py
│ │ ├── cmd.py
│ │ └── default/
│ │ ├── auto-update.py
│ │ ├── bt-tether.py
│ │ ├── example.py
│ │ ├── gpio_buttons.py
│ │ ├── gps.py
│ │ ├── grid.py
│ │ ├── led.py
│ │ ├── logtail.py
│ │ ├── memtemp.py
│ │ ├── net-pos.py
│ │ ├── onlinehashcrack.py
│ │ ├── paw-gps.py
│ │ ├── session-stats.py
│ │ ├── switcher.py
│ │ ├── ups_lite.py
│ │ ├── watchdog.py
│ │ ├── webcfg.py
│ │ ├── webgpsmap.html
│ │ ├── webgpsmap.py
│ │ ├── wigle.py
│ │ └── wpa-sec.py
│ ├── ui/
│ │ ├── __init__.py
│ │ ├── components.py
│ │ ├── display.py
│ │ ├── faces.py
│ │ ├── fonts.py
│ │ ├── hw/
│ │ │ ├── __init__.py
│ │ │ ├── adafruitssd1306i2c.py
│ │ │ ├── base.py
│ │ │ ├── dfrobot1.py
│ │ │ ├── dfrobot2.py
│ │ │ ├── inky.py
│ │ │ ├── lcdhat.py
│ │ │ ├── libs/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── adafruit/
│ │ │ │ │ └── adafruitssd1306i2c/
│ │ │ │ │ ├── SSD1306.py
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── epd.py
│ │ │ │ ├── dfrobot/
│ │ │ │ │ ├── LICENSE
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── v1/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── dfrobot.py
│ │ │ │ │ │ ├── dfrobot_epaper.py
│ │ │ │ │ │ ├── gpio.py
│ │ │ │ │ │ └── spi.py
│ │ │ │ │ └── v2/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── dfrobot.py
│ │ │ │ │ ├── dfrobot_display/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── dfrobot_display.py
│ │ │ │ │ │ ├── dfrobot_fonts.py
│ │ │ │ │ │ └── dfrobot_printString.py
│ │ │ │ │ ├── dfrobot_epaper.py
│ │ │ │ │ ├── display_extension/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── fonts_6_8.py
│ │ │ │ │ │ ├── fonts_8_16.py
│ │ │ │ │ │ ├── freetype_helper.py
│ │ │ │ │ │ └── readme.md
│ │ │ │ │ ├── gpio.py
│ │ │ │ │ ├── i2c.py
│ │ │ │ │ └── spi.py
│ │ │ │ ├── fb/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── fb.py
│ │ │ │ ├── inkyphat/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── inkyfast.py
│ │ │ │ │ └── inkyphatfast.py
│ │ │ │ ├── papirus/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── epd.py
│ │ │ │ │ └── lm75b.py
│ │ │ │ └── waveshare/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── lcdhat/
│ │ │ │ │ ├── ST7789.py
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── config.py
│ │ │ │ │ └── epd.py
│ │ │ │ ├── lcdhat144/
│ │ │ │ │ ├── LCD_1in44.py
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── config.py
│ │ │ │ │ └── epd.py
│ │ │ │ ├── oledhat/
│ │ │ │ │ ├── SH1106.py
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── config.py
│ │ │ │ │ └── epd.py
│ │ │ │ ├── v1/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── epd2in13.py
│ │ │ │ │ ├── epd2in13bc.py
│ │ │ │ │ ├── epd2in13bcFAST.py
│ │ │ │ │ └── epdconfig.py
│ │ │ │ ├── v154inch/
│ │ │ │ │ ├── epd1in54b.py
│ │ │ │ │ └── epdconfig.py
│ │ │ │ ├── v2/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── waveshare.py
│ │ │ │ ├── v213bc/
│ │ │ │ │ ├── epd2in13bc.py
│ │ │ │ │ └── epdconfig.py
│ │ │ │ ├── v213d/
│ │ │ │ │ ├── epd2in13d.py
│ │ │ │ │ └── epdconfig.py
│ │ │ │ ├── v213inb_v4/
│ │ │ │ │ ├── epd2in13b_V4.py
│ │ │ │ │ └── epdconfig.py
│ │ │ │ ├── v27inch/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── epd2in7.py
│ │ │ │ │ └── epdconfig.py
│ │ │ │ ├── v29inch/
│ │ │ │ │ ├── epd2in9.py
│ │ │ │ │ └── epdconfig.py
│ │ │ │ └── v3/
│ │ │ │ ├── epd2in13_V3.py
│ │ │ │ └── epdconfig.py
│ │ │ ├── oledhat.py
│ │ │ ├── papirus.py
│ │ │ ├── spotpear24inch.py
│ │ │ ├── waveshare1.py
│ │ │ ├── waveshare144lcd.py
│ │ │ ├── waveshare154inch.py
│ │ │ ├── waveshare2.py
│ │ │ ├── waveshare213bc.py
│ │ │ ├── waveshare213d.py
│ │ │ ├── waveshare213inb_v4.py
│ │ │ ├── waveshare27inch.py
│ │ │ ├── waveshare29inch.py
│ │ │ ├── waveshare3.py
│ │ │ └── waveshare35lcd.py
│ │ ├── state.py
│ │ ├── view.py
│ │ └── web/
│ │ ├── __init__.py
│ │ ├── handler.py
│ │ ├── server.py
│ │ ├── static/
│ │ │ ├── css/
│ │ │ │ ├── jquery.jqplot.css
│ │ │ │ └── style.css
│ │ │ └── js/
│ │ │ ├── jquery.jqplot.js
│ │ │ ├── jquery.mobile/
│ │ │ │ ├── jquery.mobile-1.4.5.css
│ │ │ │ ├── jquery.mobile-1.4.5.js
│ │ │ │ ├── jquery.mobile.external-png-1.4.5.css
│ │ │ │ ├── jquery.mobile.icons-1.4.5.css
│ │ │ │ ├── jquery.mobile.inline-png-1.4.5.css
│ │ │ │ ├── jquery.mobile.inline-svg-1.4.5.css
│ │ │ │ ├── jquery.mobile.structure-1.4.5.css
│ │ │ │ └── jquery.mobile.theme-1.4.5.css
│ │ │ ├── jquery.timeago.js
│ │ │ ├── plugins/
│ │ │ │ ├── jqplot.BezierCurveRenderer.js
│ │ │ │ ├── jqplot.barRenderer.js
│ │ │ │ ├── jqplot.blockRenderer.js
│ │ │ │ ├── jqplot.bubbleRenderer.js
│ │ │ │ ├── jqplot.canvasAxisLabelRenderer.js
│ │ │ │ ├── jqplot.canvasAxisTickRenderer.js
│ │ │ │ ├── jqplot.canvasOverlay.js
│ │ │ │ ├── jqplot.canvasTextRenderer.js
│ │ │ │ ├── jqplot.categoryAxisRenderer.js
│ │ │ │ ├── jqplot.ciParser.js
│ │ │ │ ├── jqplot.cursor.js
│ │ │ │ ├── jqplot.dateAxisRenderer.js
│ │ │ │ ├── jqplot.donutRenderer.js
│ │ │ │ ├── jqplot.dragable.js
│ │ │ │ ├── jqplot.enhancedLegendRenderer.js
│ │ │ │ ├── jqplot.enhancedPieLegendRenderer.js
│ │ │ │ ├── jqplot.funnelRenderer.js
│ │ │ │ ├── jqplot.highlighter.js
│ │ │ │ ├── jqplot.json2.js
│ │ │ │ ├── jqplot.logAxisRenderer.js
│ │ │ │ ├── jqplot.mekkoAxisRenderer.js
│ │ │ │ ├── jqplot.mekkoRenderer.js
│ │ │ │ ├── jqplot.meterGaugeRenderer.js
│ │ │ │ ├── jqplot.mobile.js
│ │ │ │ ├── jqplot.ohlcRenderer.js
│ │ │ │ ├── jqplot.pieRenderer.js
│ │ │ │ ├── jqplot.pointLabels.js
│ │ │ │ ├── jqplot.pyramidAxisRenderer.js
│ │ │ │ ├── jqplot.pyramidGridRenderer.js
│ │ │ │ ├── jqplot.pyramidRenderer.js
│ │ │ │ └── jqplot.trendline.js
│ │ │ └── viewportHeight.js
│ │ └── templates/
│ │ ├── base.html
│ │ ├── inbox.html
│ │ ├── index.html
│ │ ├── message.html
│ │ ├── new_message.html
│ │ ├── peers.html
│ │ ├── plugins.html
│ │ ├── profile.html
│ │ └── status.html
│ ├── utils.py
│ └── voice.py
├── release.stork
├── requirements.txt
├── scripts/
│ ├── backup.sh
│ ├── language.sh
│ ├── linux_connection_share.sh
│ ├── macos_connection_share.sh
│ ├── openbsd_connection_share.sh
│ ├── preview.py
│ ├── pypi_upload.sh
│ ├── restore.sh
│ └── win_connection_share.ps1
└── setup.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .DEREK.yml
================================================
maintainers:
- evilsocket
- caquino
- justin-p
features:
- comments
- pr_description_required
================================================
FILE: .editorconfig
================================================
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[Makefile]
indent_style = tab
[*.py]
indent_style = space
indent_size = 4
[*.json]
insert_final_newline = ignore
[*.js]
indent_style = ignore
insert_final_newline = ignore
[*.{md,txt}]
indent_size = 4
trim_trailing_whitespace = false
================================================
FILE: .gitattributes
================================================
/builder/** linguist-vendored
/scripts/** linguist-vendored
/pwnagotchi/ui/web/static/** linguist-vendored
/pwnagotchi/ui/web/templates/*.* linguist-vendored
/pwnagotchi/ui/web/templates/** linguist-vendored
/pwnagotchi/locale/** linguist-vendored
================================================
FILE: .github/CODEOWNERS
================================================
evilsocket
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: # Replace with up to 4 GitHubSponsors-enabled usernames e.g., [user1, user2]
patreon: evilsocket
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. ...
2. ...
3. ...
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- Pwnagotchi version
- OS version
- Type of hardware
- Any additional hardware used
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/other.md
================================================
---
name: Other
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!--- Provide a general summary of the issue in the Title above -->
## Expected Behaviour
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
## Current Behaviour
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
## Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Your Environment
- [ ] You're using the official images
- [ ] You're using a raspberry pi 0
- [ ] You're using a supported LCD
<!--- Include as many relevant details about the environment you experienced the bug in -->
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
- [ ] I have raised an issue to propose this change ([required](https://github.com/evilsocket/pwnagotchi/blob/master/CONTRIBUTING.md))
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I've read the [CONTRIBUTION](https://github.com/evilsocket/pwnagotchi/blob/master/CONTRIBUTING.md) guide
- [ ] I have signed-off my commits with `git commit -s`
================================================
FILE: .gitignore
================================================
*.img
*.img.bmap
*.pcap
*.po~
preview.png
__pycache__
_backups
_emulation
_utils
config.laptop.yml
.idea
packer_cache
output-pwnagotchi
.DS_Store
build
dist
pwnagotchi.egg-info
*backup*.tgz
*backup*.gz
.vscode
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
================================================
FILE: .travis.yml
================================================
dist: bionic
language: go
go:
- 1.x
env:
global:
- LANG=C
- LC_ALL=C
deploy:
provider: releases
api_key:
secure: "Rj0QnEDv02UzjKaxHHxJ/Sdj50EOFIrsKShr27GtVNSwHmNKxQuwlh31T0DQdif4wzcDtUZ5XWxr85vLkKJt1L8anb7Tb63qlu7Da69C+upSUow1uJkjsiScbMPqwHpwDIkkcUIbPsdbowI7qiNhRBD7nF8yyLPC5YLiU0cXKuGh4+Q5xdIlL3P7p8jm0919Y+olglzAZj0iNR/QxGOb+laNH8xi0oUsIPi5V0ZFfO/W/sm+nks9ki5nolfd1ML1gcbOD7uKuxIMTUrpDLl4p2Jx9IVQW+G2/tkmNLbP5Ga65NxQcfABQDYY3tCD8PsmFK9PEwa4cMbGJjqlo3yR7P21J5Aj3rK+L4KDntOvwem3Z3Y/v2JlQZn+gelhNFCxuPBi3ZihSf7POMHtpAYmi13N2ruzOg1ayjeYph0iN3vXIPs67DpAPaxK+8L2yoo6Nr/Cago9pGTkZoqS+J0fnWT31NXoYREPgg//L2+m42twQirFXttbhlGTBgNMLXpwcm8bZ2DW3pu3AEgVUxSoNAOjudoeyC0VzA6nUqe6STmfk06OYqcwM8q8NEyD62iAvUYU3Q7FnauZqcBqcP+ZYx82NPZybrQRX6YlJck5UomHbbEfjgpDFT+WvjrrfICmXH29YBOL1LWR4cKMT6RY58Cv8hT2PYxomB2I+DRrbqU="
skip_cleanup: true
file_glob: true
file:
- pwnagotchi-*.zip
- pwnagotchi-*.sha256
on:
tags: true
repo: evilsocket/pwnagotchi
branches:
only:
- "/^v[0-9]+\\.[0-9]+\\.[0-9]+[A-Za-z0-9]*$/"
cache:
apt: true
before_script:
- sudo apt-get -y update || true
- sudo apt-get -y install qemu-system-arm qemu-user-static binfmt-support bmap-tools kpartx
- sudo update-binfmts --display
script:
- sudo make clean
- sudo -E env "PATH=$PATH" make install
- sudo make image -e PWN_HOSTNAME=pwnagotchi PWN_VERSION=$TRAVIS_TAG
notifications:
slack:
secure: aovN87lswg+TTLobxJpevC0p2F4omTAlsOzeKqLysRW55o5rRhRC1SgwRkWUl19yr49nsyffwmv/b7OcyQiWIVnz1bxxE9XOKP8zgRMA/bKKcyAcPktPqHXsALIQDseXyl0kz7fwdkRWg0UC2HpKqi5koAhmBYTX/fbzieyeHCbcQ7lbFfVFIepE1401y9m1IqUHcHuGfFhMvTaSDIpXrDXnWdA8+gDAl0HKJv41MIsgmffbh/QhD2jLBWzItjxFC3llmNfy88pnzCk0+HBMY/4272LXb0czX7et5HJeM74oxPqkb3aKXFxZgNaDl7cYdV+kzj9dfKUk47hAqwbxlirit5WvHI1Br1VyA90+PFvcC/p41J8gCv0IlcB5vjWN8NKWA1J+Y1F+KvrujMvGtgd0foHZvaSutuRODhI1cBh5rYAiLCroRSlvKMw3IJRyCRstYgUlMIJ3cI2Ova/kU44KtDVmjT9VE/pPkhkHBPvcYThL6skZTdl19E/RlormLu3XObG1aHLZ+Znxe/aL7tWHi0KMOlpy+TMDdps4go7URnJ8yitHtIvU/zMtBrztIwN0Oy2JLKXrS5qIijmRAkBLxe0NxuG01DYFzEO3KtnRirP4uSe3QcrjyP4sqPrVhrjl3TR6gwg8V1juvDXB4e2h8yCpaUW5AdSBOlx9riY=
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at pwnagotchi@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: CONTRIBUTING.md
================================================
## Contributing
### Guidelines
Here are a few guidelines for contributing:
* If you would like to contribute to the codebase **please raise an issue to propose the change**
* Do not mix feature changes or fixes with refactoring - it makes the code harder to review and means there is more for the maintainers (with limited time) to test
* If you have found a bug please raise an issue and fill out the whole template.
* If the documentation can be improved / translated etc please raise an issue to discuss.
* Please always provide a summary of what you changed, how you did it and how it can be tested.
### License
This project is licensed under the GPL3 License.
#### Sign your work
The sign-off is a simple line at the end of the explanation for a patch. Your
signature certifies that you wrote the patch or otherwise have the right to pass
it on as an open-source patch. The rules are pretty simple: if you can certify
the below (from [developercertificate.org](http://developercertificate.org/)):
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
Then you just add a line to every git commit message:
Signed-off-by: Joe Smith <joe.smith@email.com>
If you set your `user.name` and `user.email` git configs, you can sign your
commit automatically with `git commit -s`.
* Please sign your commits with `git commit -s` so that commits are traceable.
================================================
FILE: LICENSE.md
================================================
GNU GENERAL PUBLIC LICENSE
==========================
Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. <<https://www.fsf.org/>>
Everyone is permitted to copy and distribute verbatim copies of this license
document, but changing it is not allowed.
## Preamble
The GNU General Public License is a free, copyleft license for software and other
kinds of works.
The licenses for most software and other practical works are designed to take away
your freedom to share and change the works. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change all versions of a
program--to make sure it remains free software for all its users. We, the Free
Software Foundation, use the GNU General Public License for most of our software; it
applies also to any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General
Public Licenses are designed to make sure that you have the freedom to distribute
copies of free software (and charge for them if you wish), that you receive source
code or can get it if you want it, that you can change the software or use pieces of
it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or
asking you to surrender the rights. Therefore, you have certain responsibilities if
you distribute copies of the software, or if you modify it: responsibilities to
respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee,
you must pass on to the recipients the same freedoms that you received. You must make
sure that they, too, receive or can get the source code. And you must show them these
terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert
copyright on the software, and (2) offer you this License giving you legal permission
to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is
no warranty for this free software. For both users' and authors' sake, the GPL
requires that modified versions be marked as changed, so that their problems will not
be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of
the software inside them, although the manufacturer can do so. This is fundamentally
incompatible with the aim of protecting users' freedom to change the software. The
systematic pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we have designed
this version of the GPL to prohibit the practice for those products. If such problems
arise substantially in other domains, we stand ready to extend this provision to
those domains in future versions of the GPL, as needed to protect the freedom of
users.
Finally, every program is threatened constantly by software patents. States should
not allow patents to restrict development and use of software on general-purpose
computers, but in those that do, we wish to avoid the special danger that patents
applied to a free program could make it effectively proprietary. To prevent this, the
GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
## TERMS AND CONDITIONS
### 0. Definitions.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this
License. Each licensee is addressed as “you”. “Licensees” and
“recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in
a fashion requiring copyright permission, other than the making of an exact copy. The
resulting work is called a “modified version” of the earlier work or a
work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on
the Program.
To “propagate” a work means to do anything with it that, without
permission, would make you directly or secondarily liable for infringement under
applicable copyright law, except executing it on a computer or modifying a private
copy. Propagation includes copying, distribution (with or without modification),
making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through a computer
network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the
extent that it includes a convenient and prominently visible feature that (1)
displays an appropriate copyright notice, and (2) tells the user that there is no
warranty for the work (except to the extent that warranties are provided), that
licensees may convey the work under this License, and how to view a copy of this
License. If the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
### 1. Source Code.
The “source code” for a work means the preferred form of the work for
making modifications to it. “Object code” means any non-source form of a
work.
A “Standard Interface” means an interface that either is an official
standard defined by a recognized standards body, or, in the case of interfaces
specified for a particular programming language, one that is widely used among
developers working in that language.
The “System Libraries” of an executable work include anything, other than
the work as a whole, that (a) is included in the normal form of packaging a Major
Component, but which is not part of that Major Component, and (b) serves only to
enable use of the work with that Major Component, or to implement a Standard
Interface for which an implementation is available to the public in source code form.
A “Major Component”, in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system (if any) on which
the executable work runs, or a compiler used to produce the work, or an object code
interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the
source code needed to generate, install, and (for an executable work) run the object
code and to modify the work, including scripts to control those activities. However,
it does not include the work's System Libraries, or general-purpose tools or
generally available free programs which are used unmodified in performing those
activities but which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for the work, and
the source code for shared libraries and dynamically linked subprograms that the work
is specifically designed to require, such as by intimate data communication or
control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate
automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
### 2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the
Program, and are irrevocable provided the stated conditions are met. This License
explicitly affirms your unlimited permission to run the unmodified Program. The
output from running a covered work is covered by this License only if the output,
given its content, constitutes a covered work. This License acknowledges your rights
of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without
conditions so long as your license otherwise remains in force. You may convey covered
works to others for the sole purpose of having them make modifications exclusively
for you, or provide you with facilities for running those works, provided that you
comply with the terms of this License in conveying all material for which you do not
control copyright. Those thus making or running the covered works for you must do so
exclusively on your behalf, under your direction and control, on terms that prohibit
them from making any copies of your copyrighted material outside their relationship
with you.
Conveying under any other circumstances is permitted solely under the conditions
stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any
applicable law fulfilling obligations under article 11 of the WIPO copyright treaty
adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention
of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of
technological measures to the extent such circumvention is effected by exercising
rights under this License with respect to the covered work, and you disclaim any
intention to limit operation or modification of the work as a means of enforcing,
against the work's users, your or third parties' legal rights to forbid circumvention
of technological measures.
### 4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any
medium, provided that you conspicuously and appropriately publish on each copy an
appropriate copyright notice; keep intact all notices stating that this License and
any non-permissive terms added in accord with section 7 apply to the code; keep
intact all notices of the absence of any warranty; and give all recipients a copy of
this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer
support or warranty protection for a fee.
### 5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from
the Program, in the form of source code under the terms of section 4, provided that
you also meet all of these conditions:
* **a)** The work must carry prominent notices stating that you modified it, and giving a
relevant date.
* **b)** The work must carry prominent notices stating that it is released under this
License and any conditions added under section 7. This requirement modifies the
requirement in section 4 to “keep intact all notices”.
* **c)** You must license the entire work, as a whole, under this License to anyone who
comes into possession of a copy. This License will therefore apply, along with any
applicable section 7 additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no permission to license the
work in any other way, but it does not invalidate such permission if you have
separately received it.
* **d)** If the work has interactive user interfaces, each must display Appropriate Legal
Notices; however, if the Program has interactive interfaces that do not display
Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are
not by their nature extensions of the covered work, and which are not combined with
it such as to form a larger program, in or on a volume of a storage or distribution
medium, is called an “aggregate” if the compilation and its resulting
copyright are not used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work in an aggregate
does not cause this License to apply to the other parts of the aggregate.
### 6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and
5, provided that you also convey the machine-readable Corresponding Source under the
terms of this License, in one of these ways:
* **a)** Convey the object code in, or embodied in, a physical product (including a
physical distribution medium), accompanied by the Corresponding Source fixed on a
durable physical medium customarily used for software interchange.
* **b)** Convey the object code in, or embodied in, a physical product (including a
physical distribution medium), accompanied by a written offer, valid for at least
three years and valid for as long as you offer spare parts or customer support for
that product model, to give anyone who possesses the object code either (1) a copy of
the Corresponding Source for all the software in the product that is covered by this
License, on a durable physical medium customarily used for software interchange, for
a price no more than your reasonable cost of physically performing this conveying of
source, or (2) access to copy the Corresponding Source from a network server at no
charge.
* **c)** Convey individual copies of the object code with a copy of the written offer to
provide the Corresponding Source. This alternative is allowed only occasionally and
noncommercially, and only if you received the object code with such an offer, in
accord with subsection 6b.
* **d)** Convey the object code by offering access from a designated place (gratis or for
a charge), and offer equivalent access to the Corresponding Source in the same way
through the same place at no further charge. You need not require recipients to copy
the Corresponding Source along with the object code. If the place to copy the object
code is a network server, the Corresponding Source may be on a different server
(operated by you or a third party) that supports equivalent copying facilities,
provided you maintain clear directions next to the object code saying where to find
the Corresponding Source. Regardless of what server hosts the Corresponding Source,
you remain obligated to ensure that it is available for as long as needed to satisfy
these requirements.
* **e)** Convey the object code using peer-to-peer transmission, provided you inform
other peers where the object code and Corresponding Source of the work are being
offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the
Corresponding Source as a System Library, need not be included in conveying the
object code work.
A “User Product” is either (1) a “consumer product”, which
means any tangible personal property which is normally used for personal, family, or
household purposes, or (2) anything designed or sold for incorporation into a
dwelling. In determining whether a product is a consumer product, doubtful cases
shall be resolved in favor of coverage. For a particular product received by a
particular user, “normally used” refers to a typical or common use of
that class of product, regardless of the status of the particular user or of the way
in which the particular user actually uses, or expects or is expected to use, the
product. A product is a consumer product regardless of whether the product has
substantial commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
“Installation Information” for a User Product means any methods,
procedures, authorization keys, or other information required to install and execute
modified versions of a covered work in that User Product from a modified version of
its Corresponding Source. The information must suffice to ensure that the continued
functioning of the modified object code is in no case prevented or interfered with
solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for
use in, a User Product, and the conveying occurs as part of a transaction in which
the right of possession and use of the User Product is transferred to the recipient
in perpetuity or for a fixed term (regardless of how the transaction is
characterized), the Corresponding Source conveyed under this section must be
accompanied by the Installation Information. But this requirement does not apply if
neither you nor any third party retains the ability to install modified object code
on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to
continue to provide support service, warranty, or updates for a work that has been
modified or installed by the recipient, or for the User Product in which it has been
modified or installed. Access to a network may be denied when the modification itself
materially and adversely affects the operation of the network or violates the rules
and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with
this section must be in a format that is publicly documented (and with an
implementation available to the public in source code form), and must require no
special password or key for unpacking, reading or copying.
### 7. Additional Terms.
“Additional permissions” are terms that supplement the terms of this
License by making exceptions from one or more of its conditions. Additional
permissions that are applicable to the entire Program shall be treated as though they
were included in this License, to the extent that they are valid under applicable
law. If additional permissions apply only to part of the Program, that part may be
used separately under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any
additional permissions from that copy, or from any part of it. (Additional
permissions may be written to require their own removal in certain cases when you
modify the work.) You may place additional permissions on material, added by you to a
covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a
covered work, you may (if authorized by the copyright holders of that material)
supplement the terms of this License with terms:
* **a)** Disclaiming warranty or limiting liability differently from the terms of
sections 15 and 16 of this License; or
* **b)** Requiring preservation of specified reasonable legal notices or author
attributions in that material or in the Appropriate Legal Notices displayed by works
containing it; or
* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that
modified versions of such material be marked in reasonable ways as different from the
original version; or
* **d)** Limiting the use for publicity purposes of names of licensors or authors of the
material; or
* **e)** Declining to grant rights under trademark law for use of some trade names,
trademarks, or service marks; or
* **f)** Requiring indemnification of licensors and authors of that material by anyone
who conveys the material (or modified versions of it) with contractual assumptions of
liability to the recipient, for any liability that these contractual assumptions
directly impose on those licensors and authors.
All other non-permissive additional terms are considered “further
restrictions” within the meaning of section 10. If the Program as you received
it, or any part of it, contains a notice stating that it is governed by this License
along with a term that is a further restriction, you may remove that term. If a
license document contains a further restriction but permits relicensing or conveying
under this License, you may add to a covered work material governed by the terms of
that license document, provided that the further restriction does not survive such
relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in
the relevant source files, a statement of the additional terms that apply to those
files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a
separately written license, or stated as exceptions; the above requirements apply
either way.
### 8. Termination.
You may not propagate or modify a covered work except as expressly provided under
this License. Any attempt otherwise to propagate or modify it is void, and will
automatically terminate your rights under this License (including any patent licenses
granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a
particular copyright holder is reinstated (a) provisionally, unless and until the
copyright holder explicitly and finally terminates your license, and (b) permanently,
if the copyright holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently
if the copyright holder notifies you of the violation by some reasonable means, this
is the first time you have received notice of violation of this License (for any
work) from that copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of
parties who have received copies or rights from you under this License. If your
rights have been terminated and not permanently reinstated, you do not qualify to
receive new licenses for the same material under section 10.
### 9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the
Program. Ancillary propagation of a covered work occurring solely as a consequence of
using peer-to-peer transmission to receive a copy likewise does not require
acceptance. However, nothing other than this License grants you permission to
propagate or modify any covered work. These actions infringe copyright if you do not
accept this License. Therefore, by modifying or propagating a covered work, you
indicate your acceptance of this License to do so.
### 10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license
from the original licensors, to run, modify and propagate that work, subject to this
License. You are not responsible for enforcing compliance by third parties with this
License.
An “entity transaction” is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an organization, or
merging organizations. If propagation of a covered work results from an entity
transaction, each party to that transaction who receives a copy of the work also
receives whatever licenses to the work the party's predecessor in interest had or
could give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if the predecessor
has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or
affirmed under this License. For example, you may not impose a license fee, royalty,
or other charge for exercise of rights granted under this License, and you may not
initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging
that any patent claim is infringed by making, using, selling, offering for sale, or
importing the Program or any portion of it.
### 11. Patents.
A “contributor” is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The work thus
licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims owned or
controlled by the contributor, whether already acquired or hereafter acquired, that
would be infringed by some manner, permitted by this License, of making, using, or
selling its contributor version, but do not include claims that would be infringed
only as a consequence of further modification of the contributor version. For
purposes of this definition, “control” includes the right to grant patent
sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license
under the contributor's essential patent claims, to make, use, sell, offer for sale,
import and otherwise run, modify and propagate the contents of its contributor
version.
In the following three paragraphs, a “patent license” is any express
agreement or commitment, however denominated, not to enforce a patent (such as an
express permission to practice a patent or covenant not to sue for patent
infringement). To “grant” such a patent license to a party means to make
such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the
Corresponding Source of the work is not available for anyone to copy, free of charge
and under the terms of this License, through a publicly available network server or
other readily accessible means, then you must either (1) cause the Corresponding
Source to be so available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner consistent with
the requirements of this License, to extend the patent license to downstream
recipients. “Knowingly relying” means you have actual knowledge that, but
for the patent license, your conveying the covered work in a country, or your
recipient's use of the covered work in a country, would infringe one or more
identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you
convey, or propagate by procuring conveyance of, a covered work, and grant a patent
license to some of the parties receiving the covered work authorizing them to use,
propagate, modify or convey a specific copy of the covered work, then the patent
license you grant is automatically extended to all recipients of the covered work and
works based on it.
A patent license is “discriminatory” if it does not include within the
scope of its coverage, prohibits the exercise of, or is conditioned on the
non-exercise of one or more of the rights that are specifically granted under this
License. You may not convey a covered work if you are a party to an arrangement with
a third party that is in the business of distributing software, under which you make
payment to the third party based on the extent of your activity of conveying the
work, and under which the third party grants, to any of the parties who would receive
the covered work from you, a discriminatory patent license (a) in connection with
copies of the covered work conveyed by you (or copies made from those copies), or (b)
primarily for and in connection with specific products or compilations that contain
the covered work, unless you entered into that arrangement, or that patent license
was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied
license or other defenses to infringement that may otherwise be available to you
under applicable patent law.
### 12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise)
that contradict the conditions of this License, they do not excuse you from the
conditions of this License. If you cannot convey a covered work so as to satisfy
simultaneously your obligations under this License and any other pertinent
obligations, then as a consequence you may not convey it at all. For example, if you
agree to terms that obligate you to collect a royalty for further conveying from
those to whom you convey the Program, the only way you could satisfy both those terms
and this License would be to refrain entirely from conveying the Program.
### 13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or
combine any covered work with a work licensed under version 3 of the GNU Affero
General Public License into a single combined work, and to convey the resulting work.
The terms of this License will continue to apply to the part which is the covered
work, but the special requirements of the GNU Affero General Public License, section
13, concerning interaction through a network will apply to the combination as such.
### 14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU
General Public License from time to time. Such new versions will be similar in spirit
to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that
a certain numbered version of the GNU General Public License “or any later
version” applies to it, you have the option of following the terms and
conditions either of that numbered version or of any later version published by the
Free Software Foundation. If the Program does not specify a version number of the GNU
General Public License, you may choose any version ever published by the Free
Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU
General Public License can be used, that proxy's public statement of acceptance of a
version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no
additional obligations are imposed on any author or copyright holder as a result of
your choosing to follow a later version.
### 15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
### 16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE
OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
### 17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be
given local legal effect according to their terms, reviewing courts shall apply local
law that most closely approximates an absolute waiver of all civil liability in
connection with the Program, unless a warranty or assumption of liability accompanies
a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
## How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to
the public, the best way to achieve this is to make it free software which everyone
can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them
to the start of each source file to most effectively state the exclusion of warranty;
and each file should have at least the “copyright” line and a pointer to
where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this
when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'show c' for details.
The hypothetical commands 'show w' and 'show c' should show the appropriate parts of
the General Public License. Of course, your program's commands might be different;
for a GUI interface, you would use an “about box”.
You should also get your employer (if you work as a programmer) or school, if any, to
sign a “copyright disclaimer” for the program, if necessary. For more
information on this, and how to apply and follow the GNU GPL, see
<<https://www.gnu.org/licenses/>>.
The GNU General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may consider it
more useful to permit linking proprietary applications with the library. If this is
what you want to do, use the GNU Lesser General Public License instead of this
License. But first, please read
<<https://www.gnu.org/philosophy/why-not-lgpl.html>>.
================================================
FILE: MANIFEST.in
================================================
exclude *.pyc .DS_Store .gitignore MANIFEST.in
include setup.py
include distribute_setup.py
include README.md
include LICENSE
recursive-include bin *
recursive-include pwnagotchi *.py
recursive-include pwnagotchi *.yml
recursive-include pwnagotchi *.*
================================================
FILE: Makefile
================================================
PACKER_VERSION=1.7.2
PWN_HOSTNAME=pwnagotchi
PWN_VERSION=master
all: clean install image
langs:
@for lang in pwnagotchi/locale/*/; do\
echo "compiling language: $$lang ..."; \
./scripts/language.sh compile $$(basename $$lang); \
done
install:
curl https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_amd64.zip -o /tmp/packer.zip
unzip /tmp/packer.zip -d /tmp
sudo mv /tmp/packer /usr/bin/packer
git clone https://github.com/solo-io/packer-builder-arm-image /tmp/packer-builder-arm-image
cd /tmp/packer-builder-arm-image && go get -d ./... && go build
sudo cp /tmp/packer-builder-arm-image/packer-builder-arm-image /usr/bin
image:
cd builder && sudo /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" pwnagotchi.json
sudo mv builder/output-pwnagotchi/image pwnagotchi-raspbian-lite-$(PWN_VERSION).img
sudo sha256sum pwnagotchi-raspbian-lite-$(PWN_VERSION).img > pwnagotchi-raspbian-lite-$(PWN_VERSION).sha256
sudo zip pwnagotchi-raspbian-lite-$(PWN_VERSION).zip pwnagotchi-raspbian-lite-$(PWN_VERSION).sha256 pwnagotchi-raspbian-lite-$(PWN_VERSION).img
clean:
rm -rf /tmp/packer-builder-arm-image
rm -f pwnagotchi-raspbian-lite-*.zip pwnagotchi-raspbian-lite-*.img pwnagotchi-raspbian-lite-*.sha256
rm -rf builder/output-pwnagotchi builder/packer_cache
================================================
FILE: README.md
================================================
<p align="center">
<small>Join the project community on our server!</small>
<br/><br/>
<a href="https://discord.gg/https://discord.gg/btZpkp45gQ" target="_blank" title="Join our community!">
<img src="https://dcbadge.limes.pink/api/server/https://discord.gg/btZpkp45gQ"/>
</a>
</p>
<hr/>
<p align="center">
<a href="https://github.com/evilsocket/pwnagotchi/releases/latest"><img alt="Release" src="https://img.shields.io/github/release/evilsocket/pwnagotchi.svg?style=flat-square"></a>
<a href="https://github.com/evilsocket/pwnagotchi/blob/master/LICENSE.md"><img alt="Software License" src="https://img.shields.io/badge/license-GPL3-brightgreen.svg?style=flat-square"></a>
<a href="https://github.com/evilsocket/pwnagotchi/graphs/contributors"><img alt="Contributors" src="https://img.shields.io/github/contributors/evilsocket/pwnagotchi"/></a>
<a href="https://twitter.com/intent/follow?screen_name=pwnagotchi"><img src="https://img.shields.io/twitter/follow/pwnagotchi?style=social&logo=twitter" alt="follow on Twitter"></a>
<br/>
<br/>
<img src="https://www.evilsocket.net/images/human-coded.png" height="30px" alt="This project is 100% made by humans."/>
</p>
[Pwnagotchi](https://pwnagotchi.ai/) is an [A2C](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752)-based "AI" leveraging [bettercap](https://www.bettercap.org/) that learns from its surrounding WiFi environment to maximize the crackable WPA key material it captures (either passively, or by performing authentication and association attacks). This material is collected as PCAP files containing any form of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/),
full and half WPA handshakes.

Instead of merely playing [Super Mario or Atari games](https://becominghuman.ai/getting-mario-back-into-the-gym-setting-up-super-mario-bros-in-openais-gym-8e39a96c1e41?gi=c4b66c3d5ced) like most reinforcement learning-based "AI" *(yawn)*, Pwnagotchi tunes [its parameters](https://github.com/evilsocket/pwnagotchi/blob/master/pwnagotchi/defaults.toml) over time to **get better at pwning WiFi things to** in the environments you expose it to.
More specifically, Pwnagotchi is using an [LSTM with MLP feature extractor](https://stable-baselines.readthedocs.io/en/master/modules/policies.html#stable_baselines.common.policies.MlpLstmPolicy) as its policy network for the [A2C agent](https://stable-baselines.readthedocs.io/en/master/modules/a2c.html). If you're unfamiliar with A2C, here is [a very good introductory explanation](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752) (in comic form!) of the basic principles behind how Pwnagotchi learns. (You can read more about how Pwnagotchi learns in the [Usage](https://www.pwnagotchi.ai/usage/#training-the-ai) doc.)
**Keep in mind:** Unlike the usual RL simulations, Pwnagotchi learns over time. Time for a Pwnagotchi is measured in epochs; a single epoch can last from a few seconds to minutes, depending on how many access points and client stations are visible. Do not expect your Pwnagotchi to perform amazingly well at the very beginning, as it will be [exploring](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752) several combinations of [key parameters](https://www.pwnagotchi.ai/usage/#training-the-ai) to determine ideal adjustments for pwning the particular environment you are exposing it to during its beginning epochs ... but ** listen to your Pwnagotchi when it tells you it's boring!** Bring it into novel WiFi environments with you and have it observe new networks and capture new handshakes—and you'll see. :)
Multiple units within close physical proximity can "talk" to each other, advertising their presence to each other by broadcasting custom information elements using a parasite protocol I've built on top of the existing dot11 standard. Over time, two or more units trained together will learn to cooperate upon detecting each other's presence by dividing the available channels among them for optimal pwnage.
## Documentation
https://www.pwnagotchi.ai
## Links
| Official Links
---------|-------
Website | [pwnagotchi.ai](https://pwnagotchi.ai/)
Forum | [community.pwnagotchi.ai](https://community.pwnagotchi.ai/)
Slack | [pwnagotchi.slack.com](https://invite.pwnagotchi.ai/)
Subreddit | [r/pwnagotchi](https://www.reddit.com/r/pwnagotchi/)
Twitter | [@pwnagotchi](https://twitter.com/pwnagotchi)
## License
`pwnagotchi` is made with ♥ by [@evilsocket](https://twitter.com/evilsocket) and the [amazing dev team](https://github.com/evilsocket/pwnagotchi/graphs/contributors). It is released under the GPL3 license.
================================================
FILE: bin/pwnagotchi
================================================
#!/usr/bin/python3
import logging
import argparse
import time
import signal
import sys
import toml
import pwnagotchi
from pwnagotchi import utils
from pwnagotchi.plugins import cmd as plugins_cmd
from pwnagotchi import log
from pwnagotchi import restart
from pwnagotchi import fs
from pwnagotchi.utils import DottedTomlEncoder
def do_clear(display):
logging.info("clearing the display ...")
display.clear()
sys.exit(0)
def do_manual_mode(agent):
logging.info("entering manual mode ...")
agent.mode = 'manual'
agent.last_session.parse(agent.view(), args.skip_session)
if not args.skip_session:
logging.info(
"the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
agent.last_session.duration_human,
agent.last_session.epochs,
agent.last_session.train_epochs,
agent.last_session.avg_reward,
agent.last_session.min_reward,
agent.last_session.max_reward))
while True:
display.on_manual_mode(agent.last_session)
time.sleep(5)
if grid.is_connected():
plugins.on('internet_available', agent)
def do_auto_mode(agent):
logging.info("entering auto mode ...")
agent.mode = 'auto'
agent.start()
while True:
try:
# recon on all channels
agent.recon()
# get nearby access points grouped by channel
channels = agent.get_access_points_by_channel()
# for each channel
for ch, aps in channels:
agent.set_channel(ch)
if not agent.is_stale() and agent.any_activity():
logging.info("%d access points on channel %d" % (len(aps), ch))
# for each ap on this channel
for ap in aps:
# send an association frame in order to get for a PMKID
agent.associate(ap)
# deauth all client stations in order to get a full handshake
for sta in ap['clients']:
agent.deauth(ap, sta)
# An interesting effect of this:
#
# From Pwnagotchi's perspective, the more new access points
# and / or client stations nearby, the longer one epoch of
# its relative time will take ... basically, in Pwnagotchi's universe,
# WiFi electromagnetic fields affect time like gravitational fields
# affect ours ... neat ^_^
agent.next_epoch()
if grid.is_connected():
plugins.on('internet_available', agent)
except Exception as e:
if str(e).find("wifi.interface not set") > 0:
logging.exception("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")
time.sleep(60)
agent.next_epoch()
else:
logging.exception("main loop exception (%s)", e)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser = plugins_cmd.add_parsers(parser)
parser.add_argument('-C', '--config', action='store', dest='config', default='/etc/pwnagotchi/default.toml',
help='Main configuration file.')
parser.add_argument('-U', '--user-config', action='store', dest='user_config', default='/etc/pwnagotchi/config.toml',
help='If this file exists, configuration will be merged and this will override default values.')
parser.add_argument('--manual', dest="do_manual", action="store_true", default=False, help="Manual mode.")
parser.add_argument('--skip-session', dest="skip_session", action="store_true", default=False,
help="Skip last session parsing in manual mode.")
parser.add_argument('--clear', dest="do_clear", action="store_true", default=False,
help="Clear the ePaper display and exit.")
parser.add_argument('--debug', dest="debug", action="store_true", default=False,
help="Enable debug logs.")
parser.add_argument('--version', dest="version", action="store_true", default=False,
help="Print the version.")
parser.add_argument('--print-config', dest="print_config", action="store_true", default=False,
help="Print the configuration.")
args = parser.parse_args()
if plugins_cmd.used_plugin_cmd(args):
config = utils.load_config(args)
log.setup_logging(args, config)
rc = plugins_cmd.handle_cmd(args, config)
sys.exit(rc)
if args.version:
print(pwnagotchi.__version__)
sys.exit(0)
config = utils.load_config(args)
if args.print_config:
print(toml.dumps(config, encoder=DottedTomlEncoder()))
sys.exit(0)
from pwnagotchi.identity import KeyPair
from pwnagotchi.agent import Agent
from pwnagotchi.ui import fonts
from pwnagotchi.ui.display import Display
from pwnagotchi import grid
from pwnagotchi import plugins
pwnagotchi.config = config
fs.setup_mounts(config)
log.setup_logging(args, config)
fonts.init(config)
pwnagotchi.set_name(config['main']['name'])
plugins.load(config)
display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
if args.do_clear:
do_clear(display)
sys.exit(0)
agent = Agent(view=display, config=config, keypair=KeyPair(view=display))
def usr1_handler(*unused):
logging.info('Received USR1 singal. Restart process ...')
restart("MANU" if args.do_manual else "AUTO")
signal.signal(signal.SIGUSR1, usr1_handler)
if args.do_manual:
do_manual_mode(agent)
else:
do_auto_mode(agent)
================================================
FILE: builder/data/etc/bash_completion.d/pwnagotchi_completion.sh
================================================
_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 {plugins}
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
"
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
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}')"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
opts="$(echo $opt_line | grep -Po '{\K[^}]+' | tr ',' '\n')"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
}
complete -F _show_complete pwnagotchi
================================================
FILE: builder/data/etc/network/interfaces.d/eth0-cfg
================================================
allow-hotplug eth0
iface eth0 inet dhcp
================================================
FILE: builder/data/etc/network/interfaces.d/lo-cfg
================================================
auto lo
iface lo inet loopback
================================================
FILE: builder/data/etc/network/interfaces.d/usb0-cfg
================================================
allow-hotplug usb0
iface usb0 inet static
address 10.0.0.2
netmask 255.255.255.0
network 10.0.0.0
broadcast 10.0.0.255
gateway 10.0.0.1
metric 20
================================================
FILE: builder/data/etc/network/interfaces.d/wlan0-cfg
================================================
allow-hotplug wlan0
iface wlan0 inet static
================================================
FILE: builder/data/etc/systemd/system/bettercap.service
================================================
[Unit]
Description=bettercap api.rest service.
Documentation=https://bettercap.org
Wants=network.target
[Service]
Type=simple
PermissionsStartOnly=true
ExecStart=/usr/bin/bettercap-launcher
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
================================================
FILE: builder/data/etc/systemd/system/pwnagotchi.service
================================================
[Unit]
Description=pwnagotchi Deep Reinforcement Learning instrumenting bettercap for WiFI pwning.
Documentation=https://pwnagotchi.ai
Wants=network.target
After=pwngrid-peer.service
[Service]
Type=simple
WorkingDirectory=/tmp
PermissionsStartOnly=true
ExecStart=/usr/bin/pwnagotchi-launcher
Restart=always
RestartSec=30
TasksMax=infinity
LimitNPROC=infinity
StandardOutput=null
StandardError=null
[Install]
WantedBy=multi-user.target
================================================
FILE: builder/data/etc/systemd/system/pwngrid-peer.service
================================================
[Unit]
Description=pwngrid peer service.
Documentation=https://pwnagotchi.ai
Wants=network.target
After=bettercap.service
[Service]
Type=simple
PermissionsStartOnly=true
ExecStart=/usr/bin/pwngrid -keys /etc/pwnagotchi -address 127.0.0.1:8666 -client-token /root/.api-enrollment.json -wait -log /var/log/pwngrid-peer.log -iface mon0
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
================================================
FILE: builder/data/usr/bin/bettercap-launcher
================================================
#!/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
# check if wifi driver is bugged
if ! check_brcm; then
if ! reload_brcm; then
echo "Could not reload wifi driver. Reboot"
reboot
fi
sleep 10
fi
# start mon0
start_monitor_interface
if is_auto_mode_no_delete; then
/usr/bin/bettercap -no-colors -caplet pwnagotchi-auto -iface mon0
else
/usr/bin/bettercap -no-colors -caplet pwnagotchi-manual -iface mon0
fi
================================================
FILE: builder/data/usr/bin/decryption-webserver
================================================
#!/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()
================================================
FILE: builder/data/usr/bin/hdmioff
================================================
#!/usr/bin/env bash
sudo /opt/vc/bin/tvservice -o
================================================
FILE: builder/data/usr/bin/hdmion
================================================
#!/usr/bin/env bash
sudo /opt/vc/bin/tvservice -p
================================================
FILE: builder/data/usr/bin/monstart
================================================
#!/usr/bin/env bash
source /usr/bin/pwnlib
start_monitor_interface
================================================
FILE: builder/data/usr/bin/monstop
================================================
#!/usr/bin/env bash
source /usr/bin/pwnlib
stop_monitor_interface
================================================
FILE: builder/data/usr/bin/pwnagotchi-launcher
================================================
#!/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
# blink 10 times to signal ready state
blink_led 10 &
if is_auto_mode; then
/usr/local/bin/pwnagotchi
else
/usr/local/bin/pwnagotchi --manual
fi
================================================
FILE: builder/data/usr/bin/pwnlib
================================================
#!/usr/bin/env bash
# well ... it blinks the led
blink_led() {
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_brcm() {
if [[ "$(journalctl -n10 -k --since -5m | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 5 ]]; then
return 1
fi
return 0
}
# reload mod
reload_brcm() {
if ! modprobe -r brcmfmac; then
return 1
fi
if ! modprobe brcmfmac; then
return 1
fi
return 0
}
# starts mon0
start_monitor_interface() {
iw phy "$(iw phy | head -1 | cut -d" " -f2)" interface add mon0 type monitor && ifconfig mon0 up
}
# stops mon0
stop_monitor_interface() {
ifconfig mon0 down && iw dev mon0 del
}
# returns 0 if the specificed network interface is up
is_interface_up() {
if grep -qi 'up' /sys/class/net/$1/operstate; then
return 0
fi
return 1
}
# returns 0 if conditions for AUTO mode are met
is_auto_mode() {
# check override file first
if [ -f /root/.pwnagotchi-manual ]; then
# remove the override file if found
rm -rf /root/.pwnagotchi-manual
return 1
fi
# check override file first
if [ -f /root/.pwnagotchi-auto ]; then
# remove the override file if found
rm -rf /root/.pwnagotchi-auto
return 0
fi
# if usb0 is up, we're in MANU
if is_interface_up usb0; then
return 1
fi
# if eth0 is up (for other boards), we're in MANU
if is_interface_up eth0; then
return 1
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 1
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
}
================================================
FILE: builder/pwnagotchi.json
================================================
{
"builders": [
{
"name": "pwnagotchi",
"type": "arm-image",
"iso_url": "https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-07-12/2019-07-10-raspbian-buster-lite.zip",
"iso_checksum": "9e5cf24ce483bb96e7736ea75ca422e3560e7b455eee63dd28f66fa1825db70e",
"last_partition_extra_size": 3221225472
}
],
"provisioners": [
{
"type": "shell",
"inline": [
"sed -i 's/^\\([^#]\\)/#\\1/g' /etc/ld.so.preload",
"dpkg-architecture",
"apt-get -y update",
"apt-get install -y ansible"
]
},
{
"type": "file",
"source": "data/usr/bin/pwnlib",
"destination": "/usr/bin/pwnlib"
},
{
"type": "file",
"source": "data/usr/bin/bettercap-launcher",
"destination": "/usr/bin/bettercap-launcher"
},
{
"type": "file",
"source": "data/usr/bin/pwnagotchi-launcher",
"destination": "/usr/bin/pwnagotchi-launcher"
},
{
"type": "file",
"source": "data/usr/bin/monstop",
"destination": "/usr/bin/monstop"
},
{
"type": "file",
"source": "data/usr/bin/monstart",
"destination": "/usr/bin/monstart"
},
{
"type": "file",
"source": "data/usr/bin/hdmion",
"destination": "/usr/bin/hdmion"
},
{
"type": "file",
"source": "data/usr/bin/hdmioff",
"destination": "/usr/bin/hdmioff"
},
{
"type": "file",
"source": "data/etc/network/interfaces.d/lo-cfg",
"destination": "/etc/network/interfaces.d/lo-cfg"
},
{
"type": "file",
"source": "data/etc/network/interfaces.d/wlan0-cfg",
"destination": "/etc/network/interfaces.d/wlan0-cfg"
},
{
"type": "file",
"source": "data/etc/network/interfaces.d/usb0-cfg",
"destination": "/etc/network/interfaces.d/usb0-cfg"
},
{
"type": "file",
"source": "data/etc/network/interfaces.d/eth0-cfg",
"destination": "/etc/network/interfaces.d/eth0-cfg"
},
{
"type": "file",
"source": "data/etc/systemd/system/pwngrid-peer.service",
"destination": "/etc/systemd/system/pwngrid-peer.service"
},
{
"type": "file",
"source": "data/etc/systemd/system/pwnagotchi.service",
"destination": "/etc/systemd/system/pwnagotchi.service"
},
{
"type": "file",
"source": "data/etc/systemd/system/bettercap.service",
"destination": "/etc/systemd/system/bettercap.service"
},
{
"type": "shell",
"inline": [
"chmod +x /usr/bin/*"
]
},
{
"type": "ansible-local",
"playbook_file": "pwnagotchi.yml",
"extra_arguments": [ "--extra-vars \"ansible_python_interpreter=/usr/bin/python3\"" ],
"command": "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION={{user `pwn_version`}} PWN_HOSTNAME={{user `pwn_hostname`}} ansible-playbook"
},
{
"type": "shell",
"inline": [
"sed -i 's/^#\\(.+\\)/\\1/g' /etc/ld.so.preload"
]
}
]
}
================================================
FILE: builder/pwnagotchi.yml
================================================
---
- hosts:
- 127.0.0.1
become: yes
vars:
pwnagotchi:
hostname: "{{ lookup('env', 'PWN_HOSTNAME') | default('pwnagotchi', true) }}"
version: "{{ lookup('env', 'PWN_VERSION') | default('master', true) }}"
system:
boot_options:
- "dtoverlay=dwc2"
- "dtoverlay=spi1-3cs"
- "dtparam=spi=on"
- "dtparam=i2c_arm=on"
- "dtparam=i2c1=on"
- "gpu_mem=16"
modules:
- "i2c-dev"
services:
enable:
- dphys-swapfile.service
- pwnagotchi.service
- bettercap.service
- pwngrid-peer.service
- epd-fuse.service
- fstrim.timer
disable:
- apt-daily.timer
- apt-daily.service
- apt-daily-upgrade.timer
- apt-daily-upgrade.service
- wpa_supplicant.service
- bluetooth.service
- triggerhappy.service
- ifup@wlan0.service
- dnsmasq.service
packages:
bettercap:
url: "https://github.com/bettercap/bettercap/releases/download/v2.31.0/bettercap_linux_armhf_v2.31.0.zip"
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
pwngrid:
url: "https://github.com/evilsocket/pwngrid/releases/download/v1.10.3/pwngrid_linux_armhf_v1.10.3.zip"
apt:
hold:
- firmware-atheros
- firmware-brcm80211
- firmware-libertas
- firmware-misc-nonfree
- firmware-realtek
remove:
- raspberrypi-net-mods
- dhcpcd5
- triggerhappy
- wpa_supplicant
- nfs-common
install:
- rsync
- vim
- screen
- golang
- git
- build-essential
- python3-pip
- python3-mpi4py
- python3-smbus
- unzip
- gawk
- libopenmpi-dev
- libatlas-base-dev
- libjasper-dev
- libqtgui4
- libqt4-test
- libopenjp2-7
- libtiff5
- tcpdump
- lsof
- libilmbase23
- libopenexr23
- libgstreamer1.0-0
- libavcodec58
- libavformat58
- libswscale5
- libpcap-dev
- libusb-1.0-0-dev
- libnetfilter-queue-dev
- libopenmpi3
- dphys-swapfile
- kalipi-kernel
- kalipi-bootloader
- kalipi-re4son-firmware
- kalipi-kernel-headers
- libraspberrypi0
- libraspberrypi-dev
- libraspberrypi-doc
- libraspberrypi-bin
- fonts-dejavu
- fonts-dejavu-core
- fonts-dejavu-extra
- python3-pil
- python3-smbus
- libfuse-dev
- bc
- fonts-freefont-ttf
- fbi
- fonts-ipaexfont-gothic
- cryptsetup
- dnsmasq
tasks:
- name: change hostname
hostname:
name: "{{pwnagotchi.hostname}}"
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: disable sap plugin for bluetooth.service
lineinfile:
dest: /lib/systemd/system/bluetooth.service
regexp: '^ExecStart=/usr/lib/bluetooth/bluetoothd$'
line: 'ExecStart=/usr/lib/bluetooth/bluetoothd --noplugin=sap'
state: present
- name: Add re4son-kernel repo key
apt_key:
url: https://re4son-kernel.com/keys/http/archive-key.asc
state: present
- name: Add re4son-kernel repository
apt_repository:
repo: deb http://http.re4son-kernel.com/re4son/ kali-pi main
state: present
- name: create /etc/apt/preferences.d/kali.pref
copy:
dest: /etc/apt/preferences.d/kali.pref
force: yes
content: |
# ensure kali packages that are installed take precedence
Package: *
Pin: release n=kali-pi
Pin-Priority: 999
- name: add firmware packages to hold
dpkg_selections:
name: "{{ item }}"
selection: hold
with_items: "{{ packages.apt.hold }}"
- name: update apt package cache
apt:
update_cache: yes
- name: remove unecessary apt packages
apt:
name: "{{ packages.apt.remove }}"
state: absent
purge: yes
- name: upgrade apt distro
apt:
upgrade: dist
- name: install packages
apt:
name: "{{ packages.apt.install }}"
state: present
- name: configure dphys-swapfile
file:
path: /etc/dphys-swapfile
content: "CONF_SWAPSIZE=1024"
- name: clone papirus repository
git:
repo: https://github.com/repaper/gratis.git
dest: /usr/local/src/gratis
register: gratisgit
- name: build papirus service
make:
chdir: /usr/local/src/gratis
target: rpi
params:
EPD_IO: epd_io_free_uart.h
PANEL_VERSION: 'V231_G2'
when: gratisgit.changed
- name: install papirus service
make:
chdir: /usr/local/src/gratis
target: rpi-install
params:
EPD_IO: epd_io_free_uart.h
PANEL_VERSION: 'V231_G2'
when: gratisgit.changed
- name: configure papirus display size
lineinfile:
dest: /etc/default/epd-fuse
regexp: "#EPD_SIZE=2.0"
line: "EPD_SIZE=2.0"
- name: collect python pip package list
command: "pip3 list"
register: pip_output
- name: set python pip package facts
set_fact:
pip_packages: >
{{ pip_packages | default({}) | combine( { item.split()[0]: item.split()[1] } ) }}
with_items: "{{ pip_output.stdout_lines }}"
- name: acquire python3 pip target
command: "python3 -c 'import sys;print(sys.path.pop())'"
register: pip_target
- name: clone pwnagotchi repository
git:
repo: https://github.com/evilsocket/pwnagotchi.git
dest: /usr/local/src/pwnagotchi
register: pwnagotchigit
- name: create /usr/local/share/pwnagotchi/ folder
file:
path: /usr/local/share/pwnagotchi/
state: directory
- name: clone pwnagotchi plugins repository
git:
repo: https://github.com/evilsocket/pwnagotchi-plugins-contrib.git
dest: /usr/local/share/pwnagotchi/availaible-plugins
- name: fetch pwnagotchi version
set_fact:
pwnagotchi_version: "{{ lookup('file', '/usr/local/src/pwnagotchi/pwnagotchi/_version.py') | regex_replace('.*__version__.*=.*''([0-9]+\\.[0-9]+\\.[0-9]+[A-Za-z0-9]*)''.*', '\\1') }}"
- name: pwnagotchi version found
debug:
msg: "{{ pwnagotchi_version }}"
- 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: install opencv-python
pip:
name: "https://www.piwheels.org/simple/opencv-python/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl"
extra_args: "--no-deps --no-cache-dir --platform=linux_armv6l --only-binary=:all: --target={{ pip_target.stdout }}"
when: (pip_packages['opencv-python'] is undefined) or (pip_packages['opencv-python'] != '3.4.3.18')
- name: install tensorflow
pip:
name: "https://www.piwheels.org/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv6l.whl"
extra_args: "--no-deps --no-cache-dir --platform=linux_armv6l --only-binary=:all: --target={{ pip_target.stdout }}"
when: (pip_packages['tensorflow'] is undefined) or (pip_packages['tensorflow'] != '1.13.1')
- name: install pwnagotchi wheel and dependencies
pip:
name: "{{ lookup('fileglob', '/usr/local/src/pwnagotchi/dist/pwnagotchi*.whl') }}"
extra_args: "--no-cache-dir"
when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version)
- name: download and install pwngrid
unarchive:
src: "{{ packages.pwngrid.url }}"
dest: /usr/bin
remote_src: yes
mode: 0755
- name: download and install bettercap
unarchive:
src: "{{ packages.bettercap.url }}"
dest: /usr/bin
remote_src: yes
exclude:
- README.md
- LICENSE.md
mode: 0755
- name: clone bettercap caplets
git:
repo: https://github.com/bettercap/caplets.git
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
- name: add HDMI powersave to rc.local
blockinfile:
path: /etc/rc.local
insertbefore: "exit 0"
block: |
if ! /opt/vc/bin/tvservice -s | egrep 'HDMI|DVI'; then
/opt/vc/bin/tvservice -o
fi
- name: create /etc/pwnagotchi folder
file:
path: /etc/pwnagotchi
state: directory
- name: check if user configuration exists
stat:
path: /etc/pwnagotchi/config.toml
register: user_config
- name: create /etc/pwnagotchi/config.toml
copy:
dest: /etc/pwnagotchi/config.toml
content: |
# Add your configuration overrides on this file any configuration changes done to default.toml will be lost!
# Example:
# ui.display.enabled = true
# ui.display.type = "waveshare_2"
when: not user_config.stat.exists
- name: enable ssh on boot
file:
path: /boot/ssh
state: touch
- name: adjust /boot/config.txt
lineinfile:
dest: /boot/config.txt
insertafter: EOF
line: '{{ item }}'
with_items: "{{system.boot_options}}"
- name: adjust /etc/modules
lineinfile:
dest: /etc/modules
insertafter: EOF
line: '{{ item }}'
with_items: "{{system.modules}}"
- name: change root partition
replace:
dest: /boot/cmdline.txt
backup: no
regexp: "root=PARTUUID=[a-zA-Z0-9\\-]+"
replace: "root=/dev/mmcblk0p2"
- name: configure /boot/cmdline.txt
lineinfile:
path: /boot/cmdline.txt
backrefs: True
state: present
backup: no
regexp: '(.*)$'
line: '\1 modules-load=dwc2,g_ether'
- name: configure motd
copy:
dest: /etc/motd
content: |
(◕‿‿◕) {{pwnagotchi.hostname}}
Hi! I'm a pwnagotchi, please take good care of me!
Here are some basic things you need to know to raise me properly!
If you want to change my configuration, use /etc/pwnagotchi/config.toml
All the configuration options can be found on /etc/pwnagotchi/default.toml,
but don't change this file because I will recreate it every time I'm restarted!
I'm managed by systemd. Here are some basic commands.
If you want to know what I'm doing, you can check my logs with the command
tail -f /var/log/pwnagotchi.log
If you want to know if I'm running, you can use
systemctl status pwnagotchi
You can restart me using
systemctl restart pwnagotchi
But be aware I will go into MANUAL mode when restarted!
You can put me back into AUTO mode using
touch /root/.pwnagotchi-auto && systemctl restart pwnagotchi
You learn more about me at https://pwnagotchi.ai/
when: hostname.changed
- name: clean apt cache
apt:
autoclean: yes
- name: remove dependencies that are no longer required
apt:
autoremove: yes
- name: enable services
systemd:
name: "{{ item }}"
state: started
enabled: yes
with_items: "{{ services.enable }}"
- name: disable unecessary services
systemd:
name: "{{ item }}"
state: stopped
enabled: no
with_items: "{{ services.disable }}"
- name: remove ssh keys
file:
state: absent
path: "{{item}}"
with_fileglob:
- "/etc/ssh/ssh_host*_key*"
handlers:
- name: reload systemd services
systemd:
daemon_reload: yes
================================================
FILE: pwnagotchi/__init__.py
================================================
import os
import logging
import time
import re
from pwnagotchi._version import __version__
_name = None
config = None
def set_name(new_name):
if new_name is None:
return
new_name = new_name.strip()
if new_name == '':
return
if not re.match(r'^[a-zA-Z0-9\-]{2,25}$', new_name):
logging.warning("name '%s' is invalid: min length is 2, max length 25, only a-zA-Z0-9- allowed", new_name)
return
current = name()
if new_name != current:
global _name
logging.info("setting unit hostname '%s' -> '%s'", current, new_name)
with open('/etc/hostname', 'wt') as fp:
fp.write(new_name)
with open('/etc/hosts', 'rt') as fp:
prev = fp.read()
logging.debug("old hosts:\n%s\n", prev)
with open('/etc/hosts', 'wt') as fp:
patched = prev.replace(current, new_name, -1)
logging.debug("new hosts:\n%s\n", patched)
fp.write(patched)
os.system("hostname '%s'" % new_name)
pwnagotchi.reboot()
def name():
global _name
if _name is None:
with open('/etc/hostname', 'rt') as fp:
_name = fp.read().strip()
return _name
def uptime():
with open('/proc/uptime') as fp:
return int(fp.read().split('.')[0])
def mem_usage():
with open('/proc/meminfo') as fp:
for line in fp:
line = line.strip()
if line.startswith("MemTotal:"):
kb_mem_total = int(line.split()[1])
if line.startswith("MemFree:"):
kb_mem_free = int(line.split()[1])
if line.startswith("Buffers:"):
kb_main_buffers = int(line.split()[1])
if line.startswith("Cached:"):
kb_main_cached = int(line.split()[1])
kb_mem_used = kb_mem_total - kb_mem_free - kb_main_cached - kb_main_buffers
return round(kb_mem_used / kb_mem_total, 1)
return 0
def _cpu_stat():
"""
Returns the splitted first line of the /proc/stat file
"""
with open('/proc/stat', 'rt') as fp:
return list(map(int,fp.readline().split()[1:]))
def cpu_load():
"""
Returns the current cpuload
"""
parts0 = _cpu_stat()
time.sleep(0.1)
parts1 = _cpu_stat()
parts_diff = [p1 - p0 for (p0, p1) in zip(parts0, parts1)]
user, nice, sys, idle, iowait, irq, softirq, steal, _guest, _guest_nice = parts_diff
idle_sum = idle + iowait
non_idle_sum = user + nice + sys + irq + softirq + steal
total = idle_sum + non_idle_sum
return non_idle_sum / total
def temperature(celsius=True):
with open('/sys/class/thermal/thermal_zone0/temp', 'rt') as fp:
temp = int(fp.read().strip())
c = int(temp / 1000)
return c if celsius else ((c * (9 / 5)) + 32)
def shutdown():
logging.warning("shutting down ...")
from pwnagotchi.ui import view
if view.ROOT:
view.ROOT.on_shutdown()
# give it some time to refresh the ui
time.sleep(10)
logging.warning("syncing...")
from pwnagotchi import fs
for m in fs.mounts:
m.sync()
os.system("sync")
os.system("halt")
def restart(mode):
logging.warning("restarting in %s mode ...", mode)
if mode == 'AUTO':
os.system("touch /root/.pwnagotchi-auto")
else:
os.system("touch /root/.pwnagotchi-manual")
os.system("service bettercap restart")
os.system("service pwnagotchi restart")
def reboot(mode=None):
if mode is not None:
mode = mode.upper()
logging.warning("rebooting in %s mode ...", mode)
else:
logging.warning("rebooting ...")
from pwnagotchi.ui import view
if view.ROOT:
view.ROOT.on_rebooting()
# give it some time to refresh the ui
time.sleep(10)
if mode == 'AUTO':
os.system("touch /root/.pwnagotchi-auto")
elif mode == 'MANU':
os.system("touch /root/.pwnagotchi-manual")
logging.warning("syncing...")
from pwnagotchi import fs
for m in fs.mounts:
m.sync()
os.system("sync")
os.system("shutdown -r now")
================================================
FILE: pwnagotchi/_version.py
================================================
__version__ = '1.5.5'
================================================
FILE: pwnagotchi/agent.py
================================================
import time
import json
import os
import re
import logging
import asyncio
import _thread
import pwnagotchi
import pwnagotchi.utils as utils
import pwnagotchi.plugins as plugins
from pwnagotchi.ui.web.server import Server
from pwnagotchi.automata import Automata
from pwnagotchi.log import LastSession
from pwnagotchi.bettercap import Client
from pwnagotchi.mesh.utils import AsyncAdvertiser
from pwnagotchi.ai.train import AsyncTrainer
RECOVERY_DATA_FILE = '/root/.pwnagotchi-recovery'
class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
def __init__(self, view, config, keypair):
Client.__init__(self, config['bettercap']['hostname'],
config['bettercap']['scheme'],
config['bettercap']['port'],
config['bettercap']['username'],
config['bettercap']['password'])
Automata.__init__(self, config, view)
AsyncAdvertiser.__init__(self, config, view, keypair)
AsyncTrainer.__init__(self, config)
self._started_at = time.time()
self._filter = None if not config['main']['filter'] else re.compile(config['main']['filter'])
self._current_channel = 0
self._tot_aps = 0
self._aps_on_channel = 0
self._supported_channels = utils.iface_channels(config['main']['iface'])
self._view = view
self._view.set_agent(self)
self._web_ui = Server(self, config['ui'])
self._access_points = []
self._last_pwnd = None
self._history = {}
self._handshakes = {}
self.last_session = LastSession(self._config)
self.mode = 'auto'
if not os.path.exists(config['bettercap']['handshakes']):
os.makedirs(config['bettercap']['handshakes'])
logging.info("%s@%s (v%s)", pwnagotchi.name(), self.fingerprint(), pwnagotchi.__version__)
for _, plugin in plugins.loaded.items():
logging.debug("plugin '%s' v%s", plugin.__class__.__name__, plugin.__version__)
def config(self):
return self._config
def view(self):
return self._view
def supported_channels(self):
return self._supported_channels
def setup_events(self):
logging.info("connecting to %s ...", self.url)
for tag in self._config['bettercap']['silence']:
try:
self.run('events.ignore %s' % tag, verbose_errors=False)
except Exception:
pass
def _reset_wifi_settings(self):
mon_iface = self._config['main']['iface']
self.run('set wifi.interface %s' % mon_iface)
self.run('set wifi.ap.ttl %d' % self._config['personality']['ap_ttl'])
self.run('set wifi.sta.ttl %d' % self._config['personality']['sta_ttl'])
self.run('set wifi.rssi.min %d' % self._config['personality']['min_rssi'])
self.run('set wifi.handshakes.file %s' % self._config['bettercap']['handshakes'])
self.run('set wifi.handshakes.aggregate false')
def start_monitor_mode(self):
mon_iface = self._config['main']['iface']
mon_start_cmd = self._config['main']['mon_start_cmd']
restart = not self._config['main']['no_restart']
has_mon = False
while has_mon is False:
s = self.session()
for iface in s['interfaces']:
if iface['name'] == mon_iface:
logging.info("found monitor interface: %s", iface['name'])
has_mon = True
break
if has_mon is False:
if mon_start_cmd is not None and mon_start_cmd != '':
logging.info("starting monitor interface ...")
self.run('!%s' % mon_start_cmd)
else:
logging.info("waiting for monitor interface %s ...", mon_iface)
time.sleep(1)
logging.info("supported channels: %s", self._supported_channels)
logging.info("handshakes will be collected inside %s", self._config['bettercap']['handshakes'])
self._reset_wifi_settings()
wifi_running = self.is_module_running('wifi')
if wifi_running and restart:
logging.debug("restarting wifi module ...")
self.restart_module('wifi.recon')
self.run('wifi.clear')
elif not wifi_running:
logging.debug("starting wifi module ...")
self.start_module('wifi.recon')
self.start_advertising()
def _wait_bettercap(self):
while True:
try:
_s = self.session()
return
except Exception:
logging.info("waiting for bettercap API to be available ...")
time.sleep(1)
def start(self):
self.start_ai()
self._wait_bettercap()
self.setup_events()
self.set_starting()
self.start_monitor_mode()
self.start_event_polling()
self.start_session_fetcher()
# print initial stats
self.next_epoch()
self.set_ready()
def recon(self):
recon_time = self._config['personality']['recon_time']
max_inactive = self._config['personality']['max_inactive_scale']
recon_mul = self._config['personality']['recon_inactive_multiplier']
channels = self._config['personality']['channels']
if self._epoch.inactive_for >= max_inactive:
recon_time *= recon_mul
self._view.set('channel', '*')
if not channels:
self._current_channel = 0
logging.debug("RECON %ds", recon_time)
self.run('wifi.recon.channel clear')
else:
logging.debug("RECON %ds ON CHANNELS %s", recon_time, ','.join(map(str, channels)))
try:
self.run('wifi.recon.channel %s' % ','.join(map(str, channels)))
except Exception as e:
logging.exception("Error while setting wifi.recon.channels (%s)", e)
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):
self._access_points = aps
plugins.on('wifi_update', self, aps)
self._epoch.observe(aps, list(self._peers.values()))
return self._access_points
def get_access_points(self):
whitelist = self._config['main']['whitelist']
aps = []
try:
s = self.session()
plugins.on("unfiltered_ap_list", self, s['wifi']['aps'])
for ap in s['wifi']['aps']:
if ap['encryption'] == '' or ap['encryption'] == 'OPEN':
continue
elif ap['hostname'] not in whitelist \
and ap['mac'].lower() not in whitelist \
and ap['mac'][:8].lower() not in whitelist:
if self._filter_included(ap):
aps.append(ap)
except Exception as e:
logging.exception("Error while getting acces points (%s)", e)
aps.sort(key=lambda ap: ap['channel'])
return self.set_access_points(aps)
def get_total_aps(self):
return self._tot_aps
def get_aps_on_channel(self):
return self._aps_on_channel
def get_current_channel(self):
return self._current_channel
def get_access_points_by_channel(self):
aps = self.get_access_points()
channels = self._config['personality']['channels']
grouped = {}
# group by channel
for ap in aps:
ch = ap['channel']
# if we're sticking to a channel, skip anything
# which is not on that channel
if channels and ch not in channels:
continue
if ch not in grouped:
grouped[ch] = [ap]
else:
grouped[ch].append(ap)
# sort by more populated channels
return sorted(grouped.items(), key=lambda kv: len(kv[1]), reverse=True)
def _find_ap_sta_in(self, station_mac, ap_mac, session):
for ap in session['wifi']['aps']:
if ap['mac'] == ap_mac:
for sta in ap['clients']:
if sta['mac'] == station_mac:
return (ap, sta)
return (ap, {'mac': station_mac, 'vendor': ''})
return None
def _update_uptime(self, s):
secs = pwnagotchi.uptime()
self._view.set('uptime', utils.secs_to_hhmmss(secs))
# self._view.set('epoch', '%04d' % self._epoch.epoch)
def _update_counters(self):
self._tot_aps = len(self._access_points)
tot_stas = sum(len(ap['clients']) for ap in self._access_points)
if self._current_channel == 0:
self._view.set('aps', '%d' % self._tot_aps)
self._view.set('sta', '%d' % tot_stas)
else:
self._aps_on_channel = len([ap for ap in self._access_points if ap['channel'] == self._current_channel])
stas_on_channel = sum(
[len(ap['clients']) for ap in self._access_points if ap['channel'] == self._current_channel])
self._view.set('aps', '%d (%d)' % (self._aps_on_channel, self._tot_aps))
self._view.set('sta', '%d (%d)' % (stas_on_channel, tot_stas))
def _update_handshakes(self, new_shakes=0):
if new_shakes > 0:
self._epoch.track(handshake=True, inc=new_shakes)
tot = utils.total_unique_handshakes(self._config['bettercap']['handshakes'])
txt = '%d (%d)' % (len(self._handshakes), tot)
if self._last_pwnd is not None:
txt += ' [%s]' % self._last_pwnd[:20]
self._view.set('shakes', txt)
if new_shakes > 0:
self._view.on_handshakes(new_shakes)
def _update_peers(self):
self._view.set_closest_peer(self._closest_peer, len(self._peers))
def _reboot(self):
self.set_rebooting()
self._save_recovery_data()
pwnagotchi.reboot()
def _save_recovery_data(self):
logging.warning("writing recovery data to %s ...", RECOVERY_DATA_FILE)
with open(RECOVERY_DATA_FILE, 'w') as fp:
data = {
'started_at': self._started_at,
'epoch': self._epoch.epoch,
'history': self._history,
'handshakes': self._handshakes,
'last_pwnd': self._last_pwnd
}
json.dump(data, fp)
def _load_recovery_data(self, delete=True, no_exceptions=True):
try:
with open(RECOVERY_DATA_FILE, 'rt') as fp:
data = json.load(fp)
logging.info("found recovery data: %s", data)
self._started_at = data['started_at']
self._epoch.epoch = data['epoch']
self._handshakes = data['handshakes']
self._history = data['history']
self._last_pwnd = data['last_pwnd']
if delete:
logging.info("deleting %s", RECOVERY_DATA_FILE)
os.unlink(RECOVERY_DATA_FILE)
except:
if not no_exceptions:
raise
def start_session_fetcher(self):
_thread.start_new_thread(self._fetch_stats, ())
def _fetch_stats(self):
while True:
s = self.session()
self._update_uptime(s)
self._update_advertisement(s)
self._update_peers()
self._update_counters()
self._update_handshakes(0)
time.sleep(1)
async def _on_event(self, msg):
found_handshake = False
jmsg = json.loads(msg)
if jmsg['tag'] == 'wifi.client.handshake':
filename = jmsg['data']['file']
sta_mac = jmsg['data']['station']
ap_mac = jmsg['data']['ap']
key = "%s -> %s" % (sta_mac, ap_mac)
if key not in self._handshakes:
self._handshakes[key] = jmsg
s = self.session()
ap_and_station = self._find_ap_sta_in(sta_mac, ap_mac, s)
if ap_and_station is None:
logging.warning("!!! captured new handshake: %s !!!", key)
self._last_pwnd = ap_mac
plugins.on('handshake', self, filename, ap_mac, sta_mac)
else:
(ap, sta) = ap_and_station
self._last_pwnd = ap['hostname'] if ap['hostname'] != '' and ap[
'hostname'] != '<hidden>' else ap_mac
logging.warning(
"!!! captured new handshake on channel %d, %d dBm: %s (%s) -> %s [%s (%s)] !!!",
ap['channel'],
ap['rssi'],
sta['mac'], sta['vendor'],
ap['hostname'], ap['mac'], ap['vendor'])
plugins.on('handshake', self, filename, ap, sta)
found_handshake = True
self._update_handshakes(1 if found_handshake else 0)
def _event_poller(self, loop):
self._load_recovery_data()
self.run('events.clear')
while True:
logging.debug("polling events ...")
try:
loop.create_task(self.start_websocket(self._on_event))
loop.run_forever()
except Exception as ex:
logging.debug("Error while polling via websocket (%s)", ex)
def start_event_polling(self):
# start a thread and pass in the mainloop
_thread.start_new_thread(self._event_poller, (asyncio.get_event_loop(),))
def is_module_running(self, module):
s = self.session()
for m in s['modules']:
if m['name'] == module:
return m['running']
return False
def start_module(self, module):
self.run('%s on' % module)
def restart_module(self, module):
self.run('%s off; %s on' % (module, module))
def _has_handshake(self, bssid):
for key in self._handshakes:
if bssid.lower() in key:
return True
return False
def _should_interact(self, who):
if self._has_handshake(who):
return False
elif who not in self._history:
self._history[who] = 1
return True
else:
self._history[who] += 1
return self._history[who] < self._config['personality']['max_interactions']
def associate(self, ap, throttle=0):
if self.is_stale():
logging.debug("recon is stale, skipping assoc(%s)", ap['mac'])
return
if self._config['personality']['associate'] and self._should_interact(ap['mac']):
self._view.on_assoc(ap)
try:
logging.info("sending association frame to %s (%s %s) on channel %d [%d clients], %d dBm...",
ap['hostname'], ap['mac'], ap['vendor'], ap['channel'], len(ap['clients']), ap['rssi'])
self.run('wifi.assoc %s' % ap['mac'])
self._epoch.track(assoc=True)
except Exception as e:
self._on_error(ap['mac'], e)
plugins.on('association', self, ap)
if throttle > 0:
time.sleep(throttle)
self._view.on_normal()
def deauth(self, ap, sta, throttle=0):
if self.is_stale():
logging.debug("recon is stale, skipping deauth(%s)", sta['mac'])
return
if self._config['personality']['deauth'] and self._should_interact(sta['mac']):
self._view.on_deauth(sta)
try:
logging.info("deauthing %s (%s) from %s (%s %s) on channel %d, %d dBm ...",
sta['mac'], sta['vendor'], ap['hostname'], ap['mac'], ap['vendor'], ap['channel'], ap['rssi'])
self.run('wifi.deauth %s' % sta['mac'])
self._epoch.track(deauth=True)
except Exception as e:
self._on_error(sta['mac'], e)
plugins.on('deauthentication', self, ap, sta)
if throttle > 0:
time.sleep(throttle)
self._view.on_normal()
def set_channel(self, channel, verbose=True):
if self.is_stale():
logging.debug("recon is stale, skipping set_channel(%d)", channel)
return
# if in the previous loop no client stations has been deauthenticated
# and only association frames have been sent, we don't need to wait
# very long before switching channel as we don't have to wait for
# such client stations to reconnect in order to sniff the handshake.
wait = 0
if self._epoch.did_deauth:
wait = self._config['personality']['hop_recon_time']
elif self._epoch.did_associate:
wait = self._config['personality']['min_recon_time']
if channel != self._current_channel:
if self._current_channel != 0 and wait > 0:
if verbose:
logging.info("waiting for %ds on channel %d ...", wait, self._current_channel)
else:
logging.debug("waiting for %ds on channel %d ...", wait, self._current_channel)
self.wait_for(wait)
if verbose and self._epoch.any_activity:
logging.info("CHANNEL %d", channel)
try:
self.run('wifi.recon.channel %d' % channel)
self._current_channel = channel
self._epoch.track(hop=True)
self._view.set('channel', '%d' % channel)
plugins.on('channel_hop', self, channel)
except Exception as e:
logging.error("Error while setting channel (%s)", e)
================================================
FILE: pwnagotchi/ai/__init__.py
================================================
import os
import time
import logging
# https://stackoverflow.com/questions/40426502/is-there-a-way-to-suppress-the-messages-tensorflow-prints/40426709
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # or any {'0', '1', '2'}
def load(config, agent, epoch, from_disk=True):
config = config['ai']
if not config['enabled']:
logging.info("ai disabled")
return False
try:
begin = time.time()
logging.info("[ai] bootstrapping dependencies ...")
start = time.time()
from stable_baselines import A2C
logging.debug("[ai] A2C imported in %.2fs" % (time.time() - start))
start = time.time()
from stable_baselines.common.policies import MlpLstmPolicy
logging.debug("[ai] MlpLstmPolicy imported in %.2fs" % (time.time() - start))
start = time.time()
from stable_baselines.common.vec_env import DummyVecEnv
logging.debug("[ai] DummyVecEnv imported in %.2fs" % (time.time() - start))
start = time.time()
import pwnagotchi.ai.gym as wrappers
logging.debug("[ai] gym wrapper imported in %.2fs" % (time.time() - start))
env = wrappers.Environment(agent, epoch)
env = DummyVecEnv([lambda: env])
logging.info("[ai] creating model ...")
start = time.time()
a2c = A2C(MlpLstmPolicy, env, **config['params'])
logging.debug("[ai] A2C created in %.2fs" % (time.time() - start))
if from_disk and os.path.exists(config['path']):
logging.info("[ai] loading %s ..." % config['path'])
start = time.time()
a2c.load(config['path'], env)
logging.debug("[ai] A2C loaded in %.2fs" % (time.time() - start))
else:
logging.info("[ai] model created:")
for key, value in config['params'].items():
logging.info(" %s: %s" % (key, value))
logging.debug("[ai] total loading time is %.2fs" % (time.time() - begin))
return a2c
except Exception as e:
logging.exception("error while starting AI (%s)", e)
logging.warning("[ai] AI not loaded!")
return False
================================================
FILE: pwnagotchi/ai/epoch.py
================================================
import time
import threading
import logging
import pwnagotchi
import pwnagotchi.utils as utils
import pwnagotchi.mesh.wifi as wifi
from pwnagotchi.ai.reward import RewardFunction
class Epoch(object):
def __init__(self, config):
self.epoch = 0
self.config = config
# how many consecutive epochs with no activity
self.inactive_for = 0
# how many consecutive epochs with activity
self.active_for = 0
# number of epochs with no visible access points
self.blind_for = 0
# number of epochs in sad state
self.sad_for = 0
# number of epochs in bored state
self.bored_for = 0
# did deauth in this epoch in the current channel?
self.did_deauth = False
# number of deauths in this epoch
self.num_deauths = 0
# did associate in this epoch in the current channel?
self.did_associate = False
# number of associations in this epoch
self.num_assocs = 0
# number of assocs or deauths missed
self.num_missed = 0
# did get any handshake in this epoch?
self.did_handshakes = False
# number of handshakes captured in this epoch
self.num_shakes = 0
# number of channels hops
self.num_hops = 0
# number of seconds sleeping
self.num_slept = 0
# number of peers seen during this epoch
self.num_peers = 0
# cumulative bond factor
self.tot_bond_factor = 0.0 # cum_bond_factor sounded really bad ...
# average bond factor
self.avg_bond_factor = 0.0
# any activity at all during this epoch?
self.any_activity = False
# when the current epoch started
self.epoch_started = time.time()
# last epoch duration
self.epoch_duration = 0
# https://www.metageek.com/training/resources/why-channels-1-6-11.html
self.non_overlapping_channels = {1: 0, 6: 0, 11: 0}
# observation vectors
self._observation = {
'aps_histogram': [0.0] * wifi.NumChannels,
'sta_histogram': [0.0] * wifi.NumChannels,
'peers_histogram': [0.0] * wifi.NumChannels
}
self._observation_ready = threading.Event()
self._epoch_data = {}
self._epoch_data_ready = threading.Event()
self._reward = RewardFunction()
def wait_for_epoch_data(self, with_observation=True, timeout=None):
# if with_observation:
# self._observation_ready.wait(timeout)
# self._observation_ready.clear()
self._epoch_data_ready.wait(timeout)
self._epoch_data_ready.clear()
return self._epoch_data if with_observation is False else {**self._observation, **self._epoch_data}
def data(self):
return self._epoch_data
def observe(self, aps, peers):
num_aps = len(aps)
if num_aps == 0:
self.blind_for += 1
else:
self.blind_for = 0
bond_unit_scale = self.config['personality']['bond_encounters_factor']
self.num_peers = len(peers)
num_peers = self.num_peers + 1e-10 # avoid division by 0
self.tot_bond_factor = sum((peer.encounters for peer in peers)) / bond_unit_scale
self.avg_bond_factor = self.tot_bond_factor / num_peers
num_aps = len(aps) + 1e-10
num_sta = sum(len(ap['clients']) for ap in aps) + 1e-10
aps_per_chan = [0.0] * wifi.NumChannels
sta_per_chan = [0.0] * wifi.NumChannels
peers_per_chan = [0.0] * wifi.NumChannels
for ap in aps:
ch_idx = ap['channel'] - 1
try:
aps_per_chan[ch_idx] += 1.0
sta_per_chan[ch_idx] += len(ap['clients'])
except IndexError:
logging.error("got data on channel %d, we can store %d channels" % (ap['channel'], wifi.NumChannels))
for peer in peers:
try:
peers_per_chan[peer.last_channel - 1] += 1.0
except IndexError:
logging.error(
"got peer data on channel %d, we can store %d channels" % (peer.last_channel, wifi.NumChannels))
# normalize
aps_per_chan = [e / num_aps for e in aps_per_chan]
sta_per_chan = [e / num_sta for e in sta_per_chan]
peers_per_chan = [e / num_peers for e in peers_per_chan]
self._observation = {
'aps_histogram': aps_per_chan,
'sta_histogram': sta_per_chan,
'peers_histogram': peers_per_chan
}
self._observation_ready.set()
def track(self, deauth=False, assoc=False, handshake=False, hop=False, sleep=False, miss=False, inc=1):
if deauth:
self.num_deauths += inc
self.did_deauth = True
self.any_activity = True
if assoc:
self.num_assocs += inc
self.did_associate = True
self.any_activity = True
if miss:
self.num_missed += inc
if hop:
self.num_hops += inc
# these two are used in order to determine the sleep time in seconds
# before switching to a new channel ... if nothing happened so far
# during this epoch on the current channel, we will sleep less
self.did_deauth = False
self.did_associate = False
if handshake:
self.num_shakes += inc
self.did_handshakes = True
if sleep:
self.num_slept += inc
def next(self):
if self.any_activity is False and self.did_handshakes is False:
self.inactive_for += 1
self.active_for = 0
else:
self.active_for += 1
self.inactive_for = 0
self.sad_for = 0
self.bored_for = 0
if self.inactive_for >= self.config['personality']['sad_num_epochs']:
# sad > bored; cant be sad and bored
self.bored_for = 0
self.sad_for += 1
elif self.inactive_for >= self.config['personality']['bored_num_epochs']:
# sad_treshhold > inactive > bored_treshhold; cant be sad and bored
self.sad_for = 0
self.bored_for += 1
else:
self.sad_for = 0
self.bored_for = 0
now = time.time()
cpu = pwnagotchi.cpu_load()
mem = pwnagotchi.mem_usage()
temp = pwnagotchi.temperature()
self.epoch_duration = now - self.epoch_started
# cache the state of this epoch for other threads to read
self._epoch_data = {
'duration_secs': self.epoch_duration,
'slept_for_secs': self.num_slept,
'blind_for_epochs': self.blind_for,
'inactive_for_epochs': self.inactive_for,
'active_for_epochs': self.active_for,
'sad_for_epochs': self.sad_for,
'bored_for_epochs': self.bored_for,
'missed_interactions': self.num_missed,
'num_hops': self.num_hops,
'num_peers': self.num_peers,
'tot_bond': self.tot_bond_factor,
'avg_bond': self.avg_bond_factor,
'num_deauths': self.num_deauths,
'num_associations': self.num_assocs,
'num_handshakes': self.num_shakes,
'cpu_load': cpu,
'mem_usage': mem,
'temperature': temp
}
self._epoch_data['reward'] = self._reward(self.epoch + 1, self._epoch_data)
self._epoch_data_ready.set()
logging.info("[epoch %d] duration=%s slept_for=%s blind=%d sad=%d bored=%d inactive=%d active=%d peers=%d tot_bond=%.2f "
"avg_bond=%.2f hops=%d missed=%d deauths=%d assocs=%d handshakes=%d cpu=%d%% mem=%d%% "
"temperature=%dC reward=%s" % (
self.epoch,
utils.secs_to_hhmmss(self.epoch_duration),
utils.secs_to_hhmmss(self.num_slept),
self.blind_for,
self.sad_for,
self.bored_for,
self.inactive_for,
self.active_for,
self.num_peers,
self.tot_bond_factor,
self.avg_bond_factor,
self.num_hops,
self.num_missed,
self.num_deauths,
self.num_assocs,
self.num_shakes,
cpu * 100,
mem * 100,
temp,
self._epoch_data['reward']))
self.epoch += 1
self.epoch_started = now
self.did_deauth = False
self.num_deauths = 0
self.num_peers = 0
self.tot_bond_factor = 0.0
self.avg_bond_factor = 0.0
self.did_associate = False
self.num_assocs = 0
self.num_missed = 0
self.did_handshakes = False
self.num_shakes = 0
self.num_hops = 0
self.num_slept = 0
self.any_activity = False
================================================
FILE: pwnagotchi/ai/featurizer.py
================================================
import numpy as np
import pwnagotchi.mesh.wifi as wifi
MAX_EPOCH_DURATION = 1024
def describe(extended=False):
if not extended:
histogram_size = wifi.NumChannels
else:
# see https://github.com/evilsocket/pwnagotchi/issues/583
histogram_size = wifi.NumChannelsExt
return histogram_size, (1,
# aps per channel
histogram_size +
# clients per channel
histogram_size +
# peers per channel
histogram_size +
# duration
1 +
# inactive
1 +
# active
1 +
# missed
1 +
# hops
1 +
# deauths
1 +
# assocs
1 +
# handshakes
1)
def featurize(state, step):
tot_epochs = step + 1e-10
tot_interactions = (state['num_deauths'] + state['num_associations']) + 1e-10
return np.concatenate((
# aps per channel
state['aps_histogram'],
# clients per channel
state['sta_histogram'],
# peers per channel
state['peers_histogram'],
# duration
[np.clip(state['duration_secs'] / MAX_EPOCH_DURATION, 0.0, 1.0)],
# inactive
[state['inactive_for_epochs'] / tot_epochs],
# active
[state['active_for_epochs'] / tot_epochs],
# missed
[state['missed_interactions'] / tot_interactions],
# hops
[state['num_hops'] / wifi.NumChannels],
# deauths
[state['num_deauths'] / tot_interactions],
# assocs
[state['num_associations'] / tot_interactions],
# handshakes
[state['num_handshakes'] / tot_interactions],
))
================================================
FILE: pwnagotchi/ai/gym.py
================================================
import logging
import gym
from gym import spaces
import numpy as np
import pwnagotchi.ai.featurizer as featurizer
import pwnagotchi.ai.reward as reward
from pwnagotchi.ai.parameter import Parameter
class Environment(gym.Env):
metadata = {'render.modes': ['human']}
params = [
Parameter('min_rssi', min_value=-200, max_value=-50),
Parameter('ap_ttl', min_value=30, max_value=600),
Parameter('sta_ttl', min_value=60, max_value=300),
Parameter('recon_time', min_value=5, max_value=60),
Parameter('max_inactive_scale', min_value=3, max_value=10),
Parameter('recon_inactive_multiplier', min_value=1, max_value=3),
Parameter('hop_recon_time', min_value=5, max_value=60),
Parameter('min_recon_time', min_value=1, max_value=30),
Parameter('max_interactions', min_value=1, max_value=25),
Parameter('max_misses_for_recon', min_value=3, max_value=10),
Parameter('excited_num_epochs', min_value=5, max_value=30),
Parameter('bored_num_epochs', min_value=5, max_value=30),
Parameter('sad_num_epochs', min_value=5, max_value=30),
]
def __init__(self, agent, epoch):
super(Environment, self).__init__()
self._agent = agent
self._epoch = epoch
self._epoch_num = 0
self._last_render = None
# see https://github.com/evilsocket/pwnagotchi/issues/583
self._supported_channels = agent.supported_channels()
self._extended_spectrum = any(ch > 140 for ch in self._supported_channels)
self._histogram_size, self._observation_shape = featurizer.describe(self._extended_spectrum)
Environment.params += [
Parameter('_channel_%d' % ch, min_value=0, max_value=1, meta=ch + 1) for ch in
range(self._histogram_size) if ch + 1 in self._supported_channels
]
self.last = {
'reward': 0.0,
'observation': None,
'policy': None,
'params': {},
'state': None,
'state_v': None
}
self.action_space = spaces.MultiDiscrete([p.space_size() for p in Environment.params if p.trainable])
self.observation_space = spaces.Box(low=0, high=1, shape=self._observation_shape, dtype=np.float32)
self.reward_range = reward.range
@staticmethod
def policy_size():
return len(list(p for p in Environment.params if p.trainable))
@staticmethod
def policy_to_params(policy):
num = len(policy)
params = {}
assert len(Environment.params) == num
channels = []
for i in range(num):
param = Environment.params[i]
if '_channel' not in param.name:
params[param.name] = param.to_param_value(policy[i])
else:
has_chan = param.to_param_value(policy[i])
# print("%s policy:%s bool:%s" % (param.name, policy[i], has_chan))
chan = param.meta
if has_chan:
channels.append(chan)
params['channels'] = channels
return params
def _next_epoch(self):
logging.debug("[ai] waiting for epoch to finish ...")
return self._epoch.wait_for_epoch_data()
def _apply_policy(self, policy):
new_params = Environment.policy_to_params(policy)
self.last['policy'] = policy
self.last['params'] = new_params
self._agent.on_ai_policy(new_params)
def step(self, policy):
# create the parameters from the policy and update
# update them in the algorithm
self._apply_policy(policy)
self._epoch_num += 1
# wait for the algorithm to run with the new parameters
state = self._next_epoch()
self.last['reward'] = state['reward']
self.last['state'] = state
self.last['state_v'] = featurizer.featurize(state, self._epoch_num)
self._agent.on_ai_step()
return self.last['state_v'], self.last['reward'], not self._agent.is_training(), {}
def reset(self):
# logging.info("[ai] resetting environment ...")
self._epoch_num = 0
state = self._next_epoch()
self.last['state'] = state
self.last['state_v'] = featurizer.featurize(state, 1)
return self.last['state_v']
def _render_histogram(self, hist):
for ch in range(self._histogram_size):
if hist[ch]:
logging.info(" CH %d: %s" % (ch + 1, hist[ch]))
def render(self, mode='human', close=False, force=False):
# when using a vectorialized environment, render gets called twice
# avoid rendering the same data
if self._last_render == self._epoch_num:
return
if not self._agent.is_training() and not force:
return
self._last_render = self._epoch_num
logging.info("[ai] --- training epoch %d/%d ---" % (self._epoch_num, self._agent.training_epochs()))
logging.info("[ai] REWARD: %f" % self.last['reward'])
logging.debug("[ai] policy: %s" % ', '.join("%s:%s" % (name, value) for name, value in self.last['params'].items()))
logging.info("[ai] observation:")
for name, value in self.last['state'].items():
if 'histogram' in name:
logging.info(" %s" % name.replace('_histogram', ''))
self._render_histogram(value)
================================================
FILE: pwnagotchi/ai/parameter.py
================================================
from gym import spaces
class Parameter(object):
def __init__(self, name, value=0.0, min_value=0, max_value=2, meta=None, trainable=True):
self.name = name
self.trainable = trainable
self.meta = meta
self.value = value
self.min_value = min_value
self.max_value = max_value + 1
# gym.space.Discrete is within [0, 1, 2, ..., n-1]
if self.min_value < 0:
self.scale_factor = abs(self.min_value)
elif self.min_value > 0:
self.scale_factor = -self.min_value
else:
self.scale_factor = 0
def space_size(self):
return self.max_value + self.scale_factor
def space(self):
return spaces.Discrete(self.max_value + self.scale_factor)
def to_param_value(self, policy_v):
self.value = policy_v - self.scale_factor
assert self.min_value <= self.value <= self.max_value
return int(self.value)
================================================
FILE: pwnagotchi/ai/reward.py
================================================
import pwnagotchi.mesh.wifi as wifi
range = (-.7, 1.02)
fuck_zero = 1e-20
class RewardFunction(object):
def __call__(self, epoch_n, state):
tot_epochs = epoch_n + fuck_zero
tot_interactions = max(state['num_deauths'] + state['num_associations'], state['num_handshakes']) + fuck_zero
tot_channels = wifi.NumChannels
h = state['num_handshakes'] / tot_interactions
a = .2 * (state['active_for_epochs'] / tot_epochs)
c = .1 * (state['num_hops'] / tot_channels)
b = -.3 * (state['blind_for_epochs'] / tot_epochs)
m = -.3 * (state['missed_interactions'] / tot_interactions)
i = -.2 * (state['inactive_for_epochs'] / tot_epochs)
# include emotions if state >= 5 epochs
_sad = state['sad_for_epochs'] if state['sad_for_epochs'] >= 5 else 0
_bored = state['bored_for_epochs'] if state['bored_for_epochs'] >= 5 else 0
s = -.2 * (_sad / tot_epochs)
l = -.1 * (_bored / tot_epochs)
return h + a + c + b + i + m + s + l
================================================
FILE: pwnagotchi/ai/train.py
================================================
import _thread
import threading
import time
import random
import os
import json
import logging
import pwnagotchi.plugins as plugins
import pwnagotchi.ai as ai
class Stats(object):
def __init__(self, path, events_receiver):
self._lock = threading.Lock()
self._receiver = events_receiver
self.path = path
self.born_at = time.time()
# total epochs lived (trained + just eval)
self.epochs_lived = 0
# total training epochs
self.epochs_trained = 0
self.worst_reward = 0.0
self.best_reward = 0.0
self.load()
def on_epoch(self, data, training):
best_r = False
worst_r = False
with self._lock:
reward = data['reward']
if reward < self.worst_reward:
self.worst_reward = reward
worst_r = True
elif reward > self.best_reward:
best_r = True
self.best_reward = reward
self.epochs_lived += 1
if training:
self.epochs_trained += 1
self.save()
if best_r:
self._receiver.on_ai_best_reward(reward)
elif worst_r:
self._receiver.on_ai_worst_reward(reward)
def load(self):
with self._lock:
if os.path.exists(self.path) and os.path.getsize(self.path) > 0:
logging.info("[ai] loading %s" % self.path)
with open(self.path, 'rt') as fp:
obj = json.load(fp)
self.born_at = obj['born_at']
self.epochs_lived, self.epochs_trained = obj['epochs_lived'], obj['epochs_trained']
self.best_reward, self.worst_reward = obj['rewards']['best'], obj['rewards']['worst']
def save(self):
with self._lock:
logging.info("[ai] saving %s" % self.path)
data = json.dumps({
'born_at': self.born_at,
'epochs_lived': self.epochs_lived,
'epochs_trained': self.epochs_trained,
'rewards': {
'best': self.best_reward,
'worst': self.worst_reward
}
})
temp = "%s.tmp" % self.path
with open(temp, 'wt') as fp:
fp.write(data)
os.replace(temp, self.path)
class AsyncTrainer(object):
def __init__(self, config):
self._config = config
self._model = None
self._is_training = False
self._training_epochs = 0
self._nn_path = self._config['ai']['path']
self._stats = Stats("%s.json" % os.path.splitext(self._nn_path)[0], self)
def set_training(self, training, for_epochs=0):
self._is_training = training
self._training_epochs = for_epochs
if training:
plugins.on('ai_training_start', self, for_epochs)
else:
plugins.on('ai_training_end', self)
def is_training(self):
return self._is_training
def training_epochs(self):
return self._training_epochs
def start_ai(self):
_thread.start_new_thread(self._ai_worker, ())
def _save_ai(self):
logging.info("[ai] saving model to %s ..." % self._nn_path)
temp = "%s.tmp" % self._nn_path
self._model.save(temp)
os.replace(temp, self._nn_path)
def on_ai_step(self):
self._model.env.render()
if self._is_training:
self._save_ai()
self._stats.on_epoch(self._epoch.data(), self._is_training)
def on_ai_training_step(self, _locals, _globals):
self._model.env.render()
plugins.on('ai_training_step', self, _locals, _globals)
def on_ai_policy(self, new_params):
plugins.on('ai_policy', self, new_params)
logging.info("[ai] setting new policy:")
for name, value in new_params.items():
if name in self._config['personality']:
curr_value = self._config['personality'][name]
if curr_value != value:
logging.info("[ai] ! %s: %s -> %s" % (name, curr_value, value))
self._config['personality'][name] = value
else:
logging.error("[ai] param %s not in personality configuration!" % name)
self.run('set wifi.ap.ttl %d' % self._config['personality']['ap_ttl'])
self.run('set wifi.sta.ttl %d' % self._config['personality']['sta_ttl'])
self.run('set wifi.rssi.min %d' % self._config['personality']['min_rssi'])
def on_ai_ready(self):
self._view.on_ai_ready()
plugins.on('ai_ready', self)
def on_ai_best_reward(self, r):
logging.info("[ai] best reward so far: %s" % r)
self._view.on_motivated(r)
plugins.on('ai_best_reward', self, r)
def on_ai_worst_reward(self, r):
logging.info("[ai] worst reward so far: %s" % r)
self._view.on_demotivated(r)
plugins.on('ai_worst_reward', self, r)
def _ai_worker(self):
self._model = ai.load(self._config, self, self._epoch)
if self._model:
self.on_ai_ready()
epochs_per_episode = self._config['ai']['epochs_per_episode']
obs = None
while True:
self._model.env.render()
# enter in training mode?
if random.random() > self._config['ai']['laziness']:
logging.info("[ai] learning for %d epochs ..." % epochs_per_episode)
try:
self.set_training(True, epochs_per_episode)
self._model.learn(total_timesteps=epochs_per_episode, callback=self.on_ai_training_step)
except Exception as e:
logging.exception("[ai] error while training (%s)", e)
finally:
self.set_training(False)
obs = self._model.env.reset()
# init the first time
elif obs is None:
obs = self._model.env.reset()
# run the inference
action, _ = self._model.predict(obs)
obs, _, _, _ = self._model.env.step(action)
================================================
FILE: pwnagotchi/ai/utils.py
================================================
import numpy as np
def normalize(v, min_v, max_v):
return (v - min_v) / (max_v - min_v)
def as_batches(x, y, batch_size, shuffle=True):
x_size = len(x)
assert x_size == len(y)
indices = np.random.permutation(x_size) if shuffle else None
for offset in range(0, x_size - batch_size + 1, batch_size):
excerpt = indices[offset:offset + batch_size] if shuffle else slice(offset, offset + batch_size)
yield x[excerpt], y[excerpt]
================================================
FILE: pwnagotchi/automata.py
================================================
import logging
import pwnagotchi.plugins as plugins
from pwnagotchi.ai.epoch import Epoch
# basic mood system
class Automata(object):
def __init__(self, config, view):
self._config = config
self._view = view
self._epoch = Epoch(config)
def _on_miss(self, who):
logging.info("it looks like %s is not in range anymore :/", who)
self._epoch.track(miss=True)
self._view.on_miss(who)
def _on_error(self, who, e):
# when we're trying to associate or deauth something that is not in range anymore
# (if we are moving), we get the following error from bettercap:
# error 400: 50:c7:bf:2e:d3:37 is an unknown BSSID or it is in the association skip list.
if 'is an unknown BSSID' in str(e):
self._on_miss(who)
else:
logging.error(e)
def set_starting(self):
self._view.on_starting()
def set_ready(self):
plugins.on('ready', self)
def in_good_mood(self):
return self._has_support_network_for(1.0)
def _has_support_network_for(self, factor):
bond_factor = self._config['personality']['bond_encounters_factor']
total_encounters = sum(peer.encounters for _, peer in self._peers.items())
support_factor = total_encounters / bond_factor
return support_factor >= factor
# triggered when it's a sad/bad day but you have good friends around ^_^
def set_grateful(self):
self._view.on_grateful()
plugins.on('grateful', self)
def set_lonely(self):
if not self._has_support_network_for(1.0):
logging.info("unit is lonely")
self._view.on_lonely()
plugins.on('lonely', self)
else:
logging.info("unit is grateful instead of lonely")
self.set_grateful()
def set_bored(self):
factor = self._epoch.inactive_for / self._config['personality']['bored_num_epochs']
if not self._has_support_network_for(factor):
logging.warning("%d epochs with no activity -> bored", self._epoch.inactive_for)
self._view.on_bored()
plugins.on('bored', self)
else:
logging.info("unit is grateful instead of bored")
self.set_grateful()
def set_sad(self):
factor = self._epoch.inactive_for / self._config['personality']['sad_num_epochs']
if not self._has_support_network_for(factor):
logging.warning("%d epochs with no activity -> sad", self._epoch.inactive_for)
self._view.on_sad()
plugins.on('sad', self)
else:
logging.info("unit is grateful instead of sad")
self.set_grateful()
def set_angry(self, factor):
if not self._has_support_network_for(factor):
logging.warning("%d epochs with no activity -> angry", self._epoch.inactive_for)
self._view.on_angry()
plugins.on('angry', self)
else:
logging.info("unit is grateful instead of angry")
self.set_grateful()
def set_excited(self):
logging.warning("%d epochs with activity -> excited", self._epoch.active_for)
self._view.on_excited()
plugins.on('excited', self)
def set_rebooting(self):
self._view.on_rebooting()
plugins.on('rebooting', self)
def wait_for(self, t, sleeping=True):
plugins.on('sleep' if sleeping else 'wait', self, t)
self._view.wait(t, sleeping)
self._epoch.track(sleep=True, inc=t)
def is_stale(self):
return self._epoch.num_missed > self._config['personality']['max_misses_for_recon']
def any_activity(self):
return self._epoch.any_activity
def next_epoch(self):
logging.debug("agent.next_epoch()")
was_stale = self.is_stale()
did_miss = self._epoch.num_missed
self._epoch.next()
# after X misses during an epoch, set the status to lonely or angry
if was_stale:
factor = did_miss / self._config['personality']['max_misses_for_recon']
if factor >= 2.0:
self.set_angry(factor)
else:
logging.warning("agent missed %d interactions -> lonely", did_miss)
self.set_lonely()
# after X times being bored, the status is set to sad or angry
elif self._epoch.sad_for:
factor = self._epoch.inactive_for / self._config['personality']['sad_num_epochs']
if factor >= 2.0:
self.set_angry(factor)
else:
self.set_sad()
# after X times being inactive, the status is set to bored
elif self._epoch.bored_for:
self.set_bored()
# after X times being active, the status is set to happy / excited
elif self._epoch.active_for >= self._config['personality']['excited_num_epochs']:
self.set_excited()
elif self._epoch.active_for >= 5 and self._has_support_network_for(5.0):
self.set_grateful()
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']:
logging.critical("%d epochs without visible access points -> rebooting ...", self._epoch.blind_for)
self._reboot()
self._epoch.blind_for = 0
================================================
FILE: pwnagotchi/bettercap.py
================================================
import json
import logging
import requests
import websockets
from requests.auth import HTTPBasicAuth
def decode(r, verbose_errors=True):
try:
return r.json()
except Exception as e:
if r.status_code == 200:
logging.error("error while decoding json: error='%s' resp='%s'" % (e, r.text))
else:
err = "error %d: %s" % (r.status_code, r.text.strip())
if verbose_errors:
logging.info(err)
raise Exception(err)
return r.text
class Client(object):
def __init__(self, hostname='localhost', scheme='http', port=8081, username='user', password='pass'):
self.hostname = hostname
self.scheme = scheme
self.port = port
self.username = username
self.password = password
self.url = "%s://%s:%d/api" % (scheme, hostname, port)
self.websocket = "ws://%s:%s@%s:%d/api" % (username, password, hostname, port)
self.auth = HTTPBasicAuth(username, password)
def session(self):
r = requests.get("%s/session" % self.url, auth=self.auth)
return decode(r)
async def start_websocket(self, consumer):
s = "%s/events" % self.websocket
while True:
try:
async with websockets.connect(s, ping_interval=60, ping_timeout=90) as ws:
async for msg in ws:
try:
await consumer(msg)
except Exception as ex:
logging.debug("Error while parsing event (%s)", ex)
except websockets.exceptions.ConnectionClosedError:
logging.debug("Lost websocket connection. Reconnecting...")
except websockets.exceptions.WebSocketException as wex:
logging.debug("Websocket exception (%s)", wex)
def run(self, command, verbose_errors=True):
r = requests.post("%s/session" % self.url, auth=self.auth, json={'cmd': command})
return decode(r, verbose_errors=verbose_errors)
================================================
FILE: pwnagotchi/defaults.toml
================================================
main.name = ""
main.lang = "en"
main.confd = "/etc/pwnagotchi/conf.d/"
main.custom_plugins = ""
main.custom_plugin_repos = [
"https://github.com/evilsocket/pwnagotchi-plugins-contrib/archive/master.zip"
]
main.iface = "mon0"
main.mon_start_cmd = "/usr/bin/monstart"
main.mon_stop_cmd = "/usr/bin/monstop"
main.mon_max_blind_epochs = 50
main.no_restart = false
main.whitelist = [
"EXAMPLE_NETWORK",
"ANOTHER_EXAMPLE_NETWORK",
"fo:od:ba:be:fo:od",
"fo:od:ba"
]
main.filter = ""
main.plugins.grid.enabled = true
main.plugins.grid.report = false
main.plugins.grid.exclude = [
"YourHomeNetworkHere"
]
main.plugins.auto-update.enabled = true
main.plugins.auto-update.install = true
main.plugins.auto-update.interval = 1
main.plugins.net-pos.enabled = false
main.plugins.net-pos.api_key = "test"
main.plugins.gps.enabled = false
main.plugins.gps.speed = 19200
main.plugins.gps.device = "/dev/ttyUSB0"
main.plugins.webgpsmap.enabled = false
main.plugins.onlinehashcrack.enabled = false
main.plugins.onlinehashcrack.email = ""
main.plugins.onlinehashcrack.dashboard = ""
main.plugins.onlinehashcrack.single_files = false
main.plugins.onlinehashcrack.whitelist = []
main.plugins.wpa-sec.enabled = false
main.plugins.wpa-sec.api_key = ""
main.plugins.wpa-sec.api_url = "https://wpa-sec.stanev.org"
main.plugins.wpa-sec.download_results = false
main.plugins.wpa-sec.whitelist = []
main.plugins.wigle.enabled = false
main.plugins.wigle.api_key = ""
main.plugins.wigle.whitelist = []
main.plugins.wigle.donate = true
main.plugins.bt-tether.enabled = false
main.plugins.bt-tether.devices.android-phone.enabled = false
main.plugins.bt-tether.devices.android-phone.search_order = 1
main.plugins.bt-tether.devices.android-phone.mac = ""
main.plugins.bt-tether.devices.android-phone.ip = "192.168.44.44"
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.scantime = 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.priority = 1
main.plugins.bt-tether.devices.ios-phone.enabled = false
main.plugins.bt-tether.devices.ios-phone.search_order = 2
main.plugins.bt-tether.devices.ios-phone.mac = ""
main.plugins.bt-tether.devices.ios-phone.ip = "172.20.10.6"
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.scantime = 20
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.priority = 999
main.plugins.memtemp.enabled = false
main.plugins.memtemp.scale = "celsius"
main.plugins.memtemp.orientation = "horizontal"
main.plugins.paw-gps.enabled = false
main.plugins.paw-gps.ip = "192.168.44.1:8080"
main.plugins.ups_lite.enabled = false
main.plugins.ups_lite.shutdown = 2
main.plugins.gpio_buttons.enabled = false
main.plugins.led.enabled = true
main.plugins.led.led = 0
main.plugins.led.delay = 200
main.plugins.led.patterns.loaded = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.updating = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.unread_inbox = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ready = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_ready = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_training_start = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_best_reward = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_worst_reward = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.bored = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.sad = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.excited = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.lonely = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.rebooting = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.wait = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.sleep = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.wifi_update = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.association = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.deauthentication = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.handshake = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.epoch = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.peer_detected = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.peer_lost = "oo oo oo oo oo oo oo"
main.plugins.logtail.enabled = false
main.plugins.logtail.max-lines = 10000
main.plugins.session-stats.enabled = true
main.plugins.session-stats.save_directory = "/var/tmp/pwnagotchi/sessions/"
main.log.path = "/var/log/pwnagotchi.log"
main.log.rotation.enabled = true
main.log.rotation.size = "10M"
ai.enabled = true
ai.path = "/root/brain.nn"
ai.laziness = 0.1
ai.epochs_per_episode = 50
ai.params.gamma = 0.99
ai.params.n_steps = 1
ai.params.vf_coef = 0.25
ai.params.ent_coef = 0.01
ai.params.max_grad_norm = 0.5
ai.params.learning_rate = 0.001
ai.params.alpha = 0.99
ai.params.epsilon = 0.00001
ai.params.verbose = 1
ai.params.lr_schedule = "constant"
personality.advertise = true
personality.deauth = true
personality.associate = true
personality.channels = []
personality.min_rssi = -200
personality.ap_ttl = 120
personality.sta_ttl = 300
personality.recon_time = 30
personality.max_inactive_scale = 2
personality.recon_inactive_multiplier = 2
personality.hop_recon_time = 10
personality.min_recon_time = 5
personality.max_interactions = 3
personality.max_misses_for_recon = 5
personality.excited_num_epochs = 10
personality.bored_num_epochs = 15
personality.sad_num_epochs = 25
personality.bond_encounters_factor = 20000
ui.fps = 0.0
ui.font.name = "DejaVuSansMono" # for japanese: fonts-japanese-gothic
ui.font.size_offset = 0 # will be added to the font size
ui.faces.look_r = "( ⚆_⚆)"
ui.faces.look_l = "(☉_☉ )"
ui.faces.look_r_happy = "( ◕‿◕)"
ui.faces.look_l_happy = "(◕‿◕ )"
ui.faces.sleep = "(⇀‿‿↼)"
ui.faces.sleep2 = "(≖‿‿≖)"
ui.faces.awake = "(◕‿‿◕)"
ui.faces.bored = "(-__-)"
ui.faces.intense = "(°▃▃°)"
ui.faces.cool = "(⌐■_■)"
ui.faces.happy = "(•‿‿•)"
ui.faces.excited = "(ᵔ◡◡ᵔ)"
ui.faces.grateful = "(^‿‿^)"
ui.faces.motivated = "(☼‿‿☼)"
ui.faces.demotivated = "(≖__≖)"
ui.faces.smart = "(✜‿‿✜)"
ui.faces.lonely = "(ب__ب)"
ui.faces.sad = "(╥☁╥ )"
ui.faces.angry = "(-_-')"
ui.faces.friend = "(♥‿‿♥)"
ui.faces.broken = "(☓‿‿☓)"
ui.faces.debug = "(#__#)"
ui.faces.upload = "(1__0)"
ui.faces.upload1 = "(1__1)"
ui.faces.upload2 = "(0__1)"
ui.web.enabled = true
ui.web.address = "0.0.0.0"
ui.web.username = "changeme"
ui.web.password = "changeme"
ui.web.origin = ""
ui.web.port = 8080
ui.web.on_frame = ""
ui.display.enabled = true
ui.display.rotation = 180
ui.display.type = "waveshare_2"
ui.display.color = "black"
bettercap.scheme = "http"
bettercap.hostname = "localhost"
bettercap.port = 8081
bettercap.username = "pwnagotchi"
bettercap.password = "pwnagotchi"
bettercap.handshakes = "/root/handshakes"
bettercap.silence = [
"ble.device.new",
"ble.device.lost",
"ble.device.disconnected",
"ble.device.connected",
"ble.device.service.discovered",
"ble.device.characteristic.discovered",
"wifi.client.new",
"wifi.client.lost",
"wifi.client.probe",
"wifi.ap.new",
"wifi.ap.lost",
"mod.started"
]
fs.memory.enabled = false
fs.memory.mounts.log.enabled = false
fs.memory.mounts.log.mount = "/var/log"
fs.memory.mounts.log.size = "50M"
fs.memory.mounts.log.sync = 60
fs.memory.mounts.log.zram = true
fs.memory.mounts.log.rsync = true
fs.memory.mounts.data.enabled = false
fs.memory.mounts.data.mount = "/var/tmp/pwnagotchi"
fs.memory.mounts.data.size = "10M"
fs.memory.mounts.data.sync = 3600
fs.memory.mounts.data.zram = false
fs.memory.mounts.data.rsync = true
================================================
FILE: pwnagotchi/fs/__init__.py
================================================
import os
import re
import tempfile
import contextlib
import shutil
import _thread
import logging
from time import sleep
from distutils.dir_util import copy_tree
mounts = list()
@contextlib.contextmanager
def ensure_write(filename, mode='w'):
path = os.path.dirname(filename)
fd, tmp = tempfile.mkstemp(dir=path)
with os.fdopen(fd, mode) as f:
yield f
f.flush()
os.fsync(f.fileno())
os.replace(tmp, filename)
def size_of(path):
"""
Calculate the sum of all the files in path
"""
total = 0
for root, _, files in os.walk(path):
for f in files:
total += os.path.getsize(os.path.join(root, f))
return total
def is_mountpoint(path):
"""
Checks if path is mountpoint
"""
return os.system(f"mountpoint -q {path}") == 0
def setup_mounts(config):
"""
Sets up all the configured mountpoints
"""
global mounts
fs_cfg = config['fs']['memory']
if not fs_cfg['enabled']:
return
for name, options in fs_cfg['mounts'].items():
if not options['enabled']:
continue
logging.debug("[FS] Trying to setup mount %s (%s)", name, options['mount'])
size,unit = re.match(r"(\d+)([a-zA-Z]+)", options['size']).groups()
target = os.path.join('/run/pwnagotchi/disk/', os.path.basename(options['mount']))
is_mounted = is_mountpoint(target)
logging.debug("[FS] %s is %s mounted", options['mount'],
"already" if is_mounted else "not yet")
m = MemoryFS(
options['mount'],
target,
size=options['size'],
zram=options['zram'],
zram_disk_size=f"{int(size)*2}{unit}",
rsync=options['rsync'])
if not is_mounted:
if not m.mount():
logging.debug(f"Error while mounting {m.mountpoint}")
continue
if not m.sync(to_ram=True):
logging.debug(f"Error while syncing to {m.mountpoint}")
m.umount()
continue
interval = int(options['sync'])
if interval:
logging.debug("[FS] Starting thread to sync %s (interval: %d)",
options['mount'], interval)
_thread.start_new_thread(m.daemonize, (interval,))
else:
logging.debug("[FS] Not syncing %s, because interval is 0",
options['mount'])
mounts.append(m)
class MemoryFS:
@staticmethod
def zram_install():
if not os.path.exists("/sys/class/zram-control"):
logging.debug("[FS] Installing zram")
return os.system("modprobe zram") == 0
return True
@staticmethod
def zram_dev():
logging.debug("[FS] Adding zram device")
return open("/sys/class/zram-control/hot_add", "rt").read().strip("\n")
def __init__(self, mount, disk, size="40M",
zram=True, zram_alg="lz4", zram_disk_size="100M",
zram_fs_type="ext4", rsync=True):
self.mountpoint = mount
self.disk = disk
self.size = size
self.zram = zram
self.zram_alg = zram_alg
self.zram_disk_size = zram_disk_size
self.zram_fs_type = zram_fs_type
self.zdev = None
self.rsync = True
self._setup()
def _setup(self):
if self.zram and MemoryFS.zram_install():
# setup zram
self.zdev = MemoryFS.zram_dev()
open(f"/sys/block/zram{self.zdev}/comp_algorithm", "wt").write(self.zram_alg)
open(f"/sys/block/zram{self.zdev}/disksize", "wt").write(self.zram_disk_size)
open(f"/sys/block/zram{self.zdev}/mem_limit", "wt").write(self.size)
logging.debug("[FS] Creating fs (type: %s)", self.zram_fs_type)
os.system(f"mke2fs -t {self.zram_fs_type} /dev/zram{self.zdev} >/dev/null 2>&1")
# ensure mountpoints exist
if not os.path.exists(self.disk):
logging.debug("[FS] Creating %s", self.disk)
os.makedirs(self.disk)
if not os.path.exists(self.mountpoint):
logging.debug("[FS] Creating %s", self.mountpoint)
os.makedirs(self.mountpoint)
def daemonize(self, interval=60):
logging.debug("[FS] Daemonized...")
while True:
self.sync()
sleep(interval)
def sync(self, to_ram=False):
source, dest = (self.disk, self.mountpoint) if to_ram else (self.mountpoint, self.disk)
needed, actually_free = size_of(source), shutil.disk_usage(dest)[2]
if actually_free >= needed:
logging.debug("[FS] Syncing %s -> %s", source,dest)
if self.rsync:
os.system(f"rsync -aXv --inplace --no-whole-file --delete-after {source}/ {dest}/ >/dev/null 2>&1")
else:
copy_tree(source, dest, preserve_symlinks=True)
os.system("sync")
return True
return False
def mount(self):
if os.system(f"mount --bind {self.mountpoint} {self.disk}"):
return False
if os.system(f"mount --make-private {self.disk}"):
return False
if self.zram and self.zdev is not None:
if os.system(f"mount -t {self.zram_fs_type} -o nosuid,noexec,nodev,user=pwnagotchi /dev/zram{self.zdev} {self.mountpoint}/"):
return False
else:
if os.system(f"mount -t tmpfs -o nosuid,noexec,nodev,mode=0755,size={self.size} pwnagotchi {self.mountpoint}/"):
return False
return True
def umount(self):
if os.system(f"umount -l {self.mountpoint}"):
return False
if os.system(f"umount -l {self.disk}"):
return False
return True
================================================
FILE: pwnagotchi/grid.py
================================================
import subprocess
import socket
import requests
import json
import logging
import pwnagotchi
# pwngrid-peer is running on port 8666
API_ADDRESS = "http://127.0.0.1:8666/api/v1"
def is_connected():
try:
# check DNS
host = socket.gethostbyname('api.pwnagotchi.ai')
if host:
# check connectivity itself
socket.create_connection((host, 443), timeout=30)
return True
except:
pass
return False
def call(path, obj=None):
url = '%s%s' % (API_ADDRESS, path)
if obj is None:
r = requests.get(url, headers=None, timeout=(30.0, 60.0))
elif isinstance(obj, dict):
r = requests.post(url, headers=None, json=obj, timeout=(30.0, 60.0))
else:
r = requests.post(url, headers=None, data=obj, timeout=(30.0, 60.0))
if r.status_code != 200:
raise Exception("(status %d) %s" % (r.status_code, r.text))
return r.json()
def advertise(enabled=True):
return call("/mesh/%s" % 'true' if enabled else 'false')
def set_advertisement_data(data):
return call("/mesh/data", obj=data)
def get_advertisement_data():
return call("/mesh/data")
def memory():
return call("/mesh/memory")
def peers():
return call("/mesh/peers")
def closest_peer():
all = peers()
return all[0] if len(all) else None
def update_data(last_session):
brain = {}
try:
with open('/root/brain.json') as fp:
brain = json.load(fp)
except:
pass
data = {
'session': {
'duration': last_session.duration,
'epochs': last_session.epochs,
'train_epochs': last_session.train_epochs,
'avg_reward': last_session.avg_reward,
'min_reward': last_session.min_reward,
'max_reward': last_session.max_reward,
'deauthed': last_session.deauthed,
'associated': last_session.associated,
'handshakes': last_session.handshakes,
'peers': last_session.peers,
},
'uname': subprocess.getoutput("uname -a"),
'brain': brain,
'version': pwnagotchi.__version__
}
logging.debug("updating grid data: %s" % data)
call("/data", data)
def report_ap(essid, bssid):
try:
call("/report/ap", {
'essid': essid,
'bssid': bssid,
})
return True
except Exception as e:
logging.exception("error while reporting ap %s(%s)" % (essid, bssid))
return False
def inbox(page=1, with_pager=False):
obj = call("/inbox?p=%d" % page)
return obj["messages"] if not with_pager else obj
def inbox_message(id):
return call("/inbox/%d" % int(id))
def mark_message(id, mark):
return call("/inbox/%d/%s" % (int(id), str(mark)))
def send_message(to, message):
return call("/unit/%s/inbox" % to, message.encode('utf-8'))
================================================
FILE: pwnagotchi/identity.py
================================================
from Crypto.Signature import PKCS1_PSS
from Crypto.PublicKey import RSA
import Crypto.Hash.SHA256 as SHA256
import base64
import hashlib
import os
import logging
DefaultPath = "/etc/pwnagotchi/"
class KeyPair(object):
def __init__(self, path=DefaultPath, view=None):
self.path = path
self.priv_path = os.path.join(path, "id_rsa")
self.priv_key = None
self.pub_path = "%s.pub" % self.priv_path
self.pub_key = None
self.fingerprint_path = os.path.join(path, "fingerprint")
self._view = view
if not os.path.exists(self.path):
os.makedirs(self.path)
while True:
# first time, generate new keys
if not os.path.exists(self.priv_path) or not os.path.exists(self.pub_path):
self._view.on_keys_generation()
logging.info("generating %s ..." % self.priv_path)
os.system("pwngrid -generate -keys '%s'" % self.path)
# load keys: they might be corrupted if the unit has been turned off during the generation, in this case
# the exception will remove the files and go back at the beginning of this loop.
try:
with open(self.priv_path) as fp:
self.priv_key = RSA.importKey(fp.read())
with open(self.pub_path) as fp:
self.pub_key = RSA.importKey(fp.read())
self.pub_key_pem = self.pub_key.exportKey('PEM').decode("ascii")
# python is special
if 'RSA PUBLIC KEY' not in self.pub_key_pem:
self.pub_key_pem = self.pub_key_pem.replace('PUBLIC KEY', 'RSA PUBLIC KEY')
pem_ascii = self.pub_key_pem.encode("ascii")
self.pub_key_pem_b64 = base64.b64encode(pem_ascii).decode("ascii")
self.fingerprint = hashlib.sha256(pem_ascii).hexdigest()
with open(self.fingerprint_path, 'w+t') as fp:
fp.write(self.fingerprint)
# no exception, keys loaded correctly.
self._view.on_starting()
return
except Exception as e:
# if we're here, loading the keys broke something ...
logging.exception("error loading keys, maybe corrupted, deleting and regenerating ...")
try:
os.remove(self.priv_path)
os.remove(self.pub_path)
except:
pass
def sign(self, message):
hasher = SHA256.new(message.encode("ascii"))
signer = PKCS1_PSS.new(self.priv_key, saltLen=16)
signature = signer.sign(hasher)
signature_b64 = base64.b64encode(signature).decode("ascii")
return signature, signature_b64
================================================
FILE: pwnagotchi/locale/af/LC_MESSAGES/voice.po
================================================
# Afrikaans translation of pwnagotchi.
# Copyright (C) 2020.
# This file is distributed under the same license as the pwnagotchi package.
# FIRST AUTHOR MatthewNunu https://github.com/MatthewNunu, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: 1.5.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-11-29 21:50+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: MatthewNunu https://github.com/MatthewNunu\n"
"Language-Team: \n"
"Language: Afrikaans\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr "ZzzzZZzzzzZzzz"
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Hi, ek is Pwnagotchi! Aanvang ..."
msgid "New day, new hunt, new pwns!"
msgstr "Nuwe dag, nuwe jag, nuwe pwns!"
msgid "Hack the Planet!"
msgstr "Hack die wêreld!"
msgid "AI ready."
msgstr "AI gereed."
msgid "The neural network is ready."
msgstr "Die neurale netwerk is gereed."
msgid "Generating keys, do not turn off ..."
msgstr "Genereer wagwoord, moenie afskakel nie ..."
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Haai, kanaal {channel} is gratis! Jou AP sal dankie sê."
msgid "Reading last session logs ..."
msgstr "Lees laaste sessie logs ..."
#, python-brace-format
msgid "Read {lines_so_far} log lines so far ..."
msgstr "Ek het {lines_so_far} tot dusver gelees ..."
msgid "I'm bored ..."
msgstr "Ek's verveeld ..."
msgid "Let's go for a walk!"
msgstr "Kom ons gaan vir 'n loopie!"
msgid "This is the best day of my life!"
msgstr "Dit is die beste dag van my lewe!"
msgid "Shitty day :/"
msgstr "Poes kak dag :/"
msgid "I'm extremely bored ..."
msgstr "Ek's baie verveeld ..."
msgid "I'm very sad ..."
msgstr "Ek's baie hartseer ..."
msgid "I'm sad"
msgstr "Ek's hartseer ..."
msgid "Leave me alone ..."
msgstr "Los my uit ..."
msgid "I'm mad at you!"
msgstr "Ek is kwaad vir jou!"
msgid "I'm living the life!"
msgstr "Ek leef die lewe!"
msgid "I pwn therefore I am."
msgstr "Ek pwn daarom is ek."
msgid "So many networks!!!"
msgstr "Soveel netwerke!!!"
msgid "I'm having so much fun!"
msgstr "Ek het soveel pret!"
msgid "My crime is that of curiosity ..."
msgstr "My misdaad is dié van nuuskierigheid ..."
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
msgstr "Hallo {name}! Lekker om jou te ontmoet."
#, python-brace-format
msgid "Yo {name}! Sup?"
msgstr "Yo {name}! Sup?"
#, python-brace-format
msgid "Hey {name} how are you doing?"
msgstr "Haai {name} hoe doen jy?"
#, python-brace-format
msgid "Unit {name} is nearby!"
msgstr "Eenheid {name}} is naby!"
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "Uhm ... totsiens {name}"
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} is weg ..."
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Whoops ... {name} is weg."
#, python-brace-format
msgid "{name} missed!"
msgstr "{name} gemis!"
msgid "Missed!"
msgstr "Gemis!"
msgid "Good friends are a blessing!"
msgstr "Goeie vriende is 'n seën!"
msgid "I love my friends!"
msgstr "Ek is lief vir my vriende!"
msgid "Nobody wants to play with me ..."
msgstr "Niemand wil met my speel nie ..."
msgid "I feel so alone ..."
msgstr "Ek voel so alleen ..."
msgid "Where's everybody?!"
msgstr "Waar is almal?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Slaap vir {secs}s ..."
msgid "Zzzzz"
msgstr "Zzzzz"
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr "ZzzZzzz ({secs}s)"
msgid "Good night."
msgstr "Goeie nag."
msgid "Zzz"
msgstr "Zzz"
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Wag tans vir {secs}s ..."
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Rondkyk ({secs}s)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "Haai {what} kom ons wees vriende!"
#, python-brace-format
msgid "Associating to {what}"
msgstr "Assosieer na {what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr "Yo {what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "Net besluit dat {mac} geen WiFi nodig het nie!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr "Deauthenticating {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "Kickbanning {mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "Koel, ons het {num} nuwe handdruk gekry!"
#, python-brace-format
msgid "You have {count} new message{plural}!"
msgstr "Jy het {count} nuwe boodskap!"
msgid "Oops, something went wrong ... Rebooting ..."
msgstr "Oops, iets het verkeerd gegaan ... Herlaai ..."
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "Geskop {num} stasies\n"
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "Gemaak {num} nuwe vriende\n"
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "Het {num} handdrukke\n"
msgid "Met 1 peer"
msgstr "Ontmoet 1 eweknie"
#, python-brace-format
msgid "Met {num} peers"
msgstr "Ontmoet {num} eweknie"
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
"Ek was pwning vir {duration} en het {deauthed} kliënte geskop! Ek het ook ontmoet "
"{associated} nuwe vriende en het {handshakes} handdrukke geëet! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours"
msgstr "uur"
msgid "minutes"
msgstr "minute"
msgid "seconds"
msgstr "sekondes"
msgid "hour"
msgstr "uur"
msgid "minute"
msgstr "minuut"
msgid "second"
msgstr "tweede"
================================================
FILE: pwnagotchi/locale/bg/LC_MESSAGES/voice.po
================================================
# pwnagotchi voice data.
# Copyright (C) 2019
# This file is distributed under the same license as the pwnagotchi package.
# FIRST AUTHOR <https://github.com/georgikoemdzhiev>, 2019.
#
#,
msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-10-23 20:56+0200\n"
"PO-Revision-Date: 2019-10-23 20:56+0200\n"
"Last-Translator: Georgi Koemdzhiev <https://github.com/georgikoemdzhiev>\n"
"Language-Team: \n"
"Language: bulgarian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr ""
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Здравей, аз съм Pwnagotchi! Стартиране ..."
msgid "New day, new hunt, new pwns!"
msgstr "Нов ден, нов лов, нови pwns!"
msgid "Hack the Planet!"
msgstr "Хакни планетата!"
msgid "AI ready."
msgstr "AI готов."
msgid "The neural network is ready."
msgstr "Невронната мрежа е готова."
msgid "Generating keys, do not turn off ..."
msgstr "Генериране на ключове, не изключвай ..."
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Здравей, канал {channel} е свободен! твоя AP ще каже благодаря."
msgid "I'm bored ..."
msgstr "Скучно ми е ..."
msgid "Let's go for a walk!"
msgstr "Хайда да се поразходим!"
msgid "This is the best day of my life!"
msgstr "Това е най-добрият ден в живота ми!"
msgid "Shitty day :/"
msgstr "Тъп ден :/"
msgid "I'm extremely bored ..."
msgstr "Супер много ми е скучно ..."
msgid "I'm very sad ..."
msgstr "Много съм тъжен ..."
msgid "I'm sad"
msgstr "Тъжен съм"
msgid "I'm living the life!"
msgstr "Живота ми е фантастичен!"
msgid "I pwn therefore I am."
msgstr "Аз живея за да pwn-вам."
msgid "So many networks!!!"
msgstr "Толкова много мрежи!!!"
msgid "I'm having so much fun!"
msgstr "Толкова много се забавлявам!"
msgid "My crime is that of curiosity ..."
msgstr "Моето престъпление е това че съм любопитен ..."
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
msgstr "Здравей {name}! Приятно ми е да се запознаем."
#, python-brace-format
msgid "Unit {name} is nearby!"
msgstr "Устройство {name} е наблизо!"
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "Ами ... довиждане {name}"
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} изчезна ..."
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Упс ... {name} изчезна."
#, python-brace-format
msgid "{name} missed!"
msgstr "{name} загубен!"
msgid "Missed!"
msgstr "Загубен!"
msgid "Good friends are a blessing!"
msgstr "Добрите приятели са благословия!"
msgid "I love my friends!"
msgstr "Обичам приятелите си!"
msgid "Nobody wants to play with me ..."
msgstr "Никой не иска да си играе с мен ..."
msgid "I feel so alone ..."
msgstr "Чувствам се толкова самотен ..."
msgid "Where's everybody?!"
msgstr "Къде са всички?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Заспивам за {secs} секунди ..."
msgid "Zzzzz"
msgstr "Zzzzz"
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr "ZzzZzzz ({secs}s)"
msgid "Good night."
msgstr "Лека нощ."
msgid "Zzz"
msgstr "Zzz"
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Чакам {secs} секунди ..."
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Оглеждам се ({secs}секунди)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "Хей {what} нека станем приятели!"
#, python-brace-format
msgid "Associating to {what}"
msgstr "Свръзване с {what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr "Ей {what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "Реших, че {mac} не се нуждае от WiFi!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr "Неудостоверяване на {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "Ритам и прогонвам {mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "Супер, имаме {num} нови handshake{plural}!"
#, python-brace-format
msgid "You have {count} new message{plural}!"
msgstr "Имате {count} нови съобщения!"
msgid "Oops, something went wrong ... Rebooting ..."
msgstr "Упс, нещо се обърка ... Рестартиране ..."
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "Отхвърлих {num} станции\n"
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "Направих {num} нови приятели\n"
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "Имам {num} handshakes\n"
msgid "Met 1 peer"
msgstr "Срещнах 1 връстник"
#, python-brace-format
msgid "Met {num} peers"
msgstr "Срещнах {num} връстници"
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr "Аз pwn-вах за {duration} и отхвърлих {deauthed} clients! Също така срещнах {associated} нови приятели и изядох {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours"
msgstr "часове"
msgid "minutes"
msgstr "минути"
msgid "seconds"
msgstr "секунди"
msgid "hour"
msgstr "час"
msgid "minute"
msgstr "минута"
msgid "second"
msgstr "секунда"
================================================
FILE: pwnagotchi/locale/ch/LC_MESSAGES/voice.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <511225068@qq.com>, 2019.
# 还有很多未翻译和翻译不准确,后期希望大家加入进来一起翻译!
# 翻译可以联系QQ群:959559103 找 名字叫 初九 的 管理员
msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-10-23 20:56+0200\n"
"PO-Revision-Date: 2019-11-02 10:00+0008\n"
"Last-Translator: 极客之眼-初九 <511225068@qq.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: chinese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr ""
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "主人,你好.我是WiFi狩猎兽..."
msgid "New day, new hunt, new pwns!"
msgstr "美好的一天,狩猎开始!"
msgid "Hack the Planet!"
msgstr "我要入侵整个地球!"
msgid "AI ready."
msgstr "人工智能已启动."
msgid "The neural network is ready."
msgstr "神经元网络已启动."
msgid "Generating keys, do not turn off ..."
msgstr "创建密钥中, 请勿断电..."
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "嘿,频道{channel}是免费的!你的AP会说谢谢。"
msgid "I'm bored ..."
msgstr "我无聊了..."
msgid "Let's go for a walk!"
msgstr "主人带我出门走走吧!"
msgid "This is the best day of my life!"
msgstr "这是我生命中最美好的一天!"
msgid "Shitty day :/"
msgstr "今天不开心 :/"
msgid "I'm extremely bored ..."
msgstr "主人,找点事做吧 ..."
msgid "I'm very sad ..."
msgstr "我很伤心..."
msgid "I'm sad"
msgstr "我伤心了"
msgid "I'm living the life!"
msgstr ""
msgid "I pwn therefore I am."
msgstr ""
msgid "So many networks!!!"
msgstr "哇,好多猎物!!!"
msgid "I'm having so much fun!"
msgstr "我玩的好开心!"
msgid "My crime is that of curiosity ..."
msgstr "我最大的缺点就是好奇..."
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
msgstr "你好{name}!很高兴认识你."
#, python-brace-format
msgid "Unit {name} is nearby!"
msgstr "小队{name}就在附近!"
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "额 ... 再见{name}"
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} 它走了 ..."
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "哎呀... {name} 离开了."
#, python-brace-format
msgid "{name} missed!"
msgstr "刚刚错过了{name}!"
msgid "Missed!"
msgstr "刚刚错过了一个对的它"
msgid "Good friends are a blessing!"
msgstr "有个好朋友就是福气"
msgid "I love my friends!"
msgstr "我爱我的朋友!"
msgid "Nobody wants to play with me ..."
msgstr "没有人愿意和我玩耍..."
msgid "I feel so alone ..."
msgstr "我可能是天煞孤星..."
msgid "Where's everybody?!"
msgstr "朋友们都去哪里了?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "小憩{secs}s ..."
msgid "Zzzzz"
msgstr ""
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
msgid "Good night."
msgstr "晚安宝贝."
msgid "Zzz"
msgstr ""
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "等待{secs}s ..."
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "追踪四周猎物({secs}s)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "嗨{what}我们做朋友吧!"
#, python-brace-format
msgid "Associating to {what}"
msgstr "正在连接到{what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr "追踪到你了{what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "猎物{mac}不需要联网,我们给它断开!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr "开始攻击猎物{mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "已捕获{mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "太酷了, 我们抓到了{num}新的猎物{plural}!"
#, python-brace-format
msgid "You have {count} new message{plural}!"
msgstr "主人,有{count}新消息{plural}!"
msgid "Oops, something went wrong ... Rebooting ..."
msgstr "行动,额等等有点小问题... 重启ing ..."
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "限制了{num}个猎物\n"
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "交了{num}新朋友\n"
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "捕获了{num}握手包\n"
msgid "Met 1 peer"
msgstr "有{num}同龄人"
#, python-brace-format
msgid "Met {num} peers"
msgstr ""
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
msgid "hours"
msgstr "时"
msgid "minutes"
msgstr "分"
msgid "seconds"
msgstr "秒"
msgid "hour"
msgstr "时"
msgid "minute"
msgstr "分"
msgid "second"
msgstr "秒"
================================================
FILE: pwnagotchi/locale/cs/LC_MESSAGES/voice.po
================================================
# pwnigotchi voice data
# Copyright (C) 2020
# This file is distributed under the same license as the pwnagotchi package.
# FIRST AUTHOR czechball@users.noreply.github.com, 2020.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-04-14 06:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Czechball <czechball@users.noreply.github.com>\n"
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr "ZzzzZZzzzzZzzz"
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Ahoj, já jsem Pwnagotchi! Startuju ..."
msgid "New day, new hunt, new pwns!"
msgstr "Nový den, nový lov, nové úlovky!"
msgid "Hack the Planet!"
msgstr "Hackni celou planetu!"
msgid "AI ready."
msgstr "AI připraveno."
msgid "The neural network is ready."
msgstr "Neuronová síť je připravena."
msgid "Generating keys, do not turn off ..."
msgstr "Generování klíčů, nevypínej mě..."
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Hej, kanál {channel} je volný! Tvůj AP ti poděkuje."
msgid "Reading last session logs ..."
msgstr "Čtení posledních zpráv z logu ..."
#, python-brace-format
msgid "Read {lines_so_far} log lines so far ..."
msgstr "Zatím přečteno {lines_so_far} řádků logu ..."
msgid "I'm bored ..."
msgstr "Nudím se ..."
msgid "Let's go for a walk!"
msgstr "Pojďme se projít!"
msgid "This is the best day of my life!"
msgstr "Tohle je nejlepší den mého života!"
msgid "Shitty day :/"
msgstr "Na hovno den :/"
msgid "I'm extremely bored ..."
msgstr "Strašně se nudím ..."
msgid "I'm very sad ..."
msgstr "Jsem dost smutný ..."
msgid "I'm sad"
msgstr "Jsem smutný"
msgid "Leave me alone ..."
msgstr "Nech mě být ..."
msgid "I'm mad at you!"
msgstr "Jsem na tebe naštvaný!"
msgid "I'm living the life!"
msgstr "Tohle je život!"
msgid "I pwn therefore I am."
msgstr "Chytám pakety a tedy jsem."
msgid "So many networks!!!"
msgstr "Tolik sítí!!!"
msgid "I'm having so much fun!"
msgstr "Tohle je super zábava!"
msgid "My crime is that of curiosity ..."
msgstr "Jsem kriminálně zvědavý ..."
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
msgstr "Ahoj {name}! Rád tě poznávám."
#, python-brace-format
msgid "Yo {name}! Sup?"
msgstr "Hej {name}! Jak to jde?"
#, python-brace-format
msgid "Hey {name} how are you doing?"
msgstr "Ahoj {name}, jak se máš?"
#, python-brace-format
msgid "Unit {name} is nearby!"
msgstr "Jednotka {name} je nablízku!"
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "Uhm... Měj se {name}"
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} je pryč ..."
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Whoops ... {name} je pryč."
#, python-brace-format
msgid "{name} missed!"
msgstr "Chybí mi {name}!"
msgid "Missed!"
msgstr "Chybíš mi!"
msgid "Good friends are a blessing!"
msgstr "Dobří kamarádi jsou požehnání!"
msgid "I love my friends!"
msgstr "Miluju svoje kamarády!"
msgid "Nobody wants to play with me ..."
msgstr "Nikdo si se mnou nechce hrát ..."
msgid "I feel so alone ..."
msgstr "Cítím se tak osamělý ..."
msgid "Where's everybody?!"
msgstr "Kde jsou všichni?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Spím {secs} sekund ..."
msgid "Zzzzz"
msgstr "Zzzzz"
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr "ZzzZzzz ({secs}s)"
msgid "Good night."
msgstr "Dobrou noc."
msgid "Zzz"
msgstr "Zzz"
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Čekání {secs} sekund ..."
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Rozhlížím se ({secs}s)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "Hej {what} budeme kamarádi!"
#, python-brace-format
msgid "Associating to {what}"
msgstr "Asociuju se s {what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr "Čus {what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "Rozhodl jsem se, že {mac} nepotřebuje žádnou WiFi!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr "Deautentikuju {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "Kickbanuju {mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "Super, máme {num} nových handshaků!"
#, python-brace-format
msgid "You have {count} new message{plural}!"
msgstr "Máš {count} nových zpráv!"
msgid "Oops, something went wrong ... Rebooting ..."
msgstr "Ups, něco se pokazilo ... Restartuju ..."
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "Vykopnuto {num} klientů\n"
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "Mám {num} nových kamarádů\n"
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "Mám {num} handshaků\n"
msgid "Met 1 peer"
msgstr "Potkal jsem jednoho kámoše"
#, python-brace-format
msgid "Met {num} peers"
msgstr "Potkal jsem {num} kámošů"
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
"Chytal jsem pakety po dobu {duration} a vykopnul jsem {deauthed} klientů! Taky jsem potkal "
"{associated} nových kamarádů a snědl {handshakes} handshaků! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours"
msgstr "hodiny"
msgid "minutes"
msgstr "minuty"
msgid "seconds"
msgstr "sekundy"
msgid "hour"
msgstr "hodina"
msgid "minute"
msgstr "minuta"
msgid "second"
msgstr "sekunda"
================================================
FILE: pwnagotchi/locale/de/LC_MESSAGES/voice.po
================================================
# German language
# Copyright (C) 2019
# This file is distributed under the same license as the pwnagotchi package.
# dadav <33197631+dadav@users.noreply.github.com>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-11-14 21:15+0100\n"
"PO-Revision-Date: 2019-09-29 14:00+0200\n"
"Last-Translator: dadav <33197631+dadav@users.noreply.github.com>\n"
"Language-Team: DE <33197631+dadav@users.noreply.github.com>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "ZzzzZZzzzzZzzz"
msgstr ""
msgid "Hi, I'm Pwnagotchi! Starting ..."
msgstr "Hi, ich bin ein Pwnagotchi! Starte..."
msgid "New day, new hunt, new pwns!"
msgstr "Neuer Tag, neue Jagd, neue Pwns!"
msgid "Hack the Planet!"
msgstr "Hack den Planeten!"
msgid "AI ready."
msgstr "KI bereit."
msgid "The neural network is ready."
msgstr "Das neurale Netz ist bereit."
msgid "Generating keys, do not turn off ..."
msgstr "Generiere Schlüssel, nicht ausschalten..."
#, python-brace-format
msgid "Hey, channel {channel} is free! Your AP will say thanks."
msgstr "Hey, Channel {channel} ist frei! Dein AP wird es Dir danken."
msgid "Reading last session logs ..."
msgstr "Lese die Logs der letzten Session..."
#, python-brace-format
msgid "Read {lines_so_far} log lines so far ..."
msgstr "Bisher {lines_so_far} Zeilen im Log gelesen..."
msgid "I'm bored ..."
msgstr "Mir ist langweilig..."
msgid "Let's go for a walk!"
msgstr "Lass uns spazieren gehen!"
msgid "This is the best day of my life!"
msgstr "Das ist der beste Tag meines Lebens!"
msgid "Shitty day :/"
msgstr "Scheißtag :/"
msgid "I'm extremely bored ..."
msgstr "Mir ist sau langweilig..."
msgid "I'm very sad ..."
msgstr "Ich bin sehr traurig..."
msgid "I'm sad"
msgstr "Ich bin traurig"
#, fuzzy
msgid "Leave me alone ..."
msgstr "Lass mich in Ruhe..."
msgid "I'm mad at you!"
msgstr "Ich bin sauer auf Dich!"
msgid "I'm living the life!"
msgstr "Ich lebe das Leben!"
msgid "I pwn therefore I am."
msgstr "Ich pwne, also bin ich."
msgid "So many networks!!!"
msgstr "So viele Netzwerke!!!"
msgid "I'm having so much fun!"
msgstr "Ich habe sooo viel Spaß!"
msgid "My crime is that of curiosity ..."
msgstr "Mein Verbrechen ist das der Neugier..."
#, python-brace-format
msgid "Hello {name}! Nice to meet you."
msgstr "Hallo {name}, schön Dich kennenzulernen."
#, python-brace-format
msgid "Yo {name}! Sup?"
msgstr "Jo {name}! Was geht!?"
#, python-brace-format
msgid "Hey {name} how are you doing?"
msgstr "Hey {name}, wie geht's?"
#, python-brace-format
msgid "Unit {name} is nearby!"
msgstr "Gerät {name} ist in der Nähe!"
#, python-brace-format
msgid "Uhm ... goodbye {name}"
msgstr "Uhm... tschüß {name}"
#, python-brace-format
msgid "{name} is gone ..."
msgstr "{name} ist weg..."
#, python-brace-format
msgid "Whoops ... {name} is gone."
msgstr "Whoops... {name} ist weg."
#, python-brace-format
msgid "{name} missed!"
msgstr "{name} verpasst!"
msgid "Missed!"
msgstr "Verpasst!"
msgid "Good friends are a blessing!"
msgstr "Gute Freunde sind ein Segen!"
msgid "I love my friends!"
msgstr "Ich liebe meine Freunde!"
msgid "Nobody wants to play with me ..."
msgstr "Niemand will mit mir spielen..."
msgid "I feel so alone ..."
msgstr "Ich fühl' mich so allein..."
msgid "Where's everybody?!"
msgstr "Wo sind denn alle?!"
#, python-brace-format
msgid "Napping for {secs}s ..."
msgstr "Schlafe für {secs}s..."
msgid "Zzzzz"
msgstr ""
#, python-brace-format
msgid "ZzzZzzz ({secs}s)"
msgstr ""
msgid "Good night."
msgstr "Gute Nacht."
msgid "Zzz"
msgstr ""
#, python-brace-format
msgid "Waiting for {secs}s ..."
msgstr "Warte für {secs}s..."
#, python-brace-format
msgid "Looking around ({secs}s)"
msgstr "Schaue mich um ({secs}s)"
#, python-brace-format
msgid "Hey {what} let's be friends!"
msgstr "Hey {what}, lass uns Freunde sein!"
#, python-brace-format
msgid "Associating to {what}"
msgstr "Verbinde mit {what}"
#, python-brace-format
msgid "Yo {what}!"
msgstr "Jo {what}!"
#, python-brace-format
msgid "Just decided that {mac} needs no WiFi!"
msgstr "Ich denke, dass {mac} kein WiFi braucht!"
#, python-brace-format
msgid "Deauthenticating {mac}"
msgstr "Deauthentifiziere {mac}"
#, python-brace-format
msgid "Kickbanning {mac}!"
msgstr "Kicke {mac}!"
#, python-brace-format
msgid "Cool, we got {num} new handshake{plural}!"
msgstr "Cool, wir haben {num} neue Handshake{plural}!"
#, python-brace-format
msgid "You have {count} new message{plural}!"
msgstr "Cool, wir haben {num} neue Handshake{plural}!"
msgid "Oops, something went wrong ... Rebooting ..."
msgstr "Ops, da ist was schief gelaufen... Starte neu..."
#, python-brace-format
msgid "Kicked {num} stations\n"
msgstr "{num} Stationen gekickt\n"
#, python-brace-format
msgid "Made {num} new friends\n"
msgstr "{num} neue Freunde gefunden\n"
#, python-brace-format
msgid "Got {num} handshakes\n"
msgstr "{num} Handshakes aufgez.\n"
msgid "Met 1 peer"
msgstr "1 Peer getroffen."
#, python-brace-format
msgid "Met {num} peers"
msgstr "{num} Peers getroffen"
#, python-brace-format
msgid ""
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
"#pwnlog #pwnlife #hacktheplanet #skynet"
msgstr ""
"Ich war {duration} am Pwnen und habe {deauthed} Clients gekickt! Außerdem "
"habe ich {associated} neue Freunde getroffen und {handshakes} Handshakes "
"gefressen! #pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
msgid "hours"
msgstr "Stunden"
msgid "minutes"
msgstr "Minuten"
msgid "seconds"
msgstr "Sekunden"
msgid
gitextract_zo4q6okm/ ├── .DEREK.yml ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ └── other.md │ ├── ISSUE_TEMPLATE.md │ └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── MANIFEST.in ├── Makefile ├── README.md ├── bin/ │ └── pwnagotchi ├── builder/ │ ├── data/ │ │ ├── etc/ │ │ │ ├── bash_completion.d/ │ │ │ │ └── pwnagotchi_completion.sh │ │ │ ├── network/ │ │ │ │ └── interfaces.d/ │ │ │ │ ├── eth0-cfg │ │ │ │ ├── lo-cfg │ │ │ │ ├── usb0-cfg │ │ │ │ └── wlan0-cfg │ │ │ └── systemd/ │ │ │ └── system/ │ │ │ ├── bettercap.service │ │ │ ├── pwnagotchi.service │ │ │ └── pwngrid-peer.service │ │ └── usr/ │ │ └── bin/ │ │ ├── bettercap-launcher │ │ ├── decryption-webserver │ │ ├── hdmioff │ │ ├── hdmion │ │ ├── monstart │ │ ├── monstop │ │ ├── pwnagotchi-launcher │ │ └── pwnlib │ ├── pwnagotchi.json │ └── pwnagotchi.yml ├── pwnagotchi/ │ ├── __init__.py │ ├── _version.py │ ├── agent.py │ ├── ai/ │ │ ├── __init__.py │ │ ├── epoch.py │ │ ├── featurizer.py │ │ ├── gym.py │ │ ├── parameter.py │ │ ├── reward.py │ │ ├── train.py │ │ └── utils.py │ ├── automata.py │ ├── bettercap.py │ ├── defaults.toml │ ├── fs/ │ │ └── __init__.py │ ├── grid.py │ ├── identity.py │ ├── locale/ │ │ ├── af/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── bg/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── ch/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── cs/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── de/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── dk/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── el/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── es/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── fr/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── ga/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── hr/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── hu/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── it/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── jp/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── mk/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── nl/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── no/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── pl/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── pt/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── pt-BR/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── ro/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── ru/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── se/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── sk/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── spa/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── tr/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── tw/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ ├── ua/ │ │ │ └── LC_MESSAGES/ │ │ │ ├── voice.mo │ │ │ └── voice.po │ │ └── voice.pot │ ├── log.py │ ├── mesh/ │ │ ├── __init__.py │ │ ├── peer.py │ │ ├── utils.py │ │ └── wifi.py │ ├── plugins/ │ │ ├── __init__.py │ │ ├── cmd.py │ │ └── default/ │ │ ├── auto-update.py │ │ ├── bt-tether.py │ │ ├── example.py │ │ ├── gpio_buttons.py │ │ ├── gps.py │ │ ├── grid.py │ │ ├── led.py │ │ ├── logtail.py │ │ ├── memtemp.py │ │ ├── net-pos.py │ │ ├── onlinehashcrack.py │ │ ├── paw-gps.py │ │ ├── session-stats.py │ │ ├── switcher.py │ │ ├── ups_lite.py │ │ ├── watchdog.py │ │ ├── webcfg.py │ │ ├── webgpsmap.html │ │ ├── webgpsmap.py │ │ ├── wigle.py │ │ └── wpa-sec.py │ ├── ui/ │ │ ├── __init__.py │ │ ├── components.py │ │ ├── display.py │ │ ├── faces.py │ │ ├── fonts.py │ │ ├── hw/ │ │ │ ├── __init__.py │ │ │ ├── adafruitssd1306i2c.py │ │ │ ├── base.py │ │ │ ├── dfrobot1.py │ │ │ ├── dfrobot2.py │ │ │ ├── inky.py │ │ │ ├── lcdhat.py │ │ │ ├── libs/ │ │ │ │ ├── __init__.py │ │ │ │ ├── adafruit/ │ │ │ │ │ └── adafruitssd1306i2c/ │ │ │ │ │ ├── SSD1306.py │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── epd.py │ │ │ │ ├── dfrobot/ │ │ │ │ │ ├── LICENSE │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── v1/ │ │ │ │ │ │ ├── __init__.py │ │ │ │ │ │ ├── dfrobot.py │ │ │ │ │ │ ├── dfrobot_epaper.py │ │ │ │ │ │ ├── gpio.py │ │ │ │ │ │ └── spi.py │ │ │ │ │ └── v2/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── dfrobot.py │ │ │ │ │ ├── dfrobot_display/ │ │ │ │ │ │ ├── __init__.py │ │ │ │ │ │ ├── dfrobot_display.py │ │ │ │ │ │ ├── dfrobot_fonts.py │ │ │ │ │ │ └── dfrobot_printString.py │ │ │ │ │ ├── dfrobot_epaper.py │ │ │ │ │ ├── display_extension/ │ │ │ │ │ │ ├── __init__.py │ │ │ │ │ │ ├── fonts_6_8.py │ │ │ │ │ │ ├── fonts_8_16.py │ │ │ │ │ │ ├── freetype_helper.py │ │ │ │ │ │ └── readme.md │ │ │ │ │ ├── gpio.py │ │ │ │ │ ├── i2c.py │ │ │ │ │ └── spi.py │ │ │ │ ├── fb/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── fb.py │ │ │ │ ├── inkyphat/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── inkyfast.py │ │ │ │ │ └── inkyphatfast.py │ │ │ │ ├── papirus/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── epd.py │ │ │ │ │ └── lm75b.py │ │ │ │ └── waveshare/ │ │ │ │ ├── __init__.py │ │ │ │ ├── lcdhat/ │ │ │ │ │ ├── ST7789.py │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── config.py │ │ │ │ │ └── epd.py │ │ │ │ ├── lcdhat144/ │ │ │ │ │ ├── LCD_1in44.py │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── config.py │ │ │ │ │ └── epd.py │ │ │ │ ├── oledhat/ │ │ │ │ │ ├── SH1106.py │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── config.py │ │ │ │ │ └── epd.py │ │ │ │ ├── v1/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── epd2in13.py │ │ │ │ │ ├── epd2in13bc.py │ │ │ │ │ ├── epd2in13bcFAST.py │ │ │ │ │ └── epdconfig.py │ │ │ │ ├── v154inch/ │ │ │ │ │ ├── epd1in54b.py │ │ │ │ │ └── epdconfig.py │ │ │ │ ├── v2/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── waveshare.py │ │ │ │ ├── v213bc/ │ │ │ │ │ ├── epd2in13bc.py │ │ │ │ │ └── epdconfig.py │ │ │ │ ├── v213d/ │ │ │ │ │ ├── epd2in13d.py │ │ │ │ │ └── epdconfig.py │ │ │ │ ├── v213inb_v4/ │ │ │ │ │ ├── epd2in13b_V4.py │ │ │ │ │ └── epdconfig.py │ │ │ │ ├── v27inch/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── epd2in7.py │ │ │ │ │ └── epdconfig.py │ │ │ │ ├── v29inch/ │ │ │ │ │ ├── epd2in9.py │ │ │ │ │ └── epdconfig.py │ │ │ │ └── v3/ │ │ │ │ ├── epd2in13_V3.py │ │ │ │ └── epdconfig.py │ │ │ ├── oledhat.py │ │ │ ├── papirus.py │ │ │ ├── spotpear24inch.py │ │ │ ├── waveshare1.py │ │ │ ├── waveshare144lcd.py │ │ │ ├── waveshare154inch.py │ │ │ ├── waveshare2.py │ │ │ ├── waveshare213bc.py │ │ │ ├── waveshare213d.py │ │ │ ├── waveshare213inb_v4.py │ │ │ ├── waveshare27inch.py │ │ │ ├── waveshare29inch.py │ │ │ ├── waveshare3.py │ │ │ └── waveshare35lcd.py │ │ ├── state.py │ │ ├── view.py │ │ └── web/ │ │ ├── __init__.py │ │ ├── handler.py │ │ ├── server.py │ │ ├── static/ │ │ │ ├── css/ │ │ │ │ ├── jquery.jqplot.css │ │ │ │ └── style.css │ │ │ └── js/ │ │ │ ├── jquery.jqplot.js │ │ │ ├── jquery.mobile/ │ │ │ │ ├── jquery.mobile-1.4.5.css │ │ │ │ ├── jquery.mobile-1.4.5.js │ │ │ │ ├── jquery.mobile.external-png-1.4.5.css │ │ │ │ ├── jquery.mobile.icons-1.4.5.css │ │ │ │ ├── jquery.mobile.inline-png-1.4.5.css │ │ │ │ ├── jquery.mobile.inline-svg-1.4.5.css │ │ │ │ ├── jquery.mobile.structure-1.4.5.css │ │ │ │ └── jquery.mobile.theme-1.4.5.css │ │ │ ├── jquery.timeago.js │ │ │ ├── plugins/ │ │ │ │ ├── jqplot.BezierCurveRenderer.js │ │ │ │ ├── jqplot.barRenderer.js │ │ │ │ ├── jqplot.blockRenderer.js │ │ │ │ ├── jqplot.bubbleRenderer.js │ │ │ │ ├── jqplot.canvasAxisLabelRenderer.js │ │ │ │ ├── jqplot.canvasAxisTickRenderer.js │ │ │ │ ├── jqplot.canvasOverlay.js │ │ │ │ ├── jqplot.canvasTextRenderer.js │ │ │ │ ├── jqplot.categoryAxisRenderer.js │ │ │ │ ├── jqplot.ciParser.js │ │ │ │ ├── jqplot.cursor.js │ │ │ │ ├── jqplot.dateAxisRenderer.js │ │ │ │ ├── jqplot.donutRenderer.js │ │ │ │ ├── jqplot.dragable.js │ │ │ │ ├── jqplot.enhancedLegendRenderer.js │ │ │ │ ├── jqplot.enhancedPieLegendRenderer.js │ │ │ │ ├── jqplot.funnelRenderer.js │ │ │ │ ├── jqplot.highlighter.js │ │ │ │ ├── jqplot.json2.js │ │ │ │ ├── jqplot.logAxisRenderer.js │ │ │ │ ├── jqplot.mekkoAxisRenderer.js │ │ │ │ ├── jqplot.mekkoRenderer.js │ │ │ │ ├── jqplot.meterGaugeRenderer.js │ │ │ │ ├── jqplot.mobile.js │ │ │ │ ├── jqplot.ohlcRenderer.js │ │ │ │ ├── jqplot.pieRenderer.js │ │ │ │ ├── jqplot.pointLabels.js │ │ │ │ ├── jqplot.pyramidAxisRenderer.js │ │ │ │ ├── jqplot.pyramidGridRenderer.js │ │ │ │ ├── jqplot.pyramidRenderer.js │ │ │ │ └── jqplot.trendline.js │ │ │ └── viewportHeight.js │ │ └── templates/ │ │ ├── base.html │ │ ├── inbox.html │ │ ├── index.html │ │ ├── message.html │ │ ├── new_message.html │ │ ├── peers.html │ │ ├── plugins.html │ │ ├── profile.html │ │ └── status.html │ ├── utils.py │ └── voice.py ├── release.stork ├── requirements.txt ├── scripts/ │ ├── backup.sh │ ├── language.sh │ ├── linux_connection_share.sh │ ├── macos_connection_share.sh │ ├── openbsd_connection_share.sh │ ├── preview.py │ ├── pypi_upload.sh │ ├── restore.sh │ └── win_connection_share.ps1 └── setup.py
SYMBOL INDEX (1603 symbols across 146 files)
FILE: pwnagotchi/__init__.py
function set_name (line 14) | def set_name(new_name):
function name (line 47) | def name():
function uptime (line 55) | def uptime():
function mem_usage (line 60) | def mem_usage():
function _cpu_stat (line 78) | def _cpu_stat():
function cpu_load (line 86) | def cpu_load():
function temperature (line 101) | def temperature(celsius=True):
function shutdown (line 108) | def shutdown():
function restart (line 127) | def restart(mode):
function reboot (line 139) | def reboot(mode=None):
FILE: pwnagotchi/agent.py
class Agent (line 22) | class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
method __init__ (line 23) | def __init__(self, view, config, keypair):
method config (line 57) | def config(self):
method view (line 60) | def view(self):
method supported_channels (line 63) | def supported_channels(self):
method setup_events (line 66) | def setup_events(self):
method _reset_wifi_settings (line 75) | def _reset_wifi_settings(self):
method start_monitor_mode (line 84) | def start_monitor_mode(self):
method _wait_bettercap (line 122) | def _wait_bettercap(self):
method start (line 131) | def start(self):
method recon (line 143) | def recon(self):
method _filter_included (line 167) | def _filter_included(self, ap):
method set_access_points (line 172) | def set_access_points(self, aps):
method get_access_points (line 178) | def get_access_points(self):
method get_total_aps (line 198) | def get_total_aps(self):
method get_aps_on_channel (line 201) | def get_aps_on_channel(self):
method get_current_channel (line 204) | def get_current_channel(self):
method get_access_points_by_channel (line 207) | def get_access_points_by_channel(self):
method _find_ap_sta_in (line 228) | def _find_ap_sta_in(self, station_mac, ap_mac, session):
method _update_uptime (line 237) | def _update_uptime(self, s):
method _update_counters (line 242) | def _update_counters(self):
method _update_handshakes (line 255) | def _update_handshakes(self, new_shakes=0):
method _update_peers (line 270) | def _update_peers(self):
method _reboot (line 273) | def _reboot(self):
method _save_recovery_data (line 278) | def _save_recovery_data(self):
method _load_recovery_data (line 290) | def _load_recovery_data(self, delete=True, no_exceptions=True):
method start_session_fetcher (line 309) | def start_session_fetcher(self):
method _fetch_stats (line 313) | def _fetch_stats(self):
method _on_event (line 323) | async def _on_event(self, msg):
method _event_poller (line 354) | def _event_poller(self, loop):
method start_event_polling (line 366) | def start_event_polling(self):
method is_module_running (line 371) | def is_module_running(self, module):
method start_module (line 378) | def start_module(self, module):
method restart_module (line 381) | def restart_module(self, module):
method _has_handshake (line 384) | def _has_handshake(self, bssid):
method _should_interact (line 390) | def _should_interact(self, who):
method associate (line 403) | def associate(self, ap, throttle=0):
method deauth (line 424) | def deauth(self, ap, sta, throttle=0):
method set_channel (line 445) | def set_channel(self, channel, verbose=True):
FILE: pwnagotchi/ai/__init__.py
function load (line 9) | def load(config, agent, epoch, from_disk=True):
FILE: pwnagotchi/ai/epoch.py
class Epoch (line 12) | class Epoch(object):
method __init__ (line 13) | def __init__(self, config):
method wait_for_epoch_data (line 69) | def wait_for_epoch_data(self, with_observation=True, timeout=None):
method data (line 77) | def data(self):
method observe (line 80) | def observe(self, aps, peers):
method track (line 128) | def track(self, deauth=False, assoc=False, handshake=False, hop=False,...
method next (line 157) | def next(self):
FILE: pwnagotchi/ai/featurizer.py
function describe (line 8) | def describe(extended=False):
function featurize (line 40) | def featurize(state, step):
FILE: pwnagotchi/ai/gym.py
class Environment (line 11) | class Environment(gym.Env):
method __init__ (line 30) | def __init__(self, agent, epoch):
method policy_size (line 61) | def policy_size():
method policy_to_params (line 65) | def policy_to_params(policy):
method _next_epoch (line 89) | def _next_epoch(self):
method _apply_policy (line 93) | def _apply_policy(self, policy):
method step (line 99) | def step(self, policy):
method reset (line 116) | def reset(self):
method _render_histogram (line 124) | def _render_histogram(self, hist):
method render (line 129) | def render(self, mode='human', close=False, force=False):
FILE: pwnagotchi/ai/parameter.py
class Parameter (line 4) | class Parameter(object):
method __init__ (line 5) | def __init__(self, name, value=0.0, min_value=0, max_value=2, meta=Non...
method space_size (line 21) | def space_size(self):
method space (line 24) | def space(self):
method to_param_value (line 27) | def to_param_value(self, policy_v):
FILE: pwnagotchi/ai/reward.py
class RewardFunction (line 7) | class RewardFunction(object):
method __call__ (line 8) | def __call__(self, epoch_n, state):
FILE: pwnagotchi/ai/train.py
class Stats (line 13) | class Stats(object):
method __init__ (line 14) | def __init__(self, path, events_receiver):
method on_epoch (line 30) | def on_epoch(self, data, training):
method load (line 54) | def load(self):
method save (line 65) | def save(self):
class AsyncTrainer (line 86) | class AsyncTrainer(object):
method __init__ (line 87) | def __init__(self, config):
method set_training (line 95) | def set_training(self, training, for_epochs=0):
method is_training (line 104) | def is_training(self):
method training_epochs (line 107) | def training_epochs(self):
method start_ai (line 110) | def start_ai(self):
method _save_ai (line 113) | def _save_ai(self):
method on_ai_step (line 119) | def on_ai_step(self):
method on_ai_training_step (line 127) | def on_ai_training_step(self, _locals, _globals):
method on_ai_policy (line 131) | def on_ai_policy(self, new_params):
method on_ai_ready (line 147) | def on_ai_ready(self):
method on_ai_best_reward (line 151) | def on_ai_best_reward(self, r):
method on_ai_worst_reward (line 156) | def on_ai_worst_reward(self, r):
method _ai_worker (line 161) | def _ai_worker(self):
FILE: pwnagotchi/ai/utils.py
function normalize (line 4) | def normalize(v, min_v, max_v):
function as_batches (line 8) | def as_batches(x, y, batch_size, shuffle=True):
FILE: pwnagotchi/automata.py
class Automata (line 8) | class Automata(object):
method __init__ (line 9) | def __init__(self, config, view):
method _on_miss (line 14) | def _on_miss(self, who):
method _on_error (line 19) | def _on_error(self, who, e):
method set_starting (line 28) | def set_starting(self):
method set_ready (line 31) | def set_ready(self):
method in_good_mood (line 34) | def in_good_mood(self):
method _has_support_network_for (line 37) | def _has_support_network_for(self, factor):
method set_grateful (line 44) | def set_grateful(self):
method set_lonely (line 48) | def set_lonely(self):
method set_bored (line 57) | def set_bored(self):
method set_sad (line 67) | def set_sad(self):
method set_angry (line 77) | def set_angry(self, factor):
method set_excited (line 86) | def set_excited(self):
method set_rebooting (line 91) | def set_rebooting(self):
method wait_for (line 95) | def wait_for(self, t, sleeping=True):
method is_stale (line 100) | def is_stale(self):
method any_activity (line 103) | def any_activity(self):
method next_epoch (line 106) | def next_epoch(self):
FILE: pwnagotchi/bettercap.py
function decode (line 9) | def decode(r, verbose_errors=True):
class Client (line 23) | class Client(object):
method __init__ (line 24) | def __init__(self, hostname='localhost', scheme='http', port=8081, use...
method session (line 34) | def session(self):
method start_websocket (line 38) | async def start_websocket(self, consumer):
method run (line 53) | def run(self, command, verbose_errors=True):
FILE: pwnagotchi/fs/__init__.py
function ensure_write (line 16) | def ensure_write(filename, mode='w'):
function size_of (line 28) | def size_of(path):
function is_mountpoint (line 39) | def is_mountpoint(path):
function setup_mounts (line 46) | def setup_mounts(config):
class MemoryFS (line 96) | class MemoryFS:
method zram_install (line 98) | def zram_install():
method zram_dev (line 106) | def zram_dev():
method __init__ (line 111) | def __init__(self, mount, disk, size="40M",
method _setup (line 126) | def _setup(self):
method daemonize (line 146) | def daemonize(self, interval=60):
method sync (line 153) | def sync(self, to_ram=False):
method mount (line 167) | def mount(self):
method umount (line 184) | def umount(self):
FILE: pwnagotchi/grid.py
function is_connected (line 13) | def is_connected():
function call (line 26) | def call(path, obj=None):
function advertise (line 40) | def advertise(enabled=True):
function set_advertisement_data (line 44) | def set_advertisement_data(data):
function get_advertisement_data (line 48) | def get_advertisement_data():
function memory (line 52) | def memory():
function peers (line 56) | def peers():
function closest_peer (line 60) | def closest_peer():
function update_data (line 65) | def update_data(last_session):
function report_ap (line 96) | def report_ap(essid, bssid):
function inbox (line 109) | def inbox(page=1, with_pager=False):
function inbox_message (line 114) | def inbox_message(id):
function mark_message (line 118) | def mark_message(id, mark):
function send_message (line 122) | def send_message(to, message):
FILE: pwnagotchi/identity.py
class KeyPair (line 12) | class KeyPair(object):
method __init__ (line 13) | def __init__(self, path=DefaultPath, view=None):
method sign (line 66) | def sign(self, message):
FILE: pwnagotchi/log.py
class LastSession (line 18) | class LastSession(object):
method __init__ (line 29) | def __init__(self, config):
method _get_last_saved_session_id (line 52) | def _get_last_saved_session_id(self):
method save_session_id (line 61) | def save_session_id(self):
method _parse_datetime (line 66) | def _parse_datetime(self, dt):
method _parse_stats (line 72) | def _parse_stats(self):
method parse (line 173) | def parse(self, ui, skip=False):
method is_new (line 213) | def is_new(self):
function setup_logging (line 217) | def setup_logging(args, config):
function log_rotation (line 253) | def log_rotation(filename, cfg):
function parse_max_size (line 270) | def parse_max_size(s):
function do_rotate (line 289) | def do_rotate(filename, stats, cfg):
FILE: pwnagotchi/mesh/peer.py
function parse_rfc3339 (line 8) | def parse_rfc3339(dt):
class Peer (line 14) | class Peer(object):
method __init__ (line 15) | def __init__(self, obj):
method update (line 37) | def update(self, new):
method inactive_for (line 52) | def inactive_for(self):
method first_encounter (line 55) | def first_encounter(self):
method is_good_friend (line 58) | def is_good_friend(self, config):
method face (line 61) | def face(self):
method name (line 64) | def name(self):
method identity (line 67) | def identity(self):
method full_name (line 70) | def full_name(self):
method version (line 73) | def version(self):
method pwnd_run (line 76) | def pwnd_run(self):
method pwnd_total (line 79) | def pwnd_total(self):
method uptime (line 82) | def uptime(self):
method epoch (line 85) | def epoch(self):
method full_name (line 88) | def full_name(self):
method is_closer (line 91) | def is_closer(self, other):
FILE: pwnagotchi/mesh/utils.py
class AsyncAdvertiser (line 13) | class AsyncAdvertiser(object):
method __init__ (line 14) | def __init__(self, config, view, keypair):
method fingerprint (line 32) | def fingerprint(self):
method _update_advertisement (line 35) | def _update_advertisement(self, s):
method start_advertising (line 42) | def start_advertising(self):
method _on_face_change (line 52) | def _on_face_change(self, old, new):
method cumulative_encounters (line 56) | def cumulative_encounters(self):
method _on_new_peer (line 59) | def _on_new_peer(self, peer):
method _on_lost_peer (line 64) | def _on_lost_peer(self, peer):
method _adv_poller (line 69) | def _adv_poller(self):
FILE: pwnagotchi/mesh/wifi.py
function freq_to_channel (line 5) | def freq_to_channel(freq):
FILE: pwnagotchi/plugins/__init__.py
class Plugin (line 16) | class Plugin:
method __init_subclass__ (line 18) | def __init_subclass__(cls, **kwargs):
function toggle_plugin (line 34) | def toggle_plugin(name, enable=True):
function on (line 73) | def on(event_name, *args, **kwargs):
function locked_cb (line 78) | def locked_cb(lock_name, cb, *args, **kwargs):
function one (line 88) | def one(plugin_name, event_name, *args, **kwargs):
function load_from_file (line 105) | def load_from_file(filename):
function load_from_path (line 114) | def load_from_path(path, enabled=()):
function load (line 130) | def load(config):
FILE: pwnagotchi/plugins/cmd.py
function add_parsers (line 17) | def add_parsers(parser):
function used_plugin_cmd (line 64) | def used_plugin_cmd(args):
function handle_cmd (line 71) | def handle_cmd(args, config):
function edit (line 98) | def edit(args, config):
function enable (line 130) | def enable(args, config):
function disable (line 141) | def disable(args, config):
function upgrade (line 152) | def upgrade(args, config, pattern='*'):
function list_plugins (line 187) | def list_plugins(args, config, pattern='*'):
function _extract_version (line 249) | def _extract_version(filename):
function _get_available (line 260) | def _get_available():
function _get_installed (line 271) | def _get_installed(config):
function uninstall (line 285) | def uninstall(args, config):
function install (line 298) | def install(args, config):
function _analyse_dir (line 337) | def _analyse_dir(path):
function update (line 350) | def update(config):
FILE: pwnagotchi/plugins/default/auto-update.py
function check (line 16) | def check(version, repo, native=True):
function make_path_for (line 49) | def make_path_for(name):
function download_and_unzip (line 58) | def download_and_unzip(name, path, display, update):
function verify (line 73) | def verify(name, path, source_path, display, update):
function install (line 99) | def install(display, update):
function parse_version (line 134) | def parse_version(cmd):
class AutoUpdate (line 143) | class AutoUpdate(plugins.Plugin):
method __init__ (line 150) | def __init__(self):
method on_loaded (line 155) | def on_loaded(self):
method on_internet_available (line 162) | def on_internet_available(self, agent):
FILE: pwnagotchi/plugins/default/bt-tether.py
class BTError (line 16) | class BTError(Exception):
class BTNap (line 23) | class BTNap:
method __init__ (line 35) | def __init__(self, mac):
method get_bus (line 39) | def get_bus():
method get_manager (line 49) | def get_manager():
method prop_get (line 61) | def prop_get(obj, k, iface=None):
method prop_set (line 70) | def prop_set(obj, k, v, iface=None):
method find_adapter (line 79) | def find_adapter(pattern=None):
method find_adapter_in_objects (line 87) | def find_adapter_in_objects(objects, pattern=None):
method find_device (line 103) | def find_device(device_address, adapter_pattern=None):
method find_device_in_objects (line 111) | def find_device_in_objects(objects, device_address, adapter_pattern=No...
method power (line 132) | def power(self, on=True):
method is_paired (line 155) | def is_paired(self):
method wait_for_device (line 174) | def wait_for_device(self, timeout=15):
method pair (line 220) | def pair(device):
method nap (line 235) | def nap(device):
class SystemdUnitWrapper (line 260) | class SystemdUnitWrapper:
method __init__ (line 265) | def __init__(self, unit):
method _action_on_unit (line 269) | def _action_on_unit(action, unit):
method daemon_reload (line 278) | def daemon_reload():
method is_active (line 289) | def is_active(self):
method is_enabled (line 295) | def is_enabled(self):
method is_failed (line 301) | def is_failed(self):
method enable (line 307) | def enable(self):
method disable (line 313) | def disable(self):
method start (line 319) | def start(self):
method stop (line 325) | def stop(self):
method restart (line 331) | def restart(self):
class IfaceWrapper (line 338) | class IfaceWrapper:
method __init__ (line 345) | def __init__(self, iface):
method exists (line 349) | def exists(self):
method is_up (line 355) | def is_up(self):
method set_addr (line 361) | def set_addr(self, addr):
method set_route (line 375) | def set_route(gateway, device):
class Device (line 386) | class Device:
method __init__ (line 387) | def __init__(self, name, share_internet, mac, ip, netmask, interval, g...
method connected (line 405) | def connected(self):
method interface (line 411) | def interface(self):
class BTTether (line 420) | class BTTether(plugins.Plugin):
method __init__ (line 427) | def __init__(self):
method on_loaded (line 436) | def on_loaded(self):
method on_unload (line 578) | def on_unload(self, ui):
method on_ui_setup (line 584) | def on_ui_setup(self, ui):
method on_ui_update (line 590) | def on_ui_update(self, ui):
FILE: pwnagotchi/plugins/default/example.py
class Example (line 9) | class Example(plugins.Plugin):
method __init__ (line 15) | def __init__(self):
method on_webhook (line 21) | def on_webhook(self, path, request):
method on_loaded (line 25) | def on_loaded(self):
method on_unload (line 29) | def on_unload(self, ui):
method on_internet_available (line 33) | def on_internet_available(self, agent):
method on_ui_setup (line 37) | def on_ui_setup(self, ui):
method on_ui_update (line 43) | def on_ui_update(self, ui):
method on_display_setup (line 50) | def on_display_setup(self, display):
method on_ready (line 54) | def on_ready(self, agent):
method on_ai_ready (line 62) | def on_ai_ready(self, agent):
method on_ai_policy (line 66) | def on_ai_policy(self, agent, policy):
method on_ai_training_start (line 70) | def on_ai_training_start(self, agent, epochs):
method on_ai_training_step (line 74) | def on_ai_training_step(self, agent, _locals, _globals):
method on_ai_training_end (line 78) | def on_ai_training_end(self, agent):
method on_ai_best_reward (line 82) | def on_ai_best_reward(self, agent, reward):
method on_ai_worst_reward (line 86) | def on_ai_worst_reward(self, agent, reward):
method on_free_channel (line 90) | def on_free_channel(self, agent, channel):
method on_bored (line 94) | def on_bored(self, agent):
method on_sad (line 98) | def on_sad(self, agent):
method on_excited (line 102) | def on_excited(self, agent):
method on_lonely (line 106) | def on_lonely(self, agent):
method on_rebooting (line 110) | def on_rebooting(self, agent):
method on_wait (line 114) | def on_wait(self, agent, t):
method on_sleep (line 118) | def on_sleep(self, agent, t):
method on_wifi_update (line 122) | def on_wifi_update(self, agent, access_points):
method on_unfiltered_ap_list (line 127) | def on_unfiltered_ap_list(self, agent, access_points):
method on_association (line 131) | def on_association(self, agent, access_point):
method on_deauthentication (line 135) | def on_deauthentication(self, agent, access_point, client_station):
method on_channel_hop (line 139) | def on_channel_hop(self, agent, channel):
method on_handshake (line 144) | def on_handshake(self, agent, filename, access_point, client_station):
method on_epoch (line 148) | def on_epoch(self, agent, epoch, epoch_data):
method on_peer_detected (line 152) | def on_peer_detected(self, agent, peer):
method on_peer_lost (line 156) | def on_peer_lost(self, agent, peer):
FILE: pwnagotchi/plugins/default/gpio_buttons.py
class GPIOButtons (line 7) | class GPIOButtons(plugins.Plugin):
method __init__ (line 13) | def __init__(self):
method runCommand (line 18) | def runCommand(self, channel):
method on_loaded (line 25) | def on_loaded(self):
FILE: pwnagotchi/plugins/default/gps.py
class GPS (line 11) | class GPS(plugins.Plugin):
method __init__ (line 20) | def __init__(self):
method on_loaded (line 24) | def on_loaded(self):
method on_ready (line 27) | def on_ready(self, agent):
method on_handshake (line 46) | def on_handshake(self, agent, filename, access_point, client_station):
method on_ui_setup (line 62) | def on_ui_setup(self, ui):
method on_unload (line 147) | def on_unload(self, ui):
method on_ui_update (line 153) | def on_ui_update(self, ui):
FILE: pwnagotchi/plugins/default/grid.py
function parse_pcap (line 13) | def parse_pcap(filename):
class Grid (line 45) | class Grid(plugins.Plugin):
method __init__ (line 52) | def __init__(self):
method is_excluded (line 60) | def is_excluded(self, what):
method on_loaded (line 68) | def on_loaded(self):
method set_reported (line 71) | def set_reported(self, reported, net_id):
method check_inbox (line 76) | def check_inbox(self, agent):
method check_handshakes (line 87) | def check_handshakes(self, agent):
method on_internet_available (line 124) | def on_internet_available(self, agent):
FILE: pwnagotchi/plugins/default/led.py
class Led (line 9) | class Led(plugins.Plugin):
method __init__ (line 15) | def __init__(self):
method on_loaded (line 23) | def on_loaded(self):
method _on_event (line 31) | def _on_event(self, event):
method _led (line 39) | def _led(self, on):
method _blink (line 43) | def _blink(self, pattern):
method _worker (line 54) | def _worker(self):
method on_updating (line 73) | def on_updating(self):
method on_unread_inbox (line 77) | def on_unread_inbox(self, num_unread):
method on_internet_available (line 81) | def on_internet_available(self, agent):
method on_ready (line 85) | def on_ready(self, agent):
method on_ai_ready (line 89) | def on_ai_ready(self, agent):
method on_ai_training_start (line 93) | def on_ai_training_start(self, agent, epochs):
method on_ai_best_reward (line 97) | def on_ai_best_reward(self, agent, reward):
method on_ai_worst_reward (line 101) | def on_ai_worst_reward(self, agent, reward):
method on_bored (line 105) | def on_bored(self, agent):
method on_sad (line 109) | def on_sad(self, agent):
method on_excited (line 113) | def on_excited(self, agent):
method on_lonely (line 117) | def on_lonely(self, agent):
method on_rebooting (line 121) | def on_rebooting(self, agent):
method on_wait (line 125) | def on_wait(self, agent, t):
method on_sleep (line 129) | def on_sleep(self, agent, t):
method on_wifi_update (line 133) | def on_wifi_update(self, agent, access_points):
method on_association (line 137) | def on_association(self, agent, access_point):
method on_deauthentication (line 141) | def on_deauthentication(self, agent, access_point, client_station):
method on_handshake (line 146) | def on_handshake(self, agent, filename, access_point, client_station):
method on_epoch (line 150) | def on_epoch(self, agent, epoch, epoch_data):
method on_peer_detected (line 154) | def on_peer_detected(self, agent, peer):
method on_peer_lost (line 158) | def on_peer_lost(self, agent, peer):
FILE: pwnagotchi/plugins/default/logtail.py
class Logtail (line 235) | class Logtail(plugins.Plugin):
method __init__ (line 241) | def __init__(self):
method on_config_changed (line 246) | def on_config_changed(self, config):
method on_loaded (line 250) | def on_loaded(self):
method on_webhook (line 257) | def on_webhook(self, path, request):
FILE: pwnagotchi/plugins/default/memtemp.py
class MemTemp (line 35) | class MemTemp(plugins.Plugin):
method on_loaded (line 52) | def on_loaded(self):
method mem_usage (line 55) | def mem_usage(self):
method cpu_load (line 58) | def cpu_load(self):
method cpu_temp (line 61) | def cpu_temp(self):
method cpu_freq (line 74) | def cpu_freq(self):
method pad_text (line 78) | def pad_text(self, data):
method on_ui_setup (line 81) | def on_ui_setup(self, ui):
method on_unload (line 167) | def on_unload(self, ui):
method on_ui_update (line 177) | def on_ui_update(self, ui):
FILE: pwnagotchi/plugins/default/net-pos.py
class NetPos (line 11) | class NetPos(plugins.Plugin):
method __init__ (line 22) | def __init__(self):
method on_loaded (line 28) | def on_loaded(self):
method _append_saved (line 38) | def _append_saved(self, path):
method on_internet_available (line 51) | def on_internet_available(self, agent):
method on_handshake (line 104) | def on_handshake(self, agent, filename, access_point, client_station):
method _get_netpos (line 120) | def _get_netpos(self, agent):
method _get_geo_data (line 130) | def _get_geo_data(self, path, timeout=30):
FILE: pwnagotchi/plugins/default/onlinehashcrack.py
class OnlineHashCrack (line 13) | class OnlineHashCrack(plugins.Plugin):
method __init__ (line 19) | def __init__(self):
method on_loaded (line 29) | def on_loaded(self):
method _upload_to_ohc (line 44) | def _upload_to_ohc(self, path, timeout=30):
method _download_cracked (line 63) | def _download_cracked(self, save_file, timeout=120):
method on_webhook (line 82) | def on_webhook(self, path, request):
method on_internet_available (line 91) | def on_internet_available(self, agent):
FILE: pwnagotchi/plugins/default/paw-gps.py
class PawGPS (line 11) | class PawGPS(plugins.Plugin):
method on_loaded (line 18) | def on_loaded(self):
method on_handshake (line 23) | def on_handshake(self, agent, filename, access_point, client_station):
FILE: pwnagotchi/plugins/default/session-stats.py
class GhettoClock (line 159) | class GhettoClock:
method __init__ (line 160) | def __init__(self):
method counter (line 167) | def counter(self):
method now (line 173) | def now(self):
class SessionStats (line 178) | class SessionStats(plugins.Plugin):
method __init__ (line 184) | def __init__(self):
method on_loaded (line 190) | def on_loaded(self):
method on_epoch (line 203) | def on_epoch(self, agent, epoch, epoch_data):
method extract_key_values (line 212) | def extract_key_values(data, subkeys):
method on_webhook (line 221) | def on_webhook(self, path, request):
FILE: pwnagotchi/plugins/default/switcher.py
function systemd_dropin (line 9) | def systemd_dropin(name, content):
function systemctl (line 21) | def systemctl(command, unit=None):
function run_task (line 27) | def run_task(name, options):
class Switcher (line 101) | class Switcher(plugins.Plugin):
method __init__ (line 108) | def __init__(self):
method trigger (line 112) | def trigger(self, name, *args, **kwargs):
method on_loaded (line 124) | def on_loaded(self):
FILE: pwnagotchi/plugins/default/ups_lite.py
class UPS (line 25) | class UPS:
method __init__ (line 26) | def __init__(self):
method voltage (line 32) | def voltage(self):
method capacity (line 41) | def capacity(self):
method charging (line 50) | def charging(self):
class UPSLite (line 59) | class UPSLite(plugins.Plugin):
method __init__ (line 65) | def __init__(self):
method on_loaded (line 68) | def on_loaded(self):
method on_ui_setup (line 71) | def on_ui_setup(self, ui):
method on_unload (line 75) | def on_unload(self, ui):
method on_ui_update (line 79) | def on_ui_update(self, ui):
FILE: pwnagotchi/plugins/default/watchdog.py
class Watchdog (line 9) | class Watchdog(plugins.Plugin):
method __init__ (line 15) | def __init__(self):
method on_loaded (line 19) | def on_loaded(self):
method on_epoch (line 25) | def on_epoch(self, agent, epoch, epoch_data):
FILE: pwnagotchi/plugins/default/webcfg.py
function serializer (line 460) | def serializer(obj):
class WebConfig (line 465) | class WebConfig(plugins.Plugin):
method __init__ (line 471) | def __init__(self):
method on_config_changed (line 475) | def on_config_changed(self, config):
method on_ready (line 479) | def on_ready(self, agent):
method on_internet_available (line 482) | def on_internet_available(self, agent):
method on_loaded (line 485) | def on_loaded(self):
method on_webhook (line 492) | def on_webhook(self, path, request):
FILE: pwnagotchi/plugins/default/webgpsmap.py
class Webgpsmap (line 25) | class Webgpsmap(plugins.Plugin):
method __init__ (line 35) | def __init__(self):
method on_config_changed (line 38) | def on_config_changed(self, config):
method on_loaded (line 42) | def on_loaded(self):
method on_webhook (line 48) | def on_webhook(self, path, request):
method _get_pos_from_file (line 149) | def _get_pos_from_file(self, path):
method load_gps_from_dir (line 153) | def load_gps_from_dir(self, gpsdir, newest_only=False):
method get_html (line 253) | def get_html(self):
class PositionFile (line 265) | class PositionFile:
method __init__ (line 273) | def __init__(self, path):
method mac (line 284) | def mac(self):
method ssid (line 294) | def ssid(self):
method json (line 304) | def json(self):
method timestamp_first (line 310) | def timestamp_first(self):
method timestamp_last (line 317) | def timestamp_last(self):
method password (line 333) | def password(self):
method type (line 353) | def type(self):
method lat (line 365) | def lat(self):
method lng (line 386) | def lng(self):
method accuracy (line 407) | def accuracy(self):
FILE: pwnagotchi/plugins/default/wigle.py
function _extract_gps_data (line 15) | def _extract_gps_data(path):
function _format_auth (line 37) | def _format_auth(data):
function _transform_wigle_entry (line 44) | def _transform_wigle_entry(gps_data, pcap_data, plugin_version):
function _send_to_wigle (line 72) | def _send_to_wigle(lines, api_key, donate=True, timeout=30):
class Wigle (line 101) | class Wigle(plugins.Plugin):
method __init__ (line 107) | def __init__(self):
method on_loaded (line 113) | def on_loaded(self):
method on_internet_available (line 127) | def on_internet_available(self, agent):
FILE: pwnagotchi/plugins/default/wpa-sec.py
class WpaSec (line 11) | class WpaSec(plugins.Plugin):
method __init__ (line 17) | def __init__(self):
method _upload_to_wpasec (line 28) | def _upload_to_wpasec(self, path, timeout=30):
method _download_from_wpasec (line 47) | def _download_from_wpasec(self, output, timeout=30):
method on_loaded (line 69) | def on_loaded(self):
method on_webhook (line 87) | def on_webhook(self, path, request):
method on_internet_available (line 93) | def on_internet_available(self, agent):
FILE: pwnagotchi/ui/components.py
class Widget (line 5) | class Widget(object):
method __init__ (line 6) | def __init__(self, xy, color=0):
method draw (line 10) | def draw(self, canvas, drawer):
class Bitmap (line 14) | class Bitmap(Widget):
method __init__ (line 15) | def __init__(self, path, xy, color=0):
method draw (line 19) | def draw(self, canvas, drawer):
class Line (line 23) | class Line(Widget):
method __init__ (line 24) | def __init__(self, xy, color=0, width=1):
method draw (line 28) | def draw(self, canvas, drawer):
class Rect (line 32) | class Rect(Widget):
method draw (line 33) | def draw(self, canvas, drawer):
class FilledRect (line 37) | class FilledRect(Widget):
method draw (line 38) | def draw(self, canvas, drawer):
class Text (line 42) | class Text(Widget):
method __init__ (line 43) | def __init__(self, value="", position=(0, 0), font=None, color=0, wrap...
method draw (line 51) | def draw(self, canvas, drawer):
class LabeledValue (line 60) | class LabeledValue(Widget):
method __init__ (line 61) | def __init__(self, label, value="", position=(0, 0), label_font=None, ...
method draw (line 69) | def draw(self, canvas, drawer):
FILE: pwnagotchi/ui/display.py
class Display (line 10) | class Display(View):
method __init__ (line 11) | def __init__(self, config, state={}):
method is_inky (line 28) | def is_inky(self):
method is_papirus (line 31) | def is_papirus(self):
method is_waveshare_v1 (line 34) | def is_waveshare_v1(self):
method is_waveshare_v2 (line 37) | def is_waveshare_v2(self):
method is_waveshare_v3 (line 40) | def is_waveshare_v3(self):
method is_waveshare27inch (line 43) | def is_waveshare27inch(self):
method is_waveshare29inch (line 46) | def is_waveshare29inch(self):
method is_oledhat (line 49) | def is_oledhat(self):
method is_adafruitssd1306i2c (line 52) | def is_adafruitssd1306i2c(self):
method is_lcdhat (line 55) | def is_lcdhat(self):
method is_dfrobot_v1 (line 58) | def is_dfrobot_v1(self):
method is_dfrobot_v2 (line 61) | def is_dfrobot_v2(self):
method is_waveshare144lcd (line 64) | def is_waveshare144lcd(self):
method is_waveshare154inch (line 67) | def is_waveshare154inch(self):
method is_waveshare213d (line 70) | def is_waveshare213d(self):
method is_waveshare213bc (line 73) | def is_waveshare213bc(self):
method is_waveshare213inb_v4 (line 76) | def is_waveshare213inb_v4(self):
method is_waveshare35lcd (line 79) | def is_waveshare35lcd(self):
method is_spotpear24inch (line 82) | def is_spotpear24inch(self):
method is_waveshare_any (line 85) | def is_waveshare_any(self):
method init_display (line 88) | def init_display(self):
method clear (line 96) | def clear(self):
method image (line 99) | def image(self):
method _render_thread (line 105) | def _render_thread(self):
method _on_view_rendered (line 113) | def _on_view_rendered(self, img):
FILE: pwnagotchi/ui/faces.py
function load_from_config (line 27) | def load_from_config(config):
FILE: pwnagotchi/ui/fonts.py
function init (line 18) | def init(config):
function status_font (line 25) | def status_font(old_font):
function setup (line 30) | def setup(bold, bold_small, medium, huge, bold_big, small):
FILE: pwnagotchi/ui/hw/__init__.py
function display_for (line 21) | def display_for(config):
FILE: pwnagotchi/ui/hw/adafruitssd1306i2c.py
class AdafruitSSD1306i2c (line 7) | class AdafruitSSD1306i2c(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 42) | def render(self, canvas):
method clear (line 45) | def clear(self):
FILE: pwnagotchi/ui/hw/base.py
class DisplayImpl (line 4) | class DisplayImpl(object):
method __init__ (line 5) | def __init__(self, config, name):
method layout (line 30) | def layout(self):
method initialize (line 33) | def initialize(self):
method render (line 36) | def render(self, canvas):
method clear (line 39) | def clear(self):
FILE: pwnagotchi/ui/hw/dfrobot1.py
class DFRobotV1 (line 6) | class DFRobotV1(DisplayImpl):
method __init__ (line 7) | def __init__(self, config):
method layout (line 11) | def layout(self):
method initialize (line 33) | def initialize(self):
method render (line 38) | def render(self, canvas):
method clear (line 42) | def clear(self):
FILE: pwnagotchi/ui/hw/dfrobot2.py
class DFRobotV2 (line 6) | class DFRobotV2(DisplayImpl):
method __init__ (line 7) | def __init__(self, config):
method layout (line 11) | def layout(self):
method initialize (line 33) | def initialize(self):
method render (line 38) | def render(self, canvas):
method clear (line 42) | def clear(self):
FILE: pwnagotchi/ui/hw/inky.py
class Inky (line 7) | class Inky(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 56) | def render(self, canvas):
method clear (line 87) | def clear(self):
FILE: pwnagotchi/ui/hw/lcdhat.py
class LcdHat (line 7) | class LcdHat(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 35) | def initialize(self):
method render (line 42) | def render(self, canvas):
method clear (line 45) | def clear(self):
FILE: pwnagotchi/ui/hw/libs/adafruit/adafruitssd1306i2c/SSD1306.py
class SSD1306Base (line 75) | class SSD1306Base(object):
method __init__ (line 76) | def __init__(self, width, height, rst, i2c_bus=None, i2c_address=SSD13...
method _initialize (line 94) | def _initialize(self):
method write8 (line 97) | def write8(self, register, value):
method command (line 102) | def command(self, c):
method data (line 109) | def data(self, c):
method begin (line 116) | def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
method reset (line 126) | def reset(self):
method writeList (line 139) | def writeList(self, register, data):
method display (line 143) | def display(self):
method image (line 159) | def image(self, image):
method clear (line 186) | def clear(self):
method set_contrast (line 190) | def set_contrast(self, contrast):
method dim (line 198) | def dim(self, dim):
class SSD1306_128_64 (line 212) | class SSD1306_128_64(SSD1306Base):
method __init__ (line 213) | def __init__(self, rst, i2c_bus=None, i2c_address=SSD1306_I2C_ADDRESS,
method _initialize (line 218) | def _initialize(self):
FILE: pwnagotchi/ui/hw/libs/adafruit/adafruitssd1306i2c/epd.py
class EPD (line 7) | class EPD(object):
method __init__ (line 9) | def __init__(self, rst=RST, i2c_bus=None, i2c_address=0x3c):
method init (line 19) | def init(self):
method Clear (line 22) | def Clear(self):
method display (line 26) | def display(self, image):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v1/dfrobot.py
class DFRobot (line 16) | class DFRobot:
method __init__ (line 17) | def __init__(self):
method getbuffer (line 24) | def getbuffer(self, image):
method flush (line 51) | def flush(self, type):
method display (line 54) | def display(self, buf):
method clear (line 58) | def clear(self, color):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v1/dfrobot_epaper.py
class DFRobot_Epaper (line 24) | class DFRobot_Epaper:
method __init__ (line 32) | def __init__(self, width = 250, height = 122):
method _busyCB (line 44) | def _busyCB(self, channel):
method setBusyExitEdge (line 47) | def setBusyExitEdge(self, edge):
method begin (line 52) | def begin(self):
method setBuffer (line 57) | def setBuffer(self, buffer):
method pixel (line 60) | def pixel(self, x, y, color):
method _setWindow (line 80) | def _setWindow(self, x, y):
method _initLut (line 87) | def _initLut(self, mode):
method _setRamData (line 99) | def _setRamData(self, xStart, xEnd, yStart, yStart1, yEnd, yEnd1):
method _setRamPointer (line 103) | def _setRamPointer(self, x, y, y1):
method _init (line 107) | def _init(self):
method _writeDisRam (line 117) | def _writeDisRam(self, sizeX, sizeY):
method _updateDis (line 123) | def _updateDis(self, mode):
method _waitBusyExit (line 133) | def _waitBusyExit(self):
method _powerOn (line 141) | def _powerOn(self):
method _powerOff (line 145) | def _powerOff(self):
method _disPart (line 151) | def _disPart(self, xStart, xEnd, yStart, yEnd):
method flush (line 157) | def flush(self, mode):
method startDrawBitmapFile (line 170) | def startDrawBitmapFile(self, x, y):
method bitmapFileHelper (line 174) | def bitmapFileHelper(self, buf):
method endDrawBitmapFile (line 183) | def endDrawBitmapFile(self):
class DFRobot_Epaper_SPI (line 186) | class DFRobot_Epaper_SPI(DFRobot_Epaper):
method __init__ (line 188) | def __init__(self, bus, dev, cs, cd, busy):
method writeCmdAndData (line 195) | def writeCmdAndData(self, cmd, data = []):
method readBusy (line 204) | def readBusy(self):
method setBusyCB (line 207) | def setBusyCB(self, cb):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v1/gpio.py
class GPIO (line 9) | class GPIO:
method __init__ (line 21) | def __init__(self, pin, mode, defaultOut = HIGH):
method setOut (line 35) | def setOut(self, level):
method _intCB (line 41) | def _intCB(self, status):
method setInterrupt (line 53) | def setInterrupt(self, mode, cb):
method read (line 60) | def read(self):
method cleanup (line 63) | def cleanup(self):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v1/spi.py
class SPI (line 5) | class SPI:
method __init__ (line 12) | def __init__(self, bus, dev, speed = 3900000, mode = MODE_4):
method transfer (line 18) | def transfer(self, buf):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot.py
class DFRobot (line 16) | class DFRobot:
method __init__ (line 17) | def __init__(self):
method getbuffer (line 24) | def getbuffer(self, image):
method flush (line 51) | def flush(self, type):
method display (line 54) | def display(self, buf):
method clear (line 58) | def clear(self, color):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/dfrobot_display.py
function color24to16 (line 8) | def color24to16(color):
function color16to24 (line 11) | def color16to24(color):
function swap (line 14) | def swap(o1, o2):
class DFRobot_Display (line 17) | class DFRobot_Display(PrintString):
method __init__ (line 83) | def __init__(self, w, h):
method _ternaryExpression (line 103) | def _ternaryExpression(self, condition, o1, o2):
method _getDirection (line 108) | def _getDirection(self, value):
method color16to24 (line 113) | def color16to24(self, color):
method color24to16 (line 116) | def color24to16(self, color):
method setColorTo16 (line 119) | def setColorTo16(self):
method setColorTo24 (line 137) | def setColorTo24(self):
method setLineWidth (line 155) | def setLineWidth(self, w):
method setTextFormat (line 160) | def setTextFormat(self, size, color, background, intervalRow = 2, inte...
method setTextCursor (line 169) | def setTextCursor(self, x, y):
method setBitmapSize (line 173) | def setBitmapSize(self, size):
method setBitmapFmt (line 178) | def setBitmapFmt(self, fmt):
method setExFonts (line 181) | def setExFonts(self, obj):
method setExFontsFmt (line 184) | def setExFontsFmt(self, width, height):
method setEnableDefaultFonts (line 187) | def setEnableDefaultFonts(self, opt):
method pixel (line 190) | def pixel(self, x, y, color):
method clear (line 193) | def clear(self, color):
method VLine (line 198) | def VLine(self, x, y, h, color):
method HLine (line 212) | def HLine(self, x, y, w, color):
method line (line 225) | def line(self, x, y, x1, y1, color):
method triangle (line 261) | def triangle(self, x, y, x1, y1, x2, y2, color):
method fillTriangle (line 266) | def fillTriangle(self, x, y, x1, y1, x2, y2, color):
method rect (line 333) | def rect(self, x, y, w, h, color):
method fillRect (line 345) | def fillRect(self, x, y, w, h, color):
method circleHelper (line 361) | def circleHelper(self, x, y, r, quadrant, color):
method circle (line 401) | def circle(self, x, y, r, color):
method fillCircleHelper (line 404) | def fillCircleHelper(self, x, y, r, quadrant, color):
method fillCircle (line 446) | def fillCircle(self, x, y, r, color):
method roundRect (line 449) | def roundRect(self, x, y, w, h, r, color):
method fillRoundRect (line 470) | def fillRoundRect(self, x, y, w, h, r, color):
method _bitmapHelper (line 490) | def _bitmapHelper(self, increaseAxis, staticAxis, data, dataBit, excha...
method bitmap (line 509) | def bitmap(self, x, y, bitmap, w, h, color, background):
method _bytesToNumber (line 556) | def _bytesToNumber(self, data):
method _getQuads (line 564) | def _getQuads(self, data, count):
method startDrawBitmapFile (line 575) | def startDrawBitmapFile(self, x, y):
method bitmapFileHelper (line 578) | def bitmapFileHelper(self, buf):
method endDrawBitmapFile (line 581) | def endDrawBitmapFile(self):
method bitmapFile (line 584) | def bitmapFile(self, x, y, path):
method writeOneChar (line 651) | def writeOneChar(self, c):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/dfrobot_fonts.py
class Fonts (line 5) | class Fonts:
method __init__ (line 7) | def __init__(self):
method setFontsABC (line 20) | def setFontsABC(self, fonts):
method setExFonts (line 30) | def setExFonts(self, obj):
method setEnableDefaultFonts (line 35) | def setEnableDefaultFonts(self, opt):
method setExFontsFmt (line 41) | def setExFontsFmt(self, width, height):
method getOneCharacter (line 47) | def getOneCharacter(self, c):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/dfrobot_printString.py
class PrintString (line 5) | class PrintString:
method __init__ (line 7) | def __init__(self):
method writeOneChar (line 10) | def writeOneChar(self, ch):
method printStr (line 13) | def printStr(self, c):
method printStrLn (line 23) | def printStrLn(self, c):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_epaper.py
class DFRobot_Epaper (line 26) | class DFRobot_Epaper(DFRobot_Display):
method __init__ (line 34) | def __init__(self, width = 250, height = 122):
method _busyCB (line 50) | def _busyCB(self, channel):
method setBusyExitEdge (line 53) | def setBusyExitEdge(self, edge):
method begin (line 58) | def begin(self):
method setBuffer (line 65) | def setBuffer(self, buffer):
method pixel (line 68) | def pixel(self, x, y, color):
method _initLut (line 88) | def _initLut(self, mode):
method _setRamData (line 126) | def _setRamData(self, xStart, xEnd, yStart, yStart1, yEnd, yEnd1):
method _setRamPointer (line 130) | def _setRamPointer(self, x, y, y1):
method _init (line 134) | def _init(self,mode):
method _writeDisRam (line 156) | def _writeDisRam(self, sizeX, sizeY):
method _updateDis (line 165) | def _updateDis(self, mode):
method _waitBusyExit (line 175) | def _waitBusyExit(self):
method _powerOn (line 183) | def _powerOn(self):
method _powerOff (line 187) | def _powerOff(self):
method _disPart (line 191) | def _disPart(self, xStart, xEnd, yStart, yEnd):
method flush (line 197) | def flush(self, mode):
method startDrawBitmapFile (line 210) | def startDrawBitmapFile(self, x, y):
method bitmapFileHelper (line 214) | def bitmapFileHelper(self, buf):
method endDrawBitmapFile (line 223) | def endDrawBitmapFile(self):
class DFRobot_Epaper_SPI (line 226) | class DFRobot_Epaper_SPI(DFRobot_Epaper):
method __init__ (line 228) | def __init__(self, bus, dev, cs, cd, busy):
method writeCmdAndData (line 235) | def writeCmdAndData(self, cmd, data = []):
method readBusy (line 244) | def readBusy(self):
method setBusyCB (line 247) | def setBusyCB(self, cb):
method __del__ (line 249) | def __del__(self):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/freetype_helper.py
class Freetype_Helper (line 16) | class Freetype_Helper:
method __init__ (line 18) | def __init__(self, filePath):
method setFmt (line 24) | def setFmt(self, width, height):
method setDisLowerLimite (line 29) | def setDisLowerLimite(self, limite):
method getOne (line 32) | def getOne(self, ch):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/gpio.py
class GPIO (line 9) | class GPIO:
method __init__ (line 21) | def __init__(self, pin, mode, defaultOut = HIGH):
method setOut (line 35) | def setOut(self, level):
method _intCB (line 41) | def _intCB(self, status):
method setInterrupt (line 53) | def setInterrupt(self, mode, cb):
method read (line 60) | def read(self):
method cleanup (line 63) | def cleanup(self):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/i2c.py
class I2C (line 12) | class I2C:
method __init__ (line 14) | def __init__(self, port):
method writeBytes (line 17) | def writeBytes(self, addr, reg, buf):
method readBytes (line 20) | def readBytes(self, addr, reg, length):
FILE: pwnagotchi/ui/hw/libs/dfrobot/v2/spi.py
class SPI (line 5) | class SPI:
method __init__ (line 12) | def __init__(self, bus, dev, speed = 3900000, mode = MODE_4):
method transfer (line 18) | def transfer(self, buf):
FILE: pwnagotchi/ui/hw/libs/fb/fb.py
function report_fb (line 32) | def report_fb(i=0, layer=0):
function ready_fb (line 40) | def ready_fb(_bpp=None, i=0, layer=0, _win=None):
function fill_scr (line 84) | def fill_scr(r,g,b):
function black_scr (line 94) | def black_scr():
function white_scr (line 97) | def white_scr():
function mmseekto (line 100) | def mmseekto(x,y):
function dot (line 103) | def dot(x, y, r, g, b):
function get_pixel (line 107) | def get_pixel(x,y):
function _888_to_565 (line 111) | def _888_to_565(bt):
function numpy_888_565 (line 117) | def numpy_888_565(bt):
function show_img (line 122) | def show_img(img):
FILE: pwnagotchi/ui/hw/libs/inkyphat/inkyfast.py
class InkyFast (line 4) | class InkyFast(Inky):
method __init__ (line 6) | def __init__(self, resolution=(400, 300), colour='black', cs_pin=CS0_P...
FILE: pwnagotchi/ui/hw/libs/inkyphat/inkyphatfast.py
class InkyPHATFast (line 5) | class InkyPHATFast(inkyfast.InkyFast):
method __init__ (line 16) | def __init__(self, colour):
FILE: pwnagotchi/ui/hw/libs/papirus/epd.py
function b (line 24) | def b(x):
function b (line 27) | def b(x):
class EPDError (line 30) | class EPDError(Exception):
method __init__ (line 31) | def __init__(self, value):
method __str__ (line 34) | def __str__(self):
class EPD (line 38) | class EPD(object):
method __init__ (line 57) | def __init__(self, *args, **kwargs):
method size (line 103) | def size(self):
method width (line 107) | def width(self):
method height (line 111) | def height(self):
method panel (line 115) | def panel(self):
method version (line 119) | def version(self):
method cog (line 123) | def cog(self):
method film (line 127) | def film(self):
method auto (line 131) | def auto(self):
method auto (line 135) | def auto(self, flag):
method rotation (line 142) | def rotation(self):
method rotation (line 146) | def rotation(self, rot):
method use_lm75b (line 154) | def use_lm75b(self):
method use_lm75b (line 158) | def use_lm75b(self, flag):
method error_status (line 164) | def error_status(self):
method rotation_angle (line 168) | def rotation_angle(self, rotation):
method display (line 172) | def display(self, image):
method update (line 196) | def update(self):
method partial_update (line 199) | def partial_update(self):
method fast_update (line 202) | def fast_update(self):
method clear (line 205) | def clear(self):
method _command (line 208) | def _command(self, c):
FILE: pwnagotchi/ui/hw/libs/papirus/lm75b.py
class LM75B (line 20) | class LM75B(object):
method __init__ (line 21) | def __init__(self, address=LM75B_ADDRESS, busnum=1):
method getTempCFloat (line 26) | def getTempCFloat(self):
method getTempFFloat (line 32) | def getTempFFloat(self):
method getTempC (line 36) | def getTempC(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/lcdhat/ST7789.py
class ST7789 (line 7) | class ST7789(object):
method __init__ (line 10) | def __init__(self, spi, rst=27, dc=25, bl=24):
method command (line 29) | def command(self, cmd):
method data (line 33) | def data(self, val):
method Init (line 37) | def Init(self):
method reset (line 117) | def reset(self):
method SetWindows (line 126) | def SetWindows(self, Xstart, Ystart, Xend, Yend):
method ShowImage (line 143) | def ShowImage(self, Image, Xstart, Ystart):
method clear (line 160) | def clear(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/lcdhat/epd.py
class EPD (line 5) | class EPD(object):
method __init__ (line 6) | def __init__(self):
method init (line 13) | def init(self):
method clear (line 16) | def clear(self):
method display (line 19) | def display(self, image):
FILE: pwnagotchi/ui/hw/libs/waveshare/lcdhat144/LCD_1in44.py
class LCD (line 62) | class LCD:
method __init__ (line 63) | def __init__(self):
method LCD_Reset (line 72) | def LCD_Reset(self):
method LCD_WriteReg (line 81) | def LCD_WriteReg(self, Reg):
method LCD_WriteData_8bit (line 87) | def LCD_WriteData_8bit(self, Data):
method LCD_WriteData_NLen16Bit (line 91) | def LCD_WriteData_NLen16Bit(self, Data, DataLen):
method LCD_InitReg (line 98) | def LCD_InitReg(self):
method LCD_SetGramScanWay (line 199) | def LCD_SetGramScanWay(self, Scan_dir):
method LCD_Init (line 246) | def LCD_Init(self, Lcd_ScanDir):
method LCD_SetWindows (line 279) | def LCD_SetWindows(self, Xstart, Ystart, Xend, Yend):
method LCD_Clear (line 296) | def LCD_Clear(self):
method LCD_ShowImage (line 304) | def LCD_ShowImage(self,Image,Xstart,Ystart):
FILE: pwnagotchi/ui/hw/libs/waveshare/lcdhat144/config.py
function epd_digital_write (line 54) | def epd_digital_write(pin, value):
function Driver_Delay_ms (line 57) | def Driver_Delay_ms(xms):
function SPI_Write_Byte (line 60) | def SPI_Write_Byte(data):
function GPIO_Init (line 63) | def GPIO_Init():
FILE: pwnagotchi/ui/hw/libs/waveshare/lcdhat144/epd.py
class EPD (line 15) | class EPD(object):
method __init__ (line 16) | def __init__(self):
method init (line 23) | def init(self):
method clear (line 26) | def clear(self):
method display (line 30) | def display(self, image):
FILE: pwnagotchi/ui/hw/libs/waveshare/oledhat/SH1106.py
class SH1106 (line 11) | class SH1106(object):
method __init__ (line 12) | def __init__(self):
method command (line 23) | def command(self, cmd):
method Init (line 34) | def Init(self):
method reset (line 67) | def reset(self):
method getbuffer (line 76) | def getbuffer(self, image):
method ShowImage (line 109) | def ShowImage(self, pBuf):
method clear (line 131) | def clear(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/oledhat/config.py
function digital_write (line 58) | def digital_write(pin, value):
function digital_read (line 61) | def digital_read(pin):
function delay_ms (line 64) | def delay_ms(delaytime):
function spi_writebyte (line 67) | def spi_writebyte(data):
function i2c_writebyte (line 71) | def i2c_writebyte(reg, value):
function module_init (line 75) | def module_init():
function module_exit (line 101) | def module_exit():
FILE: pwnagotchi/ui/hw/libs/waveshare/oledhat/epd.py
class EPD (line 10) | class EPD(object):
method __init__ (line 12) | def __init__(self):
method init (line 20) | def init(self):
method Clear (line 23) | def Clear(self):
method display (line 26) | def display(self, image):
FILE: pwnagotchi/ui/hw/libs/waveshare/v1/epd2in13.py
class EPD (line 38) | class EPD:
method __init__ (line 39) | def __init__(self):
method reset (line 62) | def reset(self):
method send_command (line 72) | def send_command(self, command):
method send_data (line 78) | def send_data(self, data):
method ReadBusy (line 84) | def ReadBusy(self):
method TurnOnDisplay (line 88) | def TurnOnDisplay(self):
method init (line 98) | def init(self, lut):
method SetWindows (line 138) | def SetWindows(self, x_start, y_start, x_end, y_end):
method SetCursor (line 151) | def SetCursor(self, x, y):
method getbuffer (line 160) | def getbuffer(self, image):
method display (line 188) | def display(self, image):
method Clear (line 202) | def Clear(self, color):
method sleep (line 216) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v1/epd2in13bc.py
class EPD (line 38) | class EPD:
method __init__ (line 39) | def __init__(self):
method reset (line 48) | def reset(self):
method send_command (line 56) | def send_command(self, command):
method send_data (line 62) | def send_data(self, data):
method ReadBusy (line 68) | def ReadBusy(self):
method init (line 73) | def init(self):
method getbuffer (line 99) | def getbuffer(self, image):
method displayBlack (line 119) | def displayBlack(self, imageblack):
method display (line 128) | def display(self, imageblack, imagecolor):
method Clear (line 142) | def Clear(self):
method sleep (line 156) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v1/epd2in13bcFAST.py
class EPD (line 51) | class EPD:
method __init__ (line 52) | def __init__(self):
method reset (line 166) | def reset(self):
method send_command (line 174) | def send_command(self, command):
method send_data (line 180) | def send_data(self, data):
method ReadBusy (line 186) | def ReadBusy(self):
method TurnOnDisplay (line 193) | def TurnOnDisplay(self):
method init (line 198) | def init(self):
method SetFullReg (line 235) | def SetFullReg(self):
method SetPartReg (line 243) | def SetPartReg(self):
method getbuffer (line 267) | def getbuffer(self, image):
method display (line 291) | def display(self, image):
method DisplayPartial (line 308) | def DisplayPartial(self, image):
method Clear (line 336) | def Clear(self):
method sleep (line 350) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v1/epdconfig.py
class RaspberryPi (line 36) | class RaspberryPi:
method __init__ (line 43) | def __init__(self):
method digital_write (line 52) | def digital_write(self, pin, value):
method digital_read (line 55) | def digital_read(self, pin):
method delay_ms (line 58) | def delay_ms(self, delaytime):
method spi_writebyte (line 61) | def spi_writebyte(self, data):
method module_init (line 64) | def module_init(self):
method module_exit (line 75) | def module_exit(self):
class JetsonNano (line 86) | class JetsonNano:
method __init__ (line 93) | def __init__(self):
method digital_write (line 112) | def digital_write(self, pin, value):
method digital_read (line 115) | def digital_read(self, pin):
method delay_ms (line 118) | def delay_ms(self, delaytime):
method spi_writebyte (line 121) | def spi_writebyte(self, data):
method module_init (line 124) | def module_init(self):
method module_exit (line 134) | def module_exit(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v154inch/epd1in54b.py
class EPD (line 37) | class EPD:
method __init__ (line 38) | def __init__(self):
method reset (line 56) | def reset(self):
method send_command (line 64) | def send_command(self, command):
method send_data (line 70) | def send_data(self, data):
method ReadBusy (line 76) | def ReadBusy(self):
method set_lut_bw (line 82) | def set_lut_bw(self):
method set_lut_red (line 99) | def set_lut_red(self):
method init (line 110) | def init(self):
method getbuffer (line 146) | def getbuffer(self, image):
method display (line 164) | def display(self, blackimage, redimage):
method Clear (line 189) | def Clear(self):
method sleep (line 202) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v154inch/epdconfig.py
class RaspberryPi (line 36) | class RaspberryPi:
method __init__ (line 43) | def __init__(self):
method digital_write (line 52) | def digital_write(self, pin, value):
method digital_read (line 55) | def digital_read(self, pin):
method delay_ms (line 58) | def delay_ms(self, delaytime):
method spi_writebyte (line 61) | def spi_writebyte(self, data):
method module_init (line 64) | def module_init(self):
method module_exit (line 75) | def module_exit(self):
class JetsonNano (line 86) | class JetsonNano:
method __init__ (line 93) | def __init__(self):
method digital_write (line 112) | def digital_write(self, pin, value):
method digital_read (line 115) | def digital_read(self, pin):
method delay_ms (line 118) | def delay_ms(self, delaytime):
method spi_writebyte (line 121) | def spi_writebyte(self, data):
method module_init (line 124) | def module_init(self):
method module_exit (line 134) | def module_exit(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v2/waveshare.py
function digital_write (line 63) | def digital_write(pin, value):
function digital_read (line 67) | def digital_read(pin):
function delay_ms (line 71) | def delay_ms(delaytime):
function spi_writebyte (line 75) | def spi_writebyte(data):
function module_init (line 79) | def module_init():
class EPD (line 96) | class EPD:
method __init__ (line 97) | def __init__(self):
method reset (line 143) | def reset(self):
method send_command (line 151) | def send_command(self, command):
method send_data (line 155) | def send_data(self, data):
method wait_until_idle (line 159) | def wait_until_idle(self):
method TurnOnDisplay (line 163) | def TurnOnDisplay(self):
method init (line 169) | def init(self, update):
method getbuffer (line 259) | def getbuffer(self, image):
method display (line 288) | def display(self, image):
method displayPartial (line 300) | def displayPartial(self, image):
method Clear (line 316) | def Clear(self, color):
method sleep (line 329) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v213bc/epd2in13bc.py
class EPD (line 38) | class EPD:
method __init__ (line 39) | def __init__(self):
method reset (line 152) | def reset(self):
method send_command (line 160) | def send_command(self, command):
method send_data (line 166) | def send_data(self, data):
method ReadBusy (line 172) | def ReadBusy(self):
method TurnOnDisplay (line 178) | def TurnOnDisplay(self):
method init (line 183) | def init(self):
method SetFullReg (line 264) | def SetFullReg(self):
method getbuffer (line 287) | def getbuffer(self, image):
method display (line 311) | def display(self, imageblack, imagered):
method pwndisplay (line 325) | def pwndisplay(self, imageblack):
method Clear (line 343) | def Clear(self):
method pwnclear (line 357) | def pwnclear(self):
method sleep (line 371) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v213bc/epdconfig.py
class RaspberryPi (line 36) | class RaspberryPi:
method __init__ (line 43) | def __init__(self):
method digital_write (line 52) | def digital_write(self, pin, value):
method digital_read (line 55) | def digital_read(self, pin):
method delay_ms (line 58) | def delay_ms(self, delaytime):
method spi_writebyte (line 61) | def spi_writebyte(self, data):
method module_init (line 64) | def module_init(self):
method module_exit (line 75) | def module_exit(self):
class JetsonNano (line 86) | class JetsonNano:
method __init__ (line 93) | def __init__(self):
method digital_write (line 112) | def digital_write(self, pin, value):
method digital_read (line 115) | def digital_read(self, pin):
method delay_ms (line 118) | def delay_ms(self, delaytime):
method spi_writebyte (line 121) | def spi_writebyte(self, data):
method module_init (line 124) | def module_init(self):
method module_exit (line 134) | def module_exit(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v213d/epd2in13d.py
class EPD (line 40) | class EPD:
method __init__ (line 41) | def __init__(self):
method reset (line 152) | def reset(self):
method send_command (line 160) | def send_command(self, command):
method send_data (line 166) | def send_data(self, data):
method ReadBusy (line 172) | def ReadBusy(self):
method TurnOnDisplay (line 179) | def TurnOnDisplay(self):
method init (line 184) | def init(self):
method SetFullReg (line 221) | def SetFullReg(self):
method SetPartReg (line 243) | def SetPartReg(self):
method getbuffer (line 265) | def getbuffer(self, image):
method display (line 289) | def display(self, image):
method DisplayPartial (line 306) | def DisplayPartial(self, image):
method Clear (line 334) | def Clear(self):
method sleep (line 348) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v213d/epdconfig.py
class RaspberryPi (line 36) | class RaspberryPi:
method __init__ (line 43) | def __init__(self):
method digital_write (line 52) | def digital_write(self, pin, value):
method digital_read (line 55) | def digital_read(self, pin):
method delay_ms (line 58) | def delay_ms(self, delaytime):
method spi_writebyte (line 61) | def spi_writebyte(self, data):
method module_init (line 64) | def module_init(self):
method module_exit (line 75) | def module_exit(self):
class JetsonNano (line 86) | class JetsonNano:
method __init__ (line 93) | def __init__(self):
method digital_write (line 112) | def digital_write(self, pin, value):
method digital_read (line 115) | def digital_read(self, pin):
method delay_ms (line 118) | def delay_ms(self, delaytime):
method spi_writebyte (line 121) | def spi_writebyte(self, data):
method module_init (line 124) | def module_init(self):
method module_exit (line 134) | def module_exit(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v213inb_v4/epd2in13b_V4.py
class EPD (line 40) | class EPD:
method __init__ (line 41) | def __init__(self):
method reset (line 50) | def reset(self):
method send_command (line 59) | def send_command(self, command):
method send_data (line 66) | def send_data(self, data):
method send_data2 (line 73) | def send_data2(self, data):
method busy (line 80) | def busy(self):
method set_windows (line 87) | def set_windows(self, xstart, ystart, xend, yend):
method set_cursor (line 99) | def set_cursor(self, xstart, ystart):
method init (line 108) | def init(self):
method ondisplay (line 144) | def ondisplay(self):
method getbuffer (line 149) | def getbuffer(self, image):
method display (line 167) | def display(self, imageblack, imagered):
method clear (line 177) | def clear(self):
method Clear (line 194) | def Clear(self):
method sleep (line 198) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v213inb_v4/epdconfig.py
class RaspberryPi (line 38) | class RaspberryPi:
method __init__ (line 45) | def __init__(self):
method digital_write (line 52) | def digital_write(self, pin, value):
method digital_read (line 55) | def digital_read(self, pin):
method delay_ms (line 58) | def delay_ms(self, delaytime):
method spi_writebyte (line 61) | def spi_writebyte(self, data):
method spi_writebyte2 (line 64) | def spi_writebyte2(self, data):
method module_init (line 67) | def module_init(self):
method module_exit (line 81) | def module_exit(self):
class JetsonNano (line 92) | class JetsonNano:
method __init__ (line 99) | def __init__(self):
method digital_write (line 118) | def digital_write(self, pin, value):
method digital_read (line 121) | def digital_read(self, pin):
method delay_ms (line 124) | def delay_ms(self, delaytime):
method spi_writebyte (line 127) | def spi_writebyte(self, data):
method spi_writebyte2 (line 130) | def spi_writebyte2(self, data):
method module_init (line 134) | def module_init(self):
method module_exit (line 144) | def module_exit(self):
class SunriseX3 (line 155) | class SunriseX3:
method __init__ (line 163) | def __init__(self):
method digital_write (line 170) | def digital_write(self, pin, value):
method digital_read (line 173) | def digital_read(self, pin):
method delay_ms (line 176) | def delay_ms(self, delaytime):
method spi_writebyte (line 179) | def spi_writebyte(self, data):
method spi_writebyte2 (line 182) | def spi_writebyte2(self, data):
method module_init (line 187) | def module_init(self):
method module_exit (line 205) | def module_exit(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v27inch/epd2in7.py
class EPD (line 41) | class EPD:
method __init__ (line 42) | def __init__(self):
method reset (line 153) | def reset(self):
method send_command (line 161) | def send_command(self, command):
method send_data (line 167) | def send_data(self, data):
method ReadBusy (line 173) | def ReadBusy(self):
method set_lut (line 179) | def set_lut(self):
method gray_SetLut (line 196) | def gray_SetLut(self):
method init (line 221) | def init(self):
method Init_4Gray (line 291) | def Init_4Gray(self):
method getbuffer (line 360) | def getbuffer(self, image):
method getbuffer_4Gray (line 384) | def getbuffer_4Gray(self, image):
method display (line 420) | def display(self, image):
method display_4Gray (line 430) | def display_4Gray(self, image):
method Clear (line 501) | def Clear(self, color):
method sleep (line 511) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v27inch/epdconfig.py
class RaspberryPi (line 36) | class RaspberryPi:
method __init__ (line 43) | def __init__(self):
method digital_write (line 52) | def digital_write(self, pin, value):
method digital_read (line 55) | def digital_read(self, pin):
method delay_ms (line 58) | def delay_ms(self, delaytime):
method spi_writebyte (line 61) | def spi_writebyte(self, data):
method module_init (line 64) | def module_init(self):
method module_exit (line 75) | def module_exit(self):
class JetsonNano (line 86) | class JetsonNano:
method __init__ (line 93) | def __init__(self):
method digital_write (line 112) | def digital_write(self, pin, value):
method digital_read (line 115) | def digital_read(self, pin):
method delay_ms (line 118) | def delay_ms(self, delaytime):
method spi_writebyte (line 121) | def spi_writebyte(self, data):
method module_init (line 124) | def module_init(self):
method module_exit (line 134) | def module_exit(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v29inch/epd2in9.py
class EPD (line 37) | class EPD:
method __init__ (line 38) | def __init__(self):
method reset (line 63) | def reset(self):
method send_command (line 71) | def send_command(self, command):
method send_data (line 77) | def send_data(self, data):
method ReadBusy (line 83) | def ReadBusy(self):
method TurnOnDisplay (line 87) | def TurnOnDisplay(self):
method SetWindow (line 97) | def SetWindow(self, x_start, y_start, x_end, y_end):
method SetCursor (line 108) | def SetCursor(self, x, y):
method init (line 117) | def init(self, lut):
method getbuffer (line 151) | def getbuffer(self, image):
method display (line 175) | def display(self, image):
method Clear (line 186) | def Clear(self, color):
method sleep (line 195) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v29inch/epdconfig.py
class RaspberryPi (line 36) | class RaspberryPi:
method __init__ (line 43) | def __init__(self):
method digital_write (line 52) | def digital_write(self, pin, value):
method digital_read (line 55) | def digital_read(self, pin):
method delay_ms (line 58) | def delay_ms(self, delaytime):
method spi_writebyte (line 61) | def spi_writebyte(self, data):
method module_init (line 64) | def module_init(self):
method module_exit (line 75) | def module_exit(self):
class JetsonNano (line 86) | class JetsonNano:
method __init__ (line 93) | def __init__(self):
method digital_write (line 112) | def digital_write(self, pin, value):
method digital_read (line 115) | def digital_read(self, pin):
method delay_ms (line 118) | def delay_ms(self, delaytime):
method spi_writebyte (line 121) | def spi_writebyte(self, data):
method module_init (line 124) | def module_init(self):
method module_exit (line 134) | def module_exit(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v3/epd2in13_V3.py
class EPD (line 41) | class EPD:
method __init__ (line 42) | def __init__(self):
method reset (line 98) | def reset(self):
method send_command (line 111) | def send_command(self, command):
method send_data (line 122) | def send_data(self, data):
method ReadBusy (line 132) | def ReadBusy(self):
method TurnOnDisplay (line 142) | def TurnOnDisplay(self):
method TurnOnDisplayPart (line 152) | def TurnOnDisplayPart(self):
method Lut (line 163) | def Lut(self, lut):
method SetLut (line 174) | def SetLut(self, lut):
method SetWindow (line 195) | def SetWindow(self, x_start, y_start, x_end, y_end):
method SetCursor (line 213) | def SetCursor(self, x, y):
method init (line 226) | def init(self):
method getbuffer (line 267) | def getbuffer(self, image):
method display (line 288) | def display(self, image):
method displayPartial (line 305) | def displayPartial(self, image):
method displayPartBaseImage (line 350) | def displayPartBaseImage(self, image):
method Clear (line 371) | def Clear(self, color):
method sleep (line 389) | def sleep(self):
FILE: pwnagotchi/ui/hw/libs/waveshare/v3/epdconfig.py
class RaspberryPi (line 36) | class RaspberryPi:
method __init__ (line 43) | def __init__(self):
method digital_write (line 52) | def digital_write(self, pin, value):
method digital_read (line 55) | def digital_read(self, pin):
method delay_ms (line 58) | def delay_ms(self, delaytime):
method spi_writebyte (line 61) | def spi_writebyte(self, data):
method module_init (line 64) | def module_init(self):
method module_exit (line 75) | def module_exit(self):
class JetsonNano (line 86) | class JetsonNano:
method __init__ (line 93) | def __init__(self):
method digital_write (line 112) | def digital_write(self, pin, value):
method digital_read (line 115) | def digital_read(self, pin):
method delay_ms (line 118) | def delay_ms(self, delaytime):
method spi_writebyte (line 121) | def spi_writebyte(self, data):
method module_init (line 124) | def module_init(self):
method module_exit (line 134) | def module_exit(self):
FILE: pwnagotchi/ui/hw/oledhat.py
class OledHat (line 7) | class OledHat(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 41) | def render(self, canvas):
method clear (line 44) | def clear(self):
FILE: pwnagotchi/ui/hw/papirus.py
class Papirus (line 8) | class Papirus(DisplayImpl):
method __init__ (line 9) | def __init__(self, config):
method layout (line 13) | def layout(self):
method initialize (line 35) | def initialize(self):
method render (line 42) | def render(self, canvas):
method clear (line 46) | def clear(self):
FILE: pwnagotchi/ui/hw/spotpear24inch.py
class Spotpear24inch (line 8) | class Spotpear24inch(DisplayImpl):
method __init__ (line 9) | def __init__(self, config):
method layout (line 13) | def layout(self):
method refresh (line 36) | def refresh(self):
method initialize (line 39) | def initialize(self):
method render (line 46) | def render(self, canvas):
method clear (line 50) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare1.py
class WaveshareV1 (line 7) | class WaveshareV1(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 55) | def initialize(self):
method render (line 78) | def render(self, canvas):
method clear (line 89) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare144lcd.py
class Waveshare144lcd (line 7) | class Waveshare144lcd(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 41) | def render(self, canvas):
method clear (line 44) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare154inch.py
class Waveshare154inch (line 7) | class Waveshare154inch(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 41) | def render(self, canvas):
method clear (line 45) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare2.py
class WaveshareV2 (line 7) | class WaveshareV2(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 56) | def initialize(self):
method render (line 64) | def render(self, canvas):
method clear (line 68) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare213bc.py
class Waveshare213bc (line 7) | class Waveshare213bc(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 41) | def render(self, canvas):
method clear (line 45) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare213d.py
class Waveshare213d (line 7) | class Waveshare213d(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 41) | def render(self, canvas):
method clear (line 45) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare213inb_v4.py
class Waveshare213bV4 (line 7) | class Waveshare213bV4(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 56) | def initialize(self):
method render (line 63) | def render(self, canvasBlack = None, canvasRed = None):
method clear (line 70) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare27inch.py
class Waveshare27inch (line 7) | class Waveshare27inch(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 41) | def render(self, canvas):
method clear (line 45) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare29inch.py
class Waveshare29inch (line 7) | class Waveshare29inch(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 34) | def initialize(self):
method render (line 42) | def render(self, canvas):
method clear (line 46) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare3.py
class WaveshareV3 (line 7) | class WaveshareV3(DisplayImpl):
method __init__ (line 8) | def __init__(self, config):
method layout (line 12) | def layout(self):
method initialize (line 35) | def initialize(self):
method render (line 42) | def render(self, canvas):
method clear (line 46) | def clear(self):
FILE: pwnagotchi/ui/hw/waveshare35lcd.py
class Waveshare35lcd (line 8) | class Waveshare35lcd(DisplayImpl):
method __init__ (line 9) | def __init__(self, config):
method layout (line 13) | def layout(self):
method refresh (line 36) | def refresh(self):
method initialize (line 39) | def initialize(self):
method render (line 46) | def render(self, canvas):
method clear (line 50) | def clear(self):
FILE: pwnagotchi/ui/state.py
class State (line 4) | class State(object):
method __init__ (line 5) | def __init__(self, state={}):
method add_element (line 11) | def add_element(self, key, elem):
method has_element (line 15) | def has_element(self, key):
method remove_element (line 18) | def remove_element(self, key):
method add_listener (line 22) | def add_listener(self, key, cb):
method items (line 26) | def items(self):
method get (line 30) | def get(self, key):
method reset (line 34) | def reset(self):
method changes (line 38) | def changes(self, ignore=()):
method has_changes (line 46) | def has_changes(self):
method set (line 50) | def set(self, key, value):
FILE: pwnagotchi/ui/view.py
class View (line 24) | class View(object):
method __init__ (line 25) | def __init__(self, config, impl, state=None):
method set_agent (line 95) | def set_agent(self, agent):
method has_element (line 98) | def has_element(self, key):
method add_element (line 101) | def add_element(self, key, elem):
method remove_element (line 104) | def remove_element(self, key):
method width (line 107) | def width(self):
method height (line 110) | def height(self):
method on_state_change (line 113) | def on_state_change(self, key, cb):
method on_render (line 116) | def on_render(self, cb):
method _refresh_handler (line 120) | def _refresh_handler(self):
method set (line 132) | def set(self, key, value):
method get (line 135) | def get(self, key):
method on_starting (line 138) | def on_starting(self):
method on_ai_ready (line 143) | def on_ai_ready(self):
method on_manual_mode (line 149) | def on_manual_mode(self, last_session):
method is_normal (line 162) | def is_normal(self):
method on_keys_generation (line 175) | def on_keys_generation(self):
method on_normal (line 180) | def on_normal(self):
method set_closest_peer (line 185) | def set_closest_peer(self, peer, num_total):
method on_new_peer (line 214) | def on_new_peer(self, peer):
method on_lost_peer (line 231) | def on_lost_peer(self, peer):
method on_free_channel (line 236) | def on_free_channel(self, channel):
method on_reading_logs (line 241) | def on_reading_logs(self, lines_so_far=0):
method wait (line 246) | def wait(self, secs, sleeping=True):
method on_shutdown (line 276) | def on_shutdown(self):
method on_bored (line 282) | def on_bored(self):
method on_sad (line 287) | def on_sad(self):
method on_angry (line 292) | def on_angry(self):
method on_motivated (line 297) | def on_motivated(self, reward):
method on_demotivated (line 302) | def on_demotivated(self, reward):
method on_excited (line 307) | def on_excited(self):
method on_assoc (line 312) | def on_assoc(self, ap):
method on_deauth (line 317) | def on_deauth(self, sta):
method on_miss (line 322) | def on_miss(self, who):
method on_grateful (line 327) | def on_grateful(self):
method on_lonely (line 332) | def on_lonely(self):
method on_handshakes (line 337) | def on_handshakes(self, new_shakes):
method on_unread_messages (line 342) | def on_unread_messages(self, count, total):
method on_uploading (line 348) | def on_uploading(self, to):
method on_rebooting (line 353) | def on_rebooting(self):
method on_custom (line 358) | def on_custom(self, text):
method update (line 363) | def update(self, force=False, new_data={}):
FILE: pwnagotchi/ui/web/__init__.py
function update_frame (line 10) | def update_frame(img):
FILE: pwnagotchi/ui/web/handler.py
class Handler (line 27) | class Handler:
method __init__ (line 28) | def __init__(self, config, agent, app):
method _check_creds (line 57) | def _check_creds(self, u, p):
method with_auth (line 62) | def with_auth(self, f):
method index (line 73) | def index(self):
method inbox (line 79) | def inbox(self):
method inbox_profile (line 103) | def inbox_profile(self):
method inbox_peers (line 119) | def inbox_peers(self):
method show_message (line 134) | def show_message(self, id):
method new_message (line 154) | def new_message(self):
method send_message (line 158) | def send_message(self):
method mark_message (line 173) | def mark_message(self, id, mark):
method plugins (line 181) | def plugins(self, name, subpath):
method shutdown (line 198) | def shutdown(self):
method reboot (line 206) | def reboot(self):
method restart (line 214) | def restart(self):
method ui (line 226) | def ui(self):
FILE: pwnagotchi/ui/web/server.py
class Server (line 16) | class Server:
method __init__ (line 17) | def __init__(self, agent, config):
method _http_serve (line 30) | def _http_serve(self):
FILE: pwnagotchi/ui/web/static/js/jquery.jqplot.js
function Axis (line 537) | function Axis(name) {
function Legend (line 873) | function Legend(options) {
function Title (line 1105) | function Title(text) {
function Series (line 1165) | function Series(options) {
function Grid (line 1550) | function Grid() {
function jqPlot (line 1742) | function jqPlot() {
function drawLine (line 4688) | function drawLine(bx, by, ex, ey, opts) {
function getSteps (line 5315) | function getSteps (d, f) {
function computeSteps (line 5319) | function computeSteps (d1, d2) {
function tanh (line 5324) | function tanh (x) {
function computeConstrainedSmoothedData (line 5343) | function computeConstrainedSmoothedData (gd) {
function computeHermiteSmoothedData (line 5463) | function computeHermiteSmoothedData (gd) {
function postInit (line 5992) | function postInit(target, data, options) {
function postPlotDraw (line 6006) | function postPlotDraw() {
function highlight (line 6021) | function highlight (plot, sidx, pidx, points) {
function unhighlight (line 6036) | function unhighlight (plot) {
function handleMove (line 6048) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
function handleMouseDown (line 6069) | function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
function handleMouseUp (line 6086) | function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
function handleClick (line 6093) | function handleClick(ev, gridpos, datapos, neighbor, plot) {
function handleRightClick (line 6104) | function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
function bestFormatString (line 7117) | function bestFormatString (interval)
function bestConstrainedInterval (line 7167) | function bestConstrainedInterval(min, max, nttarget) {
function bestInterval (line 7218) | function bestInterval(range, numberTicks) {
function bestLinearInterval (line 7268) | function bestLinearInterval(range, scalefact) {
function bestLinearComponents (line 7303) | function bestLinearComponents(range, scalefact) {
function numericalOrder (line 8508) | function numericalOrder(a,b) { return a-b; }
function clone (line 8776) | function clone(obj){
function merge (line 8790) | function merge(obj1, obj2) {
function getLineheight (line 9178) | function getLineheight(el) {
function writeWrappedText (line 9187) | function writeWrappedText (el, context, text, left, top, canvasWidth) {
function _jqpToImage (line 9240) | function _jqpToImage(el, x_offset, y_offset) {
function h1 (line 10655) | function h1(parsable, match) {
function inArray (line 10833) | function inArray( elem, array ) {
function get_type (line 10850) | function get_type(thing){
function pad (line 10921) | function pad(str, len, chr, leftJustify) {
function thousand_separate (line 10927) | function thousand_separate(value) {
function justify (line 10935) | function justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpac...
function formatBaseX (line 10949) | function formatBaseX(value, base, prefix, leftJustify, minWidth, precisi...
function formatString (line 10957) | function formatString(value, leftJustify, minWidth, precision, zeroPad, ...
function _normalizeArguments (line 11281) | function _normalizeArguments( effect, options, speed, callback ) {
function standardSpeed (line 11330) | function standardSpeed( speed ) {
function run (line 11371) | function run( next ) {
FILE: pwnagotchi/ui/web/static/js/jquery.mobile/jquery.mobile-1.4.5.js
function focusable (line 121) | function focusable( element, isTabIndexNotNaN ) {
function visible (line 142) | function visible( element ) {
function reduce (line 184) | function reduce( elem, size, border, margin ) {
function handlerProxy (line 1128) | function handlerProxy() {
function handlerProxy (line 1164) | function handlerProxy() {
function get_fragment (line 1650) | function get_fragment( url ) {
function poll (line 1824) | function poll() {
function propExists (line 1996) | function propExists( prop ) {
function inlineSVG (line 2017) | function inlineSVG() {
function transform3dTest (line 2037) | function transform3dTest() {
function baseTagTest (line 2066) | function baseTagTest() {
function cssPointerEventsTest (line 2090) | function cssPointerEventsTest() {
function boundingRect (line 2109) | function boundingRect() {
function fixedPosition (line 2129) | function fixedPosition() {
function getNativeEvent (line 3358) | function getNativeEvent( event ) {
function createVirtualEvent (line 3366) | function createVirtualEvent( event, eventType ) {
function getVirtualBindingFlags (line 3416) | function getVirtualBindingFlags( element ) {
function getClosestElementWithVirtualBinding (line 3435) | function getClosestElementWithVirtualBinding( element, eventType ) {
function enableTouchBindings (line 3449) | function enableTouchBindings() {
function disableTouchBindings (line 3453) | function disableTouchBindings() {
function enableMouseBindings (line 3457) | function enableMouseBindings() {
function disableMouseBindings (line 3467) | function disableMouseBindings() {
function startResetTimer (line 3473) | function startResetTimer() {
function clearResetTimer (line 3481) | function clearResetTimer() {
function triggerVirtualEvent (line 3488) | function triggerVirtualEvent( eventType, event, flags ) {
function mouseEventCallback (line 3502) | function mouseEventCallback( event ) {
function handleTouchStart (line 3522) | function handleTouchStart( event ) {
function handleScroll (line 3552) | function handleScroll( event ) {
function handleTouchMove (line 3565) | function handleTouchMove( event ) {
function handleTouchEnd (line 3587) | function handleTouchEnd( event ) {
function hasVirtualBindings (line 3623) | function hasVirtualBindings( ele ) {
function dummyMouseHandler (line 3637) | function dummyMouseHandler() {}
function getSpecialEventObject (line 3639) | function getSpecialEventObject( eventType ) {
function triggerCustomEvent (line 3843) | function triggerCustomEvent( obj, eventType, event, bubble ) {
function trigger (line 3865) | function trigger( event, state ) {
function clearTapTimer (line 3910) | function clearTapTimer() {
function clearTapHandlers (line 3914) | function clearTapHandlers() {
function clickHandler (line 3922) | function clickHandler( event ) {
function handler (line 4279) | function handler() {
function findClosestLink (line 5760) | function findClosestLink( ele ) {
function noHiddenClass (line 7178) | function noHiddenClass( elements ) {
function defaultAutodividersSelector (line 7663) | function defaultAutodividersSelector( elt ) {
function getPopup (line 9080) | function getPopup() {
function fitSegmentInsideSegment (line 10283) | function fitSegmentInsideSegment( windowSize, segmentSize, offset, desir...
function getWindowCoordinates (line 10297) | function getWindowCoordinates( theWindow ) {
function optionsToClasses (line 11848) | function optionsToClasses( options, existingClasses ) {
function classNameToOptions (line 11905) | function classNameToOptions( classes ) {
function camelCase2Hyphenated (line 11973) | function camelCase2Hyphenated( c ) {
function getArrow (line 12837) | function getArrow() {
function getNextTabId (line 14415) | function getNextTabId() {
function isLocal (line 14419) | function isLocal( anchor ) {
function constrain (line 14635) | function constrain() {
function complete (line 14981) | function complete() {
function show (line 14986) | function show() {
function checkTilt (line 15261) | function checkTilt( e ) {
function hideRenderingClass (line 15294) | function hideRenderingClass() {
FILE: pwnagotchi/ui/web/static/js/jquery.timeago.js
function substitute (line 96) | function substitute(stringOrFunction, number) {
function refresh (line 183) | function refresh() {
function prepareData (line 207) | function prepareData(element) {
function inWords (line 221) | function inWords(date) {
function distance (line 225) | function distance(date) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.BezierCurveRenderer.js
function preInit (line 289) | function preInit(target, data, options) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.barRenderer.js
function barPreInit (line 176) | function barPreInit(target, data, seriesDefaults, options) {
function computeHighlightColors (line 279) | function computeHighlightColors (colors) {
function getStart (line 295) | function getStart(sidx, didx, comp, plot, axis) {
function postInit (line 675) | function postInit(target, data, options) {
function postPlotDraw (line 689) | function postPlotDraw() {
function highlight (line 705) | function highlight (plot, sidx, pidx, points) {
function unhighlight (line 716) | function unhighlight (plot) {
function handleMove (line 728) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
function handleMouseDown (line 750) | function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
function handleMouseUp (line 767) | function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
function handleClick (line 774) | function handleClick(ev, gridpos, datapos, neighbor, plot) {
function handleRightClick (line 785) | function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.bubbleRenderer.js
function highlight (line 581) | function highlight (plot, sidx, pidx) {
function unhighlight (line 611) | function unhighlight (plot) {
function handleMove (line 624) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
function handleMouseDown (line 647) | function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
function handleMouseUp (line 666) | function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
function handleClick (line 673) | function handleClick(ev, gridpos, datapos, neighbor, plot) {
function handleRightClick (line 686) | function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
function postPlotDraw (line 706) | function postPlotDraw() {
function preInit (line 732) | function preInit(target, data, options) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.canvasOverlay.js
function LineBase (line 89) | function LineBase() {
function Rectangle (line 161) | function Rectangle(options) {
function Line (line 198) | function Line(options) {
function HorizontalLine (line 224) | function HorizontalLine(options) {
function DashedHorizontalLine (line 258) | function DashedHorizontalLine(options) {
function VerticalLine (line 289) | function VerticalLine(options) {
function DashedVerticalLine (line 315) | function DashedVerticalLine(options) {
function showTooltip (line 782) | function showTooltip(plot, obj, gridpos, datapos) {
function isNearLine (line 842) | function isNearLine(point, lstart, lstop, width) {
function isNearRectangle (line 860) | function isNearRectangle(point, lstart, lstop, width) {
function handleMove (line 879) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.ciParser.js
function handleStrings (line 83) | function handleStrings(key, value) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.cursor.js
function plotZoom (line 308) | function plotZoom(ev, gridpos, datapos, plot, cursor) {
function plotReset (line 312) | function plotReset(ev, plot, cursor) {
function updateTooltip (line 468) | function updateTooltip(gridpos, datapos, plot) {
function moveLine (line 539) | function moveLine(gridpos, plot) {
function getIntersectingPoints (line 585) | function getIntersectingPoints(plot, x, y) {
function moveTooltip (line 613) | function moveTooltip(gridpos, plot) {
function positionTooltip (line 660) | function positionTooltip(plot) {
function handleClick (line 717) | function handleClick (ev, gridpos, datapos, neighbor, plot) {
function handleDblClick (line 735) | function handleDblClick (ev, gridpos, datapos, neighbor, plot) {
function handleMouseLeave (line 753) | function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) {
function handleMouseEnter (line 789) | function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) {
function handleMouseMove (line 812) | function handleMouseMove(ev, gridpos, datapos, neighbor, plot) {
function getEventPosition (line 827) | function getEventPosition(ev) {
function handleZoomMove (line 848) | function handleZoomMove(ev) {
function handleMouseDown (line 893) | function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
function handleMouseUp (line 942) | function handleMouseUp(ev) {
function drawZoomBox (line 1002) | function drawZoomBox() {
function addrow (line 1085) | function addrow(label, color, pad, idx) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.dateAxisRenderer.js
function bestDateInterval (line 131) | function bestDateInterval(min, max, titarget) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.donutRenderer.js
function doDraw (line 294) | function doDraw () {
function preInit (line 630) | function preInit(target, data, options) {
function postInit (line 657) | function postInit(target, data, options) {
function postParseOptions (line 682) | function postParseOptions(options) {
function highlight (line 689) | function highlight (plot, sidx, pidx) {
function unhighlight (line 698) | function unhighlight (plot) {
function handleMove (line 708) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
function handleMouseDown (line 729) | function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
function handleMouseUp (line 746) | function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
function handleClick (line 753) | function handleClick(ev, gridpos, datapos, neighbor, plot) {
function handleRightClick (line 764) | function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
function postPlotDraw (line 782) | function postPlotDraw() {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.dragable.js
function DragCanvas (line 57) | function DragCanvas() {
function initDragPoint (line 104) | function initDragPoint(plot, neighbor) {
function handleMove (line 128) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
function handleDown (line 178) | function handleDown(ev, gridpos, datapos, neighbor, plot) {
function handleUp (line 201) | function handleUp(ev, gridpos, datapos, neighbor, plot) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.funnelRenderer.js
function doDraw (line 272) | function doDraw () {
function findleft (line 396) | function findleft (l) {
function findright (line 404) | function findright (l) {
function preInit (line 768) | function preInit(target, data, options) {
function postInit (line 795) | function postInit(target, data, options) {
function postParseOptions (line 809) | function postParseOptions(options) {
function highlight (line 816) | function highlight (plot, sidx, pidx) {
function unhighlight (line 825) | function unhighlight (plot) {
function handleMove (line 835) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
function handleMouseDown (line 856) | function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
function handleMouseUp (line 873) | function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
function handleClick (line 880) | function handleClick(ev, gridpos, datapos, neighbor, plot) {
function handleRightClick (line 891) | function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
function postPlotDraw (line 909) | function postPlotDraw() {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.highlighter.js
function draw (line 213) | function draw(plot, neighbor) {
function showTooltip (line 229) | function showTooltip(plot, series, neighbor) {
function handleMove (line 399) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.json2.js
function f (line 164) | function f(n) {
function quote (line 205) | function quote(string) {
function str (line 223) | function str(key, holder) {
function walk (line 406) | function walk(holder, key) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.logAxisRenderer.js
function findCeil (line 170) | function findCeil (val) {
function findFloor (line 175) | function findFloor(val) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.mekkoRenderer.js
function preInit (line 411) | function preInit(target, data, options) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.meterGaugeRenderer.js
function getnmt (line 304) | function getnmt(pos, interval, fact) {
function preInit (line 980) | function preInit(target, data, options) {
function postParseOptions (line 1013) | function postParseOptions(options) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.mobile.js
function postInit (line 23) | function postInit(target, data, options){
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.pieRenderer.js
function calcRadiusAdjustment (line 266) | function calcRadiusAdjustment(ang) {
function calcRPrime (line 270) | function calcRPrime(ang1, ang2, sliceMargin, fill, lineWidth) {
function doDraw (line 329) | function doDraw (rad) {
function preInit (line 771) | function preInit(target, data, options) {
function postInit (line 797) | function postInit(target, data, options) {
function postParseOptions (line 809) | function postParseOptions(options) {
function highlight (line 816) | function highlight (plot, sidx, pidx) {
function unhighlight (line 827) | function unhighlight (plot) {
function handleMove (line 837) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
function handleMouseDown (line 858) | function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
function handleMouseUp (line 875) | function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
function handleClick (line 882) | function handleClick(ev, gridpos, datapos, neighbor, plot) {
function handleRightClick (line 893) | function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
function postPlotDraw (line 911) | function postPlotDraw() {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.pyramidGridRenderer.js
function drawLine (line 374) | function drawLine(bx, by, ex, ey, opts) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.pyramidRenderer.js
function preInit (line 416) | function preInit(target, data, options) {
function postPlotDraw (line 445) | function postPlotDraw() {
function highlight (line 461) | function highlight (plot, sidx, pidx, points) {
function unhighlight (line 477) | function unhighlight (plot) {
function handleMove (line 489) | function handleMove(ev, gridpos, datapos, neighbor, plot) {
FILE: pwnagotchi/ui/web/static/js/plugins/jqplot.trendline.js
function addTrendlineLegend (line 95) | function addTrendlineLegend(series) {
function parseTrendLineOptions (line 107) | function parseTrendLineOptions (target, data, seriesDefaults, options, p...
function drawTrendline (line 117) | function drawTrendline(sctx, options) {
function regression (line 131) | function regression(x, y, typ) {
function linearRegression (line 175) | function linearRegression(X,Y) {
function expRegression (line 181) | function expRegression(X,Y) {
function fitData (line 191) | function fitData(data, typ) {
FILE: pwnagotchi/ui/web/static/js/viewportHeight.js
function updateViewportSize (line 5) | function updateViewportSize() {
FILE: pwnagotchi/utils.py
class DottedTomlEncoder (line 20) | class DottedTomlEncoder(TomlEncoder):
method __init__ (line 25) | def __init__(self, _dict=dict):
method dump_list (line 28) | def dump_list(self, v):
method dump_sections (line 41) | def dump_sections(self, o, sup):
function parse_version (line 66) | def parse_version(version):
function remove_whitelisted (line 73) | def remove_whitelisted(list_of_handshakes, list_of_whitelisted_strings, ...
function download_file (line 100) | def download_file(url, destination, chunk_size=128):
function unzip (line 109) | def unzip(file, destination, strip_dirs=0):
function merge_config (line 123) | def merge_config(user, default):
function keys_to_str (line 132) | def keys_to_str(data):
function save_config (line 151) | def save_config(config, target):
function load_config (line 156) | def load_config(args):
function secs_to_hhmmss (line 300) | def secs_to_hhmmss(secs):
function total_unique_handshakes (line 306) | def total_unique_handshakes(path):
function iface_channels (line 311) | def iface_channels(ifname):
function led (line 321) | def led(on=True):
function blink (line 326) | def blink(times=1, delay=0.3):
class WifiInfo (line 335) | class WifiInfo(Enum):
class FieldNotFoundError (line 346) | class FieldNotFoundError(Exception):
function md5 (line 350) | def md5(fname):
function extract_from_pcap (line 362) | def extract_from_pcap(path, fields):
class StatusFile (line 444) | class StatusFile(object):
method __init__ (line 445) | def __init__(self, path, data_format='raw'):
method data_field_or (line 459) | def data_field_or(self, name, default=""):
method newer_then_minutes (line 464) | def newer_then_minutes(self, minutes):
method newer_then_hours (line 467) | def newer_then_hours(self, hours):
method newer_then_days (line 470) | def newer_then_days(self, days):
method update (line 473) | def update(self, data=None):
FILE: pwnagotchi/voice.py
class Voice (line 6) | class Voice:
method __init__ (line 7) | def __init__(self, lang):
method custom (line 17) | def custom(self, s):
method default (line 20) | def default(self):
method on_starting (line 23) | def on_starting(self):
method on_ai_ready (line 29) | def on_ai_ready(self):
method on_keys_generation (line 34) | def on_keys_generation(self):
method on_normal (line 38) | def on_normal(self):
method on_free_channel (line 43) | def on_free_channel(self, channel):
method on_reading_logs (line 46) | def on_reading_logs(self, lines_so_far=0):
method on_bored (line 52) | def on_bored(self):
method on_motivated (line 57) | def on_motivated(self, reward):
method on_demotivated (line 60) | def on_demotivated(self, reward):
method on_sad (line 63) | def on_sad(self):
method on_angry (line 70) | def on_angry(self):
method on_excited (line 77) | def on_excited(self):
method on_new_peer (line 85) | def on_new_peer(self, peer):
method on_lost_peer (line 95) | def on_lost_peer(self, peer):
method on_miss (line 100) | def on_miss(self, who):
method on_grateful (line 106) | def on_grateful(self):
method on_lonely (line 111) | def on_lonely(self):
method on_napping (line 117) | def on_napping(self, secs):
method on_shutdown (line 123) | def on_shutdown(self):
method on_awakening (line 128) | def on_awakening(self):
method on_waiting (line 131) | def on_waiting(self, secs):
method on_assoc (line 137) | def on_assoc(self, ap):
method on_deauth (line 145) | def on_deauth(self, sta):
method on_handshakes (line 151) | def on_handshakes(self, new_shakes):
method on_unread_messages (line 155) | def on_unread_messages(self, count, total):
method on_rebooting (line 159) | def on_rebooting(self):
method on_uploading (line 162) | def on_uploading(self, to):
method on_last_session_data (line 165) | def on_last_session_data(self, last_session):
method on_last_session_tweet (line 178) | def on_last_session_tweet(self, last_session):
method hhmmss (line 186) | def hhmmss(self, count, fmt):
FILE: scripts/preview.py
class CustomDisplay (line 17) | class CustomDisplay(Display):
method __init__ (line 19) | def __init__(self, config, state):
method _http_serve (line 23) | def _http_serve(self):
method _on_view_rendered (line 27) | def _on_view_rendered(self, img):
method get_image (line 30) | def get_image(self):
class DummyPeer (line 37) | class DummyPeer:
method __init__ (line 39) | def __init__(self):
method name (line 43) | def name():
method pwnd_run (line 47) | def pwnd_run():
method pwnd_total (line 51) | def pwnd_total():
method first_encounter (line 55) | def first_encounter():
method face (line 59) | def face():
function append_images (line 63) | def append_images(images, horizontal=True, xmargin=0, ymargin=0):
function main (line 88) | def main():
FILE: setup.py
function install_file (line 11) | def install_file(source_filename, dest_filename):
function install_system_files (line 29) | def install_system_files():
function installer (line 42) | def installer():
function version (line 47) | def version(version_file):
Condensed preview — 306 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,807K chars).
[
{
"path": ".DEREK.yml",
"chars": 103,
"preview": "maintainers:\n - evilsocket\n - caquino\n - justin-p\n \nfeatures:\n - comments\n - pr_description_required\n \n"
},
{
"path": ".editorconfig",
"chars": 520,
"preview": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# edit"
},
{
"path": ".gitattributes",
"chars": 247,
"preview": "/builder/** linguist-vendored\n/scripts/** linguist-vendored\n/pwnagotchi/ui/web/static/** linguist-vendored\n/pwnagotchi/u"
},
{
"path": ".github/CODEOWNERS",
"chars": 11,
"preview": "evilsocket\n"
},
{
"path": ".github/FUNDING.yml",
"chars": 680,
"preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHubSponsors-enabled usernames e.g., [us"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 640,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG]\"\nlabels: bug\nassignees: ''\n\n---\n\n**Describe"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 604,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is"
},
{
"path": ".github/ISSUE_TEMPLATE/other.md",
"chars": 110,
"preview": "---\nname: Other\nabout: Describe this issue template's purpose here.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n\n"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 1189,
"preview": "<!--- Provide a general summary of the issue in the Title above -->\n\n## Expected Behaviour\n<!--- If you're describing a "
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 1522,
"preview": "<!--- Provide a general summary of your changes in the Title above -->\n\n## Description\n<!--- Describe your changes in de"
},
{
"path": ".gitignore",
"chars": 272,
"preview": "*.img\n*.img.bmap\n*.pcap\n*.po~\npreview.png\n__pycache__\n_backups\n_emulation\n_utils\nconfig.laptop.yml\n.idea\npacker_cache\nou"
},
{
"path": ".travis.yml",
"chars": 2098,
"preview": "dist: bionic\nlanguage: go\ngo:\n - 1.x\nenv:\n global:\n - LANG=C\n - LC_ALL=C\ndeploy:\n provider: releases\n api_key:"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3352,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "CONTRIBUTING.md",
"chars": 2746,
"preview": "## Contributing\n\n### Guidelines\n\nHere are a few guidelines for contributing:\n\n* If you would like to contribute to the c"
},
{
"path": "LICENSE.md",
"chars": 35187,
"preview": "GNU GENERAL PUBLIC LICENSE\n==========================\n\nVersion 3, 29 June 2007\n\nCopyright © 2007 Free Software Foun"
},
{
"path": "MANIFEST.in",
"chars": 252,
"preview": "exclude *.pyc .DS_Store .gitignore MANIFEST.in\ninclude setup.py\ninclude distribute_setup.py\ninclude README.md\ninclude LI"
},
{
"path": "Makefile",
"chars": 1356,
"preview": "PACKER_VERSION=1.7.2\nPWN_HOSTNAME=pwnagotchi\nPWN_VERSION=master\n\nall: clean install image\n\nlangs:\n\t@for lang in pwnagotc"
},
{
"path": "README.md",
"chars": 4897,
"preview": "<p align=\"center\">\n <small>Join the project community on our server!</small>\n <br/><br/>\n <a href=\"https://discord.gg"
},
{
"path": "bin/pwnagotchi",
"chars": 5989,
"preview": "#!/usr/bin/python3\nimport logging\nimport argparse\nimport time\nimport signal\nimport sys\nimport toml\n\nimport pwnagotchi\nfr"
},
{
"path": "builder/data/etc/bash_completion.d/pwnagotchi_completion.sh",
"chars": 1094,
"preview": "_show_complete()\n{\n local cur opts node_names all_options opt_line\n all_options=\"\npwnagotchi -h --help -C --config"
},
{
"path": "builder/data/etc/network/interfaces.d/eth0-cfg",
"chars": 39,
"preview": "allow-hotplug eth0\niface eth0 inet dhcp"
},
{
"path": "builder/data/etc/network/interfaces.d/lo-cfg",
"chars": 30,
"preview": "auto lo\niface lo inet loopback"
},
{
"path": "builder/data/etc/network/interfaces.d/usb0-cfg",
"chars": 158,
"preview": "allow-hotplug usb0\niface usb0 inet static\n address 10.0.0.2\n netmask 255.255.255.0\n network 10.0.0.0\n broadcast 10.0"
},
{
"path": "builder/data/etc/network/interfaces.d/wlan0-cfg",
"chars": 43,
"preview": "allow-hotplug wlan0\niface wlan0 inet static"
},
{
"path": "builder/data/etc/systemd/system/bettercap.service",
"chars": 257,
"preview": "[Unit]\nDescription=bettercap api.rest service.\nDocumentation=https://bettercap.org\nWants=network.target\n\n[Service]\nType="
},
{
"path": "builder/data/etc/systemd/system/pwnagotchi.service",
"chars": 437,
"preview": "[Unit]\nDescription=pwnagotchi Deep Reinforcement Learning instrumenting bettercap for WiFI pwning.\nDocumentation=https:/"
},
{
"path": "builder/data/etc/systemd/system/pwngrid-peer.service",
"chars": 400,
"preview": "[Unit]\nDescription=pwngrid peer service.\nDocumentation=https://pwnagotchi.ai\nWants=network.target\nAfter=bettercap.servic"
},
{
"path": "builder/data/usr/bin/bettercap-launcher",
"chars": 562,
"preview": "#!/usr/bin/env bash\nsource /usr/bin/pwnlib\n\n# we need to decrypt something\nif is_crypted_mode; then\n while ! is_decrypt"
},
{
"path": "builder/data/usr/bin/decryption-webserver",
"chars": 3622,
"preview": "#!/usr/bin/env python3\n\nfrom http.server import HTTPServer, BaseHTTPRequestHandler\nfrom urllib.parse import parse_qsl\n\n\n"
},
{
"path": "builder/data/usr/bin/hdmioff",
"chars": 49,
"preview": "#!/usr/bin/env bash\nsudo /opt/vc/bin/tvservice -o"
},
{
"path": "builder/data/usr/bin/hdmion",
"chars": 49,
"preview": "#!/usr/bin/env bash\nsudo /opt/vc/bin/tvservice -p"
},
{
"path": "builder/data/usr/bin/monstart",
"chars": 67,
"preview": "#!/usr/bin/env bash\nsource /usr/bin/pwnlib\nstart_monitor_interface\n"
},
{
"path": "builder/data/usr/bin/monstop",
"chars": 65,
"preview": "#!/usr/bin/env bash\nsource /usr/bin/pwnlib\nstop_monitor_interface"
},
{
"path": "builder/data/usr/bin/pwnagotchi-launcher",
"chars": 337,
"preview": "#!/usr/bin/env bash\nsource /usr/bin/pwnlib\n\n# we need to decrypt something\nif is_crypted_mode; then\n while ! is_decrypt"
},
{
"path": "builder/data/usr/bin/pwnlib",
"chars": 4372,
"preview": "#!/usr/bin/env bash\n\n# well ... it blinks the led\nblink_led() {\n for i in $(seq 1 \"$1\"); do\n echo 0 >/sys/class/leds"
},
{
"path": "builder/pwnagotchi.json",
"chars": 3072,
"preview": "{\n \"builders\": [\n {\n \"name\": \"pwnagotchi\",\n \"type\": \"arm-image\",\n \"iso_url\": \"https://downloads.raspb"
},
{
"path": "builder/pwnagotchi.yml",
"chars": 12279,
"preview": "---\n- hosts:\n - 127.0.0.1\n become: yes\n vars:\n pwnagotchi:\n hostname: \"{{ lookup('env', 'PWN_HOSTNAME') | d"
},
{
"path": "pwnagotchi/__init__.py",
"chars": 4146,
"preview": "import os\nimport logging\nimport time\nimport re\n\n\n\nfrom pwnagotchi._version import __version__\n\n_name = None\nconfig = Non"
},
{
"path": "pwnagotchi/_version.py",
"chars": 22,
"preview": "__version__ = '1.5.5'\n"
},
{
"path": "pwnagotchi/agent.py",
"chars": 17986,
"preview": "import time\nimport json\nimport os\nimport re\nimport logging\nimport asyncio\nimport _thread\n\nimport pwnagotchi\nimport pwnag"
},
{
"path": "pwnagotchi/ai/__init__.py",
"chars": 2151,
"preview": "import os\nimport time\nimport logging\n\n# https://stackoverflow.com/questions/40426502/is-there-a-way-to-suppress-the-mess"
},
{
"path": "pwnagotchi/ai/epoch.py",
"chars": 9181,
"preview": "import time\nimport threading\nimport logging\n\nimport pwnagotchi\nimport pwnagotchi.utils as utils\nimport pwnagotchi.mesh.w"
},
{
"path": "pwnagotchi/ai/featurizer.py",
"chars": 2116,
"preview": "import numpy as np\n\nimport pwnagotchi.mesh.wifi as wifi\n\nMAX_EPOCH_DURATION = 1024\n\n\ndef describe(extended=False):\n i"
},
{
"path": "pwnagotchi/ai/gym.py",
"chars": 5428,
"preview": "import logging\nimport gym\nfrom gym import spaces\nimport numpy as np\n\nimport pwnagotchi.ai.featurizer as featurizer\nimpor"
},
{
"path": "pwnagotchi/ai/parameter.py",
"chars": 952,
"preview": "from gym import spaces\n\n\nclass Parameter(object):\n def __init__(self, name, value=0.0, min_value=0, max_value=2, meta"
},
{
"path": "pwnagotchi/ai/reward.py",
"chars": 1038,
"preview": "import pwnagotchi.mesh.wifi as wifi\n\nrange = (-.7, 1.02)\nfuck_zero = 1e-20\n\n\nclass RewardFunction(object):\n def __cal"
},
{
"path": "pwnagotchi/ai/train.py",
"chars": 6250,
"preview": "import _thread\nimport threading\nimport time\nimport random\nimport os\nimport json\nimport logging\n\nimport pwnagotchi.plugin"
},
{
"path": "pwnagotchi/ai/utils.py",
"chars": 466,
"preview": "import numpy as np\n\n\ndef normalize(v, min_v, max_v):\n return (v - min_v) / (max_v - min_v)\n\n\ndef as_batches(x, y, bat"
},
{
"path": "pwnagotchi/automata.py",
"chars": 5394,
"preview": "import logging\n\nimport pwnagotchi.plugins as plugins\nfrom pwnagotchi.ai.epoch import Epoch\n\n\n# basic mood system\nclass A"
},
{
"path": "pwnagotchi/bettercap.py",
"chars": 2057,
"preview": "import json\nimport logging\nimport requests\nimport websockets\n\nfrom requests.auth import HTTPBasicAuth\n\n\ndef decode(r, ve"
},
{
"path": "pwnagotchi/defaults.toml",
"chars": 7913,
"preview": "main.name = \"\"\nmain.lang = \"en\"\nmain.confd = \"/etc/pwnagotchi/conf.d/\"\nmain.custom_plugins = \"\"\nmain.custom_plugin_repos"
},
{
"path": "pwnagotchi/fs/__init__.py",
"chars": 5818,
"preview": "import os\nimport re\nimport tempfile\nimport contextlib\nimport shutil\nimport _thread\nimport logging\n\nfrom time import slee"
},
{
"path": "pwnagotchi/grid.py",
"chars": 2893,
"preview": "import subprocess\nimport socket\nimport requests\nimport json\nimport logging\n\nimport pwnagotchi\n\n# pwngrid-peer is running"
},
{
"path": "pwnagotchi/identity.py",
"chars": 2815,
"preview": "from Crypto.Signature import PKCS1_PSS\nfrom Crypto.PublicKey import RSA\nimport Crypto.Hash.SHA256 as SHA256\nimport base6"
},
{
"path": "pwnagotchi/locale/af/LC_MESSAGES/voice.po",
"chars": 5684,
"preview": "# Afrikaans translation of pwnagotchi.\n# Copyright (C) 2020.\n# This file is distributed under the same license as the pw"
},
{
"path": "pwnagotchi/locale/bg/LC_MESSAGES/voice.po",
"chars": 5248,
"preview": "# pwnagotchi voice data.\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi packag"
},
{
"path": "pwnagotchi/locale/ch/LC_MESSAGES/voice.po",
"chars": 4377,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "pwnagotchi/locale/cs/LC_MESSAGES/voice.po",
"chars": 5723,
"preview": "# pwnigotchi voice data\n# Copyright (C) 2020\n# This file is distributed under the same license as the pwnagotchi package"
},
{
"path": "pwnagotchi/locale/de/LC_MESSAGES/voice.po",
"chars": 5783,
"preview": "# German language\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi package.\n# da"
},
{
"path": "pwnagotchi/locale/dk/LC_MESSAGES/voice.po",
"chars": 5686,
"preview": "# pwnagotchi danish voice data\n# Copyright (C) 2020\n# This file is distributed under the same license as the pwnagotchi "
},
{
"path": "pwnagotchi/locale/el/LC_MESSAGES/voice.po",
"chars": 4871,
"preview": "# pwnigotchi voice data\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi package"
},
{
"path": "pwnagotchi/locale/es/LC_MESSAGES/voice.po",
"chars": 4953,
"preview": "# pwnagotchi voice data\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi package"
},
{
"path": "pwnagotchi/locale/fr/LC_MESSAGES/voice.po",
"chars": 5923,
"preview": "# pwnigotchi voice data\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi package"
},
{
"path": "pwnagotchi/locale/ga/LC_MESSAGES/voice.po",
"chars": 5037,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "pwnagotchi/locale/hr/LC_MESSAGES/voice.po",
"chars": 5852,
"preview": "# Croatian translation\n# Copyright (C) 2021\n# This file is distributed under the same license as the pwnagotchi package."
},
{
"path": "pwnagotchi/locale/hu/LC_MESSAGES/voice.po",
"chars": 5648,
"preview": "# Hungarian translation.\n# Copyright (C) 2020\n# This file is distributed under the same license as the PACKAGE package.\n"
},
{
"path": "pwnagotchi/locale/it/LC_MESSAGES/voice.po",
"chars": 4815,
"preview": "# pwnaigotchi voice data\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi packag"
},
{
"path": "pwnagotchi/locale/jp/LC_MESSAGES/voice.po",
"chars": 5166,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "pwnagotchi/locale/mk/LC_MESSAGES/voice.po",
"chars": 4732,
"preview": "# pwnigotchi voice data\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi package"
},
{
"path": "pwnagotchi/locale/nl/LC_MESSAGES/voice.po",
"chars": 4942,
"preview": "# pwnigotchi voice data\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi package"
},
{
"path": "pwnagotchi/locale/no/LC_MESSAGES/voice.po",
"chars": 5607,
"preview": "# pwnagotchi norwegian voice data\n# Copyright (C) 2019\n# This file is distributed under the same license as the PACKAGE "
},
{
"path": "pwnagotchi/locale/pl/LC_MESSAGES/voice.po",
"chars": 5705,
"preview": "# Polish voice data for pwnagotchi.\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnago"
},
{
"path": "pwnagotchi/locale/pt/LC_MESSAGES/voice.po",
"chars": 4950,
"preview": "# pwnagotchi Portuguese (european) translation file.\n# Copyright (C) 2019 David Sopas\n# This file is distributed under t"
},
{
"path": "pwnagotchi/locale/pt-BR/LC_MESSAGES/voice.po",
"chars": 4922,
"preview": "# pwnagotchi Brazilian Portuguese translation file.\n# Copyright (C) 2019 Cassiano Aquino\n# This file is distributed unde"
},
{
"path": "pwnagotchi/locale/ro/LC_MESSAGES/voice.po",
"chars": 5818,
"preview": "# Pwnagotchi translation.\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi packa"
},
{
"path": "pwnagotchi/locale/ru/LC_MESSAGES/voice.po",
"chars": 5688,
"preview": "# Pwnagotchi Russian translation.\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotc"
},
{
"path": "pwnagotchi/locale/se/LC_MESSAGES/voice.po",
"chars": 4690,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "pwnagotchi/locale/sk/LC_MESSAGES/voice.po",
"chars": 5153,
"preview": "# Slovak language\n# Copyright (C) 2019\n# This file is distributed under the same license as the pwnagotchi package.\n# mi"
},
{
"path": "pwnagotchi/locale/spa/LC_MESSAGES/voice.po",
"chars": 5754,
"preview": "# Interfaz en español para pwnagotchi\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed und"
},
{
"path": "pwnagotchi/locale/tr/LC_MESSAGES/voice.po",
"chars": 5746,
"preview": "# Pwnagotchi Turkish translation.\n# Copyright (C) 2021\n# This file is distributed under the same license as the PACKAGE "
},
{
"path": "pwnagotchi/locale/tw/LC_MESSAGES/voice.po",
"chars": 4607,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "pwnagotchi/locale/ua/LC_MESSAGES/voice.po",
"chars": 5272,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "pwnagotchi/locale/voice.pot",
"chars": 4142,
"preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
},
{
"path": "pwnagotchi/log.py",
"chars": 10792,
"preview": "import hashlib\nimport time\nimport re\nimport os\nimport logging\nimport shutil\nimport gzip\nimport warnings\nfrom datetime im"
},
{
"path": "pwnagotchi/mesh/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/mesh/peer.py",
"chars": 2848,
"preview": "import time\nimport logging\nimport datetime\n\nimport pwnagotchi.ui.faces as faces\n\n\ndef parse_rfc3339(dt):\n if dt == \"0"
},
{
"path": "pwnagotchi/mesh/utils.py",
"chars": 3868,
"preview": "import _thread\nimport logging\nimport time\n\nimport pwnagotchi\nimport pwnagotchi.utils as utils\nimport pwnagotchi.ui.faces"
},
{
"path": "pwnagotchi/mesh/wifi.py",
"chars": 340,
"preview": "NumChannels = 140\nNumChannelsExt = 165 # see https://github.com/evilsocket/pwnagotchi/issues/583\n\n\ndef freq_to_channel("
},
{
"path": "pwnagotchi/plugins/__init__.py",
"chars": 4677,
"preview": "import os\nimport glob\nimport _thread\nimport threading\nimport importlib, importlib.util\nimport logging\n\n\n\ndefault_path = "
},
{
"path": "pwnagotchi/plugins/cmd.py",
"chars": 13081,
"preview": "# Handles the commandline stuff\n\nimport os\nimport logging\nimport glob\nimport re\nimport shutil\nfrom fnmatch import fnmatc"
},
{
"path": "pwnagotchi/plugins/default/auto-update.py",
"chars": 8040,
"preview": "import os\nimport re\nimport logging\nimport subprocess\nimport requests\nimport platform\nimport shutil\nimport glob\nfrom thre"
},
{
"path": "pwnagotchi/plugins/default/bt-tether.py",
"chars": 19471,
"preview": "import logging\nimport os\nimport subprocess\nimport time\nfrom threading import Lock\n\nimport dbus\n\nimport pwnagotchi.plugin"
},
{
"path": "pwnagotchi/plugins/default/example.py",
"chars": 5061,
"preview": "import logging\n\nimport pwnagotchi.plugins as plugins\nfrom pwnagotchi.ui.components import LabeledValue\nfrom pwnagotchi.u"
},
{
"path": "pwnagotchi/plugins/default/gpio_buttons.py",
"chars": 1252,
"preview": "import logging\nimport RPi.GPIO as GPIO\nimport subprocess\nimport pwnagotchi.plugins as plugins\n\n\nclass GPIOButtons(plugin"
},
{
"path": "pwnagotchi/plugins/default/gps.py",
"chars": 5584,
"preview": "import json\nimport logging\nimport os\n\nimport pwnagotchi.plugins as plugins\nimport pwnagotchi.ui.fonts as fonts\nfrom pwna"
},
{
"path": "pwnagotchi/plugins/default/grid.py",
"chars": 5232,
"preview": "import os\nimport logging\nimport time\nimport glob\nimport re\n\nimport pwnagotchi.grid as grid\nimport pwnagotchi.plugins as "
},
{
"path": "pwnagotchi/plugins/default/led.py",
"chars": 5320,
"preview": "from threading import Event\nimport _thread\nimport logging\nimport time\n\nimport pwnagotchi.plugins as plugins\n\n\nclass Led("
},
{
"path": "pwnagotchi/plugins/default/logtail.py",
"chars": 7296,
"preview": "import os\nimport logging\nimport threading\nfrom itertools import islice\nfrom time import sleep\nfrom datetime import datet"
},
{
"path": "pwnagotchi/plugins/default/memtemp.py",
"chars": 6625,
"preview": "# memtemp shows memory infos and cpu temperature\n#\n# mem usage, cpu load, cpu temp, cpu frequency\n#\n####################"
},
{
"path": "pwnagotchi/plugins/default/net-pos.py",
"chars": 6178,
"preview": "import logging\nimport json\nimport os\nimport threading\nimport requests\nimport time\nimport pwnagotchi.plugins as plugins\nf"
},
{
"path": "pwnagotchi/plugins/default/onlinehashcrack.py",
"chars": 6638,
"preview": "import os\nimport csv\nimport logging\nimport re\nimport requests\nfrom datetime import datetime\nfrom threading import Lock\nf"
},
{
"path": "pwnagotchi/plugins/default/paw-gps.py",
"chars": 1815,
"preview": "import logging\nimport requests\nimport pwnagotchi.plugins as plugins\n\n'''\nYou need an bluetooth connection to your androi"
},
{
"path": "pwnagotchi/plugins/default/session-stats.py",
"chars": 8503,
"preview": "import os\nimport logging\nimport threading\nfrom time import sleep\nfrom datetime import datetime,timedelta\nfrom pwnagotchi"
},
{
"path": "pwnagotchi/plugins/default/switcher.py",
"chars": 4922,
"preview": "import os\nimport logging\nfrom threading import Lock\nfrom functools import partial\nfrom pwnagotchi import plugins\nfrom pw"
},
{
"path": "pwnagotchi/plugins/default/ups_lite.py",
"chars": 2923,
"preview": "# Based on UPS Lite v1.1 from https://github.com/xenDE\n#\n# functions for get UPS status - needs enable \"i2c\" in raspi-co"
},
{
"path": "pwnagotchi/plugins/default/watchdog.py",
"chars": 1303,
"preview": "import os\nimport logging\nimport re\nimport subprocess\nfrom io import TextIOWrapper\nfrom pwnagotchi import plugins\n\n\nclass"
},
{
"path": "pwnagotchi/plugins/default/webcfg.py",
"chars": 16788,
"preview": "import logging\nimport json\nimport toml\nimport _thread\nfrom pwnagotchi import restart, plugins\nfrom pwnagotchi.utils impo"
},
{
"path": "pwnagotchi/plugins/default/webgpsmap.html",
"chars": 16205,
"preview": "<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/xml; charset=utf-8\" />\n <title>GPS MAP</title>\n <link re"
},
{
"path": "pwnagotchi/plugins/default/webgpsmap.py",
"chars": 16656,
"preview": "import pwnagotchi.plugins as plugins\nimport logging\nimport os\nimport json\nimport re\nimport datetime\nfrom flask import Re"
},
{
"path": "pwnagotchi/plugins/default/wigle.py",
"chars": 8319,
"preview": "import os\nimport logging\nimport json\nimport csv\nimport requests\n\nfrom io import StringIO\nfrom datetime import datetime\nf"
},
{
"path": "pwnagotchi/plugins/default/wpa-sec.py",
"chars": 6044,
"preview": "import os\nimport logging\nimport requests\nfrom datetime import datetime\nfrom threading import Lock\nfrom pwnagotchi.utils "
},
{
"path": "pwnagotchi/ui/__init__.py",
"chars": 1,
"preview": "\n"
},
{
"path": "pwnagotchi/ui/components.py",
"chars": 2351,
"preview": "from PIL import Image\nfrom textwrap import TextWrapper\n\n\nclass Widget(object):\n def __init__(self, xy, color=0):\n "
},
{
"path": "pwnagotchi/ui/display.py",
"chars": 3826,
"preview": "import os\nimport logging\nimport threading\n\nimport pwnagotchi.plugins as plugins\nimport pwnagotchi.ui.hw as hw\nfrom pwnag"
},
{
"path": "pwnagotchi/ui/faces.py",
"chars": 594,
"preview": "LOOK_R = '( ⚆_⚆)'\nLOOK_L = '(☉_☉ )'\nLOOK_R_HAPPY = '( ◕‿◕)'\nLOOK_L_HAPPY = '(◕‿◕ )'\nSLEEP = '(⇀‿‿↼)'\nSLEEP2 = '(≖‿‿≖)'\nA"
},
{
"path": "pwnagotchi/ui/fonts.py",
"chars": 1058,
"preview": "from PIL import ImageFont\n\n# should not be changed\nFONT_NAME = 'DejaVuSansMono'\n\n# can be changed\nSTATUS_FONT_NAME = Non"
},
{
"path": "pwnagotchi/ui/hw/__init__.py",
"chars": 2948,
"preview": "from pwnagotchi.ui.hw.inky import Inky\nfrom pwnagotchi.ui.hw.papirus import Papirus\nfrom pwnagotchi.ui.hw.oledhat import"
},
{
"path": "pwnagotchi/ui/hw/adafruitssd1306i2c.py",
"chars": 1472,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass AdafruitSSD130"
},
{
"path": "pwnagotchi/ui/hw/base.py",
"chars": 1014,
"preview": "import pwnagotchi.ui.fonts as fonts\n\n\nclass DisplayImpl(object):\n def __init__(self, config, name):\n self.name"
},
{
"path": "pwnagotchi/ui/hw/dfrobot1.py",
"chars": 1273,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\nclass DFRobotV1(Displ"
},
{
"path": "pwnagotchi/ui/hw/dfrobot2.py",
"chars": 1273,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\nclass DFRobotV2(Displ"
},
{
"path": "pwnagotchi/ui/hw/inky.py",
"chars": 3172,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass Inky(DisplayIm"
},
{
"path": "pwnagotchi/ui/hw/lcdhat.py",
"chars": 1392,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass LcdHat(Display"
},
{
"path": "pwnagotchi/ui/hw/libs/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/adafruit/adafruitssd1306i2c/SSD1306.py",
"chars": 9766,
"preview": "# Adaption of the Python driver for 0.96\" 128*64 i2c OLED displays,\n# based on the Adafruit driver without using any Ada"
},
{
"path": "pwnagotchi/ui/hw/libs/adafruit/adafruitssd1306i2c/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/adafruit/adafruitssd1306i2c/epd.py",
"chars": 619,
"preview": "from . import SSD1306\n\nRST = 24\n\ndisp = SSD1306.SSD1306_128_64(rst=RST, i2c_bus=1, i2c_address=0x3C)\n\nclass EPD(object):"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/LICENSE",
"chars": 26526,
"preview": " GNU LESSER GENERAL PUBLIC LICENSE\n Version 2.1, February 1999\n\n Copyright (C) 19"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v1/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v1/dfrobot.py",
"chars": 1769,
"preview": "# DFRobot display support\n\nimport logging\nfrom . import dfrobot_epaper\n\n#Resolution of display\nWIDTH = 250\nHEIGHT = 122\n"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v1/dfrobot_epaper.py",
"chars": 5984,
"preview": "# -*- coding:utf-8 -*-\n\nimport time\n\nimport sys\nsys.path.append(\"..\")\n\n\ntry:\n from .spi import SPI\n from .gpio import "
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v1/gpio.py",
"chars": 1528,
"preview": "# -*- coding:utf-8 -*-\n\nimport time\nimport RPi.GPIO as RPIGPIO\n\nRPIGPIO.setmode(RPIGPIO.BCM)\nRPIGPIO.setwarnings(False)\n"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v1/spi.py",
"chars": 383,
"preview": "# -*- coding:utf-8 -*-\n\nimport spidev\n\nclass SPI:\n\n MODE_1 = 1\n MODE_2 = 2\n MODE_3 = 3\n MODE_4 = 4\n\n def __init__(s"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot.py",
"chars": 1769,
"preview": "# DFRobot display support\n\nimport logging\nfrom . import dfrobot_epaper\n\n#Resolution of display\nWIDTH = 250\nHEIGHT = 122\n"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/dfrobot_display.py",
"chars": 20645,
"preview": "# -*- coding:utf-8 -*-\n\nimport sys\n\nfrom .dfrobot_printString import PrintString\nfrom .dfrobot_fonts import Fonts\n\ndef c"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/dfrobot_fonts.py",
"chars": 1782,
"preview": "# -*- coding:utf-8 -*-\n\nimport json\n\nclass Fonts:\n\n def __init__(self):\n self._haveFontsABC = False\n self._fontsA"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_display/dfrobot_printString.py",
"chars": 388,
"preview": "# -*- coding:utf-8 -*-\n\nimport sys\n\nclass PrintString:\n\n def __init__(self):\n pass\n\n def writeOneChar(self, ch):\n "
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/dfrobot_epaper.py",
"chars": 8053,
"preview": "# -*- coding:utf-8 -*-\n\nimport time\n\nimport sys\nsys.path.append(\"..\")\nimport RPi.GPIO as RPIGPIO\nfrom .dfrobot_display.d"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/fonts_6_8.py",
"chars": 3988,
"preview": "fonts = { # left to right, msb to bottom, lsb to top\n \" \": [0x00,0x00,0x00,0x00,0x00,0x00], \n \"!\": [0x00,0x00,0x5F,0x"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/fonts_8_16.py",
"chars": 8730,
"preview": "fonts = { # top to bottom, msb left, lsb right\n \" \": [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/freetype_helper.py",
"chars": 2442,
"preview": "# -*- coding:utf-8 -*-\n\n'''\ndepends: freetype-py\n'''\n\nimport freetype\nimport math\n#import sys\n\n#reload(sys)\n#sys.setdefa"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/display_extension/readme.md",
"chars": 126,
"preview": "wqydkzh.ttf = 文泉驿等宽正黑.ttf GPL2 license </br>\nzkklt.ttf = 站酷快乐体.ttf Chinese open source fonts file, use with freetype_hel"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/gpio.py",
"chars": 1528,
"preview": "# -*- coding:utf-8 -*-\n\nimport time\nimport RPi.GPIO as RPIGPIO\n\nRPIGPIO.setmode(RPIGPIO.BCM)\nRPIGPIO.setwarnings(False)\n"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/i2c.py",
"chars": 427,
"preview": "# -*- coding:utf-8 -*-\n\n'''\nchange i2c frequency on raspberry:\n 1. edit /etc/modprobe.d\n 2. add line: \n options i2c"
},
{
"path": "pwnagotchi/ui/hw/libs/dfrobot/v2/spi.py",
"chars": 379,
"preview": "# -*- coding:utf-8 -*-\n\nimport spidev\n\nclass SPI:\n\n MODE_1 = 1\n MODE_2 = 2\n MODE_3 = 3\n MODE_4 = 4\n\n def __init__(s"
},
{
"path": "pwnagotchi/ui/hw/libs/fb/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/fb/fb.py",
"chars": 3905,
"preview": "FBIOGET_VSCREENINFO=0x4600\nFBIOPUT_VSCREENINFO=0x4601\nFBIOGET_FSCREENINFO=0x4602\nFBIOGETCMAP=0x4604\nFBIOPUTCMAP=0x4605\nF"
},
{
"path": "pwnagotchi/ui/hw/libs/inkyphat/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/inkyphat/inkyfast.py",
"chars": 1334,
"preview": "from inky.inky import Inky, CS0_PIN, DC_PIN, RESET_PIN, BUSY_PIN\n\n\nclass InkyFast(Inky):\n\n def __init__(self, resolut"
},
{
"path": "pwnagotchi/ui/hw/libs/inkyphat/inkyphatfast.py",
"chars": 574,
"preview": "\"\"\"Inky pHAT e-Ink Display Driver.\"\"\"\nfrom . import inkyfast\n\n\nclass InkyPHATFast(inkyfast.InkyFast):\n \"\"\"Inky wHAT e"
},
{
"path": "pwnagotchi/ui/hw/libs/papirus/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/papirus/epd.py",
"chars": 5909,
"preview": "#qCopyright 2013-2015 Pervasive Displays, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you"
},
{
"path": "pwnagotchi/ui/hw/libs/papirus/lm75b.py",
"chars": 1585,
"preview": "# Minimal support for LM75b temperature sensor on the Papirus HAT / Papirus Zero\n# This module allows you to read the te"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/lcdhat/ST7789.py",
"chars": 4858,
"preview": "import spidev\r\nimport RPi.GPIO as GPIO\r\nimport time\r\nimport numpy as np\r\n\r\n\r\nclass ST7789(object):\r\n \"\"\"class for ST7"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/lcdhat/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/lcdhat/config.py",
"chars": 503,
"preview": "# /*****************************************************************************\n# * | File : config.py\n# * | A"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/lcdhat/epd.py",
"chars": 519,
"preview": "from . import ST7789\nfrom . import config\n\n\nclass EPD(object):\n def __init__(self):\n self.reset_pin = config.R"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/lcdhat144/LCD_1in44.py",
"chars": 9916,
"preview": " # -*- coding:UTF-8 -*-\n ##\n # | file \t:\tLCD_1IN44.py\n # |\tversion\t\t:\tV2.0\n # | date\t\t:\t2018-07-16\n # | function\t:\t"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/lcdhat144/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/lcdhat144/config.py",
"chars": 2390,
"preview": "# /*****************************************************************************\n# * | File : config.py\n# * | A"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/lcdhat144/epd.py",
"chars": 850,
"preview": "# Waveshare 1.44inch LCD HAT\n# https://www.waveshare.com/1.44inch-lcd-hat.htm\n# https://www.waveshare.com/wiki/1.44inch_"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/oledhat/SH1106.py",
"chars": 5037,
"preview": "from . import config\nimport RPi.GPIO as GPIO\nimport time\n\nDevice_SPI = config.Device_SPI\nDevice_I2C = config.Device_I2C\n"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/oledhat/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/oledhat/config.py",
"chars": 3099,
"preview": "# /*****************************************************************************\n# * | File :\t config.py\n# * | A"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/oledhat/epd.py",
"chars": 553,
"preview": "from . import SH1106\nfrom . import config\n\n# Display resolution\nEPD_WIDTH = 64\nEPD_HEIGHT = 128\n\ndisp = SH110"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v1/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v1/epd2in13.py",
"chars": 8073,
"preview": "# *****************************************************************************\n# * | File :\t epd2in13.py\n# * | "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v1/epd2in13bc.py",
"chars": 5896,
"preview": "# *****************************************************************************\n# * | File :\t epd2in13bc.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v1/epd2in13bcFAST.py",
"chars": 12546,
"preview": "# *****************************************************************************\n# * | File :\t epd2in13d.py\n# * |"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v1/epdconfig.py",
"chars": 4863,
"preview": "# /*****************************************************************************\n# * | File :\t epdconfig.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v154inch/epd1in54b.py",
"chars": 8578,
"preview": "# *****************************************************************************\n# * | File :\t epd1in54b.py\n# * |"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v154inch/epdconfig.py",
"chars": 4852,
"preview": "# /*****************************************************************************\n# * | File :\t epdconfig.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v2/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v2/waveshare.py",
"chars": 11417,
"preview": "# //*****************************************************************************\r\n# * | File :\t epd2in13.py\r\n# "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v213bc/epd2in13bc.py",
"chars": 13015,
"preview": "# *****************************************************************************\n# * | File :\t epd2in13bc.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v213bc/epdconfig.py",
"chars": 4852,
"preview": "# /*****************************************************************************\n# * | File :\t epdconfig.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v213d/epd2in13d.py",
"chars": 12194,
"preview": "# *****************************************************************************\n# * | File :\t epd2in13d.py\n# * |"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v213d/epdconfig.py",
"chars": 4852,
"preview": "# /*****************************************************************************\n# * | File :\t epdconfig.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v213inb_v4/epd2in13b_V4.py",
"chars": 6527,
"preview": "# *****************************************************************************\n# * | File :\t epd2in13b_V4.py\n# "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v213inb_v4/epdconfig.py",
"chars": 6917,
"preview": "# /*****************************************************************************\n# * | File :\t epdconfig.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v27inch/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v27inch/epd2in7.py",
"chars": 18311,
"preview": "# *****************************************************************************\n# * | File :\t epd2in7.py\n# * | A"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v27inch/epdconfig.py",
"chars": 4853,
"preview": "# /*****************************************************************************\n# * | File :\t epdconfig.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v29inch/epd2in9.py",
"chars": 7737,
"preview": "# *****************************************************************************\n# * | File :\t epd2in9.py\n# * | A"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v29inch/epdconfig.py",
"chars": 4852,
"preview": "# /*****************************************************************************\n# * | File :\t epdconfig.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v3/epd2in13_V3.py",
"chars": 12502,
"preview": "# *****************************************************************************\n# * | File :\t epd2in13_V3.py\n# *"
},
{
"path": "pwnagotchi/ui/hw/libs/waveshare/v3/epdconfig.py",
"chars": 4852,
"preview": "# /*****************************************************************************\n# * | File :\t epdconfig.py\n# * "
},
{
"path": "pwnagotchi/ui/hw/oledhat.py",
"chars": 1385,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass OledHat(Displa"
},
{
"path": "pwnagotchi/ui/hw/papirus.py",
"chars": 1439,
"preview": "import logging\nimport os\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass Papi"
},
{
"path": "pwnagotchi/ui/hw/spotpear24inch.py",
"chars": 1548,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\nimport os,time\n\nclass"
},
{
"path": "pwnagotchi/ui/hw/waveshare1.py",
"chars": 3668,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass WaveshareV1(Di"
},
{
"path": "pwnagotchi/ui/hw/waveshare144lcd.py",
"chars": 1449,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass Waveshare144lc"
},
{
"path": "pwnagotchi/ui/hw/waveshare154inch.py",
"chars": 1500,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass Waveshare154in"
},
{
"path": "pwnagotchi/ui/hw/waveshare2.py",
"chars": 2544,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass WaveshareV2(Di"
},
{
"path": "pwnagotchi/ui/hw/waveshare213bc.py",
"chars": 1489,
"preview": "import logging\n\nimport pwnagotchi.ui.fonts as fonts\nfrom pwnagotchi.ui.hw.base import DisplayImpl\n\n\nclass Waveshare213bc"
}
]
// ... and 106 more files (download for full content)
About this extraction
This page contains the full source code of the evilsocket/pwnagotchi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 306 files (3.4 MB), approximately 914.0k tokens, and a symbol index with 1603 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.