Merge pull request #747 from dadav/feature/migrate_to_toml

Switch to toml
This commit is contained in:
Simone Margaritelli 2020-01-14 11:39:13 +01:00 committed by GitHub
commit f691f737ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 252 additions and 340 deletions

View File

@ -90,9 +90,9 @@ def do_auto_mode(agent):
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-C', '--config', action='store', dest='config', default='/etc/pwnagotchi/default.yml', parser.add_argument('-C', '--config', action='store', dest='config', default='/etc/pwnagotchi/default.toml',
help='Main configuration file.') help='Main configuration file.')
parser.add_argument('-U', '--user-config', action='store', dest='user_config', default='/etc/pwnagotchi/config.yml', parser.add_argument('-U', '--user-config', action='store', dest='user_config', default='/etc/pwnagotchi/config.toml',
help='If this file exists, configuration will be merged and this will override default values.') 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('--manual', dest="do_manual", action="store_true", default=False, help="Manual mode.")
@ -119,7 +119,7 @@ if __name__ == '__main__':
config = utils.load_config(args) config = utils.load_config(args)
if args.print_config: if args.print_config:
print(yaml.dump(config, default_flow_style=False)) print(toml.dumps(config))
exit(0) exit(0)
utils.setup_logging(args, config) utils.setup_logging(args, config)

View File

@ -30,7 +30,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer):
AsyncTrainer.__init__(self, config) AsyncTrainer.__init__(self, config)
self._started_at = time.time() self._started_at = time.time()
self._filter = None if config['main']['filter'] is None else re.compile(config['main']['filter']) self._filter = None if not config['main']['filter'] else re.compile(config['main']['filter'])
self._current_channel = 0 self._current_channel = 0
self._tot_aps = 0 self._tot_aps = 0
self._aps_on_channel = 0 self._aps_on_channel = 0

205
pwnagotchi/defaults.toml Normal file
View File

