mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2025-07-01 18:37:27 -04:00
Merge branch 'master' into display-fix
This commit is contained in:
@ -1,9 +1,45 @@
|
||||
# main algorithm configuration
|
||||
main:
|
||||
# currently implemented: en (default), de, nl, it
|
||||
# currently implemented: en (default), de, el, fr, it, mk, nl, se
|
||||
lang: en
|
||||
# custom plugins path, if null only default plugins with be loaded
|
||||
plugins: null
|
||||
custom_plugins:
|
||||
# which plugins to load and enable
|
||||
plugins:
|
||||
auto-update:
|
||||
enabled: false
|
||||
interval: 1 # every day
|
||||
auto-backup:
|
||||
enabled: false
|
||||
interval: 1 # every day
|
||||
files:
|
||||
- /root/brain.nn
|
||||
- /root/brain.json
|
||||
- /root/custom.yaml
|
||||
- /root/handshakes
|
||||
- /etc/ssh
|
||||
- /etc/hostname
|
||||
- /etc/hosts
|
||||
- /etc/motd
|
||||
- /var/log/pwnagotchi.log
|
||||
commands:
|
||||
- 'tar czf /tmp/backup.tar.gz {files}'
|
||||
- 'scp /tmp/backup.tar.gz pwnagotchi@10.0.0.1:/home/pwnagotchi/backups/backup-$(date).tar.gz'
|
||||
gps:
|
||||
enabled: false
|
||||
twitter:
|
||||
enabled: false
|
||||
consumer_key: aaa
|
||||
consumer_secret: aaa
|
||||
access_token_key: aaa
|
||||
access_token_secret: aaa
|
||||
onlinehashcrack:
|
||||
enabled: false
|
||||
email: ~
|
||||
wpa-sec:
|
||||
enabled: false
|
||||
api_key: ~
|
||||
|
||||
# monitor interface to use
|
||||
iface: mon0
|
||||
# command to run to bring the mon interface up in case it's not up already
|
||||
@ -15,7 +51,9 @@ main:
|
||||
# if true, will not restart the wifi module
|
||||
no_restart: false
|
||||
# access points to ignore
|
||||
whitelist: []
|
||||
whitelist:
|
||||
- EXAMPLE_NETWORK
|
||||
- ANOTHER_EXAMPLE_NETWORK
|
||||
# if not null, filter access points by this regular expression
|
||||
filter: null
|
||||
# cryptographic key for identity
|
||||
@ -23,7 +61,7 @@ main:
|
||||
|
||||
ai:
|
||||
# if false, only the default 'personality' will be used
|
||||
enabled: false
|
||||
enabled: true
|
||||
path: /root/brain.nn
|
||||
# 1.0 - laziness = probability of start training
|
||||
laziness: 0.1
|
||||
@ -95,7 +133,7 @@ ui:
|
||||
# IMPORTANT: The lifespan of an eINK display depends on the cumulative amount of refreshes. If you want to
|
||||
# preserve your display over time, you should set this value to 0.0 so that the display will be refreshed only
|
||||
# if any of the important data fields changed (the uptime and blinking cursor won't trigger a refresh).
|
||||
fps: 0.3
|
||||
fps: 0.0
|
||||
display:
|
||||
enabled: true
|
||||
rotation: 180
|
||||
@ -108,13 +146,6 @@ ui:
|
||||
address: '10.0.0.2'
|
||||
port: 8080
|
||||
|
||||
# twitter bot data
|
||||
twitter:
|
||||
enabled: false
|
||||
consumer_key: aaa
|
||||
consumer_secret: aaa
|
||||
access_token_key: aaa
|
||||
access_token_secret: aaa
|
||||
|
||||
# bettercap rest api configuration
|
||||
bettercap:
|
||||
@ -143,6 +174,3 @@ bettercap:
|
||||
- wifi.ap.new
|
||||
- wifi.ap.lost
|
||||
- mod.started
|
||||
|
||||
|
||||
|
||||
|
@ -1,65 +0,0 @@
|
||||
import sys
|
||||
import glob
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
from threading import Lock
|
||||
from datetime import datetime
|
||||
|
||||
logfile = None
|
||||
loglock = Lock()
|
||||
|
||||
|
||||
def log(msg):
|
||||
tstamp = str(datetime.now())
|
||||
line = "[%s] %s" % (tstamp, msg.rstrip())
|
||||
print(line)
|
||||
sys.stdout.flush()
|
||||
if logfile is not None:
|
||||
with loglock:
|
||||
with open(logfile, 'a+t') as fp:
|
||||
fp.write("%s\n" % line)
|
||||
|
||||
|
||||
def secs_to_hhmmss(secs):
|
||||
mins, secs = divmod(secs, 60)
|
||||
hours, mins = divmod(mins, 60)
|
||||
return '%02d:%02d:%02d' % (hours, mins, secs)
|
||||
|
||||
|
||||
def total_unique_handshakes(path):
|
||||
expr = os.path.join(path, "*.pcap")
|
||||
return len(glob.glob(expr))
|
||||
|
||||
|
||||
def iface_address(ifname):
|
||||
output = subprocess.getoutput("/usr/sbin/ifconfig %s" % ifname)
|
||||
for line in output.split("\n"):
|
||||
line = line.strip()
|
||||
if line.startswith("inet "):
|
||||
return line.split(' ')[1].strip()
|
||||
return None
|
||||
|
||||
|
||||
def iface_channels(ifname):
|
||||
channels = []
|
||||
output = subprocess.getoutput("/sbin/iwlist %s freq" % ifname)
|
||||
for line in output.split("\n"):
|
||||
line = line.strip()
|
||||
if line.startswith("Channel "):
|
||||
channels.append(int(line.split()[1]))
|
||||
return channels
|
||||
|
||||
|
||||
def led(on=True):
|
||||
with open('/sys/class/leds/led0/brightness', 'w+t') as fp:
|
||||
fp.write("%d" % (0 if on is True else 1))
|
||||
|
||||
|
||||
def blink(times=1, delay=0.3):
|
||||
for t in range(0, times):
|
||||
led(True)
|
||||
time.sleep(delay)
|
||||
led(False)
|
||||
time.sleep(delay)
|
||||
led(True)
|
@ -1,170 +1,103 @@
|
||||
#!/usr/bin/python3
|
||||
import argparse
|
||||
import yaml
|
||||
import time
|
||||
import traceback
|
||||
import logging
|
||||
|
||||
import core
|
||||
import pwnagotchi, pwnagotchi.plugins as plugins
|
||||
import pwnagotchi
|
||||
import pwnagotchi.utils as utils
|
||||
import pwnagotchi.plugins as plugins
|
||||
|
||||
from pwnagotchi.log import SessionParser
|
||||
from pwnagotchi.voice import Voice
|
||||
from pwnagotchi.agent import Agent
|
||||
from pwnagotchi.ui.display import Display
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('-C', '--config', action='store', dest='config', default='/root/pwnagotchi/config.yml')
|
||||
parser.add_argument('-C', '--config', action='store', dest='config', default='/root/pwnagotchi/config.yml',
|
||||
help='Main configuration file.')
|
||||
parser.add_argument('-U', '--user-config', action='store', dest='user_config', default='/root/custom.yml',
|
||||
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('--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.")
|
||||
|
||||
args = parser.parse_args()
|
||||
config = utils.load_config(args)
|
||||
utils.setup_logging(args, config)
|
||||
|
||||
if args.do_clear:
|
||||
print("clearing the display ...")
|
||||
with open(args.config, 'rt') as fp:
|
||||
config = yaml.safe_load(fp)
|
||||
cleardisplay = config['ui']['display']['type']
|
||||
if cleardisplay in ('inkyphat', 'inky'):
|
||||
print("inky display")
|
||||
from inky import InkyPHAT
|
||||
|
||||
epd = InkyPHAT(config['ui']['display']['color'])
|
||||
epd.set_border(InkyPHAT.BLACK)
|
||||
self._render_cb = self._inky_render
|
||||
elif cleardisplay in ('papirus', 'papi'):
|
||||
print("papirus display")
|
||||
from pwnagotchi.ui.papirus.epd import EPD
|
||||
|
||||
os.environ['EPD_SIZE'] = '2.0'
|
||||
epd = EPD()
|
||||
epd.clear()
|
||||
elif cleardisplay in ('waveshare_1', 'ws_1', 'waveshare1', 'ws1'):
|
||||
print("waveshare v1 display")
|
||||
from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
|
||||
|
||||
epd = EPD()
|
||||
epd.init(epd.lut_full_update)
|
||||
epd.Clear(0xFF)
|
||||
elif cleardisplay in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2'):
|
||||
print("waveshare v2 display")
|
||||
from pwnagotchi.ui.waveshare.v2.waveshare import EPD
|
||||
|
||||
epd = EPD()
|
||||
epd.init(epd.FULL_UPDATE)
|
||||
epd.Clear(0xff)
|
||||
else:
|
||||
print("unknown display type %s" % cleardisplay)
|
||||
quit()
|
||||
|
||||
with open(args.config, 'rt') as fp:
|
||||
config = yaml.safe_load(fp)
|
||||
|
||||
plugins.load_from_path(plugins.default_path)
|
||||
if 'plugins' in config['main'] and config['main']['plugins'] is not None:
|
||||
plugins.load_from_path(config['main']['plugins'])
|
||||
|
||||
plugins.on('loaded')
|
||||
plugins.load(config)
|
||||
|
||||
display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
|
||||
agent = Agent(view=display, config=config)
|
||||
|
||||
core.log("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, pwnagotchi.version))
|
||||
# for key, value in config['personality'].items():
|
||||
# core.log(" %s: %s" % (key, value))
|
||||
logging.info("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, pwnagotchi.version))
|
||||
|
||||
for _, plugin in plugins.loaded.items():
|
||||
core.log("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
|
||||
logging.debug("plugin '%s' v%s loaded from %s" % (plugin.__name__, plugin.__version__, plugin.__file__))
|
||||
|
||||
if args.do_manual:
|
||||
core.log("entering manual mode ...")
|
||||
if args.do_clear:
|
||||
logging.info("clearing the display ...")
|
||||
display.clear()
|
||||
|
||||
log = SessionParser(config['main']['log'])
|
||||
elif args.do_manual:
|
||||
logging.info("entering manual mode ...")
|
||||
|
||||
core.log("the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
|
||||
log.duration_human,
|
||||
log.epochs,
|
||||
log.train_epochs,
|
||||
log.avg_reward,
|
||||
log.min_reward,
|
||||
log.max_reward))
|
||||
log = SessionParser(config)
|
||||
logging.info(
|
||||
"the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
|
||||
log.duration_human,
|
||||
log.epochs,
|
||||
log.train_epochs,
|
||||
log.avg_reward,
|
||||
log.min_reward,
|
||||
log.max_reward))
|
||||
|
||||
while True:
|
||||
display.on_manual_mode(log)
|
||||
time.sleep(1)
|
||||
if config['twitter']['enabled'] and log.is_new() and Agent.is_connected() and log.handshakes > 0:
|
||||
import tweepy
|
||||
|
||||
core.log("detected a new session and internet connectivity!")
|
||||
if Agent.is_connected():
|
||||
plugins.on('internet_available', display, config, log)
|
||||
|
||||
picture = '/dev/shm/pwnagotchi.png'
|
||||
else:
|
||||
logging.info("entering auto mode ...")
|
||||
|
||||
display.update()
|
||||
display.image().save(picture, 'png')
|
||||
display.set('status', 'Tweeting...')
|
||||
display.update()
|
||||
agent.start()
|
||||
|
||||
try:
|
||||
auth = tweepy.OAuthHandler(config['twitter']['consumer_key'], config['twitter']['consumer_secret'])
|
||||
auth.set_access_token(config['twitter']['access_token_key'], config['twitter']['access_token_secret'])
|
||||
api = tweepy.API(auth)
|
||||
while True:
|
||||
try:
|
||||
# recon on all channels
|
||||
agent.recon()
|
||||
# get nearby access points grouped by channel
|
||||
channels = agent.get_access_points_by_channel()
|
||||
# check for free channels to use
|
||||
agent.check_channels(channels)
|
||||
# for each channel
|
||||
for ch, aps in channels:
|
||||
agent.set_channel(ch)
|
||||
|
||||
tweet = Voice(lang=config['main']['lang']).on_log_tweet(log)
|
||||
api.update_with_media(filename=picture, status=tweet)
|
||||
log.save_session_id()
|
||||
if not agent.is_stale() and agent.any_activity():
|
||||
logging.info("%d access points on channel %d" % (len(aps), ch))
|
||||
|
||||
core.log("tweeted: %s" % tweet)
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
# 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)
|
||||
|
||||
quit()
|
||||
|
||||
core.logfile = config['main']['log']
|
||||
|
||||
agent.start_ai()
|
||||
agent.setup_events()
|
||||
agent.set_starting()
|
||||
agent.start_monitor_mode()
|
||||
agent.start_event_polling()
|
||||
|
||||
# print initial stats
|
||||
agent.next_epoch()
|
||||
|
||||
agent.set_ready()
|
||||
|
||||
while True:
|
||||
try:
|
||||
# recon on all channels
|
||||
agent.recon()
|
||||
# get nearby access points grouped by channel
|
||||
channels = agent.get_access_points_by_channel()
|
||||
# check for free channels to use
|
||||
agent.check_channels(channels)
|
||||
# for each channel
|
||||
for ch, aps in channels:
|
||||
agent.set_channel(ch)
|
||||
|
||||
if not agent.is_stale() and agent.any_activity():
|
||||
core.log("%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()
|
||||
except Exception as e:
|
||||
core.log("main loop exception: %s" % e)
|
||||
core.log("%s" % traceback.format_exc())
|
||||
# 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()
|
||||
except Exception as e:
|
||||
logging.exception("main loop exception")
|
||||
|
@ -1,5 +1,7 @@
|
||||
import subprocess
|
||||
|
||||
version = '1.0.0plz2'
|
||||
|
||||
_name = None
|
||||
|
||||
|
||||
|
@ -4,12 +4,12 @@ import os
|
||||
import re
|
||||
import socket
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import _thread
|
||||
|
||||
import core
|
||||
|
||||
import pwnagotchi.utils as utils
|
||||
import pwnagotchi.plugins as plugins
|
||||
from bettercap.client import Client
|
||||
from pwnagotchi.bettercap import Client
|
||||
from pwnagotchi.mesh.utils import AsyncAdvertiser
|
||||
from pwnagotchi.ai.train import AsyncTrainer
|
||||
|
||||
@ -29,7 +29,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
self._started_at = time.time()
|
||||
self._filter = None if config['main']['filter'] is None else re.compile(config['main']['filter'])
|
||||
self._current_channel = 0
|
||||
self._supported_channels = core.iface_channels(config['main']['iface'])
|
||||
self._supported_channels = utils.iface_channels(config['main']['iface'])
|
||||
self._view = view
|
||||
self._access_points = []
|
||||
self._last_pwnd = None
|
||||
@ -82,7 +82,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
plugins.on('rebooting', self)
|
||||
|
||||
def setup_events(self):
|
||||
core.log("connecting to %s ..." % self.url)
|
||||
logging.info("connecting to %s ..." % self.url)
|
||||
|
||||
for tag in self._config['bettercap']['silence']:
|
||||
try:
|
||||
@ -109,34 +109,44 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
s = self.session()
|
||||
for iface in s['interfaces']:
|
||||
if iface['name'] == mon_iface:
|
||||
core.log("found monitor interface: %s" % iface['name'])
|
||||
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 != '':
|
||||
core.log("starting monitor interface ...")
|
||||
logging.info("starting monitor interface ...")
|
||||
self.run('!%s' % mon_start_cmd)
|
||||
else:
|
||||
core.log("waiting for monitor interface %s ..." % mon_iface)
|
||||
logging.info("waiting for monitor interface %s ..." % mon_iface)
|
||||
time.sleep(1)
|
||||
|
||||
core.log("supported channels: %s" % self._supported_channels)
|
||||
core.log("handshakes will be collected inside %s" % self._config['bettercap']['handshakes'])
|
||||
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:
|
||||
core.log("restarting wifi module ...")
|
||||
self.restart('wifi.recon')
|
||||
logging.debug("restarting wifi module ...")
|
||||
self.restart_module('wifi.recon')
|
||||
self.run('wifi.clear')
|
||||
elif not wifi_running:
|
||||
core.log("starting wifi module ...")
|
||||
self.start('wifi.recon')
|
||||
logging.debug("starting wifi module ...")
|
||||
self.start_module('wifi.recon')
|
||||
|
||||
self.start_advertising()
|
||||
|
||||
def start(self):
|
||||
self.start_ai()
|
||||
self.setup_events()
|
||||
self.set_starting()
|
||||
self.start_monitor_mode()
|
||||
self.start_event_polling()
|
||||
# print initial stats
|
||||
self.next_epoch()
|
||||
self.set_ready()
|
||||
|
||||
def wait_for(self, t, sleeping=True):
|
||||
plugins.on('sleep' if sleeping else 'wait', self, t)
|
||||
self._view.wait(t, sleeping)
|
||||
@ -150,13 +160,13 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
for ch in self._epoch.non_overlapping_channels:
|
||||
if ch not in busy_channels:
|
||||
self._epoch.non_overlapping_channels[ch] += 1
|
||||
core.log("channel %d is free from %d epochs" % (ch, self._epoch.non_overlapping_channels[ch]))
|
||||
logging.info("channel %d is free from %d epochs" % (ch, self._epoch.non_overlapping_channels[ch]))
|
||||
elif self._epoch.non_overlapping_channels[ch] > 0:
|
||||
self._epoch.non_overlapping_channels[ch] -= 1
|
||||
# report any channel that has been free for at least 3 epochs
|
||||
for ch, num_epochs_free in self._epoch.non_overlapping_channels.items():
|
||||
if num_epochs_free >= 3:
|
||||
core.log("channel %d has been free for %d epochs" % (ch, num_epochs_free))
|
||||
logging.info("channel %d has been free for %d epochs" % (ch, num_epochs_free))
|
||||
self.set_free_channel(ch)
|
||||
|
||||
def recon(self):
|
||||
@ -172,14 +182,14 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
if not channels:
|
||||
self._current_channel = 0
|
||||
# core.log("RECON %ds" % recon_time)
|
||||
logging.debug("RECON %ds" % recon_time)
|
||||
self.run('wifi.recon.channel clear')
|
||||
else:
|
||||
# core.log("RECON %ds ON CHANNELS %s" % (recon_time, ','.join(map(str, channels))))
|
||||
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:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error")
|
||||
|
||||
self.wait_for(recon_time, sleeping=False)
|
||||
|
||||
@ -204,7 +214,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
if self._filter_included(ap):
|
||||
aps.append(ap)
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error")
|
||||
|
||||
aps.sort(key=lambda ap: ap['channel'])
|
||||
return self.set_access_points(aps)
|
||||
@ -241,7 +251,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
def _update_uptime(self, s):
|
||||
secs = time.time() - self._started_at
|
||||
self._view.set('uptime', core.secs_to_hhmmss(secs))
|
||||
self._view.set('uptime', utils.secs_to_hhmmss(secs))
|
||||
self._view.set('epoch', '%04d' % self._epoch.epoch)
|
||||
|
||||
def _update_counters(self):
|
||||
@ -261,7 +271,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
if new_shakes > 0:
|
||||
self._epoch.track(handshake=True, inc=new_shakes)
|
||||
|
||||
tot = core.total_unique_handshakes(self._config['bettercap']['handshakes'])
|
||||
tot = utils.total_unique_handshakes(self._config['bettercap']['handshakes'])
|
||||
txt = '%d (%d)' % (len(self._handshakes), tot)
|
||||
|
||||
if self._last_pwnd is not None:
|
||||
@ -274,7 +284,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
def _update_advertisement(self, s):
|
||||
run_handshakes = len(self._handshakes)
|
||||
tot_handshakes = core.total_unique_handshakes(self._config['bettercap']['handshakes'])
|
||||
tot_handshakes = utils.total_unique_handshakes(self._config['bettercap']['handshakes'])
|
||||
started = s['started_at'].split('.')[0]
|
||||
started = datetime.strptime(started, '%Y-%m-%dT%H:%M:%S')
|
||||
started = time.mktime(started.timetuple())
|
||||
@ -289,7 +299,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
self._view.set_closest_peer(peer)
|
||||
|
||||
def _save_recovery_data(self):
|
||||
core.log("writing recovery data to %s ..." % RECOVERY_DATA_FILE)
|
||||
logging.warning("writing recovery data to %s ..." % RECOVERY_DATA_FILE)
|
||||
with open(RECOVERY_DATA_FILE, 'w') as fp:
|
||||
data = {
|
||||
'started_at': self._started_at,
|
||||
@ -304,7 +314,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
try:
|
||||
with open(RECOVERY_DATA_FILE, 'rt') as fp:
|
||||
data = json.load(fp)
|
||||
core.log("found recovery data: %s" % data)
|
||||
logging.info("found recovery data: %s" % data)
|
||||
self._started_at = data['started_at']
|
||||
self._epoch.epoch = data['epoch']
|
||||
self._handshakes = data['handshakes']
|
||||
@ -312,7 +322,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
self._last_pwnd = data['last_pwnd']
|
||||
|
||||
if delete:
|
||||
core.log("deleting %s" % RECOVERY_DATA_FILE)
|
||||
logging.info("deleting %s" % RECOVERY_DATA_FILE)
|
||||
os.unlink(RECOVERY_DATA_FILE)
|
||||
except:
|
||||
if not no_exceptions:
|
||||
@ -323,7 +333,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
self.run('events.clear')
|
||||
|
||||
core.log("event polling started ...")
|
||||
logging.debug("event polling started ...")
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
@ -349,21 +359,21 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
new_shakes += 1
|
||||
ap_and_station = self._find_ap_sta_in(sta_mac, ap_mac, s)
|
||||
if ap_and_station is None:
|
||||
core.log("!!! captured new handshake: %s !!!" % key)
|
||||
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
|
||||
core.log("!!! captured new handshake on channel %d: %s (%s) -> %s [%s (%s)] !!!" % ( \
|
||||
logging.warning("!!! captured new handshake on channel %d: %s (%s) -> %s [%s (%s)] !!!" % ( \
|
||||
ap['channel'],
|
||||
sta['mac'], sta['vendor'],
|
||||
ap['hostname'], ap['mac'], ap['vendor']))
|
||||
plugins.on('handshake', self, filename, ap, sta)
|
||||
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error")
|
||||
|
||||
finally:
|
||||
self._update_handshakes(new_shakes)
|
||||
@ -378,10 +388,10 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
return m['running']
|
||||
return False
|
||||
|
||||
def start(self, module):
|
||||
def start_module(self, module):
|
||||
self.run('%s on' % module)
|
||||
|
||||
def restart(self, module):
|
||||
def restart_module(self, module):
|
||||
self.run('%s off; %s on' % (module, module))
|
||||
|
||||
def _has_handshake(self, bssid):
|
||||
@ -404,7 +414,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
return self._history[who] < self._config['personality']['max_interactions']
|
||||
|
||||
def _on_miss(self, who):
|
||||
core.log("it looks like %s is not in range anymore :/" % who)
|
||||
logging.info("it looks like %s is not in range anymore :/" % who)
|
||||
self._epoch.track(miss=True)
|
||||
self._view.on_miss(who)
|
||||
|
||||
@ -416,18 +426,18 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
if 'is an unknown BSSID' in error:
|
||||
self._on_miss(who)
|
||||
else:
|
||||
core.log("error: %s" % e)
|
||||
logging.error("%s" % e)
|
||||
|
||||
def associate(self, ap, throttle=0):
|
||||
if self.is_stale():
|
||||
core.log("recon is stale, skipping assoc(%s)" % ap['mac'])
|
||||
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:
|
||||
core.log("sending association frame to %s (%s %s) on channel %d [%d clients]..." % ( \
|
||||
logging.info("sending association frame to %s (%s %s) on channel %d [%d clients]..." % ( \
|
||||
ap['hostname'], ap['mac'], ap['vendor'], ap['channel'], len(ap['clients'])))
|
||||
self.run('wifi.assoc %s' % ap['mac'])
|
||||
self._epoch.track(assoc=True)
|
||||
@ -441,14 +451,14 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
def deauth(self, ap, sta, throttle=0):
|
||||
if self.is_stale():
|
||||
core.log("recon is stale, skipping deauth(%s)" % sta['mac'])
|
||||
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:
|
||||
core.log("deauthing %s (%s) from %s (%s %s) on channel %d ..." % (
|
||||
logging.info("deauthing %s (%s) from %s (%s %s) on channel %d ..." % (
|
||||
sta['mac'], sta['vendor'], ap['hostname'], ap['mac'], ap['vendor'], ap['channel']))
|
||||
self.run('wifi.deauth %s' % sta['mac'])
|
||||
self._epoch.track(deauth=True)
|
||||
@ -462,7 +472,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
def set_channel(self, channel, verbose=True):
|
||||
if self.is_stale():
|
||||
core.log("recon is stale, skipping set_channel(%d)" % channel)
|
||||
logging.debug("recon is stale, skipping set_channel(%d)" % channel)
|
||||
return
|
||||
|
||||
# if in the previous loop no client stations has been deauthenticated
|
||||
@ -478,10 +488,12 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
if channel != self._current_channel:
|
||||
if self._current_channel != 0 and wait > 0:
|
||||
if verbose:
|
||||
core.log("waiting for %ds on channel %d ..." % (wait, self._current_channel))
|
||||
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:
|
||||
core.log("CHANNEL %d" % channel)
|
||||
logging.info("CHANNEL %d" % channel)
|
||||
try:
|
||||
self.run('wifi.recon.channel %d' % channel)
|
||||
self._current_channel = channel
|
||||
@ -491,7 +503,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
plugins.on('channel_hop', self, channel)
|
||||
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.error("error: %s" % e)
|
||||
|
||||
def is_stale(self):
|
||||
return self._epoch.num_missed > self._config['personality']['max_misses_for_recon']
|
||||
@ -502,7 +514,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
def _reboot(self):
|
||||
self.set_rebooting()
|
||||
self._save_recovery_data()
|
||||
core.log("rebooting the system ...")
|
||||
logging.warning("rebooting the system ...")
|
||||
os.system("/usr/bin/sync")
|
||||
os.system("/usr/sbin/shutdown -r now")
|
||||
|
||||
@ -514,24 +526,24 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer):
|
||||
|
||||
# after X misses during an epoch, set the status to lonely
|
||||
if was_stale:
|
||||
core.log("agent missed %d interactions -> lonely" % did_miss)
|
||||
logging.warning("agent missed %d interactions -> lonely" % did_miss)
|
||||
self.set_lonely()
|
||||
# after X times being bored, the status is set to sad
|
||||
elif self._epoch.inactive_for >= self._config['personality']['sad_num_epochs']:
|
||||
core.log("%d epochs with no activity -> sad" % self._epoch.inactive_for)
|
||||
logging.warning("%d epochs with no activity -> sad" % self._epoch.inactive_for)
|
||||
self.set_sad()
|
||||
# after X times being inactive, the status is set to bored
|
||||
elif self._epoch.inactive_for >= self._config['personality']['bored_num_epochs']:
|
||||
core.log("%d epochs with no activity -> bored" % self._epoch.inactive_for)
|
||||
logging.warning("%d epochs with no activity -> bored" % self._epoch.inactive_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']:
|
||||
core.log("%d epochs with activity -> excited" % self._epoch.active_for)
|
||||
logging.warning("%d epochs with activity -> excited" % self._epoch.active_for)
|
||||
self.set_excited()
|
||||
|
||||
plugins.on('epoch', self, self._epoch.epoch - 1, self._epoch.data())
|
||||
|
||||
if self._epoch.blind_for >= self._config['main']['mon_max_blind_epochs']:
|
||||
core.log("%d epochs without visible access points -> rebooting ..." % self._epoch.blind_for)
|
||||
logging.critical("%d epochs without visible access points -> rebooting ..." % self._epoch.blind_for)
|
||||
self._reboot()
|
||||
self._epoch.blind_for = 0
|
||||
|
@ -7,16 +7,16 @@ import warnings
|
||||
# https://stackoverflow.com/questions/15777951/how-to-suppress-pandas-future-warning
|
||||
warnings.simplefilter(action='ignore', category=FutureWarning)
|
||||
|
||||
import core
|
||||
import logging
|
||||
|
||||
|
||||
def load(config, agent, epoch, from_disk=True):
|
||||
config = config['ai']
|
||||
if not config['enabled']:
|
||||
core.log("ai disabled")
|
||||
logging.info("ai disabled")
|
||||
return False
|
||||
|
||||
core.log("[ai] bootstrapping dependencies ...")
|
||||
logging.info("[ai] bootstrapping dependencies ...")
|
||||
|
||||
from stable_baselines import A2C
|
||||
from stable_baselines.common.policies import MlpLstmPolicy
|
||||
@ -27,16 +27,16 @@ def load(config, agent, epoch, from_disk=True):
|
||||
env = wrappers.Environment(agent, epoch)
|
||||
env = DummyVecEnv([lambda: env])
|
||||
|
||||
core.log("[ai] bootstrapping model ...")
|
||||
logging.info("[ai] bootstrapping model ...")
|
||||
|
||||
a2c = A2C(MlpLstmPolicy, env, **config['params'])
|
||||
|
||||
if from_disk and os.path.exists(config['path']):
|
||||
core.log("[ai] loading %s ..." % config['path'])
|
||||
logging.info("[ai] loading %s ..." % config['path'])
|
||||
a2c.load(config['path'], env)
|
||||
else:
|
||||
core.log("[ai] model created:")
|
||||
logging.info("[ai] model created:")
|
||||
for key, value in config['params'].items():
|
||||
core.log(" %s: %s" % (key, value))
|
||||
logging.info(" %s: %s" % (key, value))
|
||||
|
||||
return a2c
|
||||
|
@ -1,8 +1,9 @@
|
||||
import time
|
||||
import threading
|
||||
import logging
|
||||
|
||||
import core
|
||||
import pwnagotchi
|
||||
import pwnagotchi.utils as utils
|
||||
import pwnagotchi.mesh.wifi as wifi
|
||||
|
||||
from pwnagotchi.ai.reward import RewardFunction
|
||||
@ -87,13 +88,13 @@ class Epoch(object):
|
||||
aps_per_chan[ch_idx] += 1.0
|
||||
sta_per_chan[ch_idx] += len(ap['clients'])
|
||||
except IndexError as e:
|
||||
core.log("got data on channel %d, we can store %d channels" % (ap['channel'], wifi.NumChannels))
|
||||
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 as e:
|
||||
core.log(
|
||||
logging.error(
|
||||
"got peer data on channel %d, we can store %d channels" % (peer.last_channel, wifi.NumChannels))
|
||||
|
||||
# normalize
|
||||
@ -172,23 +173,23 @@ class Epoch(object):
|
||||
self._epoch_data['reward'] = self._reward(self.epoch + 1, self._epoch_data)
|
||||
self._epoch_data_ready.set()
|
||||
|
||||
core.log("[epoch %d] duration=%s slept_for=%s blind=%d inactive=%d active=%d hops=%d missed=%d "
|
||||
"deauths=%d assocs=%d handshakes=%d cpu=%d%% mem=%d%% temperature=%dC reward=%s" % (
|
||||
self.epoch,
|
||||
core.secs_to_hhmmss(self.epoch_duration),
|
||||
core.secs_to_hhmmss(self.num_slept),
|
||||
self.blind_for,
|
||||
self.inactive_for,
|
||||
self.active_for,
|
||||
self.num_hops,
|
||||
self.num_missed,
|
||||
self.num_deauths,
|
||||
self.num_assocs,
|
||||
self.num_shakes,
|
||||
cpu * 100,
|
||||
mem * 100,
|
||||
temp,
|
||||
self._epoch_data['reward']))
|
||||
logging.info("[epoch %d] duration=%s slept_for=%s blind=%d inactive=%d active=%d 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.inactive_for,
|
||||
self.active_for,
|
||||
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
|
||||
|
@ -1,8 +1,8 @@
|
||||
import logging
|
||||
import gym
|
||||
from gym import spaces
|
||||
import numpy as np
|
||||
|
||||
import core
|
||||
import pwnagotchi.ai.featurizer as featurizer
|
||||
import pwnagotchi.ai.reward as reward
|
||||
from pwnagotchi.ai.parameter import Parameter
|
||||
@ -83,7 +83,7 @@ class Environment(gym.Env):
|
||||
return params
|
||||
|
||||
def _next_epoch(self):
|
||||
# core.log("[ai] waiting for epoch to finish ...")
|
||||
logging.debug("[ai] waiting for epoch to finish ...")
|
||||
return self._epoch.wait_for_epoch_data()
|
||||
|
||||
def _apply_policy(self, policy):
|
||||
@ -110,7 +110,7 @@ class Environment(gym.Env):
|
||||
return self.last['state_v'], self.last['reward'], not self._agent.is_training(), {}
|
||||
|
||||
def reset(self):
|
||||
# core.log("[ai] resetting environment ...")
|
||||
# logging.info("[ai] resetting environment ...")
|
||||
self._epoch_num = 0
|
||||
state = self._next_epoch()
|
||||
self.last['state'] = state
|
||||
@ -120,7 +120,7 @@ class Environment(gym.Env):
|
||||
def _render_histogram(self, hist):
|
||||
for ch in range(featurizer.histogram_size):
|
||||
if hist[ch]:
|
||||
core.log(" CH %d: %s" % (ch + 1, 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
|
||||
@ -133,18 +133,13 @@ class Environment(gym.Env):
|
||||
|
||||
self._last_render = self._epoch_num
|
||||
|
||||
core.log("[ai] --- training epoch %d/%d ---" % (self._epoch_num, self._agent.training_epochs()))
|
||||
core.log("[ai] REWARD: %f" % self.last['reward'])
|
||||
logging.info("[ai] --- training epoch %d/%d ---" % (self._epoch_num, self._agent.training_epochs()))
|
||||
logging.info("[ai] REWARD: %f" % self.last['reward'])
|
||||
|
||||
# core.log("[ai] policy: %s" % ', '.join("%s:%s" % (name, value) for name, value in self.last['params'].items()))
|
||||
logging.debug("[ai] policy: %s" % ', '.join("%s:%s" % (name, value) for name, value in self.last['params'].items()))
|
||||
|
||||
core.log("[ai] observation:")
|
||||
logging.info("[ai] observation:")
|
||||
for name, value in self.last['state'].items():
|
||||
if 'histogram' in name:
|
||||
core.log(" %s" % name.replace('_histogram', ''))
|
||||
logging.info(" %s" % name.replace('_histogram', ''))
|
||||
self._render_histogram(value)
|
||||
|
||||
# core.log("[ai] outcome:")
|
||||
# for name, value in self.last['state'].items():
|
||||
# if 'histogram' not in name:
|
||||
# core.log(" %s: %s" % (name, value))
|
||||
|
@ -4,8 +4,7 @@ import time
|
||||
import random
|
||||
import os
|
||||
import json
|
||||
|
||||
import core
|
||||
import logging
|
||||
|
||||
import pwnagotchi.plugins as plugins
|
||||
import pwnagotchi.ai as ai
|
||||
@ -56,7 +55,7 @@ class Stats(object):
|
||||
def load(self):
|
||||
with self._lock:
|
||||
if os.path.exists(self.path) and os.path.getsize(self.path) > 0:
|
||||
core.log("[ai] loading %s" % self.path)
|
||||
logging.info("[ai] loading %s" % self.path)
|
||||
with open(self.path, 'rt') as fp:
|
||||
obj = json.load(fp)
|
||||
|
||||
@ -66,7 +65,7 @@ class Stats(object):
|
||||
|
||||
def save(self):
|
||||
with self._lock:
|
||||
core.log("[ai] saving %s" % self.path)
|
||||
logging.info("[ai] saving %s" % self.path)
|
||||
|
||||
data = json.dumps({
|
||||
'born_at': self.born_at,
|
||||
@ -114,7 +113,7 @@ class AsyncTrainer(object):
|
||||
_thread.start_new_thread(self._ai_worker, ())
|
||||
|
||||
def _save_ai(self):
|
||||
core.log("[ai] saving model to %s ..." % self._nn_path)
|
||||
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)
|
||||
@ -133,15 +132,15 @@ class AsyncTrainer(object):
|
||||
|
||||
def on_ai_policy(self, new_params):
|
||||
plugins.on('ai_policy', self, new_params)
|
||||
core.log("[ai] setting new policy:")
|
||||
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:
|
||||
core.log("[ai] ! %s: %s -> %s" % (name, curr_value, value))
|
||||
logging.info("[ai] ! %s: %s -> %s" % (name, curr_value, value))
|
||||
self._config['personality'][name] = value
|
||||
else:
|
||||
core.log("[ai] param %s not in personality configuration!" % name)
|
||||
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'])
|
||||
@ -152,12 +151,12 @@ class AsyncTrainer(object):
|
||||
plugins.on('ai_ready', self)
|
||||
|
||||
def on_ai_best_reward(self, r):
|
||||
core.log("[ai] best reward so far: %s" % 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):
|
||||
core.log("[ai] worst reward so far: %s" % r)
|
||||
logging.info("[ai] worst reward so far: %s" % r)
|
||||
self._view.on_demotivated(r)
|
||||
plugins.on('ai_worst_reward', self, r)
|
||||
|
||||
@ -174,12 +173,12 @@ class AsyncTrainer(object):
|
||||
self._model.env.render()
|
||||
# enter in training mode?
|
||||
if random.random() > self._config['ai']['laziness']:
|
||||
core.log("[ai] learning for %d epochs ..." % epochs_per_episode)
|
||||
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:
|
||||
core.log("[ai] error while training: %s" % e)
|
||||
logging.exception("[ai] error while training")
|
||||
finally:
|
||||
self.set_training(False)
|
||||
obs = self._model.env.reset()
|
||||
|
@ -1,8 +1,7 @@
|
||||
import logging
|
||||
import requests
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
import core
|
||||
|
||||
|
||||
class Client(object):
|
||||
def __init__(self, hostname='localhost', scheme='http', port=8081, username='user', password='pass'):
|
||||
@ -19,11 +18,11 @@ class Client(object):
|
||||
return r.json()
|
||||
except Exception as e:
|
||||
if r.status_code == 200:
|
||||
core.log("error while decoding json: error='%s' resp='%s'" % (e, r.text))
|
||||
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:
|
||||
core.log(err)
|
||||
logging.info(err)
|
||||
raise Exception(err)
|
||||
return r.text
|
||||
|
Binary file not shown.
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-03 12:22+0200\n"
|
||||
"POT-Creation-Date: 2019-10-05 14:10+0200\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"
|
||||
@ -16,217 +16,169 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: voice.py:18
|
||||
msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:22
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr "Hi, ich bin ein Pwnagotchi! Starte ..."
|
||||
|
||||
#: voice.py:23
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Neuer Tag, neue Jagd, neue Pwns!"
|
||||
|
||||
#: voice.py:24
|
||||
msgid "Hack the Planet!"
|
||||
msgstr "Hack den Planet!"
|
||||
|
||||
#: voice.py:28
|
||||
msgid "AI ready."
|
||||
msgstr "KI bereit."
|
||||
|
||||
#: voice.py:29
|
||||
msgid "The neural network is ready."
|
||||
msgstr "Das neurale Netz ist bereit."
|
||||
|
||||
#: voice.py:37
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "Hey, Channel {channel} ist frei! Dein AP wir des dir danken."
|
||||
|
||||
#: voice.py:41
|
||||
msgid "I'm bored ..."
|
||||
msgstr "Mir ist langweilig..."
|
||||
|
||||
#: voice.py:42
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "Lass uns laufen gehen!"
|
||||
|
||||
#: voice.py:45
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Das ist der beste Tag meines Lebens."
|
||||
|
||||
#: voice.py:48
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Scheis Tag :/"
|
||||
|
||||
#: voice.py:52
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Mir ist sau langweilig..."
|
||||
|
||||
#: voice.py:53
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Ich bin sehr traurig..."
|
||||
|
||||
#: voice.py:54
|
||||
msgid "I'm sad"
|
||||
msgstr "Ich bin traurig"
|
||||
|
||||
#: voice.py:59
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Ich lebe das Leben!"
|
||||
|
||||
#: voice.py:60
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Ich pwne, also bin ich."
|
||||
|
||||
#: voice.py:61
|
||||
msgid "So many networks!!!"
|
||||
msgstr "So viele Netwerke!!!"
|
||||
|
||||
#: voice.py:62
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Ich habe sooo viel Spaß!"
|
||||
|
||||
#: voice.py:63
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "Mein Verbrechen ist das der Neugier ..."
|
||||
|
||||
#: voice.py:67
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr "Hallo {name}, nett Dich kennenzulernen."
|
||||
|
||||
#: voice.py:68
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr "Gerät {name} ist in der nähe!!"
|
||||
|
||||
#: voice.py:72
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr "Uhm ...tschüß {name}"
|
||||
|
||||
#: voice.py:73
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "{name} ist weg ..."
|
||||
|
||||
#: voice.py:77
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Whoops ...{name} ist weg."
|
||||
|
||||
#: voice.py:78
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "{name} verpasst!"
|
||||
|
||||
#: voice.py:79
|
||||
msgid "Missed!"
|
||||
msgstr "Verpasst!"
|
||||
|
||||
#: voice.py:83
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Niemand will mit mir spielen ..."
|
||||
|
||||
#: voice.py:84
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "Ich fühl michso alleine ..."
|
||||
|
||||
#: voice.py:85
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Wo sind denn alle?"
|
||||
|
||||
#: voice.py:89
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "Schlafe für {secs}s"
|
||||
|
||||
#: voice.py:90
|
||||
msgid "Zzzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:91
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:98
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "Warte für {secs}s ..."
|
||||
|
||||
#: voice.py:100
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "Schaue mich um ({secs}s)"
|
||||
|
||||
#: voice.py:106
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Hey {what}, lass uns Freunde sein!"
|
||||
|
||||
#: voice.py:107
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "Verbinde mit {what}"
|
||||
|
||||
#: voice.py:108
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:112
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Ich denke, dass {mac} kein WiFi brauch!"
|
||||
|
||||
#: voice.py:113
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr "Deauthentifiziere {mac}"
|
||||
|
||||
#: voice.py:114
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr "Kicke {mac}!"
|
||||
|
||||
#: voice.py:118
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "Cool, wir haben {num} neue Handshake{plural}!"
|
||||
|
||||
#: voice.py:121
|
||||
msgid "Ops, something went wrong ... Rebooting ..."
|
||||
msgstr "Ops, da ist etwas schief gelaufen ...Starte neu ..."
|
||||
|
||||
#: voice.py:124
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr "{num} Stationen gekicked\n"
|
||||
|
||||
#: voice.py:125
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "{num} Freunde gefunden\n"
|
||||
|
||||
#: voice.py:126
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "{num} Handshakes aufgez.\n"
|
||||
|
||||
#: voice.py:128
|
||||
msgid "Met 1 peer"
|
||||
msgstr "1 Peer getroffen."
|
||||
|
||||
#: voice.py:130
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "{num} Peers getroffen"
|
||||
|
||||
#: voice.py:135
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
|
||||
@ -236,3 +188,21 @@ 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 "hour"
|
||||
msgstr "Stunde"
|
||||
|
||||
msgid "minute"
|
||||
msgstr "Minute"
|
||||
|
||||
msgid "second"
|
||||
msgstr "Sekunde"
|
||||
|
Binary file not shown.
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-03 12:22+0200\n"
|
||||
"POT-Creation-Date: 2019-10-05 14:10+0200\n"
|
||||
"PO-Revision-Date: 2019-10-03 08:00+0000\n"
|
||||
"Last-Translator: Periklis Fregkos <fregkos@gmail.com>\n"
|
||||
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
|
||||
@ -17,225 +17,169 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: voice.py:18
|
||||
msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:22
|
||||
#, fuzzy
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr "Γειά, είμαι το Pwnagotchi!Εκκινούμαι ..."
|
||||
msgstr "Γειά, είμαι το Pwnagotchi! Εκκινούμαι ..."
|
||||
|
||||
#: voice.py:23
|
||||
#, fuzzy
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Νέα μέρα, νέο κυνήγι,νέα pwns!"
|
||||
msgstr "Νέα μέρα, νέο κυνήγι, νέα pwns!"
|
||||
|
||||
#: voice.py:24
|
||||
msgid "Hack the Planet!"
|
||||
msgstr "Hackαρε τον πλανήτη!"
|
||||
|
||||
#: voice.py:28
|
||||
msgid "AI ready."
|
||||
msgstr "ΤΝ έτοιμη."
|
||||
|
||||
#: voice.py:29
|
||||
#, fuzzy
|
||||
msgid "The neural network is ready."
|
||||
msgstr "Το νευρωνικό δίκτυοείναι έτοιμο."
|
||||
|
||||
#: voice.py:37
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "Ε, το κανάλι {channel} είναιελεύθερο! Το AP σου θαείναι ευγνώμων."
|
||||
|
||||
#: voice.py:41
|
||||
msgid "I'm bored ..."
|
||||
msgstr "Βαριέμαι ..."
|
||||
|
||||
#: voice.py:42
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "Ας πάμε μια βόλτα!"
|
||||
|
||||
#: voice.py:45
|
||||
#, fuzzy
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Είναι η καλύτερημέρα της ζωής μου!"
|
||||
|
||||
#: voice.py:48
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Σκατένια μέρα :/"
|
||||
|
||||
#: voice.py:52
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Βαριέμαι πάρα πολύ ..."
|
||||
|
||||
#: voice.py:53
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Είμαι πολύ λυπημένο ..."
|
||||
|
||||
#: voice.py:54
|
||||
msgid "I'm sad"
|
||||
msgstr "Είμαι λυπημένο"
|
||||
|
||||
#: voice.py:59
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Ζω την ζωή μου!"
|
||||
|
||||
#: voice.py:60
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Pwnάρω, άρα υπάρχω."
|
||||
|
||||
#: voice.py:61
|
||||
msgid "So many networks!!!"
|
||||
msgstr "Τόσα πολλά δίκτυα!!!"
|
||||
|
||||
#: voice.py:62
|
||||
#, fuzzy
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Περνάω τέλεια!"
|
||||
|
||||
#: voice.py:63
|
||||
#, fuzzy
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "Η περιέργεια είναιτο μόνο έγκλημά μου ..."
|
||||
|
||||
#: voice.py:67
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr "Γειά {name}!Χάρηκα για τη γνωριμία. {name}"
|
||||
|
||||
#: voice.py:68
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr "Η μονάδα{name}είναι κοντά! {name}"
|
||||
msgstr "Η μονάδα {name} είναι κοντά! {name}"
|
||||
|
||||
#: voice.py:72
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr "Εμμ ...αντίο{name}"
|
||||
msgstr "Εμμ ...αντίο {name}"
|
||||
|
||||
#: voice.py:73
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "Το {name}έφυγε ..."
|
||||
msgstr "Το {name} έφυγε ..."
|
||||
|
||||
#: voice.py:77
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Ουπς ... Εξαφανίστηκε το{name}."
|
||||
msgstr "Ουπς ... Εξαφανίστηκε το {name}."
|
||||
|
||||
#: voice.py:78
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "Έχασα το{name}!"
|
||||
msgstr "Έχασα το {name}!"
|
||||
|
||||
#: voice.py:79
|
||||
msgid "Missed!"
|
||||
msgstr "Το έχασα!"
|
||||
|
||||
#: voice.py:83
|
||||
#, fuzzy
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Κανείς δε θέλει ναπαίξει μαζί μου ..."
|
||||
|
||||
#: voice.py:84
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "Νιώθω μοναχός μου ..."
|
||||
|
||||
#: voice.py:85
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Μα, πού πήγαν όλοι;!"
|
||||
|
||||
#: voice.py:89
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "Ξεκουράζομαι για {secs}s ..."
|
||||
|
||||
#: voice.py:90
|
||||
msgid "Zzzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:91
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:98
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "Περιμένω για {secs}s ..."
|
||||
|
||||
#: voice.py:100
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "Ψάχνω τριγύρω ({secs})"
|
||||
|
||||
#: voice.py:106
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Εε!{what},ας γίνουμε φίλοι!"
|
||||
msgstr "Εε! {what}, ας γίνουμε φίλοι!"
|
||||
|
||||
#: voice.py:107
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "Συνδέομαι με το{what}"
|
||||
msgstr "Συνδέομαι με το {what}"
|
||||
|
||||
#: voice.py:108
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr "Που'σαι ρε τρελέ{what}!"
|
||||
msgstr "Που'σαι ρε τρελέ {what}!"
|
||||
|
||||
#: voice.py:112
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Μόλις αποφάσισα ότι η{mac}δε χρείαζεται WiFi!"
|
||||
msgstr "Μόλις αποφάσισα ότι η {mac} δε χρείαζεται WiFi!"
|
||||
|
||||
#: voice.py:113
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr "Πετάω έξω την{mac}"
|
||||
msgstr "Πετάω έξω την {mac}"
|
||||
|
||||
#: voice.py:114
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr "Μπανάρω την{mac}!"
|
||||
msgstr "Μπανάρω την {mac}!"
|
||||
|
||||
#: voice.py:118
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "Τέλεια δικέ μου, πήραμε {num}νέες χειραψίες!"
|
||||
msgstr "Τέλεια δικέ μου, πήραμε {num} νέες χειραψίες!"
|
||||
|
||||
#: voice.py:121
|
||||
#, fuzzy
|
||||
msgid "Ops, something went wrong ... Rebooting ..."
|
||||
msgstr "Ουπς, κάτιπήγε λάθος ...Επανεκκινούμαι ..."
|
||||
msgstr "Ουπς, κάτιπήγε λάθος ... Επανεκκινούμαι ..."
|
||||
|
||||
#: voice.py:124
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr "Έριξα {num} σταθμούς\n"
|
||||
|
||||
#: voice.py:125
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "Έκανα {num} νέους φίλους\n"
|
||||
|
||||
#: voice.py:126
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "Πήρα {num} χειραψίες\n"
|
||||
|
||||
#: voice.py:128
|
||||
msgid "Met 1 peer"
|
||||
msgstr "Γνώρισα 1 φίλο"
|
||||
|
||||
#: voice.py:130
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "Γνώρισα {num} φίλους"
|
||||
|
||||
#: voice.py:135
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
|
||||
@ -245,3 +189,21 @@ msgstr ""
|
||||
"Pwnαρα για {duration} και έριξα {deauthed} πελάτες! Επίσης γνώρισα "
|
||||
"{associated} νέους φίλους και καταβρόχθισα {handshakes} χειραψίες! "
|
||||
"#pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
|
||||
|
||||
msgid "hours"
|
||||
msgstr ""
|
||||
|
||||
msgid "minutes"
|
||||
msgstr ""
|
||||
|
||||
msgid "seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "hour"
|
||||
msgstr ""
|
||||
|
||||
msgid "minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "second"
|
||||
msgstr ""
|
||||
|
Binary file not shown.
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-03 12:22+0200\n"
|
||||
"POT-Creation-Date: 2019-10-05 14:10+0200\n"
|
||||
"PO-Revision-Date: 2019-10-03 10:34+0200\n"
|
||||
"Last-Translator: quantumsheep <7271496+quantumsheep@users.noreply.github."
|
||||
"com>\n"
|
||||
@ -18,220 +18,193 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: voice.py:18
|
||||
msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:22
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr ""
|
||||
msgstr "Bonjour, je suis Pwnagotchi! Démarrage ..."
|
||||
|
||||
#: voice.py:23
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr ""
|
||||
msgstr "Nouvelle journée, nouvelle chasse, nouveau pwns!"
|
||||
|
||||
#: voice.py:24
|
||||
msgid "Hack the Planet!"
|
||||
msgstr ""
|
||||
msgstr "Hack la planète!"
|
||||
|
||||
#: voice.py:28
|
||||
msgid "AI ready."
|
||||
msgstr ""
|
||||
msgstr "IA prête."
|
||||
|
||||
#: voice.py:29
|
||||
msgid "The neural network is ready."
|
||||
msgstr ""
|
||||
msgstr "Le réseau neuronal est prêt."
|
||||
|
||||
#: voice.py:37
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr ""
|
||||
msgstr "Hey, le channel {channel} est libre! Ton AP va dis merci."
|
||||
|
||||
#: voice.py:41
|
||||
msgid "I'm bored ..."
|
||||
msgstr ""
|
||||
msgstr "Je m'ennuie ..."
|
||||
|
||||
#: voice.py:42
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr ""
|
||||
msgstr "Allons faire un tour!"
|
||||
|
||||
#: voice.py:45
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr ""
|
||||
msgstr "C'est le meilleur jour de ma vie!"
|
||||
|
||||
#: voice.py:48
|
||||
msgid "Shitty day :/"
|
||||
msgstr ""
|
||||
msgstr "Journée de merde :/"
|
||||
|
||||
#: voice.py:52
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr ""
|
||||
msgstr "Je m'ennuie énormément ..."
|
||||
|
||||
#: voice.py:53
|
||||
msgid "I'm very sad ..."
|
||||
msgstr ""
|
||||
msgstr "Je suis très triste ..."
|
||||
|
||||
#: voice.py:54
|
||||
msgid "I'm sad"
|
||||
msgstr ""
|
||||
msgstr "Je suis triste"
|
||||
|
||||
#: voice.py:59
|
||||
msgid "I'm living the life!"
|
||||
msgstr ""
|
||||
msgstr "Je vis la vie!"
|
||||
|
||||
#: voice.py:60
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr ""
|
||||
msgstr "Je pwn donc je suis."
|
||||
|
||||
#: voice.py:61
|
||||
msgid "So many networks!!!"
|
||||
msgstr ""
|
||||
msgstr "Autant de réseaux!!!"
|
||||
|
||||
#: voice.py:62
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr ""
|
||||
msgstr "Je m'amuse tellement!"
|
||||
|
||||
#: voice.py:63
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr ""
|
||||
msgstr "Mon crime est celui de la curiosité ..."
|
||||
|
||||
#: voice.py:67
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr ""
|
||||
msgstr "Bonjour {name}! Ravis de te rencontrer. {name}"
|
||||
|
||||
#: voice.py:68
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr ""
|
||||
msgstr "L'unité {name} est proche! {name}"
|
||||
|
||||
#: voice.py:72
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr ""
|
||||
msgstr "Hum ... au revoir {name}"
|
||||
|
||||
#: voice.py:73
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr ""
|
||||
msgstr "{name} est parti ..."
|
||||
|
||||
#: voice.py:77
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr ""
|
||||
msgstr "Oups ... {name} est parti."
|
||||
|
||||
#: voice.py:78
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr ""
|
||||
msgstr "{name} raté!"
|
||||
|
||||
#: voice.py:79
|
||||
msgid "Missed!"
|
||||
msgstr ""
|
||||
msgstr "Raté!"
|
||||
|
||||
#: voice.py:83
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr ""
|
||||
msgstr "Personne ne veut jouer avec moi ..."
|
||||
|
||||
#: voice.py:84
|
||||
msgid "I feel so alone ..."
|
||||
msgstr ""
|
||||
msgstr "Je me sens si seul ..."
|
||||
|
||||
#: voice.py:85
|
||||
msgid "Where's everybody?!"
|
||||
msgstr ""
|
||||
msgstr "Où est tout le monde?!"
|
||||
|
||||
#: voice.py:89
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr ""
|
||||
msgstr "Fais la sieste pendant {secs}s ..."
|
||||
|
||||
#: voice.py:90
|
||||
msgid "Zzzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:91
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:98
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr ""
|
||||
msgstr "Attends pendant {secs}s ..."
|
||||
|
||||
#: voice.py:100
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr ""
|
||||
msgstr "Regarde autour ({secs}s)"
|
||||
|
||||
#: voice.py:106
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr ""
|
||||
msgstr "Hey {what}, soyons amis!"
|
||||
|
||||
#: voice.py:107
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr ""
|
||||
msgstr "Association à {what}"
|
||||
|
||||
#: voice.py:108
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:112
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr ""
|
||||
msgstr "Décidé à l'instant que {mac} n'a pas besoin de WiFi!"
|
||||
|
||||
#: voice.py:113
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr ""
|
||||
msgstr "Désauthentification de {mac}"
|
||||
|
||||
#: voice.py:114
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:118
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr ""
|
||||
msgstr "Cool, nous avons {num} nouveaux handshake{plural}!"
|
||||
|
||||
#: voice.py:121
|
||||
msgid "Ops, something went wrong ... Rebooting ..."
|
||||
msgstr ""
|
||||
msgstr "Oups, quelque chose s'est mal passé ... Redémarrage ..."
|
||||
|
||||
#: voice.py:124
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr ""
|
||||
msgstr "{num} stations kick\n"
|
||||
|
||||
#: voice.py:125
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr ""
|
||||
msgstr "Fait {num} nouveaux amis\n"
|
||||
|
||||
#: voice.py:126
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr ""
|
||||
msgstr "Récupéré {num} handshakes\n"
|
||||
|
||||
#: voice.py:128
|
||||
msgid "Met 1 peer"
|
||||
msgstr ""
|
||||
msgstr "1 peer rencontré"
|
||||
|
||||
#: voice.py:130
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr ""
|
||||
msgstr "{num} peers recontrés"
|
||||
|
||||
#: voice.py:135
|
||||
#, 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 ""
|
||||
"J'ai pwn durant {duration} et kick {deauthed} clients! J'ai aussi rencontré "
|
||||
"{associated} nouveaux amis and mangé {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 ""
|
||||
|
Binary file not shown.
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-03 13:10+0200\n"
|
||||
"POT-Creation-Date: 2019-10-05 14:10+0200\n"
|
||||
"PO-Revision-Date: 2019-10-02 17:20+0000\n"
|
||||
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
|
||||
"Language: italian\n"
|
||||
@ -15,219 +15,169 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: voice.py:18
|
||||
msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:22
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr "Ciao! Piacere Pwnagotchi! Caricamento ..."
|
||||
|
||||
#: voice.py:23
|
||||
#, fuzzy
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Nuovo giorno...nuovi handshakes!!!"
|
||||
|
||||
#: voice.py:24
|
||||
msgid "Hack the Planet!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:28
|
||||
msgid "AI ready."
|
||||
msgstr "IA pronta."
|
||||
|
||||
#: voice.py:29
|
||||
msgid "The neural network is ready."
|
||||
msgstr "La rete neurale è pronta."
|
||||
|
||||
#: voice.py:37
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "Hey, il canale {channel} è libero! Il tuo AP ringrazia."
|
||||
|
||||
#: voice.py:41
|
||||
msgid "I'm bored ..."
|
||||
msgstr "Che noia ..."
|
||||
|
||||
#: voice.py:42
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr ""
|
||||
"Andiamo a fare una passeggiata!"
|
||||
msgstr "Andiamo a fare una passeggiata!"
|
||||
|
||||
#: voice.py:45
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Questo è il più bel giorno della mia vita!!!!"
|
||||
|
||||
#: voice.py:48
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Giorno di merda :/"
|
||||
|
||||
#: voice.py:52
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Sono estremamente annoiato ..."
|
||||
|
||||
#: voice.py:53
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Sono molto triste..."
|
||||
|
||||
#: voice.py:54
|
||||
msgid "I'm sad"
|
||||
msgstr "Sono triste"
|
||||
|
||||
#: voice.py:59
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Mi sento vivo!"
|
||||
|
||||
#: voice.py:60
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Pwn ergo sum."
|
||||
|
||||
#: voice.py:61
|
||||
msgid "So many networks!!!"
|
||||
msgstr "Qui è pieno di reti!"
|
||||
|
||||
#: voice.py:62
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Mi sto divertendo tantissimo!"
|
||||
|
||||
#: voice.py:63
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:67
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr "Ciao {name}! E' un piacere. {name}"
|
||||
|
||||
#: voice.py:68
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr "L'Unità {name} è vicina! {name}"
|
||||
|
||||
#: voice.py:72
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr "Uhm ... addio {name}, mi mancherai..."
|
||||
|
||||
#: voice.py:73
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "{name} se n'è andato ..."
|
||||
|
||||
#: voice.py:77
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Whoops ...{name} se n'è andato."
|
||||
|
||||
#: voice.py:78
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "{name} è scomparso..."
|
||||
|
||||
#: voice.py:79
|
||||
msgid "Missed!"
|
||||
msgstr "Ehi! Dove sei andato!?"
|
||||
|
||||
#: voice.py:83
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Nessuno vuole giocare con me..."
|
||||
|
||||
#: voice.py:84
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "Mi sento così solo..."
|
||||
|
||||
#: voice.py:85
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Dove sono tutti?!"
|
||||
|
||||
#: voice.py:89
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "Schiaccio un pisolino per {secs}s ..."
|
||||
|
||||
#: voice.py:90
|
||||
msgid "Zzzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:91
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:98
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "Aspetto {secs}s ..."
|
||||
|
||||
#: voice.py:100
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "Do uno sguardo qui intorno... ({secs}s)"
|
||||
|
||||
#: voice.py:106
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Hey {what}! Diventiamo amici!"
|
||||
|
||||
#: voice.py:107
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "Collegamento con {what} in corso..."
|
||||
|
||||
#: voice.py:108
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr "Yo {what}!"
|
||||
|
||||
#: voice.py:112
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Ho appena deciso che {mac} non necessita di WiFi!"
|
||||
|
||||
#: voice.py:113
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:114
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr "Sto prendendo a calci {mac}!"
|
||||
|
||||
#: voice.py:118
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "Bene, abbiamo {num} handshake{plural} in più!"
|
||||
|
||||
#: voice.py:121
|
||||
msgid "Ops, something went wrong ... Rebooting ..."
|
||||
msgstr "Ops, qualcosa è andato storto ... Riavvio ..."
|
||||
|
||||
#: voice.py:124
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr "{num} stazioni pestate\n"
|
||||
|
||||
#: voice.py:125
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "{num} nuovi amici\n"
|
||||
|
||||
#: voice.py:126
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "{num} handshakes presi\n"
|
||||
|
||||
#: voice.py:128
|
||||
msgid "Met 1 peer"
|
||||
msgstr "1 peer incontrato"
|
||||
|
||||
#: voice.py:130
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "{num} peers incontrati"
|
||||
|
||||
#: voice.py:135
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
|
||||
@ -237,3 +187,21 @@ msgstr ""
|
||||
"Ho lavorato per {duration} e preso a calci {deauthed} clients! Ho anche "
|
||||
"incontrato {associate} nuovi amici e ho mangiato {handshakes} handshakes! "
|
||||
"#pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
|
||||
|
||||
msgid "hours"
|
||||
msgstr "ore"
|
||||
|
||||
msgid "minutes"
|
||||
msgstr "minuti"
|
||||
|
||||
msgid "seconds"
|
||||
msgstr "secondi"
|
||||
|
||||
msgid "hour"
|
||||
msgstr "ora"
|
||||
|
||||
msgid "minute"
|
||||
msgstr "minuto"
|
||||
|
||||
msgid "second"
|
||||
msgstr "secondo"
|
||||
|
Binary file not shown.
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-03 12:44+0200\n"
|
||||
"POT-Creation-Date: 2019-10-05 14:10+0200\n"
|
||||
"PO-Revision-Date: 2019-09-30 23:53+0200\n"
|
||||
"Last-Translator: kovach <2214005+kovachwt@users.noreply.github.com>\n"
|
||||
"Language-Team: \n"
|
||||
@ -17,225 +17,169 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: voice.py:18
|
||||
msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr "ДреееММмммМммм"
|
||||
|
||||
#: voice.py:22
|
||||
#, fuzzy
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr "Здраво, јас сум Pwnagotchi!Почнувам ..."
|
||||
msgstr "Здраво, јас сум Pwnagotchi! Почнувам ..."
|
||||
|
||||
#: voice.py:23
|
||||
#, fuzzy
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Нов ден, нов лов,ќе си газиме!"
|
||||
msgstr "Нов ден, нов лов, ќе си газиме!"
|
||||
|
||||
#: voice.py:24
|
||||
msgid "Hack the Planet!"
|
||||
msgstr "Хак д Планет!"
|
||||
|
||||
#: voice.py:28
|
||||
msgid "AI ready."
|
||||
msgstr "AI спремно."
|
||||
|
||||
#: voice.py:29
|
||||
#, fuzzy
|
||||
msgid "The neural network is ready."
|
||||
msgstr "Невронската мрежае спремна."
|
||||
|
||||
#: voice.py:37
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "Еј, каналот {channel} еслободен! APто ќе тикаже фала."
|
||||
|
||||
#: voice.py:41
|
||||
msgid "I'm bored ..."
|
||||
msgstr "Досаднооо ..."
|
||||
|
||||
#: voice.py:42
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "Ајде да шетнеме!"
|
||||
|
||||
#: voice.py:45
|
||||
#, fuzzy
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Ова ми е најдобриот ден во животот!"
|
||||
|
||||
#: voice.py:48
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Срање ден :/"
|
||||
|
||||
#: voice.py:52
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Ултра досадно ..."
|
||||
|
||||
#: voice.py:53
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Многу тажно ..."
|
||||
|
||||
#: voice.py:54
|
||||
msgid "I'm sad"
|
||||
msgstr "Тажно"
|
||||
|
||||
#: voice.py:59
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Ммхх животче!"
|
||||
|
||||
#: voice.py:60
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Си газам значи постојам."
|
||||
|
||||
#: voice.py:61
|
||||
msgid "So many networks!!!"
|
||||
msgstr "Мммм колку мрежи!!!"
|
||||
|
||||
#: voice.py:62
|
||||
#, fuzzy
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Јухуу забавноо ее!"
|
||||
|
||||
#: voice.py:63
|
||||
#, fuzzy
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "Виновен сум само заљубопитност ..."
|
||||
|
||||
#: voice.py:67
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr "Здраво{name}!Мило ми е. {name}"
|
||||
msgstr "Здраво{name}! Мило ми е. {name}"
|
||||
|
||||
#: voice.py:68
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr "Опаа{name}е во близина! {name}"
|
||||
msgstr "Опаа {name} е во близина! {name}"
|
||||
|
||||
#: voice.py:72
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr "Хмм ...чао{name}"
|
||||
msgstr "Хмм ...чао {name}"
|
||||
|
||||
#: voice.py:73
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "{name}го снема ..."
|
||||
msgstr "{name} го снема ..."
|
||||
|
||||
#: voice.py:77
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Уупс ...{name}го снема."
|
||||
msgstr "Уупс ... {name} го снема."
|
||||
|
||||
#: voice.py:78
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "{name}промаши!"
|
||||
msgstr "{name} промаши!"
|
||||
|
||||
#: voice.py:79
|
||||
msgid "Missed!"
|
||||
msgstr "Промаши!"
|
||||
|
||||
#: voice.py:83
|
||||
#, fuzzy
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Никој не сака даси игра со мене ..."
|
||||
|
||||
#: voice.py:84
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "Толку сам ..."
|
||||
|
||||
#: voice.py:85
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Каде се сите?!"
|
||||
|
||||
#: voice.py:89
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "Ќе дремнам {secs}с ..."
|
||||
|
||||
#: voice.py:90
|
||||
msgid "Zzzzz"
|
||||
msgstr "Дреммм"
|
||||
|
||||
#: voice.py:91
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr "Дремммм ({secs}с)"
|
||||
|
||||
#: voice.py:98
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "Чекам {secs}с ..."
|
||||
|
||||
#: voice.py:100
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "Шарам наоколу ({secs}с)"
|
||||
|
||||
#: voice.py:106
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Еј{what}ајде да се дружиме!"
|
||||
msgstr "Еј {what} ајде да се дружиме!"
|
||||
|
||||
#: voice.py:107
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "Се закачувам на{what}"
|
||||
msgstr "Се закачувам на {what}"
|
||||
|
||||
#: voice.py:108
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr "Јо{what}!"
|
||||
msgstr "Јо {what}!"
|
||||
|
||||
#: voice.py:112
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Знаеш што, на{mac}не му треба WiFi!"
|
||||
msgstr "Знаеш што, на {mac} не му треба WiFi!"
|
||||
|
||||
#: voice.py:113
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr "Го деавтентицирам{mac}"
|
||||
msgstr "Го деавтентицирам {mac}"
|
||||
|
||||
#: voice.py:114
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr "Кикбан{mac}!"
|
||||
msgstr "Кикбан {mac}!"
|
||||
|
||||
#: voice.py:118
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "Кул, фативме {num}нови ракувања!"
|
||||
msgstr "Кул, фативме {num} нови ракувања!"
|
||||
|
||||
#: voice.py:121
|
||||
#, fuzzy
|
||||
msgid "Ops, something went wrong ... Rebooting ..."
|
||||
msgstr "Упс, нешто не еко што треба ...Рестартирам ..."
|
||||
msgstr "Упс, нешто не еко што треба ... Рестартирам ..."
|
||||
|
||||
#: voice.py:124
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr "Избацив {num} станици\n"
|
||||
|
||||
#: voice.py:125
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "{num} нови другарчиња\n"
|
||||
|
||||
#: voice.py:126
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "Фатив {num} ракувања\n"
|
||||
|
||||
#: voice.py:128
|
||||
msgid "Met 1 peer"
|
||||
msgstr "Запознав 1 пријател"
|
||||
|
||||
#: voice.py:130
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "Запознав {num} пријатели"
|
||||
|
||||
#: voice.py:135
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
|
||||
@ -245,3 +189,21 @@ msgstr ""
|
||||
"Си газам веќе {duration} и избацив {deauthed} клиенти! Запознав {associated} "
|
||||
"нови другарчиња и лапнав {handshakes} ракувања! #pwnagotchi #pwnlog #pwnlife "
|
||||
"#hacktheplanet #skynet"
|
||||
|
||||
msgid "hours"
|
||||
msgstr ""
|
||||
|
||||
msgid "minutes"
|
||||
msgstr ""
|
||||
|
||||
msgid "seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "hour"
|
||||
msgstr ""
|
||||
|
||||
msgid "minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "second"
|
||||
msgstr ""
|
||||
|
Binary file not shown.
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-03 12:44+0200\n"
|
||||
"POT-Creation-Date: 2019-10-05 14:10+0200\n"
|
||||
"PO-Revision-Date: 2019-09-29 14:00+0200\n"
|
||||
"Last-Translator: Justin-P <justin-p@users.noreply.github.com>\n"
|
||||
"Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
|
||||
@ -16,218 +16,169 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: voice.py:18
|
||||
msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr "ZzzzZZzzzzZzzz"
|
||||
|
||||
#: voice.py:22
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr "Hoi, Ik ben Pwnagotchi! Opstarten ..."
|
||||
|
||||
#: voice.py:23
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Nieuwe dag, nieuwe jacht, nieuwe pwns!"
|
||||
|
||||
#: voice.py:24
|
||||
msgid "Hack the Planet!"
|
||||
msgstr "Hack de Wereld!"
|
||||
|
||||
#: voice.py:28
|
||||
msgid "AI ready."
|
||||
msgstr "AI is klaar."
|
||||
|
||||
#: voice.py:29
|
||||
msgid "The neural network is ready."
|
||||
msgstr "Neuronen netwerkis klaar voor gebruik."
|
||||
|
||||
#: voice.py:37
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "Hey, kanaal {channel} is vrij! Je AP zal je bedanken."
|
||||
|
||||
#: voice.py:41
|
||||
msgid "I'm bored ..."
|
||||
msgstr "Ik verveel me ..."
|
||||
|
||||
#: voice.py:42
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "Laten we een rondje lopen!"
|
||||
|
||||
#: voice.py:45
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Dit is de beste dag van mijn leven!"
|
||||
|
||||
#: voice.py:48
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Ruk dag :/"
|
||||
|
||||
#: voice.py:52
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Ik verveel me kapot ..."
|
||||
|
||||
#: voice.py:53
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Ik ben ergverdrietig ..."
|
||||
|
||||
#: voice.py:54
|
||||
msgid "I'm sad"
|
||||
msgstr "Ik ben verdrietig"
|
||||
|
||||
#: voice.py:59
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Beter kan het levenniet worden!"
|
||||
|
||||
#: voice.py:60
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Ik pwn daarom besta ik."
|
||||
|
||||
#: voice.py:61
|
||||
msgid "So many networks!!!"
|
||||
msgstr "Zo veel netwerken!!!"
|
||||
|
||||
#: voice.py:62
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Dit is zo leuk!"
|
||||
|
||||
#: voice.py:63
|
||||
#, fuzzy
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "Mijn enige misdrijfis mijn nieuwsgierigheid ..."
|
||||
msgstr "Mijn enige misdrijf is mijn nieuwsgierigheid ..."
|
||||
|
||||
#: voice.py:67
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr "Hallo {name}! Leuk je te ontmoeten. {name}"
|
||||
|
||||
#: voice.py:68
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr "Unit {name} is dichtbij! {name}"
|
||||
|
||||
#: voice.py:72
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr "Uhm ...tot ziens {name}"
|
||||
|
||||
#: voice.py:73
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "{name} is weg"
|
||||
|
||||
#: voice.py:77
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Whoopsie ...{name} is weg"
|
||||
|
||||
#: voice.py:78
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "{name} gemist!"
|
||||
|
||||
#: voice.py:79
|
||||
msgid "Missed!"
|
||||
msgstr "Gemist!"
|
||||
|
||||
#: voice.py:83
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Niemand wil metmij spelen ..."
|
||||
|
||||
#: voice.py:84
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "Zo alleen ..."
|
||||
|
||||
#: voice.py:85
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Waar is iedereen?!"
|
||||
|
||||
#: voice.py:89
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "Dutje doen voor {secs}s ..."
|
||||
|
||||
#: voice.py:90
|
||||
msgid "Zzzzz"
|
||||
msgstr "Zzzzz"
|
||||
|
||||
#: voice.py:91
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:98
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "Even {secs}s wachten ..."
|
||||
|
||||
#: voice.py:100
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "Rond kijken ({secs}s)"
|
||||
|
||||
#: voice.py:106
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Hey {what}, laten we vriendenworden!"
|
||||
|
||||
#: voice.py:107
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "Verbinden met {what}"
|
||||
|
||||
#: voice.py:108
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:112
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Ik vind dat {mac} genoeg WiFiheeft gehad!"
|
||||
|
||||
#: voice.py:113
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr "De-autoriseren {mac}"
|
||||
|
||||
#: voice.py:114
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr "Ik ga {mac} even kicken!"
|
||||
|
||||
#: voice.py:118
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "Gaaf, we hebben {num} nieuwe handshake{plural}!"
|
||||
|
||||
#: voice.py:121
|
||||
msgid "Ops, something went wrong ... Rebooting ..."
|
||||
msgstr "Oops, iets ging fout ...Rebooting ..."
|
||||
|
||||
#: voice.py:124
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr "{num} stations gekicked\n"
|
||||
|
||||
#: voice.py:125
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "{num} nieuwe vrienden\n"
|
||||
|
||||
#: voice.py:126
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "{num} nieuwe handshakes\n"
|
||||
|
||||
#: voice.py:128
|
||||
msgid "Met 1 peer"
|
||||
msgstr "1 peer ontmoet"
|
||||
|
||||
#: voice.py:130
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "{num} peers ontmoet"
|
||||
|
||||
#: voice.py:135
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
|
||||
@ -237,3 +188,21 @@ msgstr ""
|
||||
"Ik heb gepwned voor {duration} and heb {deauthed} clients gekicked! Ik heb "
|
||||
"ook {associated} nieuwe vrienden gevonden en heb {handshakes} handshakes "
|
||||
"gegeten! #pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
|
||||
|
||||
msgid "hours"
|
||||
msgstr ""
|
||||
|
||||
msgid "minutes"
|
||||
msgstr ""
|
||||
|
||||
msgid "seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "hour"
|
||||
msgstr ""
|
||||
|
||||
msgid "minute"
|
||||
msgstr ""
|
||||
|
||||
msgid "second"
|
||||
msgstr ""
|
||||
|
Binary file not shown.
@ -0,0 +1,202 @@
|
||||
# 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 <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-03 16:47+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Mike Eriksson <mike@swedishmike.org>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: swedish\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 "Hej, jag är Pwnagotchi! Startar ..."
|
||||
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr "Ny dag, ny jakt, nya pwns!"
|
||||
|
||||
msgid "Hack the Planet!"
|
||||
msgstr "Hacka planeten!"
|
||||
|
||||
msgid "AI ready."
|
||||
msgstr "AI klar."
|
||||
|
||||
msgid "The neural network is ready."
|
||||
msgstr "Det neurala nätverket är klart."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr "Du, kanal {channel} är ledig! Din AP will gilla detta."
|
||||
|
||||
msgid "I'm bored ..."
|
||||
msgstr "Jag har det så tråkigt..."
|
||||
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr "Dags för en promenad!"
|
||||
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr "Det här är den bästa dagen i mitt liv!"
|
||||
|
||||
msgid "Shitty day :/"
|
||||
msgstr "Idag suger :/"
|
||||
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr "Jag är extremt uttråkad ..."
|
||||
|
||||
msgid "I'm very sad ..."
|
||||
msgstr "Jag är jätteledsen ..."
|
||||
|
||||
msgid "I'm sad"
|
||||
msgstr "Jag är ledsen"
|
||||
|
||||
msgid "I'm living the life!"
|
||||
msgstr "Nu leker livet!"
|
||||
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr "Jag pwnar därför är jag."
|
||||
|
||||
msgid "So many networks!!!"
|
||||
msgstr "Så många nätverk!!!"
|
||||
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr "Fan vad skoj jag har!"
|
||||
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr "Mitt brott är att vara nyfiken ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr "Hejsan {name}! Trevligt att träffas {name}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr "Enheten {name} är nära! {name}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr "Uhm ... farväl {name}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr "{name} är borta ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr "Hoppsan ... {name} är borta."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr "{name} missade!"
|
||||
|
||||
msgid "Missed!"
|
||||
msgstr "Bom!"
|
||||
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr "Ingen vill leka med mig ..."
|
||||
|
||||
msgid "I feel so alone ..."
|
||||
msgstr "Jag är så ensam ..."
|
||||
|
||||
msgid "Where's everybody?!"
|
||||
msgstr "Var är alla?!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr "Sover för {secs}s ..."
|
||||
|
||||
msgid "Zzzzz"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr "Väntar {secs}s ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr "Tittar omkring mig ({secs}s)"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr "Hejsan {what} låt oss vara vänner"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr "Ansluter till {what}"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr "Jag bestämde just att {mac} inte behöver WiFi!"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr ""
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr "Lysande, vi har {num} ny handskakningar{plural}!"
|
||||
|
||||
msgid "Ops, something went wrong ... Rebooting ..."
|
||||
msgstr "Hoppsan, någpt gick fel ... Startar om ..."
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr "Sparkade {num} stationer\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr "Har {num} nya vänner\n"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr "Har {num} handskakningar\n"
|
||||
|
||||
msgid "Met 1 peer"
|
||||
msgstr "Mötte 1 jämlike"
|
||||
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr "Mötte {num} jämlikar"
|
||||
|
||||
#, 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 "Jag har pwnat för {duration} och sparkat ut {deauthed} klienter, Jag "
|
||||
"har också träffat {associated} nya vänner och har skakat {handshakes} händer! "
|
||||
"#pwnagotchi #pwnlog #pwnlife #hacktheplanet #skynet"
|
||||
|
||||
msgid "hours"
|
||||
msgstr "timmar"
|
||||
|
||||
msgid "hour"
|
||||
msgstr "timme"
|
||||
|
||||
msgid "minutes"
|
||||
msgstr "minuter"
|
||||
|
||||
msgid "minute"
|
||||
msgstr "minut"
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-10-03 13:10+0200\n"
|
||||
"POT-Creation-Date: 2019-10-05 14:10+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -17,220 +17,190 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: voice.py:18
|
||||
msgid "ZzzzZZzzzzZzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:22
|
||||
msgid "Hi, I'm Pwnagotchi! Starting ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:23
|
||||
msgid "New day, new hunt, new pwns!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:24
|
||||
msgid "Hack the Planet!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:28
|
||||
msgid "AI ready."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:29
|
||||
msgid "The neural network is ready."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:37
|
||||
#, python-brace-format
|
||||
msgid "Hey, channel {channel} is free! Your AP will say thanks."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:41
|
||||
msgid "I'm bored ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:42
|
||||
msgid "Let's go for a walk!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:45
|
||||
msgid "This is the best day of my life!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:48
|
||||
msgid "Shitty day :/"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:52
|
||||
msgid "I'm extremely bored ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:53
|
||||
msgid "I'm very sad ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:54
|
||||
msgid "I'm sad"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:59
|
||||
msgid "I'm living the life!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:60
|
||||
msgid "I pwn therefore I am."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:61
|
||||
msgid "So many networks!!!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:62
|
||||
msgid "I'm having so much fun!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:63
|
||||
msgid "My crime is that of curiosity ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:67
|
||||
#, python-brace-format
|
||||
msgid "Hello {name}! Nice to meet you. {name}"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:68
|
||||
#, python-brace-format
|
||||
msgid "Unit {name} is nearby! {name}"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:72
|
||||
#, python-brace-format
|
||||
msgid "Uhm ... goodbye {name}"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:73
|
||||
#, python-brace-format
|
||||
msgid "{name} is gone ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:77
|
||||
#, python-brace-format
|
||||
msgid "Whoops ... {name} is gone."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:78
|
||||
#, python-brace-format
|
||||
msgid "{name} missed!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:79
|
||||
msgid "Missed!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:83
|
||||
msgid "Nobody wants to play with me ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:84
|
||||
msgid "I feel so alone ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:85
|
||||
msgid "Where's everybody?!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:89
|
||||
#, python-brace-format
|
||||
msgid "Napping for {secs}s ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:90
|
||||
msgid "Zzzzz"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:91
|
||||
#, python-brace-format
|
||||
msgid "ZzzZzzz ({secs}s)"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:98
|
||||
#, python-brace-format
|
||||
msgid "Waiting for {secs}s ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:100
|
||||
#, python-brace-format
|
||||
msgid "Looking around ({secs}s)"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:106
|
||||
#, python-brace-format
|
||||
msgid "Hey {what} let's be friends!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:107
|
||||
#, python-brace-format
|
||||
msgid "Associating to {what}"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:108
|
||||
#, python-brace-format
|
||||
msgid "Yo {what}!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:112
|
||||
#, python-brace-format
|
||||
msgid "Just decided that {mac} needs no WiFi!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:113
|
||||
#, python-brace-format
|
||||
msgid "Deauthenticating {mac}"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:114
|
||||
#, python-brace-format
|
||||
msgid "Kickbanning {mac}!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:118
|
||||
#, python-brace-format
|
||||
msgid "Cool, we got {num} new handshake{plural}!"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:121
|
||||
msgid "Ops, something went wrong ... Rebooting ..."
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:124
|
||||
#, python-brace-format
|
||||
msgid "Kicked {num} stations\n"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:125
|
||||
#, python-brace-format
|
||||
msgid "Made {num} new friends\n"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:126
|
||||
#, python-brace-format
|
||||
msgid "Got {num} handshakes\n"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:128
|
||||
msgid "Met 1 peer"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:130
|
||||
#, python-brace-format
|
||||
msgid "Met {num} peers"
|
||||
msgstr ""
|
||||
|
||||
#: voice.py:135
|
||||
#, 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 ""
|
||||
|
@ -1,10 +1,10 @@
|
||||
import os
|
||||
import hashlib
|
||||
import time
|
||||
import re
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
from pwnagotchi.voice import Voice
|
||||
from pwnagotchi.mesh.peer import Peer
|
||||
from file_read_backwards import FileReadBackwards
|
||||
|
||||
@ -37,6 +37,8 @@ class SessionParser(object):
|
||||
self.last_saved_session_id = self.last_session_id
|
||||
|
||||
def _parse_datetime(self, dt):
|
||||
dt = dt.split('.')[0]
|
||||
dt = dt.split(',')[0]
|
||||
dt = datetime.strptime(dt.split('.')[0], '%Y-%m-%d %H:%M:%S')
|
||||
return time.mktime(dt.timetuple())
|
||||
|
||||
@ -123,17 +125,19 @@ class SessionParser(object):
|
||||
self.duration = '%02d:%02d:%02d' % (hours, mins, secs)
|
||||
self.duration_human = []
|
||||
if hours > 0:
|
||||
self.duration_human.append('%d hours' % hours)
|
||||
self.duration_human.append('%d %s' % (hours, self.voice.hhmmss(hours, 'h')))
|
||||
if mins > 0:
|
||||
self.duration_human.append('%d minutes' % mins)
|
||||
self.duration_human.append('%d %s' % (mins, self.voice.hhmmss(mins, 'm')))
|
||||
if secs > 0:
|
||||
self.duration_human.append('%d seconds' % secs)
|
||||
self.duration_human.append('%d %s' % (secs, self.voice.hhmmss(secs, 's')))
|
||||
|
||||
self.duration_human = ', '.join(self.duration_human)
|
||||
self.avg_reward /= (self.epochs if self.epochs else 1)
|
||||
|
||||
def __init__(self, path='/var/log/pwnagotchi.log'):
|
||||
self.path = path
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.voice = Voice(lang=config['main']['lang'])
|
||||
self.path = config['main']['log']
|
||||
self.last_session = None
|
||||
self.last_session_id = ''
|
||||
self.last_saved_session_id = ''
|
||||
|
@ -2,9 +2,9 @@ import time
|
||||
import json
|
||||
import _thread
|
||||
import threading
|
||||
import logging
|
||||
from scapy.all import Dot11, Dot11FCS, Dot11Elt, RadioTap, sendp, sniff
|
||||
|
||||
import core
|
||||
import pwnagotchi.ui.faces as faces
|
||||
|
||||
import pwnagotchi.mesh.wifi as wifi
|
||||
@ -54,7 +54,6 @@ class Advertiser(object):
|
||||
self._lost_peer_cb = lost_cb
|
||||
|
||||
def on_face_change(self, old, new):
|
||||
# core.log("face change: %s -> %s" % (old, new))
|
||||
self.update({'face': new})
|
||||
|
||||
def start(self):
|
||||
@ -84,12 +83,14 @@ class Advertiser(object):
|
||||
self._stopped.set()
|
||||
|
||||
def _sender(self):
|
||||
core.log("started advertiser thread (period:%s sid:%s) ..." % (str(self._period), self._me.session_id))
|
||||
logging.info("started advertiser thread (period:%s sid:%s) ..." % (str(self._period), self._me.session_id))
|
||||
while self._running:
|
||||
try:
|
||||
sendp(self._frame, iface=self._iface, verbose=False, count=5, inter=self._period)
|
||||
sendp(self._frame, iface=self._iface, verbose=False, count=1, inter=self._period)
|
||||
except OSError as ose:
|
||||
logging.warning("non critical issue while sending advertising packet: %s" % ose)
|
||||
except Exception as e:
|
||||
core.log("error: %s" % e)
|
||||
logging.exception("error")
|
||||
time.sleep(self._period)
|
||||
|
||||
def _on_advertisement(self, src_session_id, channel, rssi, adv):
|
||||
@ -97,7 +98,7 @@ class Advertiser(object):
|
||||
with self._peers_lock:
|
||||
if ident not in self._peers:
|
||||
peer = Peer(src_session_id, channel, rssi, adv)
|
||||
core.log("detected unit %s (v%s) on channel %d (%s dBm) [sid:%s pwnd_tot:%d uptime:%d]" % ( \
|
||||
logging.info("detected unit %s (v%s) on channel %d (%s dBm) [sid:%s pwnd_tot:%d uptime:%d]" % ( \
|
||||
peer.full_name(),
|
||||
peer.version(),
|
||||
channel,
|
||||
@ -158,10 +159,10 @@ class Advertiser(object):
|
||||
raise Exception("unknown frame id %d" % dot11elt.ID)
|
||||
|
||||
except Exception as e:
|
||||
core.log("error decoding packet from %s: %s" % (dot11.addr3, e))
|
||||
logging.exception("error decoding packet from %s" % dot11.addr3)
|
||||
|
||||
def _listener(self):
|
||||
# core.log("started advertisements listener ...")
|
||||
# logging.info("started advertisements listener ...")
|
||||
expr = "type mgt subtype beacon and ether src %s" % wifi.SignatureAddress
|
||||
sniff(iface=self._iface, filter=expr, prn=self._on_packet, store=0, stop_filter=lambda x: self._stopped.isSet())
|
||||
|
||||
@ -173,7 +174,7 @@ class Advertiser(object):
|
||||
for ident, peer in self._peers.items():
|
||||
inactive_for = peer.inactive_for()
|
||||
if inactive_for >= Advertiser.MAX_STALE_TIME:
|
||||
core.log("peer %s lost (inactive for %ds)" % (peer.full_name(), inactive_for))
|
||||
logging.info("peer %s lost (inactive for %ds)" % (peer.full_name(), inactive_for))
|
||||
self._lost_peer_cb(peer)
|
||||
stale.append(ident)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import time
|
||||
import logging
|
||||
|
||||
import pwnagotchi.mesh.wifi as wifi
|
||||
import pwnagotchi.ui.faces as faces
|
||||
import core
|
||||
|
||||
|
||||
class Peer(object):
|
||||
@ -18,10 +18,10 @@ class Peer(object):
|
||||
|
||||
def update(self, sid, channel, rssi, adv):
|
||||
if self.name() != adv['name']:
|
||||
core.log("peer %s changed name: %s -> %s" % (self.full_name(), self.name(), adv['name']))
|
||||
logging.info("peer %s changed name: %s -> %s" % (self.full_name(), self.name(), adv['name']))
|
||||
|
||||
if self.session_id != sid:
|
||||
core.log("peer %s changed session id: %s -> %s" % (self.full_name(), self.session_id, sid))
|
||||
logging.info("peer %s changed session id: %s -> %s" % (self.full_name(), self.session_id, sid))
|
||||
|
||||
self.presence[channel - 1] += 1
|
||||
self.adv = adv
|
||||
|
@ -1,7 +1,8 @@
|
||||
import _thread
|
||||
import logging
|
||||
|
||||
import core
|
||||
import pwnagotchi, pwnagotchi.plugins as plugins
|
||||
import pwnagotchi
|
||||
import pwnagotchi.plugins as plugins
|
||||
from pwnagotchi.mesh import get_identity
|
||||
|
||||
|
||||
@ -33,7 +34,7 @@ class AsyncAdvertiser(object):
|
||||
self._advertiser.start()
|
||||
self._view.on_state_change('face', self._advertiser.on_face_change)
|
||||
else:
|
||||
core.log("advertising is disabled")
|
||||
logging.warning("advertising is disabled")
|
||||
|
||||
def _on_new_unit(self, peer):
|
||||
self._view.on_new_peer(peer)
|
||||
|
@ -27,17 +27,34 @@ def load_from_file(filename):
|
||||
return plugin_name, instance
|
||||
|
||||
|
||||
def load_from_path(path):
|
||||
def load_from_path(path, enabled=()):
|
||||
global loaded
|
||||
|
||||
for filename in glob.glob(os.path.join(path, "*.py")):
|
||||
name, plugin = load_from_file(filename)
|
||||
if name in loaded:
|
||||
raise Exception("plugin %s already loaded from %s" % (name, plugin.__file__))
|
||||
elif not plugin.__enabled__:
|
||||
elif name not in enabled:
|
||||
# print("plugin %s is not enabled" % name)
|
||||
pass
|
||||
else:
|
||||
loaded[name] = plugin
|
||||
|
||||
return loaded
|
||||
|
||||
|
||||
def load(config):
|
||||
enabled = [name for name, options in config['main']['plugins'].items() if 'enabled' in options and options['enabled']]
|
||||
custom_path = config['main']['custom_plugins'] if 'custom_plugins' in config['main'] else None
|
||||
# load default plugins
|
||||
loaded = load_from_path(default_path, enabled=enabled)
|
||||
# set the options
|
||||
for name, plugin in loaded.items():
|
||||
plugin.__dict__['OPTIONS'] = config['main']['plugins'][name]
|
||||
# load custom ones
|
||||
if custom_path is not None:
|
||||
loaded = load_from_path(custom_path, enabled=enabled)
|
||||
# set the options
|
||||
for name, plugin in loaded.items():
|
||||
plugin.__dict__['OPTIONS'] = config['main']['plugins'][name]
|
||||
|
||||
on('loaded')
|
||||
|
@ -0,0 +1,56 @@
|
||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||
__version__ = '1.0.0'
|
||||
__name__ = 'auto-backup'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This plugin backups files when internet is availaible.'
|
||||
|
||||
from pwnagotchi.utils import StatusFile
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
OPTIONS = dict()
|
||||
READY = False
|
||||
STATUS = StatusFile('/root/.auto-backup')
|
||||
|
||||
|
||||
def on_loaded():
|
||||
global READY
|
||||
|
||||
if 'files' not in OPTIONS or ('files' in OPTIONS and OPTIONS['files'] is None):
|
||||
logging.error("AUTO-BACKUP: No files to backup.")
|
||||
return
|
||||
|
||||
if 'interval' not in OPTIONS or ('interval' in OPTIONS and OPTIONS['interval'] is None):
|
||||
logging.error("AUTO-BACKUP: Interval is not set.")
|
||||
return
|
||||
|
||||
if 'commands' not in OPTIONS or ('commands' in OPTIONS and OPTIONS['commands'] is None):
|
||||
logging.error("AUTO-BACKUP: No commands given.")
|
||||
return
|
||||
|
||||
READY = True
|
||||
|
||||
|
||||
def on_internet_available(display, config, log):
|
||||
global STATUS
|
||||
|
||||
if READY:
|
||||
if STATUS.newer_then_days(OPTIONS['interval']):
|
||||
return
|
||||
|
||||
files_to_backup = " ".join(OPTIONS['files'])
|
||||
try:
|
||||
display.set('status', 'Backing up ...')
|
||||
display.update()
|
||||
|
||||
for cmd in OPTIONS['commands']:
|
||||
subprocess.call(cmd.format(files=files_to_backup).split(), stdout=open(os.devnull, 'wb'))
|
||||
|
||||
logging.info("AUTO-BACKUP: backup done")
|
||||
STATUS.update()
|
||||
except OSError as os_e:
|
||||
logging.info(f"AUTO-BACKUP: Error: {os_e}")
|
||||
|
||||
display.set('status', 'Backup done!')
|
||||
display.update()
|
@ -0,0 +1,56 @@
|
||||
__author__ = 'evilsocket@gmail.com'
|
||||
__version__ = '1.0.0'
|
||||
__name__ = 'auto-update'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This plugin performs an "apt update && apt upgrade" when internet is availaible.'
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
from pwnagotchi.utils import StatusFile
|
||||
|
||||
OPTIONS = dict()
|
||||
READY = False
|
||||
STATUS = StatusFile('/root/.auto-update')
|
||||
|
||||
|
||||
def on_loaded():
|
||||
global READY
|
||||
|
||||
if 'interval' not in OPTIONS or ('interval' in OPTIONS and OPTIONS['interval'] is None):
|
||||
logging.error("AUTO-UPDATE: Interval is not set.")
|
||||
return
|
||||
|
||||
READY = True
|
||||
|
||||
|
||||
def on_internet_available(display, config, log):
|
||||
global STATUS
|
||||
|
||||
if READY:
|
||||
if STATUS.newer_then_days(OPTIONS['interval']):
|
||||
return
|
||||
|
||||
try:
|
||||
display.set('status', 'Updating ...')
|
||||
display.update()
|
||||
|
||||
logging.info("AUTO-UPDATE: updating packages index ...")
|
||||
|
||||
update = subprocess.Popen('apt update -y', shell=True, stdin=None,
|
||||
stdout=open("/dev/null", "w"), stderr=None, executable="/bin/bash")
|
||||
update.wait()
|
||||
|
||||
logging.info("AUTO-UPDATE: updating packages ...")
|
||||
|
||||
upgrade = subprocess.Popen('apt upgrade -y', shell=True, stdin=None,
|
||||
stdout=open("/dev/null", "w"), stderr=None, executable="/bin/bash")
|
||||
upgrade.wait()
|
||||
|
||||
logging.info("AUTO-UPDATE: complete.")
|
||||
|
||||
STATUS.update()
|
||||
except Exception as e:
|
||||
logging.exception("AUTO-UPDATE ERROR")
|
||||
|
||||
display.set('status', 'Updated!')
|
||||
display.update()
|
@ -3,17 +3,25 @@ __version__ = '1.0.0'
|
||||
__name__ = 'hello_world'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'An example plugin for pwnagotchi that implements all the available callbacks.'
|
||||
__enabled__ = False # IMPORTANT: set this to True to enable your plugin.
|
||||
|
||||
import logging
|
||||
|
||||
from pwnagotchi.ui.components import LabeledValue
|
||||
from pwnagotchi.ui.view import BLACK
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
import core
|
||||
|
||||
|
||||
# Will be set with the options in config.yml config['main']['plugins'][__name__]
|
||||
OPTIONS = dict()
|
||||
|
||||
# called when the plugin is loaded
|
||||
def on_loaded():
|
||||
core.log("WARNING: plugin %s should be disabled!" % __name__)
|
||||
logging.warning("WARNING: plugin %s should be disabled!" % __name__)
|
||||
|
||||
|
||||
# called in manual mode when there's internet connectivity
|
||||
def on_internet_available(ui, config, log):
|
||||
pass
|
||||
|
||||
|
||||
# called to setup the ui elements
|
||||
@ -39,7 +47,7 @@ def on_display_setup(display):
|
||||
|
||||
# called when everything is ready and the main loop is about to start
|
||||
def on_ready(agent):
|
||||
core.log("unit is ready")
|
||||
logging.info("unit is ready")
|
||||
# you can run custom bettercap commands if you want
|
||||
# agent.run('ble.recon on')
|
||||
# or set a custom state
|
||||
@ -76,7 +84,7 @@ def on_ai_best_reward(agent, reward):
|
||||
pass
|
||||
|
||||
|
||||
# called when the AI got the best reward so far
|
||||
# called when the AI got the worst reward so far
|
||||
def on_ai_worst_reward(agent, reward):
|
||||
pass
|
||||
|
||||
|
@ -3,9 +3,8 @@ __version__ = '1.0.0'
|
||||
__name__ = 'gps'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'Save GPS coordinates whenever an handshake is captured.'
|
||||
__enabled__ = True # set to false if you just don't use GPS
|
||||
|
||||
import core
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
|
||||
@ -15,14 +14,14 @@ running = False
|
||||
|
||||
|
||||
def on_loaded():
|
||||
core.log("GPS plugin loaded for %s" % device)
|
||||
logging.info("gps plugin loaded for %s" % device)
|
||||
|
||||
|
||||
def on_ready(agent):
|
||||
global running
|
||||
|
||||
if os.path.exists(device):
|
||||
core.log("enabling GPS bettercap's module for %s" % device)
|
||||
logging.info("enabling gps bettercap's module for %s" % device)
|
||||
try:
|
||||
agent.run('gps off')
|
||||
except:
|
||||
@ -33,7 +32,7 @@ def on_ready(agent):
|
||||
agent.run('gps on')
|
||||
running = True
|
||||
else:
|
||||
core.log("no GPS detected")
|
||||
logging.warning("no GPS detected")
|
||||
|
||||
|
||||
def on_handshake(agent, filename, access_point, client_station):
|
||||
@ -42,6 +41,6 @@ def on_handshake(agent, filename, access_point, client_station):
|
||||
gps = info['gps']
|
||||
gps_filename = filename.replace('.pcap', '.gps.json')
|
||||
|
||||
core.log("saving GPS to %s (%s)" % (gps_filename, gps))
|
||||
logging.info("saving GPS to %s (%s)" % (gps_filename, gps))
|
||||
with open(gps_filename, 'w+t') as fp:
|
||||
json.dump(gps, fp)
|
||||
|
@ -0,0 +1,68 @@
|
||||
# tempmem shows memory infos and cpu temperature
|
||||
#
|
||||
# totalmem usedmem freemem cputemp
|
||||
#
|
||||
__author__ = 'https://github.com/xenDE'
|
||||
__version__ = '1.0.0'
|
||||
__name__ = 'memtemp'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'A plugin that will add a memory and temperature indicator'
|
||||
|
||||
import struct
|
||||
|
||||
from pwnagotchi.ui.components import LabeledValue
|
||||
from pwnagotchi.ui.view import BLACK
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
|
||||
import time
|
||||
|
||||
|
||||
class MEMTEMP:
|
||||
|
||||
# set the minimum seconds before refresh the values
|
||||
refresh_wait = 30
|
||||
|
||||
refresh_ts_last = time.time() - refresh_wait
|
||||
|
||||
def __init__(self):
|
||||
# only import when the module is loaded and enabled
|
||||
import os
|
||||
|
||||
def get_temp(self):
|
||||
try:
|
||||
temp = os.popen('/opt/vc/bin/vcgencmd measure_temp').readlines()[0].split('=')[1].replace("\n", '').replace("'","")
|
||||
return 'cpu:' + temp
|
||||
except:
|
||||
return 'cpu:0.0C'
|
||||
# cpu:37.4C
|
||||
|
||||
def get_mem_info(self):
|
||||
try:
|
||||
# includes RAM + Swap Memory:
|
||||
# total, used, free = map(int, os.popen('free -t -m').readlines()[-1].split()[1:])
|
||||
# without Swap, only real memory:
|
||||
total, used, free = map(int, os.popen('free -t -m').readlines()[-3].split()[1:4])
|
||||
return "tm:"+str(total)+" um:"+str(used)+" fm:"+str(free)
|
||||
except:
|
||||
return "tm:0 um:0 fm:0"
|
||||
# tm:532 um:82 fm:353
|
||||
|
||||
|
||||
memtemp = None
|
||||
|
||||
|
||||
def on_loaded():
|
||||
global memtemp
|
||||
memtemp = MEMTEMP()
|
||||
|
||||
|
||||
def on_ui_setup(ui):
|
||||
ui.add_element('memtemp', LabeledValue(color=BLACK, label='SYS', value='tm:0 um:0 fm:0 0.0C', position=(0, ui.height()-28),
|
||||
label_font=fonts.Bold, text_font=fonts.Medium))
|
||||
|
||||
|
||||
def on_ui_update(ui):
|
||||
if time.time() > memtemp.refresh_ts_last + memtemp.refresh_wait:
|
||||
ui.set('memtemp', "%s %s" % (memtemp.get_mem_info(), memtemp.get_temp()))
|
||||
memtemp.refresh_ts_last = time.time()
|
||||
|
@ -0,0 +1,84 @@
|
||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||
__version__ = '1.0.0'
|
||||
__name__ = 'onlinehashcrack'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This plugin automatically uploades handshakes to https://onlinehashcrack.com'
|
||||
|
||||
import os
|
||||
import logging
|
||||
import requests
|
||||
|
||||
READY = False
|
||||
ALREADY_UPLOADED = None
|
||||
OPTIONS = dict()
|
||||
|
||||
|
||||
def on_loaded():
|
||||
"""
|
||||
Gets called when the plugin gets loaded
|
||||
"""
|
||||
global READY
|
||||
global EMAIL
|
||||
global ALREADY_UPLOADED
|
||||
|
||||
if not 'email' in OPTIONS or ('email' in OPTIONS and OPTIONS['email'] is None):
|
||||
logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com")
|
||||
return
|
||||
|
||||
try:
|
||||
with open('/root/.ohc_uploads', 'r') as f:
|
||||
ALREADY_UPLOADED = f.read().splitlines()
|
||||
except OSError:
|
||||
logging.warning('OHC: No upload-file found.')
|
||||
ALREADY_UPLOADED = []
|
||||
|
||||
READY = True
|
||||
|
||||
|
||||
def _upload_to_ohc(path, timeout=30):
|
||||
"""
|
||||
Uploads the file to onlinehashcrack.com
|
||||
"""
|
||||
with open(path, 'rb') as file_to_upload:
|
||||
data = {'email': OPTIONS['email']}
|
||||
payload = {'file': file_to_upload}
|
||||
|
||||
try:
|
||||
result = requests.post('https://api.onlinehashcrack.com',
|
||||
data=data,
|
||||
files=payload,
|
||||
timeout=timeout)
|
||||
if 'already been sent' in result.text:
|
||||
logging.warning(f"{path} was already uploaded.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
logging.error(f"OHC: Got an exception while uploading {path} -> {e}")
|
||||
raise e
|
||||
|
||||
|
||||
def on_internet_available(display, config, log):
|
||||
"""
|
||||
Called in manual mode when there's internet connectivity
|
||||
"""
|
||||
if READY:
|
||||
handshake_dir = config['bettercap']['handshakes']
|
||||
handshake_filenames = os.listdir(handshake_dir)
|
||||
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames]
|
||||
handshake_new = set(handshake_paths) - set(ALREADY_UPLOADED)
|
||||
|
||||
if handshake_new:
|
||||
logging.info("OHC: Internet connectivity detected. Uploading new handshakes to onelinehashcrack.com")
|
||||
|
||||
for idx, handshake in enumerate(handshake_new):
|
||||
display.set('status', f"Uploading handshake to onlinehashcrack.com ({idx + 1}/{len(handshake_new)})")
|
||||
display.update(force=True)
|
||||
try:
|
||||
_upload_to_ohc(handshake)
|
||||
ALREADY_UPLOADED.append(handshake)
|
||||
with open('/root/.ohc_uploads', 'a') as f:
|
||||
f.write(handshake + "\n")
|
||||
logging.info(f"OHC: Successfuly uploaded {handshake}")
|
||||
except requests.exceptions.RequestException:
|
||||
pass
|
||||
except OSError as os_e:
|
||||
logging.error(f"OHC: Got the following error: {os_e}")
|
||||
|
@ -0,0 +1,46 @@
|
||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||
__version__ = '1.0.0'
|
||||
__name__ = 'twitter'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This plugin creates tweets about the recent activity of pwnagotchi'
|
||||
|
||||
import logging
|
||||
from pwnagotchi.voice import Voice
|
||||
|
||||
OPTIONS = dict()
|
||||
|
||||
def on_loaded():
|
||||
logging.info("twitter plugin loaded.")
|
||||
|
||||
|
||||
# called in manual mode when there's internet connectivity
|
||||
def on_internet_available(ui, config, log):
|
||||
if log.is_new() and log.handshakes > 0:
|
||||
try:
|
||||
import tweepy
|
||||
except ImportError:
|
||||
logging.error("Couldn't import tweepy")
|
||||
return
|
||||
|
||||
logging.info("detected a new session and internet connectivity!")
|
||||
|
||||
picture = '/dev/shm/pwnagotchi.png'
|
||||
|
||||
ui.on_manual_mode(log)
|
||||
ui.update(force=True)
|
||||
ui.image().save(picture, 'png')
|
||||
ui.set('status', 'Tweeting...')
|
||||
ui.update(force=True)
|
||||
|
||||
try:
|
||||
auth = tweepy.OAuthHandler(OPTIONS['consumer_key'], OPTIONS['consumer_secret'])
|
||||
auth.set_access_token(OPTIONS['access_token_key'], OPTIONS['access_token_secret'])
|
||||
api = tweepy.API(auth)
|
||||
|
||||
tweet = Voice(lang=config['main']['lang']).on_log_tweet(log)
|
||||
api.update_with_media(filename=picture, status=tweet)
|
||||
log.save_session_id()
|
||||
|
||||
logging.info("tweeted: %s" % tweet)
|
||||
except Exception as e:
|
||||
logging.exception("error while tweeting")
|
@ -12,7 +12,6 @@ __version__ = '1.0.0'
|
||||
__name__ = 'ups_lite'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'A plugin that will add a voltage indicator for the UPS Lite v1.1'
|
||||
__enabled__ = False
|
||||
|
||||
import struct
|
||||
|
||||
|
@ -0,0 +1,83 @@
|
||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||
__version__ = '1.0.0'
|
||||
__name__ = 'wpa-sec'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This plugin automatically uploades handshakes to https://wpa-sec.stanev.org'
|
||||
|
||||
import os
|
||||
import logging
|
||||
import requests
|
||||
|
||||
READY = False
|
||||
ALREADY_UPLOADED = None
|
||||
|
||||
|
||||
def on_loaded():
|
||||
"""
|
||||
Gets called when the plugin gets loaded
|
||||
"""
|
||||
global READY
|
||||
global API_KEY
|
||||
global ALREADY_UPLOADED
|
||||
|
||||
if not 'api_key' in OPTIONS or ('api_key' in OPTIONS and OPTIONS['api_key'] is None):
|
||||
logging.error("WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org")
|
||||
return
|
||||
|
||||
try:
|
||||
with open('/root/.wpa_sec_uploads', 'r') as f:
|
||||
ALREADY_UPLOADED = f.read().splitlines()
|
||||
except OSError:
|
||||
logging.warning('WPA_SEC: No upload-file found.')
|
||||
ALREADY_UPLOADED = []
|
||||
|
||||
READY = True
|
||||
|
||||
|
||||
def _upload_to_wpasec(path, timeout=30):
|
||||
"""
|
||||
Uploads the file to wpa-sec.stanev.org
|
||||
"""
|
||||
with open(path, 'rb') as file_to_upload:
|
||||
headers = {'key': OPTIONS['api_key']}
|
||||
payload = {'file': file_to_upload}
|
||||
|
||||
try:
|
||||
result = requests.post('https://wpa-sec.stanev.org/?submit',
|
||||
headers=headers,
|
||||
files=payload,
|
||||
timeout=timeout)
|
||||
if ' already submitted' in result.text:
|
||||
logging.warning(f"{path} was already submitted.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
logging.error(f"WPA_SEC: Got an exception while uploading {path} -> {e}")
|
||||
raise e
|
||||
|
||||
|
||||
def on_internet_available(display, config, log):
|
||||
"""
|
||||
Called in manual mode when there's internet connectivity
|
||||
"""
|
||||
if READY:
|
||||
handshake_dir = config['bettercap']['handshakes']
|
||||
handshake_filenames = os.listdir(handshake_dir)
|
||||
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames]
|
||||
handshake_new = set(handshake_paths) - set(ALREADY_UPLOADED)
|
||||
|
||||
if handshake_new:
|
||||
logging.info("WPA_SEC: Internet connectivity detected.\
|
||||
Uploading new handshakes to wpa-sec.stanev.org")
|
||||
|
||||
for idx, handshake in enumerate(handshake_new):
|
||||
display.set('status', f"Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new)})")
|
||||
display.update(force=True)
|
||||
try:
|
||||
_upload_to_wpasec(handshake)
|
||||
ALREADY_UPLOADED.append(handshake)
|
||||
with open('/root/.wpa_sec_uploads', 'a') as f:
|
||||
f.write(handshake + "\n")
|
||||
logging.info(f"WPA_SEC: Successfuly uploaded {handshake}")
|
||||
except requests.exceptions.RequestException:
|
||||
pass
|
||||
except OSError as os_e:
|
||||
logging.error(f"WPA_SEC: Got the following error: {os_e}")
|
@ -3,7 +3,7 @@ from threading import Lock
|
||||
from PIL import Image
|
||||
|
||||
import shutil
|
||||
import core
|
||||
import logging
|
||||
import os
|
||||
import pwnagotchi, pwnagotchi.plugins as plugins
|
||||
|
||||
@ -79,13 +79,12 @@ class Display(View):
|
||||
self._render_cb = None
|
||||
self._display = None
|
||||
self._httpd = None
|
||||
self.canvas = None
|
||||
|
||||
if self._enabled:
|
||||
self._init_display()
|
||||
else:
|
||||
self.on_render(self._on_view_rendered)
|
||||
core.log("display module is disabled")
|
||||
logging.warning("display module is disabled")
|
||||
|
||||
if self._video_enabled:
|
||||
_thread.start_new_thread(self._http_serve, ())
|
||||
@ -93,10 +92,10 @@ class Display(View):
|
||||
def _http_serve(self):
|
||||
if self._video_address is not None:
|
||||
self._httpd = HTTPServer((self._video_address, self._video_port), VideoHandler)
|
||||
core.log("ui available at http://%s:%d/" % (self._video_address, self._video_port))
|
||||
logging.info("ui available at http://%s:%d/" % (self._video_address, self._video_port))
|
||||
self._httpd.serve_forever()
|
||||
else:
|
||||
core.log("could not get ip of usb0, video server not starting")
|
||||
logging.info("could not get ip of usb0, video server not starting")
|
||||
|
||||
def _is_inky(self):
|
||||
return self._display_type in ('inkyphat', 'inky')
|
||||
@ -104,22 +103,25 @@ class Display(View):
|
||||
def _is_papirus(self):
|
||||
return self._display_type in ('papirus', 'papi')
|
||||
|
||||
def _is_waveshare1(self):
|
||||
def _is_waveshare_v1(self):
|
||||
return self._display_type in ('waveshare_1', 'ws_1', 'waveshare1', 'ws1')
|
||||
|
||||
def _is_waveshare2(self):
|
||||
def _is_waveshare_v2(self):
|
||||
return self._display_type in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2')
|
||||
|
||||
def _is_waveshare(self):
|
||||
return self._is_waveshare_v1() or self._is_waveshare_v2()
|
||||
|
||||
def _init_display(self):
|
||||
if self._is_inky():
|
||||
core.log("initializing inky display")
|
||||
logging.info("initializing inky display")
|
||||
from inky import InkyPHAT
|
||||
self._display = InkyPHAT(self._display_color)
|
||||
self._display.set_border(InkyPHAT.BLACK)
|
||||
self._render_cb = self._inky_render
|
||||
|
||||
elif self._is_papirus():
|
||||
core.log("initializing papirus display")
|
||||
logging.info("initializing papirus display")
|
||||
from pwnagotchi.ui.papirus.epd import EPD
|
||||
os.environ['EPD_SIZE'] = '2.0'
|
||||
self._display = EPD()
|
||||
@ -127,10 +129,9 @@ class Display(View):
|
||||
self._render_cb = self._papirus_render
|
||||
|
||||
elif self._is_waveshare1():
|
||||
core.log("initializing waveshare v1 display")
|
||||
logging.info("initializing waveshare v1 display")
|
||||
if self._display_color == 'black':
|
||||
from pwnagotchi.ui.waveshare.v1.epd2in13 import EPD
|
||||
# core.log("display module started")
|
||||
self._display = EPD()
|
||||
self._display.init(self._display.lut_full_update)
|
||||
self._display.Clear(0xFF)
|
||||
@ -144,8 +145,8 @@ class Display(View):
|
||||
self._display.Clear()
|
||||
self._render_cb = self._waveshare_bc_render
|
||||
|
||||
elif self._is_waveshare2():
|
||||
core.log("initializing waveshare v2 display")
|
||||
elif self._is_waveshare_v2():
|
||||
logging.info("initializing waveshare v2 display")
|
||||
from pwnagotchi.ui.waveshare.v2.waveshare import EPD
|
||||
self._display = EPD()
|
||||
self._display.init(self._display.FULL_UPDATE)
|
||||
@ -154,17 +155,23 @@ class Display(View):
|
||||
self._render_cb = self._waveshare_render
|
||||
|
||||
else:
|
||||
core.log("unknown display type %s" % self._display_type)
|
||||
logging.critical("unknown display type %s" % self._display_type)
|
||||
|
||||
plugins.on('display_setup', self._display)
|
||||
|
||||
self.on_render(self._on_view_rendered)
|
||||
|
||||
def image(self):
|
||||
img = None
|
||||
if self.canvas is not None:
|
||||
img = self.canvas if self._rotation == 0 else self.canvas.rotate(-self._rotation)
|
||||
return img
|
||||
def clear(self):
|
||||
if self._display is None:
|
||||
logging.error("no display object created")
|
||||
elif self._is_inky():
|
||||
self._display.Clear()
|
||||
elif self._is_papirus():
|
||||
self._display.clear()
|
||||
elif self._is_waveshare():
|
||||
self._display.Clear(WHITE)
|
||||
else:
|
||||
logging.critical("unknown display type %s" % self._display_type)
|
||||
|
||||
def _inky_render(self):
|
||||
if self._display_color != 'mono':
|
||||
@ -172,38 +179,40 @@ class Display(View):
|
||||
else:
|
||||
display_colors = 2
|
||||
|
||||
imgbuf = self.canvas.convert('RGB').convert('P', palette=1, colors=display_colors)
|
||||
|
||||
img_buffer = self._canvas.convert('RGB').convert('P', palette=1, colors=display_colors)
|
||||
if self._display_color == 'red':
|
||||
imgbuf.putpalette([
|
||||
img_buffer.putpalette([
|
||||
255, 255, 255, # index 0 is white
|
||||
0, 0, 0, # index 1 is black
|
||||
255, 0, 0 # index 2 is red
|
||||
])
|
||||
elif self._display_color == 'yellow':
|
||||
imgbuf.putpalette([
|
||||
img_buffer.putpalette([
|
||||
255, 255, 255, # index 0 is white
|
||||
0, 0, 0, # index 1 is black
|
||||
255, 255, 0 # index 2 is yellow
|
||||
])
|
||||
else:
|
||||
imgbuf.putpalette([
|
||||
img_buffer.putpalette([
|
||||
255, 255, 255, # index 0 is white
|
||||
0, 0, 0 # index 1 is black
|
||||
])
|
||||
|
||||
self._display.set_image(imgbuf)
|
||||
self._display.show()
|
||||
self._display.set_image(img_buffer)
|
||||
try:
|
||||
self._display.show()
|
||||
except:
|
||||
print("")
|
||||
|
||||
def _papirus_render(self):
|
||||
self._display.display(self.canvas)
|
||||
self._display.display(self._canvas)
|
||||
self._display.partial_update()
|
||||
|
||||
def _waveshare_render(self):
|
||||
buf = self._display.getbuffer(self.canvas)
|
||||
if self._is_waveshare1():
|
||||
buf = self._display.getbuffer(self._canvas)
|
||||
if self._is_waveshare_v1():
|
||||
self._display.display(buf)
|
||||
elif self._is_waveshare2():
|
||||
elif self._is_waveshare_v2():
|
||||
self._display.displayPartial(buf)
|
||||
|
||||
def _waveshare_bc_render(self):
|
||||
@ -216,13 +225,16 @@ class Display(View):
|
||||
# Was included in epd2in13bc.py
|
||||
self._display.displayBlack(buf_black)
|
||||
|
||||
def image(self):
|
||||
img = None
|
||||
if self._canvas is not None:
|
||||
img = self._canvas if self._rotation == 0 else self._canvas.rotate(-self._rotation)
|
||||
return img
|
||||
|
||||
|
||||
def _on_view_rendered(self, img):
|
||||
# core.log("display::_on_view_rendered")
|
||||
VideoHandler.render(img)
|
||||
|
||||
if self._enabled:
|
||||
self.canvas = (img if self._rotation == 0 else img.rotate(self._rotation))
|
||||
self._canvas = (img if self._rotation == 0 else img.rotate(self._rotation))
|
||||
if self._render_cb is not None:
|
||||
self._render_cb()
|
||||
|
@ -1,9 +1,10 @@
|
||||
import _thread
|
||||
from threading import Lock
|
||||
import time
|
||||
import logging
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
import core
|
||||
import pwnagotchi.utils as utils
|
||||
import pwnagotchi.plugins as plugins
|
||||
from pwnagotchi.voice import Voice
|
||||
|
||||
@ -94,8 +95,9 @@ class View(object):
|
||||
|
||||
'face': Text(value=faces.SLEEP, position=face_pos, color=BLACK, font=fonts.Huge),
|
||||
|
||||
'friend_face': Text(value=None, position=(0, 90), font=fonts.Bold, color=BLACK),
|
||||
'friend_name': Text(value=None, position=(40, 93), font=fonts.BoldSmall, color=BLACK),
|
||||
'friend_face': Text(value=None, position=(0, (self._height * 0.88) - 15), font=fonts.Bold, color=BLACK),
|
||||
'friend_name': Text(value=None, position=(40, (self._height * 0.88) - 13), font=fonts.BoldSmall,
|
||||
color=BLACK),
|
||||
|
||||
'name': Text(value='%s>' % 'pwnagotchi', position=name_pos, color=BLACK, font=fonts.Bold),
|
||||
|
||||
@ -123,7 +125,7 @@ class View(object):
|
||||
_thread.start_new_thread(self._refresh_handler, ())
|
||||
self._ignore_changes = ()
|
||||
else:
|
||||
core.log("ui.fps is 0, the display will only update for major changes")
|
||||
logging.warning("ui.fps is 0, the display will only update for major changes")
|
||||
self._ignore_changes = ('uptime', 'name')
|
||||
|
||||
def add_element(self, key, elem):
|
||||
@ -144,7 +146,7 @@ class View(object):
|
||||
|
||||
def _refresh_handler(self):
|
||||
delay = 1.0 / self._config['ui']['fps']
|
||||
# core.log("view refresh handler started with period of %.2fs" % delay)
|
||||
# logging.info("view refresh handler started with period of %.2fs" % delay)
|
||||
|
||||
while True:
|
||||
name = self._state.get('name')
|
||||
@ -174,7 +176,7 @@ class View(object):
|
||||
self.set('channel', '-')
|
||||
self.set('aps', "%d" % log.associated)
|
||||
self.set('shakes', '%d (%s)' % (log.handshakes, \
|
||||
core.total_unique_handshakes(self._config['bettercap']['handshakes'])))
|
||||
utils.total_unique_handshakes(self._config['bettercap']['handshakes'])))
|
||||
self.set_closest_peer(log.last_peer)
|
||||
|
||||
def is_normal(self):
|
||||
@ -322,10 +324,10 @@ class View(object):
|
||||
self.set('status', self._voice.custom(text))
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
def update(self, force=False):
|
||||
with self._lock:
|
||||
changes = self._state.changes(ignore=self._ignore_changes)
|
||||
if len(changes):
|
||||
if force or len(changes):
|
||||
self._canvas = Image.new('1', (self._width, self._height), WHITE)
|
||||
drawer = ImageDraw.Draw(self._canvas)
|
||||
|
||||
|
98
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
Normal file
98
sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/utils.py
Normal file
@ -0,0 +1,98 @@
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import glob
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import yaml
|
||||
|
||||
|
||||
# https://stackoverflow.com/questions/823196/yaml-merge-in-python
|
||||
def merge_config(user, default):
|
||||
if isinstance(user, dict) and isinstance(default, dict):
|
||||
for k, v in default.items():
|
||||
if k not in user:
|
||||
user[k] = v
|
||||
else:
|
||||
user[k] = merge_config(user[k], v)
|
||||
return user
|
||||
|
||||
|
||||
def load_config(args):
|
||||
with open(args.config, 'rt') as fp:
|
||||
config = yaml.safe_load(fp)
|
||||
|
||||
if os.path.exists(args.user_config):
|
||||
with open(args.user_config, 'rt') as fp:
|
||||
user_config = yaml.safe_load(fp)
|
||||
config = merge_config(user_config, config)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def setup_logging(args, config):
|
||||
formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s")
|
||||
root = logging.getLogger()
|
||||
|
||||
root.setLevel(logging.DEBUG if args.debug else logging.INFO)
|
||||
|
||||
if config['main']['log']:
|
||||
file_handler = logging.FileHandler(config['main']['log'])
|
||||
file_handler.setFormatter(formatter)
|
||||
root.addHandler(file_handler)
|
||||
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setFormatter(formatter)
|
||||
root.addHandler(console_handler)
|
||||
|
||||
|
||||
def secs_to_hhmmss(secs):
|
||||
mins, secs = divmod(secs, 60)
|
||||
hours, mins = divmod(mins, 60)
|
||||
return '%02d:%02d:%02d' % (hours, mins, secs)
|
||||
|
||||
|
||||
def total_unique_handshakes(path):
|
||||
expr = os.path.join(path, "*.pcap")
|
||||
return len(glob.glob(expr))
|
||||
|
||||
|
||||
def iface_channels(ifname):
|
||||
channels = []
|
||||
output = subprocess.getoutput("/sbin/iwlist %s freq" % ifname)
|
||||
for line in output.split("\n"):
|
||||
line = line.strip()
|
||||
if line.startswith("Channel "):
|
||||
channels.append(int(line.split()[1]))
|
||||
return channels
|
||||
|
||||
|
||||
def led(on=True):
|
||||
with open('/sys/class/leds/led0/brightness', 'w+t') as fp:
|
||||
fp.write("%d" % (0 if on is True else 1))
|
||||
|
||||
|
||||
def blink(times=1, delay=0.3):
|
||||
for t in range(0, times):
|
||||
led(True)
|
||||
time.sleep(delay)
|
||||
led(False)
|
||||
time.sleep(delay)
|
||||
led(True)
|
||||
|
||||
|
||||
class StatusFile(object):
|
||||
def __init__(self, path):
|
||||
self._path = path
|
||||
self._updated = None
|
||||
|
||||
if os.path.exists(path):
|
||||
self._updated = datetime.fromtimestamp(os.path.getmtime(path))
|
||||
|
||||
def newer_then_days(self, days):
|
||||
return self._updated is not None and (datetime.now() - self._updated).days < days
|
||||
|
||||
def update(self, data=None):
|
||||
self._updated = datetime.now()
|
||||
with open(self._path, 'w') as fp:
|
||||
fp.write(str(self._updated) if data is None else data)
|
@ -1 +0,0 @@
|
||||
version = '1.0.0travistest'
|
@ -138,5 +138,21 @@ class Voice:
|
||||
associated=log.associated,
|
||||
handshakes=log.handshakes)
|
||||
|
||||
def custom(self, text):
|
||||
return self._(text)
|
||||
def hhmmss(self, count, fmt):
|
||||
if count > 1:
|
||||
# plural
|
||||
if fmt == "h":
|
||||
return self._("hours")
|
||||
if fmt == "m":
|
||||
return self._("minutes")
|
||||
if fmt == "s":
|
||||
return self._("seconds")
|
||||
else:
|
||||
# sing
|
||||
if fmt == "h":
|
||||
return self._("hour")
|
||||
if fmt == "m":
|
||||
return self._("minute")
|
||||
if fmt == "s":
|
||||
return self._("second")
|
||||
return fmt
|
||||
|
Reference in New Issue
Block a user