Cryptography init implemented
parent
2112070e44
commit
f6d7ea8f24
|
@ -8,13 +8,17 @@ from time import sleep
|
|||
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||
from SocketServer import ThreadingMixIn
|
||||
from urlparse import urlparse, parse_qs
|
||||
import base64
|
||||
import psutil
|
||||
import threading
|
||||
import webview
|
||||
import random
|
||||
import os
|
||||
import sys
|
||||
import md5
|
||||
|
||||
portlist = []
|
||||
volumelist = []
|
||||
kiss_interface = None
|
||||
|
||||
class RNS():
|
||||
|
@ -50,24 +54,59 @@ class Interface:
|
|||
pass
|
||||
|
||||
class KISS():
|
||||
FEND = chr(0xC0)
|
||||
FESC = chr(0xDB)
|
||||
TFEND = chr(0xDC)
|
||||
TFESC = chr(0xDD)
|
||||
CMD_UNKNOWN = chr(0xFE)
|
||||
CMD_DATA = chr(0x00)
|
||||
CMD_TXDELAY = chr(0x01)
|
||||
CMD_P = chr(0x02)
|
||||
CMD_SLOTTIME = chr(0x03)
|
||||
CMD_TXTAIL = chr(0x04)
|
||||
CMD_FULLDUPLEX = chr(0x05)
|
||||
CMD_SETHARDWARE = chr(0x06)
|
||||
CMD_READY = chr(0x0F)
|
||||
CMD_AUDIO_PEAK = chr(0x12)
|
||||
CMD_OUTPUT_GAIN = chr(0x09)
|
||||
CMD_INPUT_GAIN = chr(0x0A)
|
||||
CMD_EN_DIAGS = chr(0x13)
|
||||
CMD_RETURN = chr(0xFF)
|
||||
FEND = chr(0xC0)
|
||||
FESC = chr(0xDB)
|
||||
TFEND = chr(0xDC)
|
||||
TFESC = chr(0xDD)
|
||||
CMD_UNKNOWN = chr(0xFE)
|
||||
CMD_DATA = chr(0x00)
|
||||
CMD_TXDELAY = chr(0x01)
|
||||
CMD_P = chr(0x02)
|
||||
CMD_SLOTTIME = chr(0x03)
|
||||
CMD_TXTAIL = chr(0x04)
|
||||
CMD_FULLDUPLEX = chr(0x05)
|
||||
CMD_SETHARDWARE = chr(0x06)
|
||||
CMD_SAVE_CONFIG = chr(0x07)
|
||||
CMD_READY = chr(0x0F)
|
||||
CMD_AUDIO_PEAK = chr(0x12)
|
||||
CMD_OUTPUT_GAIN = chr(0x09)
|
||||
CMD_INPUT_GAIN = chr(0x0A)
|
||||
CMD_PASSALL = chr(0x0B)
|
||||
CMD_LOG_PACKETS = chr(0x0C)
|
||||
CMD_GPS_MODE = chr(0x0D)
|
||||
CMD_BT_MODE = chr(0x0E)
|
||||
CMD_SERIAL_BAUDRATE = chr(0x10)
|
||||
CMD_EN_DIAGS = chr(0x13)
|
||||
CMD_PRINT_CONFIG = chr(0xF0)
|
||||
CMD_LED_INTENSITY = chr(0x08)
|
||||
CMD_RETURN = chr(0xFF)
|
||||
|
||||
ADDR_E_MAJ_VERSION = chr(0x00)
|
||||
ADDR_E_MIN_VERSION = chr(0x01)
|
||||
ADDR_E_CONF_VERSION = chr(0x02)
|
||||
ADDR_E_P = chr(0x03)
|
||||
ADDR_E_SLOTTIME = chr(0x04)
|
||||
ADDR_E_PREAMBLE = chr(0x05)
|
||||
ADDR_E_TAIL = chr(0x06)
|
||||
ADDR_E_LED_INTENSITY = chr(0x07)
|
||||
ADDR_E_OUTPUT_GAIN = chr(0x08)
|
||||
ADDR_E_INPUT_GAIN = chr(0x09)
|
||||
ADDR_E_PASSALL = chr(0x0A)
|
||||
ADDR_E_LOG_PACKETS = chr(0x0B)
|
||||
ADDR_E_CRYPTO_LOCK = chr(0x0C)
|
||||
ADDR_E_GPS_MODE = chr(0x0D)
|
||||
ADDR_E_BLUETOOTH_MODE = chr(0x0E)
|
||||
ADDR_E_SERIAL_BAUDRATE = chr(0x0F)
|
||||
ADDR_E_CHECKSUM = chr(0x10)
|
||||
ADDR_E_END = chr(0x20)
|
||||
|
||||
CONFIG_GPS_OFF = chr(0x00)
|
||||
CONFIG_GPS_AUTODETECT = chr(0x01)
|
||||
CONFIG_GPS_REQUIRED = chr(0x02)
|
||||
|
||||
CONFIG_BLUETOOTH_OFF = chr(0x00)
|
||||
CONFIG_BLUETOOTH_AUTODETECT = chr(0x01)
|
||||
CONFIG_BLUETOOTH_REQUIRED = chr(0x02)
|
||||
|
||||
@staticmethod
|
||||
def escape(data):
|
||||
|
@ -109,6 +148,22 @@ class KISSInterface(Interface):
|
|||
self.persistence = persistence if persistence != None else 64;
|
||||
self.slottime = slottime if slottime != None else 20;
|
||||
|
||||
self.config_p = None
|
||||
self.config_slottime = None
|
||||
self.config_preamble = None
|
||||
self.config_tail = None
|
||||
self.config_led_intensity = None
|
||||
self.config_output_gain = None
|
||||
self.config_input_gain = None
|
||||
self.config_passall = None
|
||||
self.config_log_packets = None
|
||||
self.config_crypto_lock = None
|
||||
self.config_gps_mode = None
|
||||
self.config_bluetooth_mode = None
|
||||
self.config_serial_baudrate = None
|
||||
self.config_valid = False
|
||||
|
||||
|
||||
if parity.lower() == "e" or parity.lower() == "even":
|
||||
self.parity = serial.PARITY_EVEN
|
||||
|
||||
|
@ -136,7 +191,7 @@ class KISSInterface(Interface):
|
|||
|
||||
if self.serial.is_open:
|
||||
# Allow time for interface to initialise before config
|
||||
sleep(1.5)
|
||||
sleep(2.2)
|
||||
thread = threading.Thread(target=self.readLoop)
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
|
@ -159,22 +214,21 @@ class KISSInterface(Interface):
|
|||
self.audiopeak = peak_value[0]
|
||||
|
||||
def setPreamble(self, preamble):
|
||||
preamble_ms = preamble
|
||||
preamble = int(preamble_ms / 10)
|
||||
#preamble_ms = preamble
|
||||
#preamble = int(preamble_ms / 10)
|
||||
if preamble < 0:
|
||||
preamble = 0
|
||||
if preamble > 255:
|
||||
preamble = 255
|
||||
|
||||
RNS.log("Setting preamble to "+str(preamble)+" "+chr(preamble))
|
||||
kiss_command = KISS.FEND+KISS.CMD_TXDELAY+chr(preamble)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface preamble to "+str(preamble_ms)+" (command value "+str(preamble)+")")
|
||||
raise IOError("Could not configure KISS interface preamble to "+str(preamble)+" (command value "+str(preamble)+")")
|
||||
|
||||
def setTxTail(self, txtail):
|
||||
txtail_ms = txtail
|
||||
txtail = int(txtail_ms / 10)
|
||||
#txtail_ms = txtail
|
||||
#txtail = int(txtail_ms / 10)
|
||||
if txtail < 0:
|
||||
txtail = 0
|
||||
if txtail > 255:
|
||||
|
@ -183,7 +237,7 @@ class KISSInterface(Interface):
|
|||
kiss_command = KISS.FEND+KISS.CMD_TXTAIL+chr(txtail)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface TX tail to "+str(txtail_ms)+" (command value "+str(txtail)+")")
|
||||
raise IOError("Could not configure KISS interface TX tail to "+str(txtail)+" (command value "+str(txtail)+")")
|
||||
|
||||
def setPersistence(self, persistence):
|
||||
if persistence < 0:
|
||||
|
@ -197,8 +251,8 @@ class KISSInterface(Interface):
|
|||
raise IOError("Could not configure KISS interface persistence to "+str(persistence))
|
||||
|
||||
def setSlotTime(self, slottime):
|
||||
slottime_ms = slottime
|
||||
slottime = int(slottime_ms / 10)
|
||||
#slottime_ms = slottime
|
||||
#slottime = int(slottime_ms / 10)
|
||||
if slottime < 0:
|
||||
slottime = 0
|
||||
if slottime > 255:
|
||||
|
@ -207,7 +261,7 @@ class KISSInterface(Interface):
|
|||
kiss_command = KISS.FEND+KISS.CMD_SLOTTIME+chr(slottime)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface slot time to "+str(slottime_ms)+" (command value "+str(slottime)+")")
|
||||
raise IOError("Could not configure KISS interface slot time to "+str(slottime)+" (command value "+str(slottime)+")")
|
||||
|
||||
def setFlowControl(self, flow_control):
|
||||
kiss_command = KISS.FEND+KISS.CMD_READY+chr(0x01)+KISS.FEND
|
||||
|
@ -241,12 +295,103 @@ class KISSInterface(Interface):
|
|||
raise IOError("Could not configure KISS interface input gain to "+str(gain))
|
||||
|
||||
|
||||
def setLEDIntensity(self, val):
|
||||
if val < 0:
|
||||
val = 0
|
||||
if val > 255:
|
||||
val = 255
|
||||
|
||||
kiss_command = KISS.FEND+KISS.CMD_LED_INTENSITY+chr(val)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface LED intensity to "+str(val))
|
||||
|
||||
|
||||
def setGPSMode(self, val):
|
||||
if val < 0:
|
||||
val = 0
|
||||
if val > 2:
|
||||
val = 2
|
||||
|
||||
kiss_command = KISS.FEND+KISS.CMD_GPS_MODE+chr(val)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface GPS mode to "+str(val))
|
||||
|
||||
def setBluetoothMode(self, val):
|
||||
if val < 0:
|
||||
val = 0
|
||||
if val > 2:
|
||||
val = 2
|
||||
|
||||
kiss_command = KISS.FEND+KISS.CMD_BT_MODE+chr(val)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface BT mode to "+str(val))
|
||||
|
||||
def setBaudrate(self, val):
|
||||
if val < 1:
|
||||
val = 1
|
||||
if val > 12:
|
||||
val = 12
|
||||
|
||||
kiss_command = KISS.FEND+KISS.CMD_SERIAL_BAUDRATE+chr(val)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface baudrate to "+str(gain))
|
||||
|
||||
def setBaudrate(self, val):
|
||||
if val < 1:
|
||||
val = 1
|
||||
if val > 12:
|
||||
val = 12
|
||||
|
||||
kiss_command = KISS.FEND+KISS.CMD_SERIAL_BAUDRATE+chr(val)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface baudrate to "+str(gain))
|
||||
|
||||
def setPassall(self, val):
|
||||
if val < 0:
|
||||
val = 0
|
||||
if val > 1:
|
||||
val = 1
|
||||
|
||||
kiss_command = KISS.FEND+KISS.CMD_PASSALL+chr(val)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface passall to "+str(gain))
|
||||
|
||||
def setLogToSD(self, val):
|
||||
if val < 0:
|
||||
val = 0
|
||||
if val > 1:
|
||||
val = 1
|
||||
|
||||
kiss_command = KISS.FEND+KISS.CMD_LOG_PACKETS+chr(val)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not configure KISS interface logtosd to "+str(gain))
|
||||
|
||||
|
||||
def saveConfig(self):
|
||||
kiss_command = KISS.FEND+KISS.CMD_SAVE_CONFIG+chr(0x01)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not send save config command")
|
||||
|
||||
def enableDiagnostics(self):
|
||||
kiss_command = KISS.FEND+KISS.CMD_EN_DIAGS+chr(0x01)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not enable KISS interface diagnostics")
|
||||
|
||||
def retrieveConfig(self):
|
||||
kiss_command = KISS.FEND+KISS.CMD_PRINT_CONFIG+chr(0x01)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("Could not ask for config data")
|
||||
|
||||
def disableDiagnostics(self):
|
||||
kiss_command = KISS.FEND+KISS.CMD_EN_DIAGS+chr(0x00)+KISS.FEND
|
||||
written = self.serial.write(kiss_command)
|
||||
|
@ -260,6 +405,34 @@ class KISSInterface(Interface):
|
|||
self.has_decode = True
|
||||
RNS.log("Decoded packet");
|
||||
|
||||
def processConfig(self, data):
|
||||
md5sum = md5.new()
|
||||
md5sum.update(data[:16])
|
||||
md5_result = md5sum.digest()
|
||||
|
||||
print("Config data: "+RNS.hexrep(data[:16]))
|
||||
print("Config chks: "+RNS.hexrep(data[16:]))
|
||||
print("Config calc: "+RNS.hexrep(md5_result))
|
||||
|
||||
if md5_result == data[16:]:
|
||||
print("Config checksum match")
|
||||
self.config_p = data[ord(KISS.ADDR_E_P)]
|
||||
self.config_slottime = data[ord(KISS.ADDR_E_SLOTTIME)]
|
||||
self.config_preamble = data[ord(KISS.ADDR_E_PREAMBLE)]
|
||||
self.config_tail = data[ord(KISS.ADDR_E_TAIL)]
|
||||
self.config_led_intensity = data[ord(KISS.ADDR_E_LED_INTENSITY)]
|
||||
self.config_output_gain = data[ord(KISS.ADDR_E_OUTPUT_GAIN)]
|
||||
self.config_input_gain = data[ord(KISS.ADDR_E_INPUT_GAIN)]
|
||||
self.config_passall = data[ord(KISS.ADDR_E_PASSALL)]
|
||||
self.config_log_packets = data[ord(KISS.ADDR_E_LOG_PACKETS)]
|
||||
self.config_crypto_lock = data[ord(KISS.ADDR_E_CRYPTO_LOCK)]
|
||||
self.config_gps_mode = data[ord(KISS.ADDR_E_GPS_MODE)]
|
||||
self.config_bluetooth_mode = data[ord(KISS.ADDR_E_BLUETOOTH_MODE)]
|
||||
self.config_serial_baudrate = data[ord(KISS.ADDR_E_SERIAL_BAUDRATE)]
|
||||
self.config_valid = True
|
||||
else:
|
||||
print("Invalid checksum")
|
||||
self.config_valid = False
|
||||
|
||||
def processOutgoing(self,data):
|
||||
pass
|
||||
|
@ -276,6 +449,7 @@ class KISSInterface(Interface):
|
|||
escape = False
|
||||
command = KISS.CMD_UNKNOWN
|
||||
data_buffer = ""
|
||||
config_buffer = ""
|
||||
last_read_ms = int(time.time()*1000)
|
||||
|
||||
while self.serial.is_open:
|
||||
|
@ -286,10 +460,14 @@ class KISSInterface(Interface):
|
|||
if (in_frame and byte == KISS.FEND and command == KISS.CMD_DATA):
|
||||
in_frame = False
|
||||
self.processIncoming(data_buffer)
|
||||
elif (in_frame and byte == KISS.FEND and command == KISS.CMD_PRINT_CONFIG):
|
||||
in_frame = False
|
||||
self.processConfig(config_buffer)
|
||||
elif (byte == KISS.FEND):
|
||||
in_frame = True
|
||||
command = KISS.CMD_UNKNOWN
|
||||
data_buffer = ""
|
||||
config_buffer = ""
|
||||
elif (in_frame and len(data_buffer) < 611):
|
||||
if (len(data_buffer) == 0 and command == KISS.CMD_UNKNOWN):
|
||||
command = byte
|
||||
|
@ -304,6 +482,17 @@ class KISSInterface(Interface):
|
|||
byte = KISS.FESC
|
||||
escape = False
|
||||
data_buffer = data_buffer+byte
|
||||
elif (command == KISS.CMD_PRINT_CONFIG):
|
||||
if (byte == KISS.FESC):
|
||||
escape = True
|
||||
else:
|
||||
if (escape):
|
||||
if (byte == KISS.TFEND):
|
||||
byte = KISS.FEND
|
||||
if (byte == KISS.TFESC):
|
||||
byte = KISS.FESC
|
||||
escape = False
|
||||
config_buffer = config_buffer+byte
|
||||
elif (command == KISS.CMD_AUDIO_PEAK):
|
||||
self.displayPeak(byte)
|
||||
else:
|
||||
|
@ -319,8 +508,9 @@ class KISSInterface(Interface):
|
|||
except Exception as e:
|
||||
self.online = False
|
||||
RNS.log("A serial port error occurred, the contained exception was: "+str(e))
|
||||
RNS.log("The interface "+str(self.name)+" is now offline. Restart Reticulum to attempt reconnection.")
|
||||
RNS.log("The interface "+str(self.name)+" is now offline.")
|
||||
raise e
|
||||
close_device()
|
||||
|
||||
def __str__(self):
|
||||
return "KISSInterface["+self.name+"]"
|
||||
|
@ -338,6 +528,8 @@ class appRequestHandler(BaseHTTPRequestHandler):
|
|||
request.end_headers()
|
||||
|
||||
def do_GET(request):
|
||||
global kiss_interface, keyfile_exists, entropy_source_exists, aes_disabled
|
||||
|
||||
if (request.path == "/"):
|
||||
request.send_response(302)
|
||||
request.send_header("Location", "/app/")
|
||||
|
@ -351,12 +543,38 @@ class appRequestHandler(BaseHTTPRequestHandler):
|
|||
request.json_headers()
|
||||
request.wfile.write(json.dumps(list_serial_ports()).encode("utf-8"))
|
||||
|
||||
if (request.path == "/getconfig"):
|
||||
if (request.path == "/getvolumes"):
|
||||
request.json_headers()
|
||||
request.wfile.write(json.dumps(list_volumes()).encode("utf-8"))
|
||||
|
||||
if (request.path == "/saveconfig"):
|
||||
request.json_headers()
|
||||
kiss_interface.saveConfig()
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path == "/getconfig"):
|
||||
request.json_headers()
|
||||
if kiss_interface and kiss_interface.config_valid:
|
||||
configData = {
|
||||
"preamble": ord(kiss_interface.config_preamble),
|
||||
"tail": ord(kiss_interface.config_tail),
|
||||
"p": ord(kiss_interface.config_p),
|
||||
"slottime": ord(kiss_interface.config_slottime),
|
||||
"led_intensity": ord(kiss_interface.config_led_intensity),
|
||||
"output_gain": ord(kiss_interface.config_output_gain),
|
||||
"input_gain": ord(kiss_interface.config_input_gain),
|
||||
"passall": ord(kiss_interface.config_passall),
|
||||
"log_packets": ord(kiss_interface.config_log_packets),
|
||||
"crypto_lock": ord(kiss_interface.config_crypto_lock),
|
||||
"gps_mode": ord(kiss_interface.config_gps_mode),
|
||||
"bluetooth_mode": ord(kiss_interface.config_bluetooth_mode),
|
||||
"serial_baudrate": ord(kiss_interface.config_serial_baudrate)
|
||||
}
|
||||
request.wfile.write(json.dumps({"response":"ok", "config":configData}).encode("utf-8"))
|
||||
else:
|
||||
request.wfile.write(json.dumps({"response":"fail"}).encode("utf-8"))
|
||||
|
||||
if (request.path == "/getpeak"):
|
||||
global kiss_interface
|
||||
request.json_headers()
|
||||
request.wfile.write(json.dumps({"response":"ok", "peak":kiss_interface.audiopeak, "decode": kiss_interface.has_decode}).encode("utf-8"))
|
||||
kiss_interface.has_decode = False
|
||||
|
@ -375,6 +593,132 @@ class appRequestHandler(BaseHTTPRequestHandler):
|
|||
else:
|
||||
request.wfile.write(json.dumps({"response":"failed"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/volumeinit")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_path = query["path"][0]
|
||||
|
||||
if (volume_init(q_path)):
|
||||
request.wfile.write(json.dumps({"response":"ok", "key_installed": keyfile_exists, "aes_disabled":aes_disabled}).encode("utf-8"))
|
||||
else:
|
||||
request.wfile.write(json.dumps({"response":"failed"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setled")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setLEDIntensity(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setingain")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setInputGain(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setoutgain")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setOutputGain(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setpersistence")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setPersistence(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setpreamble")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setPreamble(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/settail")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setTxTail(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setslottime")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setSlotTime(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setbaudrate")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setBaudrate(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setpassall")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setPassall(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setlogtosd")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setLogToSD(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setgpsmode")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setGPSMode(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/setbluetoothmode")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = int(query["val"][0])
|
||||
kiss_interface.setBluetoothMode(q_val)
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
|
||||
if (request.path == "/aesenable"):
|
||||
request.json_headers()
|
||||
if aes_enable():
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
else:
|
||||
request.wfile.write(json.dumps({"response":"fail"}).encode("utf-8"))
|
||||
|
||||
if (request.path == "/aesdisable"):
|
||||
request.json_headers()
|
||||
if aes_disable():
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
else:
|
||||
request.wfile.write(json.dumps({"response":"fail"}).encode("utf-8"))
|
||||
|
||||
if (request.path == "/generatekey"):
|
||||
request.json_headers()
|
||||
if generate_key():
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
else:
|
||||
request.wfile.write(json.dumps({"response":"fail"}).encode("utf-8"))
|
||||
|
||||
if (request.path.startswith("/loadkey")):
|
||||
request.json_headers()
|
||||
query = parse_qs(urlparse(request.path).query)
|
||||
q_val = query["val"][0]
|
||||
if load_key(q_val):
|
||||
request.wfile.write(json.dumps({"response":"ok"}).encode("utf-8"))
|
||||
else:
|
||||
request.wfile.write(json.dumps({"response":"fail"}).encode("utf-8"))
|
||||
|
||||
|
||||
|
||||
if (request.path.startswith("/app/")):
|
||||
path = request.path.replace("/app/", "")
|
||||
file = None
|
||||
|
@ -410,12 +754,23 @@ def list_serial_ports():
|
|||
|
||||
return portlist
|
||||
|
||||
def list_volumes():
|
||||
partitions = psutil.disk_partitions()
|
||||
volumelist = []
|
||||
for partition in partitions:
|
||||
if partition.mountpoint != "/" and partition.mountpoint != "C://" and not partition.mountpoint.startswith("/private") and not partition.mountpoint.startswith("/Volumes/Time Machine Backups"):
|
||||
RNS.log("Found partition:")
|
||||
RNS.log("\t"+str(partition))
|
||||
volumelist.append(partition.mountpoint)
|
||||
|
||||
return volumelist
|
||||
|
||||
def open_device(port, baud):
|
||||
global kiss_interface
|
||||
try:
|
||||
kiss_interface = KISSInterface(None, "OpenModem", port, baud, 8, "N", 1, None, None, None, None, False)
|
||||
kiss_interface.enableDiagnostics()
|
||||
kiss_interface.setInputGain(200)
|
||||
kiss_interface.retrieveConfig()
|
||||
return True
|
||||
except Exception as e:
|
||||
#raise e
|
||||
|
@ -424,8 +779,128 @@ def open_device(port, baud):
|
|||
def close_device():
|
||||
os._exit(0)
|
||||
|
||||
keyfile_exists = False
|
||||
entropy_source_exists = False
|
||||
aes_disabled = False
|
||||
volume_ok = False
|
||||
volume_path = None
|
||||
def volume_init(path):
|
||||
global keyfile_exists, entropy_source_exists, volume_ok, volume_path, aes_disabled
|
||||
|
||||
volume_ok = False
|
||||
RNS.log("Volume init: "+path)
|
||||
|
||||
if os.path.isdir(path+"/OpenModem"):
|
||||
RNS.log("OpenModem data directory exists")
|
||||
else:
|
||||
RNS.log("OpenModem data directory does not exist, creating")
|
||||
try:
|
||||
os.mkdir(path+"/OpenModem")
|
||||
RNS.log("Directory created")
|
||||
except Exception as e:
|
||||
RNS.log("Could not create directory")
|
||||
volume_ok = False
|
||||
return False
|
||||
|
||||
if os.path.isfile(path+"/OpenModem/entropy.source"):
|
||||
entropy_source_exists = True
|
||||
RNS.log("Entropy source installed")
|
||||
else:
|
||||
RNS.log("Entropy source is not installed, installing...")
|
||||
if install_entropy_source(path+"/OpenModem/"):
|
||||
entropy_source_exists = True
|
||||
else:
|
||||
entropy_source_exists = False
|
||||
|
||||
if os.path.isfile(path+"/OpenModem/aes128.key"):
|
||||
keyfile_exists = True
|
||||
RNS.log("AES-128 key installed")
|
||||
else:
|
||||
RNS.log("AES-128 key is not installed")
|
||||
keyfile_exists = False
|
||||
|
||||
if os.path.isfile(path+"/OpenModem/aes128.disable"):
|
||||
aes_disabled = True
|
||||
RNS.log("AES-128 is disabled")
|
||||
else:
|
||||
RNS.log("AES-128 is allowed")
|
||||
aes_disabled = False
|
||||
|
||||
volume_ok = True
|
||||
volume_path = path + "/OpenModem/"
|
||||
RNS.log("Volume path is "+volume_path)
|
||||
return True
|
||||
|
||||
def generate_key():
|
||||
global volume_ok, volume_path
|
||||
if volume_ok:
|
||||
RNS.log("Generating new AES-128 key in "+volume_path+"...")
|
||||
try:
|
||||
file = open(volume_path+"aes128.key", "w")
|
||||
file.write(os.urandom(128/8))
|
||||
file.close()
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
RNS.log("Could not generate key")
|
||||
return False
|
||||
|
||||
def load_key(keydata):
|
||||
global volume_ok, volume_path
|
||||
if volume_ok:
|
||||
RNS.log("Loading supplied key onto "+volume_path+"...")
|
||||
try:
|
||||
key = base64.b64decode(keydata)
|
||||
file = open(volume_path+"aes128.key", "w")
|
||||
file.write(key)
|
||||
file.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
raise e
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def aes_disable():
|
||||
global volume_ok, volume_path
|
||||
if volume_ok:
|
||||
open(volume_path+"aes128.disable", 'a').close()
|
||||
RNS.log("Disabling AES-128")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def aes_enable():
|
||||
global volume_ok, volume_path
|
||||
if volume_ok:
|
||||
if os.path.isfile(volume_path+"aes128.disable"):
|
||||
os.remove(volume_path+"aes128.disable")
|
||||
RNS.log("Allowing AES-128")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def install_entropy_source(path):
|
||||
RNS.log("Installing entropy source in "+path+"...")
|
||||
try:
|
||||
megabytes_to_write = 32
|
||||
bytes_per_block = 1024
|
||||
bytes_written = 0
|
||||
file = open(path+"entropy.source", "a")
|
||||
while bytes_written < megabytes_to_write*1024*1024:
|
||||
file.write(os.urandom(bytes_per_block))
|
||||
bytes_written = bytes_written + bytes_per_block
|
||||
file.close()
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
RNS.log("Could not install entropy source")
|
||||
return False
|
||||
|
||||
|
||||
def get_port():
|
||||
return 44444
|
||||
return random.randrange(40000,49999,1)
|
||||
|
||||
def start_server():
|
||||
|
@ -454,8 +929,8 @@ def start_server():
|
|||
def main():
|
||||
include_path = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
os.chdir(include_path)
|
||||
ports = list_serial_ports()
|
||||
print(ports)
|
||||
list_serial_ports()
|
||||
list_volumes()
|
||||
if (len(sys.argv) == 1):
|
||||
start_server()
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
<div class="ui dimmer" id="ind_connecting">
|
||||
<div class="ui loader"></div>
|
||||
</div>
|
||||
<div class="ui dimmer" id="crypt_loader">
|
||||
<div class="ui text loader">Initialising cryptography...<br/><br/><small>If this takes a long time, move your mouse or hit some keys to generate more entropy</small></div>
|
||||
|
||||
</div>
|
||||
<div class="ui styled fullwidth accordion" id="configutil">
|
||||
<div class="title active">
|
||||
<i class="dropdown icon"></i>
|
||||
|
@ -29,7 +33,7 @@
|
|||
<i class="fas fa-circle connected" id="ind_connected"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="content active">
|
||||
<div class="content active" id="tab_connection">
|
||||
<p class="transition visible" style="display: block !important;">
|
||||
<div class="ui grid">
|
||||
<!-- Serial Port selection-->
|
||||
|
@ -55,6 +59,7 @@
|
|||
<select class="ui fullwidth dropdown" id="connectbaudrate">
|
||||
<option value="1200">1200</option>
|
||||
<option value="2400">2400</option>
|
||||
<option value="4800">4800</option>
|
||||
<option value="9600">9600</option>
|
||||
<option value="14400">14400</option>
|
||||
<option value="19200">19200</option>
|
||||
|
@ -83,7 +88,7 @@
|
|||
<i class="dropdown icon"></i>
|
||||
<i class="fas fa-cog"></i> Modem Settings
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="content" id="tab_settings">
|
||||
<p class="transition hidden">
|
||||
<div class="ui grid">
|
||||
<!-- Modem mode selection-->
|
||||
|
@ -94,7 +99,7 @@
|
|||
</div>
|
||||
|
||||
<div class="eight wide column">
|
||||
<select class="ui fullwidth dropdown">
|
||||
<select class="ui fullwidth dropdown disabled">
|
||||
<option value="AFSK300">AFSK300</option>
|
||||
<option value="AFSK1200" selected>AFSK1200</option>
|
||||
<option value="AFSK2400">AFSK2400</option>
|
||||
|
@ -110,7 +115,7 @@
|
|||
|
||||
<div class="eight wide column">
|
||||
<div class="ui right labeled fullwidth input">
|
||||
<input type="text" placeholder="">
|
||||
<input type="text" placeholder="" id="f_preamble">
|
||||
<div class="ui basic label">
|
||||
ms
|
||||
</div>
|
||||
|
@ -126,7 +131,7 @@
|
|||
|
||||
<div class="eight wide column">
|
||||
<div class="ui right labeled fullwidth input">
|
||||
<input type="text" placeholder="">
|
||||
<input type="text" placeholder="" id="f_tail">
|
||||
<div class="ui basic label">
|
||||
ms
|
||||
</div>
|
||||
|
@ -142,7 +147,7 @@
|
|||
|
||||
<div class="eight wide column">
|
||||
<div class="ui right labeled fullwidth input">
|
||||
<input type="text" placeholder="">
|
||||
<input type="text" placeholder="" id="f_slottime">
|
||||
<div class="ui basic label">
|
||||
ms
|
||||
</div>
|
||||
|
@ -158,7 +163,7 @@
|
|||
|
||||
<div class="two wide column norightpadding">
|
||||
<div class="ui fullwidth input">
|
||||
<input type="text" placeholder="">
|
||||
<input type="text" placeholder="" id="f_p">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -185,10 +190,10 @@
|
|||
</div>
|
||||
|
||||
<div class="eight wide column">
|
||||
<select class="ui fullwidth dropdown">
|
||||
<option value="autodetect" selected>Autodetect</option>
|
||||
<option value="disabled">Disabled</option>
|
||||
<option value="required">Required</option>
|
||||
<select class="ui fullwidth dropdown" id="s_gpsmode">
|
||||
<option value="1">Autodetect</option>
|
||||
<option value="0" selected>Disabled</option>
|
||||
<option value="2">Required</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
@ -200,10 +205,10 @@
|
|||
</div>
|
||||
|
||||
<div class="eight wide column">
|
||||
<select class="ui fullwidth dropdown">
|
||||
<option value="autodetect" selected>Autodetect</option>
|
||||
<option value="disabled">Disabled</option>
|
||||
<option value="required">Required</option>
|
||||
<select class="ui fullwidth dropdown" id="s_bluetoothmode">
|
||||
<option value="1">Autodetect</option>
|
||||
<option value="0" selected>Disabled</option>
|
||||
<option value="2">Required</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
@ -215,18 +220,19 @@
|
|||
</div>
|
||||
|
||||
<div class="eight wide column">
|
||||
<select class="ui fullwidth dropdown">
|
||||
<option value="1200">1200</option>
|
||||
<option value="2400">2400</option>
|
||||
<option value="9600">9600</option>
|
||||
<option value="14400">14400</option>
|
||||
<option value="19200">19200</option>
|
||||
<option value="28800">28800</option>
|
||||
<option value="38400">38400</option>
|
||||
<option value="57600">57600</option>
|
||||
<option value="76800">76800</option>
|
||||
<option value="115200" selected>115200</option>
|
||||
<option value="230400">230400</option>
|
||||
<select class="ui fullwidth dropdown" id="s_baudrate">
|
||||
<option value="1" selected>1200</option>
|
||||
<option value="2">2400</option>
|
||||
<option value="3">4800</option>
|
||||
<option value="4">9600</option>
|
||||
<option value="5">14400</option>
|
||||
<option value="6">19200</option>
|
||||
<option value="7">28800</option>
|
||||
<option value="8">38400</option>
|
||||
<option value="9">57600</option>
|
||||
<option value="10">76800</option>
|
||||
<option value="11">115200</option>
|
||||
<option value="12">230400</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
@ -238,7 +244,7 @@
|
|||
</div>
|
||||
|
||||
<div class="eight wide column">
|
||||
<div class="ui rightfloated toggle checkbox">
|
||||
<div class="ui rightfloated toggle checkbox" id="c_passall">
|
||||
<input type="checkbox" name="passall">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -251,14 +257,14 @@
|
|||
</div>
|
||||
|
||||
<div class="eight wide column">
|
||||
<div class="ui rightfloated toggle checkbox">
|
||||
<div class="ui rightfloated toggle checkbox" id="c_logtosd">
|
||||
<input type="checkbox" name="logtosd">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column">
|
||||
<div class="ui teal fullwidth button" tabindex="0">
|
||||
Apply Modem Configuration
|
||||
<div class="ui teal fullwidth disabled button savebutton" tabindex="0">
|
||||
Save Configuration
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -269,7 +275,7 @@
|
|||
<i class="dropdown icon"></i>
|
||||
<i class="fas fa-volume"></i> Audio
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="audiosection content" id="tab_audio">
|
||||
<p class="transition hidden">
|
||||
|
||||
<div class="ui grid">
|
||||
|
@ -301,8 +307,8 @@
|
|||
</div>
|
||||
|
||||
<div class="sixteen wide column">
|
||||
<div class="ui teal fullwidth button" tabindex="0">
|
||||
Save Audio Configuration
|
||||
<div class="ui teal fullwidth disabled button savebutton" tabindex="0">
|
||||
Save Configuration
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -315,7 +321,7 @@
|
|||
<i class="dropdown icon"></i>
|
||||
<i class="fas fa-lock-alt"></i> Cryptography
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="content" id="tab_crypto">
|
||||
<p class="transition hidden">
|
||||
<div class="ui grid">
|
||||
<!-- SD selection-->
|
||||
|
@ -326,13 +332,12 @@
|
|||
</div>
|
||||
|
||||
<div class="eight wide column">
|
||||
<select class="ui fullwidth dropdown">
|
||||
<select class="ui fullwidth dropdown" id="s_volumes">
|
||||
<option value="none" selected>None</option>
|
||||
<option value="0">SD Card 1</option>
|
||||
<option value="1">SD Card 2</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Encryption enabled selection-->
|
||||
<div class="eight wide column">
|
||||
<div class="ui fullwidth label">
|
||||
|
@ -341,7 +346,7 @@
|
|||
</div>
|
||||
|
||||
<div class="eight wide column">
|
||||
<div class="ui rightfloated toggle checkbox">
|
||||
<div class="ui rightfloated disabled toggle checkbox" id="c_aes128">
|
||||
<input type="checkbox" name="aesenable">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -353,19 +358,37 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="four wide column">
|
||||
<div class="ui teal fullwidth button" tabindex="0">
|
||||
<div class="four wide column" id="keygenerate">
|
||||
<div class="ui disabled teal fullwidth button" tabindex="0">
|
||||
Generate
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="four wide column">
|
||||
<div class="ui teal fullwidth button" tabindex="0">
|
||||
<div class="four wide column" id="keyload">
|
||||
|
||||
<input type="file" (change)="fileEvent($event)" class="inputfile" id="keyfileinput" />
|
||||
|
||||
<label for="keyfileinput" class="ui disabled teal fullwidth button">
|
||||
Load
|
||||
</label>
|
||||
|
||||
<!--
|
||||
<div class="ui disabled teal fullwidth button" tabindex="0">
|
||||
Load
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="eight wide column" id="keyisready">
|
||||
<div class="ui green disabled fullwidth button" tabindex="0">
|
||||
AES-128 Key Installed
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Entropy selection-->
|
||||
<!--
|
||||
<div class="eight wide column">
|
||||
<div class="ui fullwidth label">
|
||||
Entropy Source
|
||||
|
@ -377,6 +400,7 @@
|
|||
Install
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
</div>
|
||||
</p>
|
||||
|
@ -387,15 +411,24 @@
|
|||
<i class="dropdown icon"></i>
|
||||
<i class="fas fa-info-circle"></i> About
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="transition hidden">Lorem Ipsum</p>
|
||||
<ul>
|
||||
<li>semantic-ui-range</li>
|
||||
<li>https://pywebview.flowrl.com</li>
|
||||
<li>SemanticUI</li>
|
||||
<li>FontAwesome</li>
|
||||
<li>Raphaël</li>
|
||||
<div class="content" id="tab_about">
|
||||
<p class="transition hidden">
|
||||
The source code for this utility is available at the OpenModem page on <a href="https://unsigned.io/" target="_blank">unsigned.io</a>. The following open source components have been used in this utility:
|
||||
<ul class="licenses">
|
||||
<li><a href="https://pywebview.flowrl.com" target="_blank">pywebview</a> <span class="license"><a href="https://github.com/r0x0r/pywebview/blob/master/LICENSE.md" target="_blank">BSD 3-Clause</a></span></li>
|
||||
|
||||
<li><a href="https://github.com/Semantic-Org/Semantic-UI" target="_blank">Semantic UI</a> <span class="license"><a href="https://github.com/Semantic-Org/Semantic-UI/blob/master/LICENSE.md" target="_blank">MIT</a></span></li>
|
||||
|
||||
<li><a href="https://github.com/tyleryasaka/semantic-ui-range" target="_blank">Semantic UI Range</a> <span class="license"><a href="https://github.com/tyleryasaka/semantic-ui-range/blob/master/LICENSE" target="_blank">MIT</a></span></li>
|
||||
|
||||
<li><a href="http://dmitrybaranovskiy.github.io/raphael/" target="_blank">Raphaël</a> <span class="license"><a href="https://github.com/DmitryBaranovskiy/raphael/blob/master/license.txt" target="_blank">MIT</a></span></li>
|
||||
|
||||
<li><a href="https://fontawesome.com/" target="_blank">FontAwesome</a> <span class="license"><a href="https://fontawesome.com/license" target="_blank">FontAwesome Pro</a></span></li>
|
||||
|
||||
<li><a href="https://github.com/giampaolo/psutil" target="_blank">psutil</a> <span class="license"><a href="https://github.com/giampaolo/psutil/blob/master/LICENSE" target="_blank">BSD</a></span></li>
|
||||
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
455
public/main.js
455
public/main.js
|
@ -2,6 +2,7 @@ jQuery(document).ready(function() {
|
|||
init_elements();
|
||||
init_gfx();
|
||||
update_ports();
|
||||
update_volumes();
|
||||
})
|
||||
|
||||
function update_ports() {
|
||||
|
@ -14,6 +15,17 @@ function update_ports() {
|
|||
});
|
||||
}
|
||||
|
||||
function update_volumes() {
|
||||
jQuery.getJSON("/getvolumes", function(data) {
|
||||
jQuery("#s_volumes").empty();
|
||||
jQuery("#s_volumes").append("<option value=\"none\">None</option>")
|
||||
jQuery.each(data, function(key, val) {
|
||||
jQuery("#s_volumes").append("<option value=\""+val+"\">"+val+"</option>")
|
||||
console.log(val);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function request_disconnect() {
|
||||
jQuery.getJSON("/disconnect", function(data) {
|
||||
console.log("Exiting...");
|
||||
|
@ -29,7 +41,6 @@ function request_connection() {
|
|||
console.log(data);
|
||||
if (data["response"] == "ok") {
|
||||
console.log("Serial port open");
|
||||
document.connection_state = true;
|
||||
setTimeout(request_config, 250);
|
||||
} else {
|
||||
console.log("Could not connect");
|
||||
|
@ -57,9 +68,14 @@ function request_config() {
|
|||
jQuery("#ind_disconnected").hide();
|
||||
jQuery("#ind_connected").show();
|
||||
jQuery("#configutil").accordion("open", 1);
|
||||
jQuery(".savebutton").removeClass("disabled");
|
||||
update_fields_from_config(data["config"]);
|
||||
setInterval(function() {
|
||||
askForPeakData();
|
||||
}, 250);
|
||||
setTimeout(function() {
|
||||
document.connection_state = true;
|
||||
}, 500);
|
||||
} else {
|
||||
console.log("Invalid response on config request");
|
||||
alert("Could not get configuration from selected device. Please make sure the correct serial port is selected.");
|
||||
|
@ -74,40 +90,351 @@ function request_config() {
|
|||
});
|
||||
}
|
||||
|
||||
function update_slider_p() {
|
||||
var pval = parseInt(jQuery("#f_p").val());
|
||||
if (isNaN(pval)) pval = 255;
|
||||
if (pval > 255) pval = 255;
|
||||
if (pval < 0) pval = 0;
|
||||
jQuery("#p-selection").range("set value", pval);
|
||||
jQuery("#f_p").val(pval);
|
||||
}
|
||||
|
||||
function update_slider_led(val) {
|
||||
if (isNaN(val)) val = 192;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
jQuery("#led-selection").range("set value", val);
|
||||
}
|
||||
|
||||
function update_slider_ingain(val) {
|
||||
if (isNaN(val)) val = 63;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
jQuery("#ingain-selection").range("set value", val);
|
||||
}
|
||||
|
||||
function update_slider_outgain(val) {
|
||||
if (isNaN(val)) val = 63;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
jQuery("#outgain-selection").range("set value", val);
|
||||
}
|
||||
|
||||
function request_led_change(val) {
|
||||
if (document.connection_state) {
|
||||
if (isNaN(val)) val = 192;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
jQuery.getJSON("/setled?val="+val, function(data) {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function request_p_change(val) {
|
||||
jQuery("#f_p").val(val);
|
||||
if (document.connection_state) {
|
||||
if (isNaN(val)) val = 192;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
console.log("Setting p to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setpersistence?val="+val, function(data) {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function request_preamble_change() {
|
||||
if (document.connection_state) {
|
||||
var val = parseInt(parseInt(jQuery("#f_preamble").val())/10);
|
||||
if (isNaN(val)) val = 150;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
console.log("Setting preamble to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setpreamble?val="+val, function(data) {
|
||||
|
||||
});
|
||||
jQuery("#f_preamble").val(parseInt(val*10));
|
||||
}
|
||||
}
|
||||
|
||||
function request_tail_change() {
|
||||
if (document.connection_state) {
|
||||
var val = parseInt(parseInt(jQuery("#f_tail").val())/10);
|
||||
if (isNaN(val)) val = 150;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
console.log("Setting tail to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/settail?val="+val, function(data) {
|
||||
|
||||
});
|
||||
jQuery("#f_tail").val(parseInt(val*10));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function request_slottime_change() {
|
||||
if (document.connection_state) {
|
||||
var val = parseInt(parseInt(jQuery("#f_slottime").val())/10);
|
||||
if (isNaN(val)) val = 150;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
console.log("Setting slottime to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setslottime?val="+val, function(data) {
|
||||
|
||||
});
|
||||
jQuery("#f_slottime").val(parseInt(val*10));
|
||||
}
|
||||
}
|
||||
|
||||
function request_ingain_change(val) {
|
||||
if (document.connection_state) {
|
||||
if (isNaN(val)) val = 128;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
console.log("Setting input gain to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setingain?val="+val, function(data) {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function request_outgain_change(val) {
|
||||
if (document.connection_state) {
|
||||
if (isNaN(val)) val = 192;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 255) val = 255;
|
||||
console.log("Setting output gain to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setoutgain?val="+val, function(data) {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function request_bluetoothmode_change() {
|
||||
if (document.connection_state) {
|
||||
var val = parseInt(jQuery("#s_bluetoothmode").val());
|
||||
if (isNaN(val)) val = 1;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 2) val = 2;
|
||||
console.log("Setting bluetooth mode to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setbluetoothmode?val="+val, function(data) {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function request_gpsmode_change() {
|
||||
if (document.connection_state) {
|
||||
var val = parseInt(jQuery("#s_gpsmode").val());
|
||||
if (isNaN(val)) val = 1;
|
||||
if (val < 0) val = 0;
|
||||
if (val > 2) val = 2;
|
||||
console.log("Setting GPS mode to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setgpsmode?val="+val, function(data) {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function request_baudrate_change() {
|
||||
if (document.connection_state) {
|
||||
var val = parseInt(jQuery("#s_baudrate").val());
|
||||
if (isNaN(val)) val = 11;
|
||||
if (val < 1) val = 1;
|
||||
if (val > 12) val = 12;
|
||||
console.log("Setting baudrate to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setbaudrate?val="+val, function(data) {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function request_passall_change() {
|
||||
if (document.connection_state) {
|
||||
var val = jQuery("#c_passall").checkbox("is checked");
|
||||
val = val ? 1 : 0;
|
||||
console.log("Setting passall to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setpassall?val="+val, function(data) { });
|
||||
}
|
||||
}
|
||||
|
||||
function request_logtosd_change() {
|
||||
if (document.connection_state) {
|
||||
var val = jQuery("#c_passall").checkbox("is checked");
|
||||
val = val ? 1 : 0;
|
||||
console.log("Setting logtosd to:");
|
||||
console.log(val);
|
||||
jQuery.getJSON("/setlogtosd?val="+val, function(data) { });
|
||||
}
|
||||
}
|
||||
|
||||
function request_aes_change() {
|
||||
if (volume_ok) {
|
||||
var val = jQuery("#c_aes128").checkbox("is checked");
|
||||
if (val) {
|
||||
console.log("Enabling AES");
|
||||
jQuery.getJSON("/aesenable", function(data) { });
|
||||
} else {
|
||||
console.log("Disabling AES");
|
||||
jQuery.getJSON("/aesdisable", function(data) { });
|
||||
}
|
||||
} else {
|
||||
console.log("Not updating AES state, since no SD card is available")
|
||||
}
|
||||
}
|
||||
|
||||
function request_generatekey() {
|
||||
if (volume_ok) {
|
||||
alert("A new AES-128 key will now be generated and installed onto the specified SD card. Please make a backup of this key somewhere secure, as there is no way to recover it if lost. Load this key to other modems that should be able to communicate with this one.");
|
||||
jQuery.getJSON("/generatekey", function(data) {
|
||||
if (data["response"] == "ok") {
|
||||
volume_changed();
|
||||
} else {
|
||||
alert("Could not generate new key. Make sure that you have write permission to the SD card.");
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function request_save_config() {
|
||||
if (document.connection_state) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: "/saveconfig",
|
||||
timeout: 500,
|
||||
success: function(data) {
|
||||
if (data["response"] == "ok") {
|
||||
console.log("Config saved");
|
||||
alert("Configuration was saved to the device");
|
||||
|
||||
} else {
|
||||
console.log("Invalid response on config request");
|
||||
alert("Could not save configuration to selected device. Please make sure the correct serial port is selected.");
|
||||
request_disconnect();
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, status, error) {
|
||||
console.log("Request timed out");
|
||||
alert("Could not save configuration to selected device. Please make sure the correct serial port is selected.");
|
||||
request_disconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function set_audio_sliders() {
|
||||
if (document.connection_state && !document.audioslidersset) {
|
||||
update_slider_ingain(parseInt(document.configdata["input_gain"]));
|
||||
update_slider_outgain(parseInt(document.configdata["output_gain"]));
|
||||
document.audioslidersset = true;
|
||||
}
|
||||
}
|
||||
|
||||
function update_fields_from_config(configdata) {
|
||||
console.log("Config data:");
|
||||
console.log(configdata);
|
||||
document.configdata = configdata;
|
||||
|
||||
jQuery("#f_preamble").val(parseInt(configdata["preamble"])*10);
|
||||
jQuery("#f_tail").val(parseInt(configdata["tail"])*10);
|
||||
jQuery("#f_slottime").val(parseInt(configdata["slottime"])*10);
|
||||
setTimeout(function() {
|
||||
jQuery("#f_p").val(parseInt(configdata["p"]));
|
||||
update_slider_p();
|
||||
update_slider_led(parseInt(configdata["led_intensity"]));
|
||||
jQuery("#s_gpsmode").dropdown("set selected", configdata["gps_mode"]);
|
||||
jQuery("#s_bluetoothmode").dropdown("set selected", configdata["bluetooth_mode"]);
|
||||
jQuery("#s_baudrate").dropdown("set selected", configdata["serial_baudrate"]);
|
||||
if (parseInt(configdata["passall"]) == 1) {
|
||||
jQuery("#c_passall").checkbox("check");
|
||||
} else {
|
||||
jQuery("#c_passall").checkbox("uncheck");
|
||||
}
|
||||
if (parseInt(configdata["log_packets"]) == 1) {
|
||||
jQuery("#c_logtosd").checkbox("check");
|
||||
} else {
|
||||
jQuery("#c_logtosd").checkbox("uncheck");
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function init_elements() {
|
||||
document.connection_state = false;
|
||||
document.audioslidersset = false;
|
||||
|
||||
jQuery("#keyisready").hide();
|
||||
jQuery("#ind_connected").hide();
|
||||
jQuery("#disconnectbutton").hide();
|
||||
|
||||
jQuery('.ui.accordion').accordion();
|
||||
jQuery('#configutil').accordion({
|
||||
onOpen: function() {
|
||||
if (jQuery(this).hasClass("audiosection")) {
|
||||
setTimeout(set_audio_sliders, 50);
|
||||
}
|
||||
}
|
||||
});
|
||||
jQuery('.ui.dropdown').dropdown();
|
||||
|
||||
jQuery("#s_gpsmode").dropdown("setting", "onChange", function() { request_gpsmode_change(); });
|
||||
jQuery("#s_bluetoothmode").dropdown("setting", "onChange", function() { request_bluetoothmode_change(); });
|
||||
jQuery("#s_baudrate").dropdown("setting", "onChange", function() { request_baudrate_change(); });
|
||||
jQuery("#s_volumes").dropdown("setting", "onChange", function() { volume_changed(); });
|
||||
|
||||
jQuery('.ui.checkbox').checkbox()
|
||||
jQuery("#c_passall").checkbox("setting", "onChange", function() { request_passall_change(); });
|
||||
jQuery("#c_logtosd").checkbox("setting", "onChange", function() { request_logtosd_change(); });
|
||||
jQuery("#c_aes128").checkbox("setting", "onChange", function() { request_aes_change(); });
|
||||
|
||||
jQuery('#p-selection').range({
|
||||
min: 0,
|
||||
max: 255,
|
||||
start: 128
|
||||
start: 128,
|
||||
onChange: function(val) {
|
||||
request_p_change(val);
|
||||
}
|
||||
});
|
||||
|
||||
jQuery('#led-selection').range({
|
||||
min: 0,
|
||||
max: 255,
|
||||
start: 0
|
||||
start: 0,
|
||||
onChange: function(val) {
|
||||
request_led_change(val);
|
||||
}
|
||||
});
|
||||
|
||||
jQuery('#ingain-selection').range({
|
||||
min: 0,
|
||||
max: 255,
|
||||
start: 0
|
||||
start: 0,
|
||||
onChange: function(val) {
|
||||
request_ingain_change(val);
|
||||
}
|
||||
});
|
||||
|
||||
jQuery('#outgain-selection').range({
|
||||
min: 0,
|
||||
max: 255,
|
||||
start: 0
|
||||
start: 0,
|
||||
onChange: function(val) {
|
||||
request_outgain_change(val);
|
||||
}
|
||||
});
|
||||
|
||||
jQuery(".savebutton").click(function() {
|
||||
request_save_config();
|
||||
})
|
||||
|
||||
jQuery("#connectbutton").click(function() {
|
||||
request_connection();
|
||||
});
|
||||
|
@ -115,6 +442,45 @@ function init_elements() {
|
|||
jQuery("#disconnectbutton").click(function() {
|
||||
request_disconnect();
|
||||
});
|
||||
|
||||
jQuery("#keygenerate .button").click(function() {
|
||||
request_generatekey();
|
||||
});
|
||||
|
||||
jQuery("#keyfileinput").change(function(e) {
|
||||
if (e.target.files.length == 1) {
|
||||
var kf = e.target.files[0];
|
||||
var fr = new FileReader();
|
||||
fr.onload = function(e) {
|
||||
try {
|
||||
var stream = e.target.result;
|
||||
var keydata = btoa(stream);
|
||||
var url = "/loadkey?val="+encodeURIComponent(keydata);
|
||||
jQuery.getJSON(url, function(data) {
|
||||
if (data["response"] == "ok") {
|
||||
volume_changed();
|
||||
alert("The key was successfully installed onto the SD card.");
|
||||
} else {
|
||||
alert("There was an error loading the specified key");
|
||||
}
|
||||
});
|
||||
} catch (exception) {
|
||||
alert("An exception occurred while reading the specified key");
|
||||
console.log(exception);
|
||||
}
|
||||
}
|
||||
fr.readAsBinaryString(kf);
|
||||
/////////////////////////////////////
|
||||
} else {
|
||||
console.log("No or multiple files selected, not loading");
|
||||
}
|
||||
});
|
||||
|
||||
jQuery("#f_p").on("blur", update_slider_p);
|
||||
|
||||
jQuery("#f_preamble").on("blur", request_preamble_change);
|
||||
jQuery("#f_tail").on("blur", request_tail_change);
|
||||
jQuery("#f_slottime").on("blur", request_slottime_change);
|
||||
}
|
||||
|
||||
var graph_height = 0;
|
||||
|
@ -125,17 +491,17 @@ function init_gfx() {
|
|||
}
|
||||
|
||||
function askForPeakData() {
|
||||
jQuery.getJSON("/getpeak", function(data) {
|
||||
if (data["response"] == "ok") {
|
||||
console.log(data);
|
||||
if (data["decode"] == true) {
|
||||
udpateInputGraph(1024);
|
||||
console.log("DECODE");
|
||||
} else {
|
||||
udpateInputGraph(parseInt(data["peak"]));
|
||||
if (document.connection_state) {
|
||||
jQuery.getJSON("/getpeak", function(data) {
|
||||
if (data["response"] == "ok") {
|
||||
if (data["decode"] == true) {
|
||||
udpateInputGraph(1024);
|
||||
} else {
|
||||
udpateInputGraph(parseInt(data["peak"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function normalize(sample) {
|
||||
|
@ -149,7 +515,7 @@ var in_samples_max = 103;
|
|||
var in_samples = [];
|
||||
var starty;
|
||||
var t = 5;
|
||||
var peak_threshold = 96;
|
||||
var peak_threshold = 122;
|
||||
var sw = t-2;
|
||||
var ofs = 4;
|
||||
|
||||
|
@ -173,4 +539,57 @@ function udpateInputGraph(peakval) {
|
|||
line.attr({stroke: "#0c0", "stroke-width": sw});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var volume_ok = false;
|
||||
document.crypt_loading = false;
|
||||
function volume_changed() {
|
||||
var volume = jQuery("#s_volumes").val();
|
||||
if (volume != "none") {
|
||||
document.crypt_loading = true;
|
||||
setTimeout(function() {
|
||||
if (document.crypt_loading) jQuery("#crypt_loader").addClass("active");
|
||||
}, 150);
|
||||
var url = "/volumeinit?path="+encodeURIComponent(volume)
|
||||
jQuery.getJSON(url, function(data) {
|
||||
console.log(data)
|
||||
document.crypt_loading = false;
|
||||
jQuery("#crypt_loader").removeClass("active");
|
||||
if (data["response"] == "ok") {
|
||||
if (data["aes_disabled"] == false && data["key_installed"] == true) {
|
||||
jQuery("#c_aes128").checkbox("check");
|
||||
} else {
|
||||
jQuery("#c_aes128").checkbox("uncheck");
|
||||
}
|
||||
if (data["key_installed"] == true) {
|
||||
jQuery("#keyisready").show();
|
||||
jQuery("#keyload").hide();
|
||||
jQuery("#keygenerate").hide();
|
||||
jQuery("#keyload .button").addClass("disabled");
|
||||
jQuery("#keygenerate .button").addClass("disabled");
|
||||
jQuery("#c_aes128").removeClass("disabled");
|
||||
} else {
|
||||
jQuery("#c_aes128").addClass("disabled");
|
||||
jQuery("#keyisready").hide();
|
||||
jQuery("#keyload .button").removeClass("disabled");
|
||||
jQuery("#keygenerate .button").removeClass("disabled");
|
||||
jQuery("#keyload").show();
|
||||
jQuery("#keygenerate").show();
|
||||
}
|
||||
volume_ok = true;
|
||||
} else {
|
||||
volume_ok = false;
|
||||
alert("The selected volume could not be initialised for use with OpenModem. Please make sure that you have write access to the volume, and that it is correctly formatted.");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
volume_ok = false;
|
||||
jQuery("#keyisready").hide();
|
||||
jQuery("#keyload .button").addClass("disabled");
|
||||
jQuery("#keygenerate .button").addClass("disabled");
|
||||
jQuery("#keyload").show();
|
||||
jQuery("#keygenerate").show();
|
||||
jQuery("#c_aes128").checkbox("uncheck");
|
||||
jQuery("#c_aes128").addClass("disabled");
|
||||
}
|
||||
}
|
|
@ -53,4 +53,22 @@ i.fa-circle.connected {
|
|||
height: 100px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.licenses li a {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.licenses li .license a {
|
||||
color: #555;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.inputfile {
|
||||
width: 0.1px;
|
||||
height: 0.1px;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
Loading…
Reference in New Issue