@ -0,0 +1,205 @@
main.name = ""
main.lang = "en"
main.custom_plugins = ""
main.iface = "mon0"
main.mon_start_cmd = "/usr/bin/monstart"
main.mon_stop_cmd = "/usr/bin/monstop"
main.mon_max_blind_epochs = 50.0
main.no_restart = false
main.whitelist = [
"EXAMPLE_NETWORK",
"ANOTHER_EXAMPLE_NETWORK",
"fo:od:ba:be:fo:od",
"fo:od:ba"
]
main.filter = ""
main.plugins.grid.enabled = true
main.plugins.grid.report = false
main.plugins.grid.exclude = [
"YourHomeNetworkHere"
]
main.plugins.auto-update.enabled = true
main.plugins.auto-update.install = true
main.plugins.auto-update.interval = 1.0
main.plugins.net-pos.enabled = false
main.plugins.net-pos.api_key = "test"
main.plugins.gps.enabled = false
main.plugins.gps.speed = 19200.0
main.plugins.gps.device = "/dev/ttyUSB0"
main.plugins.webgpsmap.enabled = false
main.plugins.onlinehashcrack.enabled = false
main.plugins.onlinehashcrack.email = ""
main.plugins.wpa-sec.enabled = false
main.plugins.wpa-sec.api_key = ""
main.plugins.wpa-sec.api_url = "https://wpa-sec.stanev.org"
main.plugins.wpa-sec.download_results = false
main.plugins.wigle.enabled = false
main.plugins.wigle.api_key = ""
main.plugins.bt-tether.enabled = false
main.plugins.bt-tether.devices.android-phone.enabled = false
main.plugins.bt-tether.devices.android-phone.search_order = 1.0
main.plugins.bt-tether.devices.android-phone.mac = ""
main.plugins.bt-tether.devices.android-phone.ip = "192.168.44.44"
main.plugins.bt-tether.devices.android-phone.netmask = 24.0
main.plugins.bt-tether.devices.android-phone.interval = 1.0
main.plugins.bt-tether.devices.android-phone.scantime = 10.0
main.plugins.bt-tether.devices.android-phone.max_tries = 10.0
main.plugins.bt-tether.devices.android-phone.share_internet = false
main.plugins.bt-tether.devices.android-phone.priority = 1.0
main.plugins.bt-tether.devices.ios-phone.enabled = false
main.plugins.bt-tether.devices.ios-phone.search_order = 2.0
main.plugins.bt-tether.devices.ios-phone.mac = ""
main.plugins.bt-tether.devices.ios-phone.ip = "172.20.10.6"
main.plugins.bt-tether.devices.ios-phone.netmask = 24.0
main.plugins.bt-tether.devices.ios-phone.interval = 5.0
main.plugins.bt-tether.devices.ios-phone.scantime = 20.0
main.plugins.bt-tether.devices.ios-phone.max_tries = 0.0
main.plugins.bt-tether.devices.ios-phone.share_internet = false
main.plugins.bt-tether.devices.ios-phone.priority = 999.0
main.plugins.memtemp.enabled = false
main.plugins.memtemp.scale = "celsius"
main.plugins.memtemp.orientation = "horizontal"
main.plugins.paw-gps.enabled = false
main.plugins.paw-gps.ip = ""
main.plugins.gpio_buttons.enabled = false
main.plugins.led.enabled = true
main.plugins.led.led = 0.0
main.plugins.led.delay = 200.0
main.plugins.led.patterns.loaded = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.updating = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.unread_inbox = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ready = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_ready = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_training_start = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_best_reward = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_worst_reward = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.bored = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.sad = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.excited = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.lonely = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.rebooting = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.wait = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.sleep = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.wifi_update = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.association = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.deauthentication = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.handshake = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.epoch = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.peer_detected = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.peer_lost = "oo oo oo oo oo oo oo"
main.plugins.session-stats.enabled = true
main.log.path = "/var/log/pwnagotchi.log"
main.log.rotation.enabled = true
main.log.rotation.size = "10M"
ai.enabled = true
ai.path = "/root/brain.nn"
ai.laziness = 0.1
ai.epochs_per_episode = 50.0
ai.params.gamma = 0.99
ai.params.n_steps = 1.0
ai.params.vf_coef = 0.25
ai.params.ent_coef = 0.01
ai.params.max_grad_norm = 0.5
ai.params.learning_rate = 0.001
ai.params.alpha = 0.99
ai.params.epsilon = 0.00001
ai.params.verbose = 1.0
ai.params.lr_schedule = "constant"
personality.advertise = true
personality.deauth = true
personality.associate = true
personality.channels = []
personality.min_rssi = -200.0
personality.ap_ttl = 120.0
personality.sta_ttl = 300.0
personality.recon_time = 30.0
personality.max_inactive_scale = 2.0
personality.recon_inactive_multiplier = 2.0
personality.hop_recon_time = 10.0
personality.min_recon_time = 5.0
personality.max_interactions = 3.0
personality.max_misses_for_recon = 5.0
personality.excited_num_epochs = 10.0
personality.bored_num_epochs = 15.0
personality.sad_num_epochs = 25.0
personality.bond_encounters_factor = 20000.0
ui.fps = 0.0
ui.faces.look_r = "( ⚆_⚆)"
ui.faces.look_l = "(☉_☉ )"
ui.faces.look_r_happy = "( ◕‿◕)"
ui.faces.look_l_happy = "(◕‿◕ )"
ui.faces.sleep = "(⇀‿‿↼)"
ui.faces.sleep2 = "(≖‿‿≖)"
ui.faces.awake = "(◕‿‿◕)"
ui.faces.bored = "(-__-)"
ui.faces.intense = "(°▃▃°)"
ui.faces.cool = "(⌐■_■)"
ui.faces.happy = "(•‿‿•)"
ui.faces.excited = "(ᵔ◡◡ᵔ)"
ui.faces.grateful = "(^‿‿^)"
ui.faces.motivated = "(☼‿‿☼)"
ui.faces.demotivated = "(≖__≖)"
ui.faces.smart = "(✜‿‿✜)"
ui.faces.lonely = "(ب__ب)"
ui.faces.sad = "(╥☁╥ )"
ui.faces.angry = "(-_-')"
ui.faces.friend = "(♥‿‿♥)"
ui.faces.broken = "(☓‿‿☓)"
ui.faces.debug = "(#__#)"
ui.web.enabled = true
ui.web.address = "0.0.0.0"
ui.web.username = "changeme"
ui.web.password = "changeme"
ui.web.origin = ""
ui.web.port = 8080.0
ui.web.on_frame = ""
ui.display.enabled = true
ui.display.rotation = 180.0
ui.display.type = "waveshare_2"
ui.display.color = "black"
bettercap.scheme = "http"
bettercap.hostname = "localhost"
bettercap.port = 8081.0
bettercap.username = "pwnagotchi"
bettercap.password = "pwnagotchi"
bettercap.handshakes = "/root/handshakes"
bettercap.silence = [
"ble.device.new",
"ble.device.lost",
"ble.device.disconnected",
"ble.device.connected",
"ble.device.service.discovered",
"ble.device.characteristic.discovered",
"wifi.client.new",
"wifi.client.lost",
"wifi.client.probe",
"wifi.ap.new",
"wifi.ap.lost",
"mod.started"
]

