Merge pull request #74 from danielperna84/netstats

Modify BANNED_IPS and ALLOWED_NETWORKS at runtime
This commit is contained in:
Daniel Perna 2018-01-24 23:08:38 +01:00 committed by GitHub
commit 07cf5d5219
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 601 additions and 7 deletions

View file

@ -79,6 +79,25 @@ The way this is implemented works in the following order:
- No: Return error 420 - No: Return error 420
- Yes: Continue and display UI of configurator - Yes: Continue and display UI of configurator
### API
Starting at version 0.2.5 you can add / remove IP addresses and networks from and to the `ALLOWED_NETWORKS` and `BANNED_IPS` lists at runtime. Keep in mind though, that these changes are not persistent and will be lost when the service is restarted. The API can be used through the UI in the _Network status_ menu or by sending POST requests. A possible use case could be programmatically allowing access from your dynamic public IP, which can be required for some setups involving SSL.
#### API targets:
- `api/allowed_networks`
#### Methods:
- `add`
- `remove`
#### Example:
- `curl -d "method=add&network=1.2.3.4" -X POST http://127.0.0.1:3218/api/allowed_networks`
- `api/banned_ips`
#### Methods:
- `ban`
- `unban`
#### Example:
- Example: `curl -d "method=ban&ip=9.9.9.9" -X POST http://127.0.0.1:3218/api/banned_ips`
### Embedding into HASS ### Embedding into HASS
HASS has the [panel_iframe](https://home-assistant.io/components/panel_iframe/) component. With this it is possible to embed the configurator directly into HASS, allowing you to modify your configuration through the HASS frontend. HASS has the [panel_iframe](https://home-assistant.io/components/panel_iframe/) component. With this it is possible to embed the configurator directly into HASS, allowing you to modify your configuration through the HASS frontend.
An example configuration would look like this: An example configuration would look like this:

View file

@ -2,6 +2,7 @@ Version 0.2.5 (2018-)
- Added warning-logs for access failure @danielperna84 - Added warning-logs for access failure @danielperna84
- Added transparency to whitespace characters @danielperna84 - Added transparency to whitespace characters @danielperna84
- Using external repository for Docker @Munsio - Using external repository for Docker @Munsio
- Modify BANNED_IPS and ALLOWED_NETWORKS at runtime @danielperna84
Version 0.2.4 (2018-01-02) Version 0.2.4 (2018-01-02)
- Added YAML linting @AtoxIO - Added YAML linting @AtoxIO

View file

@ -299,8 +299,13 @@ INDEX = Template(r"""<!DOCTYPE html>
} }
.input-field input[type=text].valid { .input-field input[type=text].valid {
border-bottom: 1px solid #03a9f4;; border-bottom: 1px solid #03a9f4 !important;
box-shadow: 0 1px 0 0 #03a9f4;; box-shadow: 0 1px 0 0 #03a9f4 !important;
}
.input-field input[type=text]:focus {
border-bottom: 1px solid #03a9f4 !important;
box-shadow: 0 1px 0 0 #03a9f4 !important;
} }
.row .input-field input:focus { .row .input-field input:focus {
@ -624,6 +629,7 @@ INDEX = Template(r"""<!DOCTYPE html>
<li><a class="modal-trigger" target="_blank" href="#modal_components">HASS Components</a></li> <li><a class="modal-trigger" target="_blank" href="#modal_components">HASS Components</a></li>
<li><a class="modal-trigger" target="_blank" href="#modal_icons">Material Icons</a></li> <li><a class="modal-trigger" target="_blank" href="#modal_icons">Material Icons</a></li>
<li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li> <li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li>
<li><a class="modal-trigger" href="#modal_netstat" onclick="get_netstat()">Network status</a></li>
<li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li> <li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li>
<li class="divider"></li> <li class="divider"></li>
<!--<li><a href="#modal_check_config">Check HASS Configuration</a></li>--> <!--<li><a href="#modal_check_config">Check HASS Configuration</a></li>-->
@ -640,6 +646,7 @@ INDEX = Template(r"""<!DOCTYPE html>
<li><a target="_blank" href="https://home-assistant.io/components/">HASS Components</a></li> <li><a target="_blank" href="https://home-assistant.io/components/">HASS Components</a></li>
<li><a target="_blank" href="https://materialdesignicons.com/">Material Icons</a></li> <li><a target="_blank" href="https://materialdesignicons.com/">Material Icons</a></li>
<li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li> <li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li>
<li><a class="modal-trigger" href="#modal_netstat" onclick="get_netstat()">Network status</a></li>
<li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li> <li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li>
<li class="divider"></li> <li class="divider"></li>
<!--<li><a href="#modal_check_config">Check HASS Configuration</a></li>--> <!--<li><a href="#modal_check_config">Check HASS Configuration</a></li>-->
@ -1343,6 +1350,46 @@ INDEX = Template(r"""<!DOCTYPE html>
<a onclick="restart()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a> <a onclick="restart()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div> </div>
</div> </div>
<div id="modal_a_net_remove" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Remove allowed network / IP<i class="mdi mdi-settings right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
<p>Do you really want to remove the network / IP <b><span id="removenet"></span></b> from the list of allowed networks?</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">No</a>
<a onclick="a_net_remove()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div>
</div>
<div id="modal_a_net_add" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Add allowed network / IP<i class="mdi mdi-settings right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
<p>Do you really want to Add the network / IP <b><span id="addnet"></span></b> to the list of allowed networks?</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">No</a>
<a onclick="a_net_add()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div>
</div>
<div id="modal_unban" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Unban IP<i class="mdi mdi-settings right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
<p>Do you really want to unban the IP <b><span id="unbanip"></span></b>?</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">No</a>
<a onclick="banned_unban()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div>
</div>
<div id="modal_ban" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Ban IP<i class="mdi mdi-settings right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
<p>Do you really want to ban the IP <b><span id="banip"></span></b>?</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">No</a>
<a onclick="banned_ban()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div>
</div>
<div id="modal_exec_command" class="modal"> <div id="modal_exec_command" class="modal">
<div class="modal-content"> <div class="modal-content">
<h4 class="grey-text text-darken-3">Execute shell command<i class="mdi mdi-laptop right grey-text text-darken-3" style="font-size: 2rem;"></i></h4> <h4 class="grey-text text-darken-3">Execute shell command<i class="mdi mdi-laptop right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
@ -1419,6 +1466,35 @@ INDEX = Template(r"""<!DOCTYPE html>
<a onclick="newbranch(document.getElementById('newbranch').value)" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">OK</a> <a onclick="newbranch(document.getElementById('newbranch').value)" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">OK</a>
</div> </div>
</div> </div>
<div id="modal_netstat" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Network status<i class="mdi mdi-network right grey-text text-darken-3" style="font-size: 2.48rem;"></i></h4>
<p><label for="listening_address">Listening address:&nbsp;</label><span id="listening_address">$listening_address</span></p>
<p><label for="hass_api_address">HASS API address:&nbsp;</label><span id="hass_api_address">$hass_api_address</span></p>
<p>Modifying the following lists is not persistent. To statically control access please use the configuration file.</p>
<p>
<ul id="allowed_networks" class="collection with-header"></ul>
<br />
<div class="input-field">
<a href="#" class="prefix" onclick="helper_a_net_add()"><i class="mdi mdi-plus-circle prefix light-blue-text"></i></a></i>
<input placeholder="192.168.0.0/16" id="add_net_ip" type="text">
<label for="add_net_ip">Add network / IP</label>
</div>
</p>
<p>
<ul id="banned_ips" class="collection with-header"></ul>
<br />
<div class="input-field">
<a href="#" class="prefix" onclick="helper_banned_ban()"><i class="mdi mdi-plus-circle prefix light-blue-text"></i></a></i>
<input placeholder="1.2.3.4" id="add_banned_ip" type="text">
<label for="add_banned_ip">Ban IP</label>
</div>
</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">Cancel</a>
</div>
</div>
<div id="modal_about" class="modal modal-fixed-footer"> <div id="modal_about" class="modal modal-fixed-footer">
<div class="modal-content"> <div class="modal-content">
<h4 class="grey-text text-darken-3"><a class="black-text" href="https://github.com/danielperna84/hass-configurator/" target="_blank">HASS Configurator</a></h4> <h4 class="grey-text text-darken-3"><a class="black-text" href="https://github.com/danielperna84/hass-configurator/" target="_blank">HASS Configurator</a></h4>
@ -2378,6 +2454,175 @@ INDEX = Template(r"""<!DOCTYPE html>
}); });
} }
function get_netstat() {
$.get("api/netstat", function (resp) {
if (resp.hasOwnProperty("allowed_networks")) {
var allowed_list = document.getElementById("allowed_networks");
while (allowed_list.firstChild) {
allowed_list.removeChild(allowed_list.firstChild);
}
var header = document.createElement("li");
header.classList.add("collection-header");
var header_h4 = document.createElement("h4");
header_h4.innerText = "Allowed networks";
header_h4.classList.add("grey-text");
header_h4.classList.add("text-darken-3");
header.appendChild(header_h4);
allowed_list.appendChild(header);
for (var i = 0; i < resp.allowed_networks.length; i++) {
var li = document.createElement("li");
li.classList.add("collection-item");
var li_div = document.createElement("div");
var address = document.createElement("span");
address.innerText = resp.allowed_networks[i];
li_div.appendChild(address);
var li_a = document.createElement("a");
li_a.classList.add("light-blue-text");
li_a.href = "#!";
li_a.classList.add("secondary-content");
var li_a_i = document.createElement("i");
li_a_i.classList.add("mdi");
li_a_i.classList.add("mdi-delete");
li_a_i.innerText = "Remove";
li_a.appendChild(li_a_i);
li_a.setAttribute("onclick", "helper_a_net_remove('" + resp.allowed_networks[i] + "')");
li_div.appendChild(li_a);
li.appendChild(li_div);
allowed_list.appendChild(li);
}
}
if (resp.hasOwnProperty("banned_ips")) {
var banlist = document.getElementById("banned_ips");
while (banlist.firstChild) {
banlist.removeChild(banlist.firstChild);
}
var header = document.createElement("li");
header.classList.add("collection-header");
var header_h4 = document.createElement("h4");
header_h4.innerText = "Banned IPs";
header_h4.classList.add("grey-text");
header_h4.classList.add("text-darken-3");
header.appendChild(header_h4);
banlist.appendChild(header);
for (var i = 0; i < resp.banned_ips.length; i++) {
var li = document.createElement("li");
li.classList.add("collection-item");
var li_div = document.createElement("div");
var address = document.createElement("span");
address.innerText = resp.banned_ips[i];
li_div.appendChild(address);
var li_a = document.createElement("a");
li_a.classList.add("light-blue-text");
li_a.href = "#!";
li_a.classList.add("secondary-content");
var li_a_i = document.createElement("i");
li_a_i.classList.add("mdi");
li_a_i.classList.add("mdi-delete");
li_a_i.innerText = "Unban";
li_a.appendChild(li_a_i);
li_a.setAttribute("onclick", "helper_banned_unban('" + resp.banned_ips[i] + "')");
li_div.appendChild(li_a);
li.appendChild(li_div);
banlist.appendChild(li);
}
}
});
}
function helper_a_net_remove(network) {
document.getElementById("removenet").innerText = network;
$('#modal_netstat').modal('close');
$('#modal_a_net_remove').modal('open');
}
function a_net_remove() {
var network = document.getElementById("removenet").innerText
data = new Object();
data.network = network;
data.method = 'remove';
$.post("api/allowed_networks", data).done(function(resp) {
if (resp.error) {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 5000);
}
else {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 2000);
}
});
}
function helper_a_net_add() {
document.getElementById("addnet").innerText = document.getElementById("add_net_ip").value;
document.getElementById("add_net_ip").value = "";
$('#modal_netstat').modal('close');
$('#modal_a_net_add').modal('open');
}
function a_net_add() {
var network = document.getElementById("addnet").innerText
data = new Object();
data.network = network;
data.method = 'add';
$.post("api/allowed_networks", data).done(function(resp) {
if (resp.error) {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 5000);
}
else {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 2000);
}
});
}
function helper_banned_unban(ip) {
document.getElementById("unbanip").innerText = ip;
$('#modal_netstat').modal('close');
$('#modal_unban').modal('open');
}
function banned_unban() {
var ip = document.getElementById("unbanip").innerText
data = new Object();
data.ip = ip;
data.method = 'unban';
$.post("api/banned_ips", data).done(function(resp) {
if (resp.error) {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 5000);
}
else {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 2000);
}
});
}
function helper_banned_ban() {
document.getElementById("banip").innerText = document.getElementById("add_banned_ip").value;
document.getElementById("add_banned_ip").value = "";
$('#modal_netstat').modal('close');
$('#modal_ban').modal('open');
}
function banned_ban() {
var ip = document.getElementById("banip").innerText
data = new Object();
data.ip = ip;
data.method = 'ban';
$.post("api/banned_ips", data).done(function(resp) {
if (resp.error) {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 5000);
}
else {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 2000);
}
});
}
function save() { function save() {
var filepath = document.getElementById('currentfile').value; var filepath = document.getElementById('currentfile').value;
if (filepath.length > 0) { if (filepath.length > 0) {
@ -3063,6 +3308,16 @@ class RequestHandler(BaseHTTPRequestHandler):
if os.path.isdir(dirpath): if os.path.isdir(dirpath):
self.wfile.write(os.path.abspath(os.path.dirname(dirpath))) self.wfile.write(os.path.abspath(os.path.dirname(dirpath)))
return return
elif req.path == '/api/netstat':
content = ""
self.send_header('Content-type', 'text/json')
self.end_headers()
res = {
"allowed_networks": ALLOWED_NETWORKS,
"banned_ips": BANNED_IPS
}
self.wfile.write(bytes(json.dumps(res), "utf8"))
return
elif req.path == '/api/restart': elif req.path == '/api/restart':
LOG.info("/api/restart") LOG.info("/api/restart")
self.send_header('Content-type', 'text/json') self.send_header('Content-type', 'text/json')
@ -3227,7 +3482,10 @@ class RequestHandler(BaseHTTPRequestHandler):
states=states, states=states,
current=VERSION, current=VERSION,
versionclass=color, versionclass=color,
separator="\%s" % os.sep if os.sep == "\\" else os.sep) separator="\%s" % os.sep if os.sep == "\\" else os.sep,
listening_address="%s://%s:%i" % (
'https' if SSL_CERTIFICATE else 'http', LISTENIP, LISTENPORT),
hass_api_address="%s" % (HASS_API, ))
self.wfile.write(bytes(html, "utf8")) self.wfile.write(bytes(html, "utf8"))
return return
else: else:
@ -3236,6 +3494,7 @@ class RequestHandler(BaseHTTPRequestHandler):
self.wfile.write(bytes("File not found", "utf8")) self.wfile.write(bytes("File not found", "utf8"))
def do_POST(self): def do_POST(self):
global ALLOWED_NETWORKS, BANNED_IPS
if not check_access(self.client_address[0]): if not check_access(self.client_address[0]):
self.do_BLOCK() self.do_BLOCK()
return return
@ -3649,6 +3908,76 @@ class RequestHandler(BaseHTTPRequestHandler):
LOG.warning(err) LOG.warning(err)
else: else:
response['message'] = "Missing filename or text" response['message'] = "Missing filename or text"
elif req.path == '/api/allowed_networks':
try:
postvars = parse_qs(self.rfile.read(length).decode('utf-8'), keep_blank_values=1)
except Exception as err:
LOG.warning(err)
response['message'] = "%s" % (str(err))
postvars = {}
if 'network' in postvars.keys() and 'method' in postvars.keys():
if postvars['network'] and postvars['method']:
try:
network = unquote(postvars['network'][0])
method = unquote(postvars['method'][0])
if method == 'remove':
if network in ALLOWED_NETWORKS:
ALLOWED_NETWORKS.remove(network)
if not ALLOWED_NETWORKS:
ALLOWED_NETWORKS.append("0.0.0.0/0")
response['error'] = False
elif method == 'add':
ipaddress.ip_network(network)
ALLOWED_NETWORKS.append(network)
response['error'] = False
else:
response['error'] = True
self.send_response(200)
self.send_header('Content-type', 'text/json')
self.end_headers()
response['error'] = False
response['message'] = "ALLOWED_NETWORKS (%s): %s" % (method, network)
self.wfile.write(bytes(json.dumps(response), "utf8"))
return
except Exception as err:
response['error'] = True
response['message'] = "%s" % (str(err))
LOG.warning(err)
else:
response['message'] = "Missing network"
elif req.path == '/api/banned_ips':
try:
postvars = parse_qs(self.rfile.read(length).decode('utf-8'), keep_blank_values=1)
except Exception as err:
LOG.warning(err)
response['message'] = "%s" % (str(err))
postvars = {}
if 'ip' in postvars.keys() and 'method' in postvars.keys():
if postvars['ip'] and postvars['method']:
try:
ip = unquote(postvars['ip'][0])
method = unquote(postvars['method'][0])
if method == 'unban':
if ip in BANNED_IPS:
BANNED_IPS.remove(ip)
response['error'] = False
elif method == 'ban':
ipaddress.ip_network(ip)
BANNED_IPS.append(ip)
else:
response['error'] = True
self.send_response(200)
self.send_header('Content-type', 'text/json')
self.end_headers()
response['message'] = "BANNED_IPS (%s): %s" % (method, ip)
self.wfile.write(bytes(json.dumps(response), "utf8"))
return
except Exception as err:
response['error'] = True
response['message'] = "%s" % (str(err))
LOG.warning(err)
else:
response['message'] = "Missing IP"
else: else:
response['message'] = "Invalid method" response['message'] = "Invalid method"
self.send_response(200) self.send_response(200)

249
dev.html
View file

@ -220,8 +220,13 @@
} }
.input-field input[type=text].valid { .input-field input[type=text].valid {
border-bottom: 1px solid #03a9f4;; border-bottom: 1px solid #03a9f4 !important;
box-shadow: 0 1px 0 0 #03a9f4;; box-shadow: 0 1px 0 0 #03a9f4 !important;
}
.input-field input[type=text]:focus {
border-bottom: 1px solid #03a9f4 !important;
box-shadow: 0 1px 0 0 #03a9f4 !important;
} }
.row .input-field input:focus { .row .input-field input:focus {
@ -545,6 +550,7 @@
<li><a class="modal-trigger" target="_blank" href="#modal_components">HASS Components</a></li> <li><a class="modal-trigger" target="_blank" href="#modal_components">HASS Components</a></li>
<li><a class="modal-trigger" target="_blank" href="#modal_icons">Material Icons</a></li> <li><a class="modal-trigger" target="_blank" href="#modal_icons">Material Icons</a></li>
<li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li> <li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li>
<li><a class="modal-trigger" href="#modal_netstat" onclick="get_netstat()">Network status</a></li>
<li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li> <li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li>
<li class="divider"></li> <li class="divider"></li>
<!--<li><a href="#modal_check_config">Check HASS Configuration</a></li>--> <!--<li><a href="#modal_check_config">Check HASS Configuration</a></li>-->
@ -561,6 +567,7 @@
<li><a target="_blank" href="https://home-assistant.io/components/">HASS Components</a></li> <li><a target="_blank" href="https://home-assistant.io/components/">HASS Components</a></li>
<li><a target="_blank" href="https://materialdesignicons.com/">Material Icons</a></li> <li><a target="_blank" href="https://materialdesignicons.com/">Material Icons</a></li>
<li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li> <li><a href="#" data-activates="ace_settings" class="ace_settings-collapse">Editor Settings</a></li>
<li><a class="modal-trigger" href="#modal_netstat" onclick="get_netstat()">Network status</a></li>
<li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li> <li><a class="modal-trigger" href="#modal_about">About HASS-Configurator</a></li>
<li class="divider"></li> <li class="divider"></li>
<!--<li><a href="#modal_check_config">Check HASS Configuration</a></li>--> <!--<li><a href="#modal_check_config">Check HASS Configuration</a></li>-->
@ -1264,6 +1271,46 @@
<a onclick="restart()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a> <a onclick="restart()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div> </div>
</div> </div>
<div id="modal_a_net_remove" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Remove allowed network / IP<i class="mdi mdi-settings right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
<p>Do you really want to remove the network / IP <b><span id="removenet"></span></b> from the list of allowed networks?</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">No</a>
<a onclick="a_net_remove()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div>
</div>
<div id="modal_a_net_add" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Add allowed network / IP<i class="mdi mdi-settings right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
<p>Do you really want to Add the network / IP <b><span id="addnet"></span></b> to the list of allowed networks?</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">No</a>
<a onclick="a_net_add()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div>
</div>
<div id="modal_unban" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Unban IP<i class="mdi mdi-settings right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
<p>Do you really want to unban the IP <b><span id="unbanip"></span></b>?</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">No</a>
<a onclick="banned_unban()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div>
</div>
<div id="modal_ban" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Ban IP<i class="mdi mdi-settings right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
<p>Do you really want to ban the IP <b><span id="banip"></span></b>?</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">No</a>
<a onclick="banned_ban()" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">Yes</a>
</div>
</div>
<div id="modal_exec_command" class="modal"> <div id="modal_exec_command" class="modal">
<div class="modal-content"> <div class="modal-content">
<h4 class="grey-text text-darken-3">Execute shell command<i class="mdi mdi-laptop right grey-text text-darken-3" style="font-size: 2rem;"></i></h4> <h4 class="grey-text text-darken-3">Execute shell command<i class="mdi mdi-laptop right grey-text text-darken-3" style="font-size: 2rem;"></i></h4>
@ -1340,6 +1387,35 @@
<a onclick="newbranch(document.getElementById('newbranch').value)" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">OK</a> <a onclick="newbranch(document.getElementById('newbranch').value)" class=" modal-action modal-close waves-effect waves-green btn-flat light-blue-text">OK</a>
</div> </div>
</div> </div>
<div id="modal_netstat" class="modal">
<div class="modal-content">
<h4 class="grey-text text-darken-3">Network status<i class="mdi mdi-network right grey-text text-darken-3" style="font-size: 2.48rem;"></i></h4>
<p><label for="listening_address">Listening address:&nbsp;</label><span id="listening_address">$listening_address</span></p>
<p><label for="hass_api_address">HASS API address:&nbsp;</label><span id="hass_api_address">$hass_api_address</span></p>
<p>Modifying the following lists is not persistent. To statically control access please use the configuration file.</p>
<p>
<ul id="allowed_networks" class="collection with-header"></ul>
<br />
<div class="input-field">
<a href="#" class="prefix" onclick="helper_a_net_add()"><i class="mdi mdi-plus-circle prefix light-blue-text"></i></a></i>
<input placeholder="192.168.0.0/16" id="add_net_ip" type="text">
<label for="add_net_ip">Add network / IP</label>
</div>
</p>
<p>
<ul id="banned_ips" class="collection with-header"></ul>
<br />
<div class="input-field">
<a href="#" class="prefix" onclick="helper_banned_ban()"><i class="mdi mdi-plus-circle prefix light-blue-text"></i></a></i>
<input placeholder="1.2.3.4" id="add_banned_ip" type="text">
<label for="add_banned_ip">Ban IP</label>
</div>
</p>
</div>
<div class="modal-footer">
<a class=" modal-action modal-close waves-effect waves-red btn-flat light-blue-text">Cancel</a>
</div>
</div>
<div id="modal_about" class="modal modal-fixed-footer"> <div id="modal_about" class="modal modal-fixed-footer">
<div class="modal-content"> <div class="modal-content">
<h4 class="grey-text text-darken-3"><a class="black-text" href="https://github.com/danielperna84/hass-configurator/" target="_blank">HASS Configurator</a></h4> <h4 class="grey-text text-darken-3"><a class="black-text" href="https://github.com/danielperna84/hass-configurator/" target="_blank">HASS Configurator</a></h4>
@ -2299,6 +2375,175 @@
}); });
} }
function get_netstat() {
$.get("api/netstat", function (resp) {
if (resp.hasOwnProperty("allowed_networks")) {
var allowed_list = document.getElementById("allowed_networks");
while (allowed_list.firstChild) {
allowed_list.removeChild(allowed_list.firstChild);
}
var header = document.createElement("li");
header.classList.add("collection-header");
var header_h4 = document.createElement("h4");
header_h4.innerText = "Allowed networks";
header_h4.classList.add("grey-text");
header_h4.classList.add("text-darken-3");
header.appendChild(header_h4);
allowed_list.appendChild(header);
for (var i = 0; i < resp.allowed_networks.length; i++) {
var li = document.createElement("li");
li.classList.add("collection-item");
var li_div = document.createElement("div");
var address = document.createElement("span");
address.innerText = resp.allowed_networks[i];
li_div.appendChild(address);
var li_a = document.createElement("a");
li_a.classList.add("light-blue-text");
li_a.href = "#!";
li_a.classList.add("secondary-content");
var li_a_i = document.createElement("i");
li_a_i.classList.add("mdi");
li_a_i.classList.add("mdi-delete");
li_a_i.innerText = "Remove";
li_a.appendChild(li_a_i);
li_a.setAttribute("onclick", "helper_a_net_remove('" + resp.allowed_networks[i] + "')");
li_div.appendChild(li_a);
li.appendChild(li_div);
allowed_list.appendChild(li);
}
}
if (resp.hasOwnProperty("banned_ips")) {
var banlist = document.getElementById("banned_ips");
while (banlist.firstChild) {
banlist.removeChild(banlist.firstChild);
}
var header = document.createElement("li");
header.classList.add("collection-header");
var header_h4 = document.createElement("h4");
header_h4.innerText = "Banned IPs";
header_h4.classList.add("grey-text");
header_h4.classList.add("text-darken-3");
header.appendChild(header_h4);
banlist.appendChild(header);
for (var i = 0; i < resp.banned_ips.length; i++) {
var li = document.createElement("li");
li.classList.add("collection-item");
var li_div = document.createElement("div");
var address = document.createElement("span");
address.innerText = resp.banned_ips[i];
li_div.appendChild(address);
var li_a = document.createElement("a");
li_a.classList.add("light-blue-text");
li_a.href = "#!";
li_a.classList.add("secondary-content");
var li_a_i = document.createElement("i");
li_a_i.classList.add("mdi");
li_a_i.classList.add("mdi-delete");
li_a_i.innerText = "Unban";
li_a.appendChild(li_a_i);
li_a.setAttribute("onclick", "helper_banned_unban('" + resp.banned_ips[i] + "')");
li_div.appendChild(li_a);
li.appendChild(li_div);
banlist.appendChild(li);
}
}
});
}
function helper_a_net_remove(network) {
document.getElementById("removenet").innerText = network;
$('#modal_netstat').modal('close');
$('#modal_a_net_remove').modal('open');
}
function a_net_remove() {
var network = document.getElementById("removenet").innerText
data = new Object();
data.network = network;
data.method = 'remove';
$.post("api/allowed_networks", data).done(function(resp) {
if (resp.error) {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 5000);
}
else {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 2000);
}
});
}
function helper_a_net_add() {
document.getElementById("addnet").innerText = document.getElementById("add_net_ip").value;
document.getElementById("add_net_ip").value = "";
$('#modal_netstat').modal('close');
$('#modal_a_net_add').modal('open');
}
function a_net_add() {
var network = document.getElementById("addnet").innerText
data = new Object();
data.network = network;
data.method = 'add';
$.post("api/allowed_networks", data).done(function(resp) {
if (resp.error) {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 5000);
}
else {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 2000);
}
});
}
function helper_banned_unban(ip) {
document.getElementById("unbanip").innerText = ip;
$('#modal_netstat').modal('close');
$('#modal_unban').modal('open');
}
function banned_unban() {
var ip = document.getElementById("unbanip").innerText
data = new Object();
data.ip = ip;
data.method = 'unban';
$.post("api/banned_ips", data).done(function(resp) {
if (resp.error) {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 5000);
}
else {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 2000);
}
});
}
function helper_banned_ban() {
document.getElementById("banip").innerText = document.getElementById("add_banned_ip").value;
document.getElementById("add_banned_ip").value = "";
$('#modal_netstat').modal('close');
$('#modal_ban').modal('open');
}
function banned_ban() {
var ip = document.getElementById("banip").innerText
data = new Object();
data.ip = ip;
data.method = 'ban';
$.post("api/banned_ips", data).done(function(resp) {
if (resp.error) {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 5000);
}
else {
var $toastContent = $("<div><pre>" + resp.message + "</pre></div>");
Materialize.toast($toastContent, 2000);
}
});
}
function save() { function save() {
var filepath = document.getElementById('currentfile').value; var filepath = document.getElementById('currentfile').value;
if (filepath.length > 0) { if (filepath.length > 0) {