[enh] Add firewall admin view."

First draft.
This commit is contained in:
opi 2014-06-05 01:51:42 +02:00
parent a37a9b7136
commit 0c595b1867
7 changed files with 373 additions and 1 deletions

View file

@ -344,3 +344,11 @@ select option[default] {
min-height: 1.5em;
}
}
.table-firewall .btn {visibility: hidden;}
.table-firewall td:hover .btn {visibility: visible;}
@media screen and (max-width: 767px) {
.table-responsive {border: none;}
}

2
css/style.min.css vendored

File diff suppressed because one or more lines are too long

146
js/app.js
View file

@ -1086,6 +1086,152 @@ app = Sammy('#main', function (sam) {
}
});
/**
* Firewall
*
*/
// Firewall status
sam.get('#/firewall', function (c) {
c.api('/firewall?raw', function(data) {
var firewall = {
ports : {},
upnp : false
};
// Reorganize ports
$.each(['ipv4', 'ipv6', 'uPnP'], function(i, protocol) {
$.each(['TCP', 'UDP'], function(j, connection) {
firewall.ports[connection] = firewall.ports[connection] || {}; 
$.each(data[protocol][connection], function(k, port) {
firewall.ports[connection][port] = firewall.ports[connection][port] || {}; 
firewall.ports[connection][port][protocol] = true;
});
});
});
// Get UPnP status
firewall.upnp = data.uPnP.enabled;
c.view('firewall/firewall', firewall);
});
});
// Enable/Disable UPnP
sam.get('#/firewall/upnp/:action', function (c) {
if (confirm(y18n.t('confirm_upnp_action', [y18n.t(c.params['action'])] ))) {
params = {'action' : c.params['action']}
c.api('/firewall/upnp', function(data) {
store.clear('slide');
c.redirect('#/firewall');
}, 'GET', params);
}
else {
store.clear('slide');
c.redirect('#/firewall');
}
});
// Toggle port status
sam.helper('togglePort', function(port, protocol, connection, action) {
var method = null
, endurl = []
, c = this
;
if (port != parseInt(port) || port < 0 || port > 65535) {
c.flash('fail', y18n.t('unknown_argument', [port]));
store.clear('slide');
c.redirect('#/firewall');
}
switch (connection) {
case 'ipv4':
break;
case 'ipv6':
endurl = 'ipv6'
break;
}
switch (protocol) {
case 'udp':
protocol = 'UDP';
break;
case 'both':
protocol = 'Both';
break;
case 'tcp':
default:
protocol = [];
}
switch (action) {
case "open":
method = 'POST';
break;
case "close":
method = 'DELETE';
break;
default:
c.flash('fail', y18n.t('unknown_action', [action]));
store.clear('slide');
c.redirect('#/firewall');
}
if (method !== null && protocol !== null && port != null) {
// port:
// protocol:
// - UDP
// - TCP
// - Both
// --ipv6:
// --no-upnp:
var params = {
'port' : port,
'protocol' : protocol,
}
c.api('/firewall/port?'+endurl, function(data) {
store.clear('slide');
c.redirect('#/firewall');
}, method, params);
}
else {
store.clear('slide');
c.redirect('#/firewall');
}
return;
});
// #/firewall/port/{{@key}}/tcp/ipv4/close
sam.get('#/firewall/port/:port/:protocol/:connection/:action', function (c) {
if (confirm(y18n.t('confirm_firewall', [ y18n.t(c.params['action']), c.params['port'], c.params['protocol'], c.params['connection'] ]))) {
c.togglePort(
c.params['port'],
c.params['protocol'],
c.params['connection'],
c.params['action']
);
}
else {
store.clear('slide');
c.redirect('#/firewall');
}
});
sam.post('#/firewall/port', function (c) {
if (confirm(y18n.t('confirm_firewall', [ y18n.t(c.params['action']), c.params['port'], c.params['protocol'], c.params['connection'] ]))) {
c.togglePort(
c.params['port'],
c.params['protocol'],
c.params['connection'],
c.params['action']
);
}
else {
store.clear('slide');
c.redirect('#/firewall');
}
});
/**
* Monitor

View file

@ -32,6 +32,9 @@
"log" : "Log",
"yes" : "Yes",
"no" : "No",
"open" : "Open",
"close" : "Close",
"both" : "Both",
"installing" : "Installing",
"installed" : "Installed",
@ -51,6 +54,7 @@
"non_compatible_api" : "Non-compatible API",
"warning_first_user" : "You probably need to <a href='#/users/create' class='alert-link'>create a user</a> first.",
"unknown_action" : "Unknown action %s",
"unknown_argument" : "Unknown argument : %s",
"confirm_delete" : "Are you sure you want to delete %s ?",
"confirm_change_maindomain" : "Are you sure you want to change the main domain ?",
@ -169,6 +173,20 @@
"service_status" : "Status: ",
"service_log" : "%s log",
"firewall" : "Firewall",
"upnp" : "UPnP",
"upnp_enabled" : "UPnP is enabled.",
"upnp_disabled" : "UPnP is disabled.",
"confirm_upnp_action" : "Are you sure you want to %s UPnP ?",
"action" : "Action",
"protocol" : "Protocol",
"connection" : "Connection",
"tcp" : "TCP",
"udp" : "UDP",
"port" : "Port",
"ports" : "Ports",
"confirm_firewall" : "Are you sure to %s port %s (protocol: %s, connection: %s)",
"tools" : "Tools",
"tools_adminpw" : "Change administration password",
"tools_adminpw_current" : "Current password",

View file

@ -32,6 +32,9 @@
"log" : "Journal",
"yes" : "Oui",
"no" : "Non",
"open" : "Ouvrir",
"close" : "Fermer",
"both" : "Les deux",
"installing" : "Installation",
"installed" : "Installé",
@ -51,6 +54,7 @@
"non_compatible_api" : "API non compatible",
"warning_first_user" : "Vous devez probablement d'abord <a href='#/users/create' class='alert-link'>créer un utilisateur</a>.",
"unknown_action" : "Action %s inconnue",
"unknown_argument" : "Argument inconnu : %s",
"confirm_delete" : "Êtes-vous sur de vouloir supprimer %s ?",
"confirm_change_maindomain" : "Êtes-vous sur de vouloir changer le domaine principal ?",
@ -170,6 +174,20 @@
"service_status" : "Statut : ",
"service_log" : "Journal de %s",
"firewall" : "Pare-feu",
"upnp" : "UPnP",
"upnp_enabled" : "l'UPnP est activé.",
"upnp_disabled" : "l'UPnP est désactivé.",
"confirm_upnp_action" : "Êtes-vous sur de vouloir %s l'UPnP ?",
"action" : "Action",
"protocol" : "Protocole",
"connection" : "Connexion",
"tcp" : "TCP",
"udp" : "UDP",
"port" : "Port",
"ports" : "Ports",
"confirm_firewall" : "Êtes-vous sur de vouloir %s le port %s (protocole: %s, connexion: %s)",
"tools" : "Outils",
"tools_adminpw" : "Changer le mot de passe d'administration",
"tools_adminpw_current" : "Mot de passe actuel",

178
views/firewall/firewall.ms Normal file
View file

@ -0,0 +1,178 @@
<div class="pull-left">
<a href="#/" class="btn btn-default slide back">
<span class="fa-chevron-left"></span> {{t 'menu'}}
</a>
</div>
<div class="clearfix"></div>
<h1 class="view-title">{{t 'firewall'}}</h1>
<div class="br"></div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title"><span class="fa-fw fa-shield"></span> {{t 'ports'}}</h2>
</div>
<div class="panel-body">
<div class="table-responsive">
<h3>{{t 'tcp'}}</h3>
<table class="table table-striped table-hover table-condensed table-firewall">
<thead>
<tr>
<th>{{t 'port'}}</th>
<th>{{t 'ipv4'}}</th>
<th>{{t 'ipv6'}}</th>
<th>{{t 'upnp'}}</th>
</tr>
</thead>
<tbody>
{{#each ports.TCP}}
<tr>
<td>{{@key}}</td>
<td>
{{#if this.ipv4}}
<span class="fa-check"></span>
<a class="btn btn-xs btn-danger" href="#/firewall/port/{{@key}}/tcp/ipv4/close">{{t 'close'}}</a>
{{else}}
<span></span>
<span class="fa-times"></span>
<a class="btn btn-xs btn-success" href="#/firewall/port/{{@key}}/tcp/ipv4/open">{{t 'open'}}</a>
{{/if}}
</td>
<td>
{{#if this.ipv6}}
<span class="fa-check"></span>
<a class="btn btn-xs btn-danger" href="#/firewall/port/{{@key}}/tcp/ipv6/close">{{t 'close'}}</a>
{{else}}
<span class="fa-times"></span>
<a class="btn btn-xs btn-success" href="#/firewall/port/{{@key}}/tcp/ipv6/open">{{t 'open'}}</a>
{{/if}}
</td>
<td>
{{#if this.uPnP}}
<span class="fa-check"></span>
{{else}}
<span class="fa-times"></span>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<div class="table-responsive">
<h3>{{t 'udp'}}</h3>
<table class="table table-striped table-hover table-condensed table-firewall">
<thead>
<tr>
<th>{{t 'port'}}</th>
<th>{{t 'ipv4'}}</th>
<th>{{t 'ipv6'}}</th>
<th>{{t 'upnp'}}</th>
</tr>
</thead>
<tbody>
{{#each ports.UDP}}
<tr>
<td>{{@key}}</td>
<td>
{{#if this.ipv4}}
<span class="fa-check"></span>
<a class="btn btn-xs btn-danger" href="#/firewall/port/{{@key}}/tcp/ipv4/close">{{t 'close'}}</a>
{{else}}
<span></span>
<span class="fa-times"></span>
<a class="btn btn-xs btn-success" href="#/firewall/port/{{@key}}/tcp/ipv4/open">{{t 'open'}}</a>
{{/if}}
</td>
<td>
{{#if this.ipv6}}
<span class="fa-check"></span>
<a class="btn btn-xs btn-danger" href="#/firewall/port/{{@key}}/tcp/ipv6/close">{{t 'close'}}</a>
{{else}}
<span class="fa-times"></span>
<a class="btn btn-xs btn-success" href="#/firewall/port/{{@key}}/tcp/ipv6/open">{{t 'open'}}</a>
{{/if}}
</td>
<td>
{{#if this.uPnP}}
<span class="fa-check"></span>
{{else}}
<span class="fa-times"></span>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
</div>
<!--
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">{{t 'udp'}}</h2>
</div>
<div class="panel-body table-responsive">
</div>
</div>
-->
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title"><span class="fa-fw fa-cog"></span> {{t 'operations'}}</h2>
</div>
<div class="panel-body">
<form action="#/firewall/port" method="POST" class="">
<div class="form-group row">
<div class="col-xs-6 col-sm-3">
<label for="action" class="control-label">{{t 'action'}}</label>
<select id="action" name="action" class="form-control" required>
<option value="open">{{t 'open'}}</option>
<option value="close">{{t 'close'}}</option>
</select>
</div>
<div class="col-xs-6 col-sm-3">
<label for="port" class="control-label">{{t 'port'}}</label>
<input type="number" id="port" name="port" class="form-control" required>
</div>
<div class="col-xs-6 col-sm-3">
<label for="connection" class="control-label">{{t 'connection'}}</label>
<select id="connection" name="connection" class="form-control" required>
<option value="ipv4">{{t 'ipv4'}}</option>
<option value="ipv6">{{t 'ipv6'}}</option>
</select>
</div>
<div class="col-xs-6 col-sm-3">
<label for="protocol" class="control-label">{{t 'protocol'}}</label>
<select id="protocol" name="protocol" class="form-control" required>
<option value="tcp">{{t 'tcp'}}</option>
<option value="udp">{{t 'udp'}}</option>
<option value="both">{{t 'both'}}</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="col-xs-6 col-sm-3">
<input type="submit" class="btn btn-success slide back" value="{{t 'save'}}">
</div>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title"><span class="fa-fw fa-exchange"></span> {{t 'upnp'}}</h2>
</div>
<div class="panel-body">
{{#if upnp}}
<p class="text-success">{{t 'upnp_enabled'}}</p>
<a href="#/firewall/upnp/disable" class="btn btn-danger">{{t 'disable'}}</a>
{{else}}
<p class="text-danger">{{t 'upnp_disabled'}}</p>
<a href="#/firewall/upnp/enable" class="btn btn-success">{{t 'enable'}}</a>
{{/if}}
</div>
</div>

View file

@ -15,6 +15,10 @@
<span class="pull-right fa-chevron-right"></span>
<h2 class="list-group-item-heading">{{t 'services'}}</h2>
</a>
<a href="#/firewall" class="list-group-item slide clearfix">
<span class="pull-right fa-chevron-right"></span>
<h2 class="list-group-item-heading">{{t 'firewall'}}</h2>
</a>
<a href="#/monitor" class="list-group-item slide clearfix">
<span class="pull-right fa-chevron-right"></span>
<h2 class="list-group-item-heading">{{t 'monitoring'}}</h2>