View File

@ -1,307 +0,0 @@
#
# This file is recreated with default settings on every pwnagotchi restart,
# use /etc/pwnagotchi/config.yml to configure this unit.
#
#
# main algorithm configuration
main:
# if set this will set the hostname of the unit. min length is 2, max length 25, only a-zA-Z0-9- allowed
name: ''
# currently implemented: en (default), de, el, fr, it, mk, nl, ru, se, pt-BR, es, pt
lang: en
# custom plugins path, if null only default plugins with be loaded
custom_plugins:
# which plugins to load and enable
plugins:
switcher:
enabled: false
tasks:
bored:
enabled: false
reboot: true
commands:
- systemctl start fisch # see https://github.com/dadav/fisch
stopwatch: 15 # timeout of the task (in minutes)
grid:
enabled: true
report: false # don't report pwned networks by default!
exclude: # do not report the following networks (accepts both ESSIDs and BSSIDs)
- YourHomeNetworkHere
auto-update:
enabled: true
install: true # if false, it will only warn that updates are available, if true it will install them
interval: 1 # every 1 hour
net-pos:
enabled: false
api_key: 'test'
gps:
enabled: false
speed: 19200
device: /dev/ttyUSB0
webgpsmap:
enabled: false
onlinehashcrack:
enabled: false
email: ~
wpa-sec:
enabled: false
api_key: ~
api_url: "https://wpa-sec.stanev.org"
download_results: false
wigle:
enabled: false
api_key: ~
bt-tether:
enabled: false # if you want to use this, set ui.display.web.address to 0.0.0.0
devices:
android-phone:
enabled: false
search_order: 1 # search for this first
mac: ~ # mac of your bluetooth device
ip: '192.168.44.44' # ip from which your pwnagotchi should be reachable
netmask: 24
interval: 1 # check every minute for device
scantime: 10 # search for 10 seconds
max_tries: 10 # after 10 tries of "not found"; don't try anymore
share_internet: false
priority: 1 # low routing priority; ios (prio: 999) would win here
ios-phone:
enabled: false
search_order: 2 # search for this second
mac: ~ # mac of your bluetooth device
ip: '172.20.10.6' # ip from which your pwnagotchi should be reachable
netmask: 24
interval: 5 # check every 5 minutes for device
scantime: 20
max_tries: 0 # infinity
share_internet: false
priority: 999 # routing priority
memtemp: # Display memory usage, cpu load and cpu temperature on screen
enabled: false
scale: celsius
orientation: horizontal # horizontal/vertical
paw-gps:
enabled: false
#The IP Address of your phone with Paw Server running, default (option is empty) is 192.168.44.1
ip: ''
gpio_buttons:
enabled: false
#The following is a list of the GPIO number for your button, and the command you want to run when it is pressed
gpios:
#20: 'touch /root/.pwnagotchi-auto && systemctl restart pwnagotchi'
#21: 'shutdown -h now'
led:
enabled: true
# for /sys/class/leds/led0/brightness
led: 0
# time in milliseconds for each element of the patterns
delay: 200
# o=on space=off, comment the ones you don't want
patterns:
loaded: 'oo oo oo oo oo oo oo'
updating: 'oo oo oo oo oo oo oo'
# internet_available: 'oo oo oo oo oo oo oo'
unread_inbox: 'oo oo oo oo oo oo oo'
ready: 'oo oo oo oo oo oo oo'
ai_ready: 'oo oo oo oo oo oo oo'
ai_training_start: 'oo oo oo oo oo oo oo'
ai_best_reward: 'oo oo oo oo oo oo oo'
ai_worst_reward: 'oo oo oo oo oo oo oo'
bored: 'oo oo oo oo oo oo oo'
sad: 'oo oo oo oo oo oo oo'
excited: 'oo oo oo oo oo oo oo'
lonely: 'oo oo oo oo oo oo oo'
rebooting: 'oo oo oo oo oo oo oo'
wait: 'oo oo oo oo oo oo oo'
sleep: 'oo oo oo oo oo oo oo'
wifi_update: 'oo oo oo oo oo oo oo'
association: 'oo oo oo oo oo oo oo'
deauthentication: 'oo oo oo oo oo oo oo'
handshake: 'oo oo oo oo oo oo oo'
epoch: 'oo oo oo oo oo oo oo'
peer_detected: 'oo oo oo oo oo oo oo'
peer_lost: 'oo oo oo oo oo oo oo'
webcfg:
enabled: false
session-stats:
enabled: true
ups_lite:
enabled: false
shutdown: 2 # Auto-shutdown when <= 2%
# monitor interface to use
iface: mon0
# command to run to bring the mon interface up in case it's not up already
mon_start_cmd: /usr/bin/monstart
mon_stop_cmd: /usr/bin/monstop
mon_max_blind_epochs: 50
# if true, will not restart the wifi module
no_restart: false
# access points to ignore. Could be the ssid, bssid or the vendor part of bssid.
whitelist:
- EXAMPLE_NETWORK
- ANOTHER_EXAMPLE_NETWORK
- fo:od:ba:be:fo:od # BSSID
- fo:od:ba # Vendor BSSID
# if not null, filter access points by this regular expression
filter: null
# logging
log:
# file to log to
path: /var/log/pwnagotchi.log
rotation:
enabled: true
# specify a maximum size to rotate ( format is 10/10B, 10K, 10M 10G )
size: '10M'
ai:
# if false, only the default 'personality' will be used
enabled: true
path: /root/brain.nn
# 1.0 - laziness = probability of start training
laziness: 0.1
# how many epochs to train on
epochs_per_episode: 50
params:
# discount factor
gamma: 0.99
# the number of steps to run for each environment per update
n_steps: 1
# value function coefficient for the loss calculation
vf_coef: 0.25
# entropy coefficient for the loss calculation
ent_coef: 0.01
# maximum value for the gradient clipping
max_grad_norm: 0.5
# the learning rate
learning_rate: 0.0010
# rmsprop decay parameter
alpha: 0.99
# rmsprop epsilon
epsilon: 0.00001
# the verbosity level: 0 none, 1 training information, 2 tensorflow debug
verbose: 1
# type of scheduler for the learning rate update ('linear', 'constant', 'double_linear_con', 'middle_drop' or 'double_middle_drop')
lr_schedule: 'constant'
# the log location for tensorboard (if None, no logging)
tensorboard_log: null
personality:
# advertise our presence
advertise: true
# perform a deauthentication attack to client stations in order to get full or half handshakes
deauth: true
# send association frames to APs in order to get the PMKID
associate: true
# list of channels to recon on, or empty for all channels
channels: []
# minimum WiFi signal strength in dBm
min_rssi: -200
# number of seconds for wifi.ap.ttl
ap_ttl: 120
# number of seconds for wifi.sta.ttl
sta_ttl: 300
# time in seconds to wait during channel recon
recon_time: 30
# number of inactive epochs after which recon_time gets multiplied by recon_inactive_multiplier
max_inactive_scale: 2
# if more than max_inactive_scale epochs are inactive, recon_time *= recon_inactive_multiplier
recon_inactive_multiplier: 2
# time in seconds to wait during channel hopping if activity has been performed
hop_recon_time: 10
# time in seconds to wait during channel hopping if no activity has been performed
min_recon_time: 5
# maximum amount of deauths/associations per BSSID per session
max_interactions: 3
# maximum amount of misses before considering the data stale and triggering a new recon
max_misses_for_recon: 5
# number of active epochs that triggers the excited state
excited_num_epochs: 10
# number of inactive epochs that triggers the bored state
bored_num_epochs: 15
# number of inactive epochs that triggers the sad state
sad_num_epochs: 25
# number of encounters (times met on a channel) with another unit before considering it a friend and bond
# also used for cumulative bonding score of nearby units
bond_encounters_factor: 20000
# ui configuration
ui:
# here you can customize the faces
faces:
look_r: '( ⚆_⚆)'
look_l: '(☉_☉ )'
look_r_happy: '( ◕‿◕)'
look_l_happy: '(◕‿◕ )'
sleep: '(⇀‿‿↼)'
sleep2: '(≖‿‿≖)'
awake: '(◕‿‿◕)'
bored: '(-__-)'
intense: '(°▃▃°)'
cool: '(⌐■_■)'
happy: '(•‿‿•)'
excited: '(ᵔ◡◡ᵔ)'
grateful: '(^‿‿^)'
motivated: '(☼‿‿☼)'
demotivated: '(≖__≖)'
smart: '(✜‿‿✜)'
lonely: '(ب__ب)'
sad: '(╥☁╥ )'
angry: "(-_-')"
friend: '(♥‿‿♥)'
broken: '(☓‿‿☓)'
debug: '(#__#)'
# ePaper display can update every 3 secs anyway, set to 0 to only refresh for major data changes
# 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.0
# web ui
web:
enabled: true
address: '0.0.0.0'
username: changeme # !!! CHANGE THIS !!!
password: changeme # !!! CHANGE THIS !!!
origin: null
port: 8080
# command to be executed when a new png frame is available
# for instance, to use with framebuffer based displays:
# on_frame: 'fbi --noverbose -a -d /dev/fb1 -T 1 /root/pwnagotchi.png > /dev/null 2>&1'
on_frame: ''
# hardware display
display:
enabled: true
rotation: 180
# Possible options inkyphat/inky, papirus/papi, waveshare_1/ws_1 or waveshare_2/ws_2, oledhat, lcdhat, waveshare154inch, waveshare27inch, waveshare29inch, dfrobot/df, waveshare144lcd/ws144inch
type: 'waveshare_2'
# Possible options red/yellow/black (black used for monocromatic displays)
# Waveshare tri-color 2.13in display can be over-driven with color set as 'fastAndFurious'
# THIS IS POTENTIALLY DANGEROUS. DO NOT USE UNLESS YOU UNDERSTAND THAT IT COULD KILL YOUR DISPLAY
color: 'black'
# bettercap rest api configuration
bettercap:
# api scheme://hostname:port username and password
scheme: http
hostname: localhost
port: 8081
username: pwnagotchi
password: pwnagotchi
# folder where bettercap stores the WPA handshakes, given that
# wifi.handshakes.aggregate will be set to false and individual
# pcap files will be created in order to minimize the chances
# of a single pcap file to get corrupted
handshakes: /root/handshakes
# events to mute in bettercap's events stream
silence:
- ble.device.new
- ble.device.lost
- ble.device.disconnected
- ble.device.connected
- ble.device.service.discovered
- ble.device.characteristic.discovered
- wifi.client.new
- wifi.client.lost
- wifi.client.probe
- wifi.ap.new
- wifi.ap.lost
- mod.started

