Cryptography init implemented

master
Mark Qvist 2019-02-15 20:44:24 +01:00
parent 2112070e44
commit f6d7ea8f24
4 changed files with 1050 additions and 105 deletions

View File

@ -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()

View File

@ -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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;&nbsp;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>&nbsp;<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>&nbsp;<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>&nbsp;<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>&nbsp;<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>&nbsp;<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>&nbsp;<span class="license"><a href="https://github.com/giampaolo/psutil/blob/master/LICENSE" target="_blank">BSD</a></span></li>
</ul>
</p>
</div>
</div>
</body>

View File

@ -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");
}
}

View File

@ -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;
}