Files
pwnagotchi_plugins/age.py
AlienMajik ad6088f14f Update age.py
Pwnagotchi Age Plugin v2.0.1 - New Features and Enhancements!

Release Notes: Version 2.0.1 of the Pwnagotchi Age Plugin has just dropped! Here's what's new:

    Achievement Tiers: Unlock titles based on your activity. Titles like WiFi Deity, Handshake Titan, and Unstoppable await!
    Configurable Titles: You can now define custom titles for Age and Strength.
    Decay Mechanics: Inactivity will cause points decay—stay active or risk losing points!
    Progress Tracking: Track your network points and handshakes using a star system. Reach milestones and gain rewards!
    UI Enhancements: New dynamic status updates with motivational messages and faces that show up when you level up!

edit config.toml file: 

main.plugins.age.enabled = true
main.plugins.age.age_x_coord = 101
main.plugins.age.age_y_coord = 80
main.plugins.age.str_x_coord = 160
main.plugins.age.str_y_coord = 80
main.plugins.age.decay_interval = 50
main.plugins.age.decay_amount = 5
2025-02-01 18:08:59 -08:00

283 lines
10 KiB
Python

import os
import json
import logging
import time
import pwnagotchi
import pwnagotchi.plugins as plugins
import pwnagotchi.ui.faces as faces
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.components import LabeledValue
from pwnagotchi.ui.view import BLACK
class Age(plugins.Plugin):
__author__ = 'AlienMajik'
__version__ = '2.0.1'
__license__ = 'MIT'
__description__ = 'Enhanced plugin with achievement tiers, configurable titles, decay mechanics, and progress tracking.'
DEFAULT_AGE_TITLES = {
500: "Newborn",
1000: "Script Kiddie",
2000: "WiFi Hobo",
5000: "Packet Wizard",
10000: "Elder Hacker",
33333: "WiFi Deity"
}
DEFAULT_STRENGTH_TITLES = {
500: "Weakling",
1000: "Lightweight",
2000: "Deauth King",
5000: "Handshake Titan",
20000: "Unstoppable"
}
def __init__(self):
# Default positions (x, y)
self.default_positions = {
'age': (10, 40),
'strength': (80, 40),
'points': (10, 60),
'stars': (10, 80)
}
self.epochs = 0
self.train_epochs = 0
self.network_points = 0
self.handshake_count = 0
self.last_active_epoch = 0
self.data_path = '/root/age_strength.json'
self.log_path = '/root/network_points.log'
self.handshake_dir = '/home/pi/handshakes'
# Configurable settings with defaults
self.max_stars = 5
self.star_interval = 1000
self.decay_interval = 50
self.decay_amount = 10
self.age_titles = self.DEFAULT_AGE_TITLES
self.strength_titles = self.DEFAULT_STRENGTH_TITLES
def on_loaded(self):
# Load configuration with fallbacks
self.max_stars = self.options.get('max_stars', 5)
self.star_interval = self.options.get('star_interval', 1000)
self.decay_interval = self.options.get('decay_interval', 50)
self.decay_amount = self.options.get('decay_amount', 10)
self.age_titles = self.options.get('age_titles', self.DEFAULT_AGE_TITLES)
self.strength_titles = self.options.get('strength_titles', self.DEFAULT_STRENGTH_TITLES)
self.load_data()
self.initialize_handshakes()
def initialize_handshakes(self):
if self.handshake_count == 0 and os.path.isdir(self.handshake_dir):
existing = [f for f in os.listdir(self.handshake_dir) if f.endswith('.pcap')]
if existing:
self.handshake_count = len(existing)
logging.info(f"[Age] Initialized with {self.handshake_count} handshakes")
self.save_data()
def get_age_title(self):
thresholds = sorted(self.age_titles.keys(), reverse=True)
for t in thresholds:
if self.epochs >= t:
return self.age_titles[t]
return "Unborn"
def get_strength_title(self):
thresholds = sorted(self.strength_titles.keys(), reverse=True)
for t in thresholds:
if self.train_epochs >= t:
return self.strength_titles[t]
return "Untrained"
def check_achievements(self, agent):
current_age = self.get_age_title()
current_strength = self.get_strength_title()
if current_age != self.prev_age_title:
agent.view().set('face', faces.HAPPY)
agent.view().set('status', f"Promoted to {current_age}!")
self.prev_age_title = current_age
if current_strength != self.prev_strength_title:
agent.view().set('face', faces.MOTIVATED)
agent.view().set('status', f"Evolved to {current_strength}!")
self.prev_strength_title = current_strength
def apply_decay(self, agent):
inactive_epochs = self.epochs - self.last_active_epoch
if inactive_epochs >= self.decay_interval:
decay_cycles = inactive_epochs // self.decay_interval
points_lost = decay_cycles * self.decay_amount
self.network_points = max(0, self.network_points - points_lost)
if points_lost > 0:
agent.view().set('face', faces.SAD)
agent.view().set('status', f"Inactivity decay: -{points_lost} points!")
self.last_active_epoch = self.epochs
self.save_data()
def on_ui_setup(self, ui):
def get_position(element):
x = self.options.get(
f"{element}_x",
self.options.get(
f"{element}_x_coord", # Backwards compatibility
self.default_positions[element][0]
)
)
y = self.options.get(
f"{element}_y",
self.options.get(
f"{element}_y_coord", # Backwards compatibility
self.default_positions[element][1]
)
)
return (int(x), int(y))
positions = {
'age': get_position('age'),
'strength': get_position('strength'),
'points': get_position('points'),
'stars': get_position('stars')
}
ui.add_element('Age', LabeledValue(
color=BLACK, label='Age', value="Newborn",
position=positions['age'], label_font=fonts.Bold, text_font=fonts.Medium))
ui.add_element('Strength', LabeledValue(
color=BLACK, label='Str', value="Rookie",
position=positions['strength'], label_font=fonts.Bold, text_font=fonts.Medium))
ui.add_element('Points', LabeledValue(
color=BLACK, label='★ Pts', value="0",
position=positions['points'], label_font=fonts.Bold, text_font=fonts.Medium))
ui.add_element('ReP', LabeledValue(
color=BLACK, label='ReP', value="",
position=positions['stars'], label_font=fonts.Bold, text_font=fonts.Medium))
def on_ui_update(self, ui):
ui.set('Age', self.get_age_title())
ui.set('Strength', self.get_strength_title())
ui.set('Points', self.abrev_number(self.network_points))
ui.set('ReP', self.get_star_string())
# Modified Event Handlers
def on_epoch(self, agent, epoch, epoch_data):
self.epochs += 1
self.train_epochs += 1 if self.epochs % 10 == 0 else 0
self.apply_decay(agent)
self.check_achievements(agent)
if self.epochs % 100 == 0:
self.age_checkpoint(agent)
self.save_data()
def on_handshake(self, agent, *args):
self.last_active_epoch = self.epochs
enc = args[2].get('encryption', '').lower()
points = {
'wpa3': 10, 'wpa2': 5,
'wep': 2, 'wpa': 2
}.get(enc, 1)
self.network_points += points
self.handshake_count += 1
# Log details
with open(self.log_path, 'a') as f:
essid = args[2].get('essid', 'unknown')
f.write(f"{time.time()},{essid},{enc},{points}\n")
self.new_star_checkpoint(agent)
self.save_data()
# Star System
def new_star_checkpoint(self, agent):
stars = self.get_stars_count()
if stars > self.prev_stars:
symbol = self.get_symbol_for_handshakes()
agent.view().set('face', faces.EXCITED)
agent.view().set('status', f"New {symbol} Tier Achieved!")
self.prev_stars = stars
# Data Management
def load_data(self):
try: # <- Added indentation here
if os.path.exists(self.data_path):
with open(self.data_path, 'r') as f:
data = json.load(f)
# Handle old format compatibility
self.epochs = data.get('epochs', data.get('epochs_lived', 0))
self.train_epochs = data.get('train_epochs', data.get('epochs_trained', 0))
self.network_points = data.get('points', data.get('network_points', 0))
self.handshake_count = data.get('handshakes', data.get('handshake_count', 0))
# New fields with defaults
self.last_active_epoch = data.get('last_active', 0)
self.prev_age_title = data.get('prev_age', self.get_age_title())
self.prev_strength_title = data.get('prev_strength', self.get_strength_title())
self.prev_stars = data.get('prev_stars', self.get_stars_count())
# Migrate old format to new format
if 'epochs_lived' in data:
self.save_data() # Resave in new format
logging.info("[Age] Migrated old data format to new format")
except Exception as e:
logging.error(f"[Age] Load error: {str(e)}")
def save_data(self):
data = { # <- Added indentation here
# New format keys
'epochs': self.epochs,
'train_epochs': self.train_epochs,
'points': self.network_points,
'handshakes': self.handshake_count,
# Old format aliases for compatibility
'epochs_lived': self.epochs,
'epochs_trained': self.train_epochs,
'network_points': self.network_points,
'handshake_count': self.handshake_count,
# New fields
'last_active': self.last_active_epoch,
'prev_age': self.get_age_title(),
'prev_strength': self.get_strength_title(),
'prev_stars': self.get_stars_count()
}
try:
with open(self.data_path, 'w') as f:
json.dump(data, f, indent=2)
except Exception as e:
logging.error(f"[Age] Save error: {str(e)}")
# Helper Methods
def get_stars_count(self):
return min(self.handshake_count // self.star_interval, self.max_stars)
def get_symbol_for_handshakes(self):
return '' if self.handshake_count >= 10000 else '' if self.handshake_count >= 5000 else ''
def get_star_string(self):
return self.get_symbol_for_handshakes() * self.get_stars_count()
def abrev_number(self, num):
for unit in ['','K','M','B']:
if abs(num) < 1000:
return f"{num:.1f}{unit}".rstrip('.0')
num /= 1000.0
return f"{num:.1f}T"