View File

@ -154,7 +154,7 @@ class AutoUpdate(plugins.Plugin):
self.lock = Lock() self.lock = Lock()
def on_loaded(self): def on_loaded(self):
if 'interval' not in self.options or ('interval' in self.options and self.options['interval'] is None): if 'interval' not in self.options or ('interval' in self.options and not self.options['interval']):
logging.error("[update] main.plugins.auto-update.interval is not set") logging.error("[update] main.plugins.auto-update.interval is not set")
return return
self.ready = True self.ready = True

View File

@ -437,7 +437,7 @@ class BTTether(plugins.Plugin):
for device_opt in ['enabled', 'priority', 'scantime', 'search_order', for device_opt in ['enabled', 'priority', 'scantime', 'search_order',
'max_tries', 'share_internet', 'mac', 'ip', 'max_tries', 'share_internet', 'mac', 'ip',
'netmask', 'interval']: 'netmask', 'interval']:
if device_opt not in options or (device_opt in options and options[device_opt] is None): if device_opt not in options or (device_opt in options and not options[device_opt]):
logging.error("BT-TETHER: Please specify the %s for device %s.", logging.error("BT-TETHER: Please specify the %s for device %s.",
device_opt, device) device_opt, device)
break break
@ -448,7 +448,7 @@ class BTTether(plugins.Plugin):
# legacy # legacy
if 'mac' in self.options: if 'mac' in self.options:
for opt in ['share_internet', 'mac', 'ip', 'netmask', 'interval']: for opt in ['share_internet', 'mac', 'ip', 'netmask', 'interval']:
if opt not in self.options or (opt in self.options and self.options[opt] is None): if opt not in self.options or (opt in self.options and not self.options[opt]):
logging.error("BT-TETHER: Please specify the %s in your config.yml.", opt) logging.error("BT-TETHER: Please specify the %s in your config.yml.", opt)
return return

View File

@ -26,7 +26,7 @@ class NetPos(plugins.Plugin):
self.lock = threading.Lock() self.lock = threading.Lock()
def on_loaded(self): def on_loaded(self):
if 'api_key' not in self.options or ('api_key' in self.options and self.options['api_key'] is None): if 'api_key' not in self.options or ('api_key' in self.options and not self.options['api_key']):
logging.error("NET-POS: api_key isn't set. Can't use mozilla's api.") logging.error("NET-POS: api_key isn't set. Can't use mozilla's api.")
return return

View File

@ -28,7 +28,7 @@ class OnlineHashCrack(plugins.Plugin):
""" """
Gets called when the plugin gets loaded Gets called when the plugin gets loaded
""" """
if 'email' not in self.options or ('email' in self.options and self.options['email'] is None): if 'email' not in self.options or ('email' in self.options and not self.options['email']):
logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com") logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com")
return return

View File

@ -1,13 +1,12 @@
import logging import logging
import json import json
import yaml import toml
import _thread import _thread
import pwnagotchi.plugins as plugins import pwnagotchi.plugins as plugins
from pwnagotchi import restart from pwnagotchi import restart
from flask import abort from flask import abort
from flask import render_template_string from flask import render_template_string
INDEX = """ INDEX = """
<html> <html>
<head> <head>
@ -500,13 +499,13 @@ class WebConfig(plugins.Plugin):
elif request.method == "POST": elif request.method == "POST":
if path == "save-config": if path == "save-config":
try: try:
parsed_yaml = yaml.safe_load(str(request.get_json())) parsed_toml = toml.loads(request.get_json())
with open('/etc/pwnagotchi/config.yml', 'w') as config_file: with open('/etc/pwnagotchi/config.toml') as config_file:
yaml.safe_dump(parsed_yaml, config_file, encoding='utf-8', toml.dump(parsed_toml, config_file)
allow_unicode=True, default_flow_style=False)
_thread.start_new_thread(restart, (self.mode,)) _thread.start_new_thread(restart, (self.mode,))
return "success" return "success"
except yaml.YAMLError as yaml_ex: except Exception as ex:
logging.error(ex)
return "config error" return "config error"
abort(404) abort(404)

View File

@ -70,11 +70,11 @@ class WpaSec(plugins.Plugin):
""" """
Gets called when the plugin gets loaded Gets called when the plugin gets loaded
""" """
if 'api_key' not in self.options or ('api_key' in self.options and self.options['api_key'] is None): if 'api_key' not in self.options or ('api_key' in self.options and not self.options['api_key']):
logging.error("WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org") logging.error("WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org")
return return
if 'api_url' not in self.options or ('api_url' in self.options and self.options['api_url'] is None): if 'api_url' not in self.options or ('api_url' in self.options and not self.options['api_url']):
logging.error("WPA_SEC: API-URL isn't set. Can't upload, no endpoint configured.") logging.error("WPA_SEC: API-URL isn't set. Can't upload, no endpoint configured.")
return return

View File

@ -12,6 +12,7 @@ import shutil
import gzip import gzip
import contextlib import contextlib
import tempfile import tempfile
import toml
import pwnagotchi import pwnagotchi
@ -32,15 +33,17 @@ def load_config(args):
if not os.path.exists(default_config_path): if not os.path.exists(default_config_path):
os.makedirs(default_config_path) os.makedirs(default_config_path)
ref_defaults_file = os.path.join(os.path.dirname(pwnagotchi.__file__), 'defaults.yml') ref_defaults_file = os.path.join(os.path.dirname(pwnagotchi.__file__), 'defaults.toml')
ref_defaults_data = None ref_defaults_data = None
# check for a config.yml file on /boot/ # check for a config.yml file on /boot/
if os.path.exists("/boot/config.yml"): for boot_conf in ['/boot/config.yml', '/boot/config.toml']:
# logging not configured here yet if os.path.exists(boot_conf):
print("installing /boot/config.yml to %s ...", args.user_config) # logging not configured here yet
# https://stackoverflow.com/questions/42392600/oserror-errno-18-invalid-cross-device-link print("installing %s to %s ...", boot_conf, args.user_config)
shutil.move("/boot/config.yml", args.user_config) # https://stackoverflow.com/questions/42392600/oserror-errno-18-invalid-cross-device-link
shutil.move(boot_conf, args.user_config)
break
# check for an entire pwnagotchi folder on /boot/ # check for an entire pwnagotchi folder on /boot/
if os.path.isdir('/boot/pwnagotchi'): if os.path.isdir('/boot/pwnagotchi'):
@ -54,6 +57,7 @@ def load_config(args):
shutil.copy(ref_defaults_file, args.config) shutil.copy(ref_defaults_file, args.config)
else: else:
# check if the user messed with the defaults # check if the user messed with the defaults
with open(ref_defaults_file) as fp: with open(ref_defaults_file) as fp:
ref_defaults_data = fp.read() ref_defaults_data = fp.read()
@ -66,18 +70,28 @@ def load_config(args):
# load the defaults # load the defaults
with open(args.config) as fp: with open(args.config) as fp:
config = yaml.safe_load(fp) config = toml.load(fp)
# load the user config # load the user config
try: try:
if os.path.exists(args.user_config): user_config = None
with open(args.user_config) as fp: # migrate
user_config = yaml.safe_load(fp) yaml_name = args.user_config.replace('.toml', '.yml')
# if the file is empty, safe_load will return None and merge_config will boom. if not os.path.exists(args.user_config) and os.path.exists(yaml_name):
if user_config: # no toml found; convert yaml
config = merge_config(user_config, config) logging.info('Old yaml-config found. Converting to toml...')
except yaml.YAMLError as ex: with open(args.user_config, 'w') as toml_file, open(yaml_name) as yaml_file:
print("There was an error processing the configuration file:\n%s " % ex) user_config = yaml.safe_load(yaml_file)
# convert to toml but use loaded yaml
toml.dump(user_config, toml_file)
elif os.path.exists(args.user_config):
with open(args.user_config) as toml_file:
user_config = toml.load(toml_file)
if user_config:
config = merge_config(user_config, config)
except Exception as ex:
logging.error("There was an error processing the configuration file:\n%s ",ex)
exit(1) exit(1)
# the very first step is to normalize the display name so we don't need dozens of if/elif around # the very first step is to normalize the display name so we don't need dozens of if/elif around

View File

@ -18,3 +18,4 @@ gast==0.2.2
flask==1.0.2 flask==1.0.2
flask-cors==3.0.7 flask-cors==3.0.7
flask-wtf==0.14.2 flask-wtf==0.14.2
toml==0.10.0