Issue #2: Unable to write ipAssignments
This commit is contained in:
parent
d0b120bf44
commit
09f1e841b3
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
||||
*.swp
|
||||
Release/
|
||||
Staging/
|
||||
|
@ -6,10 +6,11 @@ if [ `basename $THISDIR` != 'build' ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC_DIR=../src
|
||||
BUILD_DIR=`pwd`
|
||||
PKG_DIR=Release
|
||||
STAGING_DIR=Staging
|
||||
BASE_DIR=`dirname $THISDIR`
|
||||
SRC_DIR=$BASE_DIR/src
|
||||
BUILD_DIR=$BASE_DIR/build
|
||||
PKG_DIR=$BASE_DIR/Release
|
||||
STAGING_DIR=$BASE_DIR/Staging
|
||||
|
||||
NAME='ztncui'
|
||||
DESCRIPTION='ZeroTier network controller user interface'
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
@ -13,52 +13,68 @@ storage.initSync({dir: 'etc/storage'});
|
||||
|
||||
// ZT network controller home page
|
||||
exports.index = async function(req, res) {
|
||||
const page = 'controller_home';
|
||||
const nav =
|
||||
{
|
||||
active: 'controller_home',
|
||||
}
|
||||
|
||||
try {
|
||||
zt_address = await zt.get_zt_address();
|
||||
res.render('index', {title: 'ztncui', page: page, zt_address: zt_address});
|
||||
res.render('index', {title: 'ztncui', nav: nav, zt_address: zt_address});
|
||||
} catch (err) {
|
||||
res.render('index', {title: 'ztncui',
|
||||
page: page, error: 'ERROR resolving ZT address: ' + err});
|
||||
nav: nav, error: 'ERROR resolving ZT address: ' + err});
|
||||
}
|
||||
};
|
||||
|
||||
// Display list of all networks on this ZT network controller
|
||||
exports.network_list = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
}
|
||||
|
||||
try {
|
||||
networks = await zt.network_list();
|
||||
res.render('networks', {title: 'Networks on this controller', page: page, networks: networks});
|
||||
res.render('networks', {title: 'Networks on this controller', nav: nav, networks: networks});
|
||||
} catch (err) {
|
||||
res.render('networks', {title: 'Networks on this controller', page: page, error: 'Error retrieving list of networks on this controller: ' + err});
|
||||
res.render('networks', {title: 'Networks on this controller', nav: nav, error: 'Error retrieving list of networks on this controller: ' + err});
|
||||
}
|
||||
};
|
||||
|
||||
// Display detail page for specific network
|
||||
exports.network_detail = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: '/controller/networks'
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
const members = await zt.members(req.params.nwid);
|
||||
res.render('network_detail', {title: 'Detail for network', page: page, network: network, members: members});
|
||||
res.render('network_detail', {title: 'Detail for network', nav: nav, network: network, members: members});
|
||||
} catch (err) {
|
||||
res.render('network_detail', {title: 'Detail for network', page: page, error: 'Error resolving detail for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('network_detail', {title: 'Detail for network', nav: nav, error: 'Error resolving detail for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
};
|
||||
|
||||
// Display Network create form on GET
|
||||
exports.network_create_get = function(req, res) {
|
||||
const page = 'add_network';
|
||||
const nav =
|
||||
{
|
||||
active: 'add_network',
|
||||
}
|
||||
|
||||
res.render('network_create', {title: 'Create network', page: page});
|
||||
res.render('network_create', {title: 'Create network', nav: nav});
|
||||
};
|
||||
|
||||
// Handle Network create on POST
|
||||
exports.network_create_post = async function(req, res) {
|
||||
const page = 'add_network';
|
||||
const nav =
|
||||
{
|
||||
active: 'add_network',
|
||||
}
|
||||
|
||||
req.checkBody('name', 'Network name required').notEmpty();
|
||||
|
||||
@ -70,66 +86,83 @@ exports.network_create_post = async function(req, res) {
|
||||
const name = { name: req.body.name };
|
||||
|
||||
if (errors) {
|
||||
res.render('network_create', {title: 'Create Network', page: page, name: name, errors: errors});
|
||||
res.render('network_create', {title: 'Create Network', nav: nav, name: name, errors: errors});
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
const network = await zt.network_create(name);
|
||||
res.redirect('/controller/networks');
|
||||
} catch (err) {
|
||||
res.render('network_detail', {title: 'Create Network - error', page: page, error: 'Error creating network ' + name.name});
|
||||
res.render('network_detail', {title: 'Create Network - error', nav: nav, error: 'Error creating network ' + name.name});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Display Network delete form on GET
|
||||
exports.network_delete_get = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: '/controller/networks'
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
res.render('network_delete', {title: 'Delete network', page: page,
|
||||
res.render('network_delete', {title: 'Delete network', nav: nav,
|
||||
nwid: req.params.nwid, network: network});
|
||||
} catch (err) {
|
||||
res.render('network_delete', {title: 'Delete network', page: page, error: 'Error resolving network ' + req.params.nwid + ': ' + err});
|
||||
res.render('network_delete', {title: 'Delete network', nav: nav, error: 'Error resolving network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
};
|
||||
|
||||
// Handle Network delete on POST
|
||||
exports.network_delete_post = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: '/controller/networks'
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_delete(req.params.nwid);
|
||||
res.render('network_delete', {title: 'Delete network', page: page, network: network});
|
||||
res.render('network_delete', {title: 'Delete network', nav: nav, network: network});
|
||||
} catch (err) {
|
||||
res.render('network_delete', {title: 'Delete network', page: page, error: 'Error deleting network ' + req.params.nwid + ': ' + err});
|
||||
res.render('network_delete', {title: 'Delete network', nav: nav, error: 'Error deleting network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
};
|
||||
|
||||
// Network object GET
|
||||
exports.network_object = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
res.render(req.params.object, {title: req.params.object, page: page, network: network}, function(err, html) {
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render(req.params.object, {title: req.params.object, nav: nav, network: network}, function(err, html) {
|
||||
if (err) {
|
||||
if (err.message.indexOf('Failed to lookup view') !== -1 ) {
|
||||
return res.render('not_implemented', {title: req.params.object, page: page, network: network});
|
||||
return res.render('not_implemented', {title: req.params.object, nav: nav, network: network});
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
res.send(html);
|
||||
});
|
||||
} catch (err) {
|
||||
res.render(req.params.object, {title: req.params.object, page: page, error: 'Error resolving detail for network ' + req.params.nwid + ': ' + err});
|
||||
res.render(req.params.object, {title: req.params.object, nav: nav, error: 'Error resolving detail for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Network rename form on POST
|
||||
exports.name = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: '/controller/networks'
|
||||
}
|
||||
|
||||
req.checkBody('name', 'Network name required').notEmpty();
|
||||
req.sanitize('name').escape();
|
||||
@ -142,16 +175,16 @@ exports.name = async function(req, res) {
|
||||
if (errors) {
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
res.render('name', {title: 'Rename network', page: page, network: network, name: name, errors: errors});
|
||||
res.render('name', {title: 'Rename network', nav: nav, network: network, name: name, errors: errors});
|
||||
} catch (err) {
|
||||
res.render('name', {title: 'Rename network', page: page, error: 'Error resolving network detail for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('name', {title: 'Rename network', nav: nav, error: 'Error resolving network detail for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const network = await zt.network_object(req.params.nwid, name);
|
||||
res.redirect('/controller/networks');
|
||||
} catch ( err) {
|
||||
res.render('name', {title: 'Rename network', page: page, error: 'Error renaming network ' + req.params.nwid + ': ' + err});
|
||||
res.render('name', {title: 'Rename network', nav: nav, error: 'Error renaming network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +192,11 @@ exports.name = async function(req, res) {
|
||||
|
||||
// ipAssignmentPools POST
|
||||
exports.ipAssignmentPools = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
req.checkBody('ipRangeStart', 'IP range start required').notEmpty();
|
||||
req.checkBody('ipRangeStart', 'IP range start needs a valid IPv4 or IPv6 address').isIP();
|
||||
@ -181,16 +218,18 @@ exports.ipAssignmentPools = async function(req, res) {
|
||||
if (errors) {
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', page: page, ipAssignmentPool: ipAssignmentPool, network: network, errors: errors});
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', nav: nav, ipAssignmentPool: ipAssignmentPool, network: network, errors: errors});
|
||||
} catch (err) {
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', page: page, error: 'Error resolving network detail for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', nav: nav, error: 'Error resolving network detail for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const network = await zt.ipAssignmentPools(req.params.nwid, ipAssignmentPool, 'add');
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', page: page, ipAssignmentPool: ipAssignmentPool, network: network});
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', nav: nav, ipAssignmentPool: ipAssignmentPool, network: network});
|
||||
} catch (err) {
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', page: page, error: 'Error applying IP Assignment Pools for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', nav: nav, error: 'Error applying IP Assignment Pools for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,7 +241,11 @@ isValidPrefix = function(str, max) {
|
||||
|
||||
// routes POST
|
||||
exports.routes = async function (req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
req.checkBody('target', 'Target network is required').notEmpty();
|
||||
req.sanitize('target').trim();
|
||||
@ -242,16 +285,18 @@ exports.routes = async function (req, res) {
|
||||
if (errors) {
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
res.render('routes', {title: 'routes', page: page, route: route, network: network, errors: errors});
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render('routes', {title: 'routes', nav: nav, route: route, network: network, errors: errors});
|
||||
} catch (err) {
|
||||
res.render('routes', {title: 'routes', page: page, error: 'Error resolving network detail'});
|
||||
res.render('routes', {title: 'routes', nav: nav, error: 'Error resolving network detail'});
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const network = await zt.routes(req.params.nwid, route, 'add');
|
||||
res.render('routes', {title: 'routes', page: page, route: route, network: network});
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render('routes', {title: 'routes', nav: nav, route: route, network: network});
|
||||
} catch (err) {
|
||||
res.render('routes', {title: 'routes', page: page, error: 'Error adding route for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('routes', {title: 'routes', nav: nav, error: 'Error adding route for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +304,11 @@ exports.routes = async function (req, res) {
|
||||
|
||||
// route_delete GET
|
||||
exports.route_delete = async function (req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
const route =
|
||||
{
|
||||
@ -270,15 +319,20 @@ exports.route_delete = async function (req, res) {
|
||||
|
||||
try {
|
||||
const network = await zt.routes(req.params.nwid, route, 'delete');
|
||||
res.render('routes', {title: 'routes', page: page, route: route, network: network});
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render('routes', {title: 'routes', nav: nav, route: route, network: network});
|
||||
} catch (err) {
|
||||
res.render('routes', {title: 'routes', page: page, error: 'Error deleting route for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('routes', {title: 'routes', nav: nav, error: 'Error deleting route for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// ipAssignmentPool_delete GET
|
||||
exports.ipAssignmentPool_delete = async function (req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
const ipAssignmentPool =
|
||||
{
|
||||
@ -289,15 +343,20 @@ exports.ipAssignmentPool_delete = async function (req, res) {
|
||||
|
||||
try {
|
||||
const network = await zt.ipAssignmentPools(req.params.nwid, ipAssignmentPool, 'delete');
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', page: page, ipAssignmentPool: ipAssignmentPool, network: network});
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', nav: nav, ipAssignmentPool: ipAssignmentPool, network: network});
|
||||
} catch (err) {
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', page: page, error: 'Error deleting IP Assignment Pool for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('ipAssignmentPools', {title: 'ipAssignmentPools', nav: nav, error: 'Error deleting IP Assignment Pool for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// v4AssignMode POST
|
||||
exports.v4AssignMode = async function (req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
const v4AssignMode =
|
||||
{
|
||||
@ -306,15 +365,20 @@ exports.v4AssignMode = async function (req, res) {
|
||||
|
||||
try {
|
||||
const network = await zt.network_object(req.params.nwid, v4AssignMode);
|
||||
res.render('v4AssignMode', {title: 'v4AssignMode', page: page, network: network});
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render('v4AssignMode', {title: 'v4AssignMode', nav: nav, network: network});
|
||||
} catch (err) {
|
||||
res.render('v4AssignMode', {title: 'v4AssignMode', page: page, error: 'Error applying v4AssignMode for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('v4AssignMode', {title: 'v4AssignMode', nav: nav, error: 'Error applying v4AssignMode for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// v6AssignMode POST
|
||||
exports.v6AssignMode = async function (req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
const v6AssignMode =
|
||||
{
|
||||
@ -328,76 +392,103 @@ exports.v6AssignMode = async function (req, res) {
|
||||
|
||||
try {
|
||||
const network = await zt.network_object(req.params.nwid, v6AssignMode);
|
||||
res.render('v6AssignMode', {title: 'v6AssignMode', page: page, network: network});
|
||||
nav.whence = '/controller/network/' + network.nwid;
|
||||
res.render('v6AssignMode', {title: 'v6AssignMode', nav: nav, network: network});
|
||||
} catch (err) {
|
||||
res.render('v6AssignMode', {title: 'v6AssignMode', page: page, error: 'Error applying v6AssignMode for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('v6AssignMode', {title: 'v6AssignMode', nav: nav, error: 'Error applying v6AssignMode for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// Display detail page for specific member
|
||||
exports.member_detail = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
const member = await zt.member_detail(req.params.nwid, req.params.id);
|
||||
res.render('member_detail', {title: 'Network member detail', page: page, network: network, member: member});
|
||||
nav.whence = '/controller/network/' + network.nwid + '/members';
|
||||
res.render('member_detail', {title: 'Network member detail', nav: nav, network: network, member: member});
|
||||
} catch (err) {
|
||||
res.render(req.params.object, {title: req.params.object, page: page, error: 'Error resolving detail for member ' + req.params.id + ' of network ' + req.params.nwid + ': ' + err});
|
||||
res.render(req.params.object, {title: req.params.object, nav: nav, error: 'Error resolving detail for member ' + req.params.id + ' of network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
};
|
||||
|
||||
// Member object GET
|
||||
exports.member_object = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
const member = await zt.member_detail(req.params.nwid, req.params.id);
|
||||
res.render(req.params.object, {title: req.params.object, page: page, network: network, member: member}, function(err, html) {
|
||||
const name = await storage.getItem(member.id);
|
||||
if (!name) name = '';
|
||||
member.name = name;
|
||||
nav.whence = '/controller/network/' + network.nwid + '/members';
|
||||
res.render(req.params.object, {title: req.params.object, nav: nav, network: network, member: member}, function(err, html) {
|
||||
if (err) {
|
||||
if (err.message.indexOf('Failed to lookup view') !== -1 ) {
|
||||
return res.render('not_implemented', {title: req.params.object, page: page, network: network, member: member});
|
||||
return res.render('not_implemented', {title: req.params.object, nav: nav, network: network, member: member});
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
res.send(html);
|
||||
});
|
||||
} catch (err) {
|
||||
res.render(req.params.object, {title: req.params.object, page: page, error: 'Error resolving detail for member ' + req.params.id + ' of network ' + req.params.nwid + ': ' + err});
|
||||
res.render(req.params.object, {title: req.params.object, nav: nav, error: 'Error resolving detail for member ' + req.params.id + ' of network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// Member authorized POST
|
||||
exports.member_authorized = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
const authorized = { authorized: req.body.authorized };
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
const member = await zt.member_object(req.params.nwid, req.params.id, authorized);
|
||||
res.render('authorized', {title: 'authorized', page: page, network: network, member: member});
|
||||
nav.whence = '/controller/network/' + network.nwid + '/members';
|
||||
res.render('authorized', {title: 'authorized', nav: nav, network: network, member: member});
|
||||
} catch (err) {
|
||||
res.render('authorized', {title: 'authorized', page: page, error: 'Error authorizing member ' + req.params.id + ' on network ' + req.params.nwid + ': ' + err});
|
||||
res.render('authorized', {title: 'authorized', nav: nav, error: 'Error authorizing member ' + req.params.id + ' on network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// Easy network setup GET
|
||||
exports.easy_get = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: '/controller/networks'
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
res.render('network_easy', {title: 'Easy setup of network', page: page, network: network});
|
||||
res.render('network_easy', {title: 'Easy setup of network', nav: nav, network: network});
|
||||
} catch (err) {
|
||||
res.render('network_easy', {title: 'Easy setup of network', page: page, error: 'Error resolving detail for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('network_easy', {title: 'Easy setup of network', nav: nav, error: 'Error resolving detail for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// Easy network setup POST
|
||||
exports.easy_post = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: '/controller/networks'
|
||||
}
|
||||
|
||||
req.checkBody('networkCIDR', 'Network address is required').notEmpty();
|
||||
req.sanitize('networkCIDR').trim();
|
||||
@ -447,23 +538,27 @@ exports.easy_post = async function(req, res) {
|
||||
v4AssignMode: v4AssignMode
|
||||
};
|
||||
|
||||
res.render('network_easy', {title: 'Easy setup of network', page: page, network: network, errors: errors});
|
||||
res.render('network_easy', {title: 'Easy setup of network', nav: nav, network: network, errors: errors});
|
||||
} else {
|
||||
try {
|
||||
const network = await zt.network_easy_setup(req.params.nwid,
|
||||
routes,
|
||||
ipAssignmentPools,
|
||||
v4AssignMode);
|
||||
res.render('network_easy', {title: 'Easy setup of network', page: page, network: network, message: 'Network setup succeeded'});
|
||||
res.render('network_easy', {title: 'Easy setup of network', nav: nav, network: network, message: 'Network setup succeeded'});
|
||||
} catch (err) {
|
||||
res.render('network_easy', {title: 'Easy setup of network', page: page, error: 'Error resolving detail for network ' + req.params.nwid + ': ' + err});
|
||||
res.render('network_easy', {title: 'Easy setup of network', nav: nav, error: 'Error resolving detail for network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Easy members auth GET or POST
|
||||
exports.members = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: '/controller/networks'
|
||||
}
|
||||
|
||||
let errors = null;
|
||||
|
||||
@ -520,18 +615,22 @@ exports.members = async function(req, res) {
|
||||
members.push(member);
|
||||
}
|
||||
|
||||
res.render('members', {title: 'Members of this network', page: page,
|
||||
res.render('members', {title: 'Members of this network', nav: nav,
|
||||
network: network, members: members, errors: errors});
|
||||
} catch (err) {
|
||||
res.render('members', {title: 'Members of this network', page: page,
|
||||
res.render('members', {title: 'Members of this network', nav: nav,
|
||||
error: 'Error resolving detail for network ' + req.params.nwid
|
||||
+ ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// Member delete GET and POST
|
||||
// Member delete GET or POST
|
||||
exports.member_delete = async function(req, res) {
|
||||
const page = 'networks';
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
@ -548,12 +647,109 @@ exports.member_delete = async function(req, res) {
|
||||
}
|
||||
if (!name) name = '';
|
||||
member.name = name;
|
||||
|
||||
nav.whence = '/controller/network/' + network.nwid + '/members';
|
||||
res.render('member_delete', {title: 'Delete member from ' + network.name,
|
||||
network: network, member: member});
|
||||
} catch (err) {
|
||||
res.render('member_delete', {title: 'Delete member from network', page: page,
|
||||
res.render('member_delete', {title: 'Delete member from network', nav: nav,
|
||||
error: 'Error resolving detail for member ' + req.params.id
|
||||
+ ' of network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// ipAssignment delete GET
|
||||
exports.delete_ip = async function(req, res) {
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
try {
|
||||
const network = await zt.network_detail(req.params.nwid);
|
||||
let member = await zt.member_detail(req.params.nwid, req.params.id);
|
||||
nav.whence = '/controller/network/' + network.nwid + '/members';
|
||||
const name = await storage.getItem(member.id);
|
||||
if (!name) name = '';
|
||||
member.name = name;
|
||||
if (req.params.index) {
|
||||
member = await zt.ipAssignmentDelete(network.nwid, member.id,
|
||||
req.params.index);
|
||||
res.redirect('/controller/network/' + network.nwid + '/member/' +
|
||||
member.id + '/ipAssignments');
|
||||
}
|
||||
res.render('ipAssignments', {title: 'ipAssignments ' + network.name,
|
||||
index: req.params.index, network: network, member: member});
|
||||
} catch (err) {
|
||||
res.render('ipAssignments', {title: 'ipAssignments', nav: nav,
|
||||
error: 'Error resolving detail for member ' + req.params.id
|
||||
+ ' of network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
||||
// ipAssignments POST
|
||||
exports.assign_ip = async function(req, res) {
|
||||
const nav =
|
||||
{
|
||||
active: 'networks',
|
||||
whence: ''
|
||||
}
|
||||
|
||||
try {
|
||||
var network = await zt.network_detail(req.params.nwid);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
req.checkBody('ipAddress', 'IP address required').notEmpty();
|
||||
req.checkBody('ipAddress', 'IP address must be a valid IPv4 or IPv6 address').isIP();
|
||||
req.checkBody('ipAddress', 'IP address must fall within a managed route')
|
||||
.custom(value => {
|
||||
let ipAddressInManagedRoute = false;
|
||||
network.routes.forEach(function(item) {
|
||||
let ipv4 = new ipaddr.Address4(value);
|
||||
console.log('ipv4 = ' + JSON.stringify(ipv4));
|
||||
let target4 = new ipaddr.Address4(item.target);
|
||||
console.log('target4 = ' + JSON.stringify(target4));
|
||||
if (ipv4.isValid() && target4.isValid()) {
|
||||
if (ipv4.isInSubnet(target4)) ipAddressInManagedRoute = true;
|
||||
}
|
||||
let ipv6 = new ipaddr.Address6(value);
|
||||
console.log('ipv6 = ' + JSON.stringify(ipv6));
|
||||
let target6 = new ipaddr.Address6(item.target);
|
||||
console.log('target6 = ' + JSON.stringify(target6));
|
||||
if (ipv6.isValid() && target6.isValid()) {
|
||||
if (ipv6.isInSubnet(target6)) ipAddressInManagedRoute = true;
|
||||
}
|
||||
});
|
||||
return ipAddressInManagedRoute;
|
||||
});
|
||||
req.sanitize('ipAddress').escape();
|
||||
req.sanitize('ipAddress').trim();
|
||||
|
||||
const errors = req.validationErrors();
|
||||
|
||||
const ipAssignment = { ipAddress: req.body.ipAddress };
|
||||
|
||||
try {
|
||||
let member = await zt.member_detail(req.params.nwid, req.params.id);
|
||||
nav.whence = '/controller/network/' + network.nwid + '/members';
|
||||
|
||||
if (!errors) {
|
||||
member = await zt.ipAssignmentAdd(network.nwid, member.id, ipAssignment);
|
||||
}
|
||||
|
||||
const name = await storage.getItem(member.id);
|
||||
if (!name) name = '';
|
||||
member.name = name;
|
||||
|
||||
res.render('ipAssignments', {title: 'ipAssignments', nav: nav,
|
||||
ipAssignment: ipAssignment, network: network, member: member,
|
||||
errors: errors});
|
||||
} catch (err) {
|
||||
res.render('ipAssignments', {title: 'ipAssignments', nav: nav,
|
||||
error: 'Error resolving detail for member ' + req.params.id
|
||||
+ ' of network ' + req.params.nwid + ': ' + err});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
@ -44,18 +44,24 @@ update_users = async function(users) {
|
||||
}
|
||||
|
||||
exports.users_list = async function(req, res) {
|
||||
const page = 'users';
|
||||
const nav =
|
||||
{
|
||||
active: 'users',
|
||||
}
|
||||
|
||||
try {
|
||||
const users = await get_users();
|
||||
res.render('users', { title: 'Admin users', page: page, message: 'List of users with admin priviledges', users: users });
|
||||
res.render('users', { title: 'Admin users', nav: nav, message: 'List of users with admin priviledges', users: users });
|
||||
} catch (err) {
|
||||
res.render('users', { title: 'Admin users', page: page, message: 'Error', users: null, error: 'Error returning list of users: ' + err });
|
||||
res.render('users', { title: 'Admin users', nav: nav, message: 'Error', users: null, error: 'Error returning list of users: ' + err });
|
||||
}
|
||||
}
|
||||
|
||||
exports.password_get = async function(req, res) {
|
||||
const page = 'users';
|
||||
const nav =
|
||||
{
|
||||
active: 'users',
|
||||
}
|
||||
|
||||
const user =
|
||||
{
|
||||
@ -63,11 +69,14 @@ exports.password_get = async function(req, res) {
|
||||
password1: null,
|
||||
password2: null
|
||||
};
|
||||
res.render('password', { title: 'Set password', page: page, user: user, readonly: true, message: '' });
|
||||
res.render('password', { title: 'Set password', nav: nav, user: user, readonly: true, message: '' });
|
||||
}
|
||||
|
||||
exports.password_post = async function(req, res) {
|
||||
const page = 'users';
|
||||
const nav =
|
||||
{
|
||||
active: 'users',
|
||||
}
|
||||
|
||||
req.checkBody('username', 'Username required').notEmpty();
|
||||
req.sanitize('username').escape();
|
||||
@ -90,7 +99,7 @@ exports.password_post = async function(req, res) {
|
||||
password2: req.body.password2
|
||||
};
|
||||
const message = 'Please check errors below';
|
||||
res.render('password', { title: 'Set password', page: page, user: user, readonly: true, message: message, errors: errors });
|
||||
res.render('password', { title: 'Set password', nav: nav, user: user, readonly: true, message: message, errors: errors });
|
||||
} else {
|
||||
let pass_set = true;
|
||||
if (req.body.pass_set === 'check') pass_set = false;
|
||||
@ -115,12 +124,15 @@ exports.password_post = async function(req, res) {
|
||||
users = await update_users(users);
|
||||
|
||||
const message = 'Successfully set password for ' + req.body.username;
|
||||
res.render('password', { title: 'Set password', page: page, user: user, readonly: true, message: message });
|
||||
res.render('password', { title: 'Set password', nav: nav, user: user, readonly: true, message: message });
|
||||
}
|
||||
}
|
||||
|
||||
exports.user_create_get = async function(req, res) {
|
||||
const page = 'create_user';
|
||||
const nav =
|
||||
{
|
||||
active: 'create_user',
|
||||
}
|
||||
|
||||
const user =
|
||||
{
|
||||
@ -129,17 +141,23 @@ exports.user_create_get = async function(req, res) {
|
||||
password2: null
|
||||
};
|
||||
|
||||
res.render('password', { title: 'Create new admin user', page: page, user: user, readonly: false});
|
||||
res.render('password', { title: 'Create new admin user', nav: nav, user: user, readonly: false});
|
||||
}
|
||||
|
||||
exports.user_create_post = async function(req, res) {
|
||||
const page = 'create_user';
|
||||
const nav =
|
||||
{
|
||||
active: 'create_user',
|
||||
}
|
||||
|
||||
res.redirect(307, '/users/' + req.body.username + '/password');
|
||||
}
|
||||
|
||||
exports.user_delete = async function(req, res) {
|
||||
const page = 'users';
|
||||
const nav =
|
||||
{
|
||||
active: 'users',
|
||||
}
|
||||
|
||||
try {
|
||||
var users = await get_users();
|
||||
@ -150,7 +168,7 @@ exports.user_delete = async function(req, res) {
|
||||
const user = users[req.params.name];
|
||||
|
||||
if (user && (req.session.user.name === user.name)) {
|
||||
res.render('user_delete', { title: 'Delete user', page: page, user: user, self_delete: true });
|
||||
res.render('user_delete', { title: 'Delete user', nav: nav, user: user, self_delete: true });
|
||||
}
|
||||
|
||||
if (req.body.delete === 'delete') {
|
||||
@ -158,15 +176,15 @@ exports.user_delete = async function(req, res) {
|
||||
const deleted_user = { name: user.name };
|
||||
delete users[user.name];
|
||||
users = await update_users(users);
|
||||
res.render('user_delete', { title: 'Deleted user', page: page, user: deleted_user, deleted: true });
|
||||
res.render('user_delete', { title: 'Deleted user', nav: nav, user: deleted_user, deleted: true });
|
||||
} else {
|
||||
res.render('user_delete', { title: 'Delete user', page: page, user: null });
|
||||
res.render('user_delete', { title: 'Delete user', nav: nav, user: null });
|
||||
}
|
||||
} else {
|
||||
if (user) {
|
||||
res.render('user_delete', { title: 'Delete user', page: page, user: user });
|
||||
res.render('user_delete', { title: 'Delete user', nav: nav, user: user });
|
||||
} else {
|
||||
res.render('user_delete', { title: 'Delete user', page: page, user: null });
|
||||
res.render('user_delete', { title: 'Delete user', nav: nav, user: null });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
@ -139,6 +139,42 @@ exports.ipAssignmentPools = async function(nwid, ipAssignmentPool, action) {
|
||||
}
|
||||
}
|
||||
|
||||
exports.ipAssignmentDelete = async function(nwid, id, ipAssignmentIndex) {
|
||||
const options = await init_options();
|
||||
options.method = 'POST';
|
||||
|
||||
try {
|
||||
const member = await member_detail(nwid, id);
|
||||
const ipAssignments = member.ipAssignments;
|
||||
ipAssignments.splice(ipAssignmentIndex, 1);
|
||||
options.body = { ipAssignments: ipAssignments };
|
||||
const response = await got(ZT_ADDR + '/controller/network/'
|
||||
+ nwid + '/member/' + id, options);
|
||||
response.body.deleted = true;
|
||||
return response.body;
|
||||
} catch(err) {
|
||||
throw(err);
|
||||
}
|
||||
}
|
||||
|
||||
exports.ipAssignmentAdd = async function(nwid, id, ipAssignment) {
|
||||
const options = await init_options();
|
||||
options.method = 'POST';
|
||||
|
||||
try {
|
||||
const member = await member_detail(nwid, id);
|
||||
const ipAssignments = member.ipAssignments;
|
||||
ipAssignments.push(ipAssignment.ipAddress);
|
||||
options.body = { ipAssignments: ipAssignments };
|
||||
const response = await got(ZT_ADDR + '/controller/network/'
|
||||
+ nwid + '/member/' + id, options);
|
||||
response.body.added = true;
|
||||
return response.body;
|
||||
} catch(err) {
|
||||
throw(err);
|
||||
}
|
||||
}
|
||||
|
||||
exports.routes = async function(nwid, route, action) {
|
||||
const options = await init_options();
|
||||
options.method = 'POST';
|
||||
@ -205,7 +241,7 @@ exports.members = async function(nwid) {
|
||||
}
|
||||
}
|
||||
|
||||
exports.member_detail = async function(nwid, id) {
|
||||
member_detail = async function(nwid, id) {
|
||||
const options = await init_options();
|
||||
|
||||
try {
|
||||
@ -216,6 +252,7 @@ exports.member_detail = async function(nwid, id) {
|
||||
throw(err);
|
||||
}
|
||||
}
|
||||
exports.member_detail = member_detail;
|
||||
|
||||
exports.member_object = async function(nwid, id, object) {
|
||||
const options = await init_options();
|
||||
|
2
src/package-lock.json
generated
2
src/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ztncui",
|
||||
"version": "0.3.2",
|
||||
"version": "0.4.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ztncui",
|
||||
"version": "0.3.2",
|
||||
"version": "0.4.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node ./bin/www",
|
||||
|
@ -11,6 +11,20 @@ input[type=radio] {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.table > tbody > tr > td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.left {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.navbar-inverse {
|
||||
background-color: #315b80;
|
||||
border-color: #23415c;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
*/
|
||||
|
||||
@ -76,6 +76,12 @@ router.get('/network/:nwid/members', restrict, networkController.members);
|
||||
// POST request for easy member (de)authorization
|
||||
router.post('/network/:nwid/members', restrict, networkController.members);
|
||||
|
||||
// GET request for member ipAssignment delete
|
||||
router.get('/network/:nwid/member/:id/ipAssignments/:index/delete', restrict, networkController.delete_ip);
|
||||
|
||||
// POST request for member ipAssignment add
|
||||
router.post('/network/:nwid/member/:id/ipAssignments', restrict, networkController.assign_ip);
|
||||
|
||||
|
||||
|
||||
// GET request for any network object
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends head_layout
|
||||
@ -18,13 +18,13 @@ block body_content
|
||||
| Key Networks
|
||||
.collapse.navbar-collapse(id='BarNav')
|
||||
ul.nav.navbar-nav
|
||||
li(class=(page === 'controller_home'? 'active' : ''))
|
||||
li(class=(nav.active === 'controller_home'? 'active' : ''))
|
||||
a(href='/controller') Home
|
||||
li(class=(page === 'users'? 'active' : ''))
|
||||
li(class=(nav.active === 'users'? 'active' : ''))
|
||||
a(href='/users') Users
|
||||
li(class=(page === 'networks'? 'active' : ''))
|
||||
li(class=(nav.active === 'networks'? 'active' : ''))
|
||||
a(href='/controller/networks') Networks
|
||||
li(class=(page === 'add_network'? 'active' : ''))
|
||||
li(class=(nav.active === 'add_network'? 'active' : ''))
|
||||
a(href='/controller/network/create') Add network
|
||||
ul.nav.navbar-nav.navbar-right
|
||||
li
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends login_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
doctype html
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends controller_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
70
src/views/ipAssignments.pug
Normal file
70
src/views/ipAssignments.pug
Normal file
@ -0,0 +1,70 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
||||
block net_content
|
||||
if errors
|
||||
.row
|
||||
.col-sm-12
|
||||
.alert.alert-warning
|
||||
b Note errors listed below
|
||||
|
||||
form(method='POST' action='')
|
||||
|
||||
.row
|
||||
.col-sm-6
|
||||
h4 Member name:
|
||||
b= member.name
|
||||
.col-sm-6.right
|
||||
h4 ZeroTier address:
|
||||
b= member.id
|
||||
|
||||
.row
|
||||
.col-sm-12
|
||||
table.table.table-responsive.table-striped.table-hover
|
||||
tr
|
||||
th(width='3%')
|
||||
th IP address
|
||||
|
||||
each ipAssignment, index in member.ipAssignments
|
||||
tr
|
||||
td(width='3%')
|
||||
a.btn.btn-link(role='button' href='/controller/network/' + network.nwid + '/member/' + member.id + '/ipAssignments/' + index + '/delete')
|
||||
i.glyphicon.glyphicon-trash
|
||||
td
|
||||
each digit in ipAssignment
|
||||
= digit
|
||||
|
||||
tr
|
||||
td
|
||||
button.btn.btn-link(type='submit')
|
||||
i.glyphicon.glyphicon-plus
|
||||
td
|
||||
input#ipAddress.form-control(type='text' name='ipAddress' placeholder='IP address' value=(undefined===ipAssignment? '' : ipAssignment.ipAddress))
|
||||
|
||||
.row
|
||||
.col-sm-12
|
||||
a(href='/controller/network/' + network.nwid + '/routes')
|
||||
h3 Managed routes
|
||||
table.table.table-responsive.table-striped.table-hover
|
||||
tr
|
||||
th
|
||||
th Target
|
||||
th Gateway
|
||||
each route in network.routes
|
||||
tr
|
||||
td(width='3%')
|
||||
a.btn.btn-link(role='button' href='/controller/network/' + network.nwid + '/routes/' + route.target + '/delete')
|
||||
i.glyphicon.glyphicon-trash
|
||||
td= route.target
|
||||
td= route.via
|
||||
|
||||
if errors
|
||||
.row
|
||||
.col-sm-12
|
||||
ul
|
||||
for err in errors
|
||||
li!= err.msg
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends login_layout
|
||||
@ -26,7 +26,7 @@ block login_content
|
||||
.input-group
|
||||
span.input-group-addon
|
||||
i.glyphicon.glyphicon-user
|
||||
input#username.form-control.input-lg(type='text' name='username' placeholder='Enter your username')
|
||||
input#username.form-control(type='text' name='username' placeholder='Enter your username')
|
||||
|
||||
.form-group.row
|
||||
.col-sm-2
|
||||
@ -35,11 +35,11 @@ block login_content
|
||||
.input-group
|
||||
span.input-group-addon
|
||||
i.glyphicon.glyphicon-lock
|
||||
input#password.form-control.input-lg(type='password' name='password' placeholder='Enter your password')
|
||||
input#password.form-control(type='password' name='password' placeholder='Enter your password')
|
||||
|
||||
.form-group.row
|
||||
.col-sm-2
|
||||
.col-sm-10
|
||||
button.btn.btn-primary.btn-lg(type='submit') Login
|
||||
button.btn.btn-primary(type='submit') Login
|
||||
= ' '
|
||||
a.btn.btn-default.btn-lg(href='/' name='cancel' role='button') Cancel
|
||||
a.btn.btn-default(href='/' name='cancel' role='button') Cancel
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends head_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
@ -46,9 +46,13 @@ block net_content
|
||||
input.checkbox(type='checkbox' name='authCheckBox' value=member.id checked=(member.authorized? true : false))
|
||||
td
|
||||
each ipAssignment in member.ipAssignments
|
||||
each digit in ipAssignment
|
||||
= digit
|
||||
= ' '
|
||||
a(href='/controller/network/' + network.nwid + '/member/' + member.id + '/ipAssignments')
|
||||
each digit in ipAssignment
|
||||
= digit
|
||||
= ' '
|
||||
else
|
||||
a(href='/controller/network/' + network.nwid + '/member/' + member.id + '/ipAssignments')
|
||||
| IP assignment
|
||||
|
||||
else
|
||||
.alert.alert-info
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends controller_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
@ -1,18 +1,14 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends controller_layout
|
||||
extends network_layout
|
||||
|
||||
block content
|
||||
block net_content
|
||||
if error
|
||||
b #{error}
|
||||
else
|
||||
h2
|
||||
a(href= network.nwid + '/name') #{network.name}
|
||||
| (#{network.nwid}):
|
||||
|
||||
- if (members !== undefined)
|
||||
h3 Members
|
||||
each value, key in members
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends controller_layout
|
||||
@ -10,10 +10,13 @@ block content
|
||||
b #{error}
|
||||
else
|
||||
.row
|
||||
.col-sm-12
|
||||
.col-sm-10
|
||||
h2
|
||||
a(href='/controller/network/' + network.nwid) #{network.name}
|
||||
| (#{network.nwid}):
|
||||
h3= title
|
||||
|
||||
|
||||
.col-sm-2
|
||||
h2.right
|
||||
a.btn.btn-default(href=nav.whence role='button') Back
|
||||
block net_content
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends controller_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends users_layout
|
||||
@ -20,7 +20,7 @@ block users_content
|
||||
.input-group
|
||||
span.input-group-addon
|
||||
i.glyphicon.glyphicon-user
|
||||
input#username.form-control.input-lg(type='text' name='username' placeholder='Enter username' value=user.name readonly=readonly)
|
||||
input#username.form-control(type='text' name='username' placeholder='Enter username' value=user.name readonly=readonly)
|
||||
|
||||
.form-group.row
|
||||
.col-sm-2
|
||||
@ -29,7 +29,7 @@ block users_content
|
||||
.input-group
|
||||
span.input-group-addon
|
||||
i.glyphicon.glyphicon-lock
|
||||
input#password1.form-control.input-lg(type='password' name='password1' placeholder='Enter new password' value=(undefined===user.password1? '' : user.password1))
|
||||
input#password1.form-control(type='password' name='password1' placeholder='Enter new password' value=(undefined===user.password1? '' : user.password1))
|
||||
|
||||
.form-group.row
|
||||
.col-sm-2
|
||||
@ -38,7 +38,7 @@ block users_content
|
||||
.input-group
|
||||
span.input-group-addon
|
||||
i.glyphicon.glyphicon-lock
|
||||
input#password2.form-control.input-lg(type='password' name='password2' placeholder='Re-enter password' value=(undefined===user.password2? '' : user.password2))
|
||||
input#password2.form-control(type='password' name='password2' placeholder='Re-enter password' value=(undefined===user.password2? '' : user.password2))
|
||||
|
||||
.form-group.row
|
||||
.col-sm-2
|
||||
@ -49,9 +49,9 @@ block users_content
|
||||
.form-group.row
|
||||
.col-sm-2
|
||||
.col-sm-10
|
||||
button.btn.btn-primary.btn-lg(type='submit') Set password
|
||||
button.btn.btn-primary(type='submit') Set password
|
||||
= ' '
|
||||
a.btn.btn-default.btn-lg(href='/users' name='cancel' role='button') Cancel
|
||||
a.btn.btn-default(href='/users' name='cancel' role='button') Cancel
|
||||
|
||||
if errors
|
||||
.form-group.row
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
@ -42,7 +42,7 @@ block net_content
|
||||
.col-sm-2
|
||||
button.btn.btn-primary(type='submit') Submit
|
||||
= ' '
|
||||
a.btn.btn-default(href='/controller/network/' + network.nwid name='cancel' role='button') Cancel
|
||||
a.btn.btn-default(href='/controller/networks' name='cancel' role='button') Cancel
|
||||
|
||||
if errors
|
||||
.row
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends users_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends users_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends head_layout
|
||||
@ -18,11 +18,11 @@ block body_content
|
||||
| Key Networks
|
||||
.collapse.navbar-collapse(id='BarNav')
|
||||
ul.nav.navbar-nav
|
||||
li(class=(page === 'home'? 'active' : ''))
|
||||
li(class=(nav.active === 'home'? 'active' : ''))
|
||||
a(href='/controller') Home
|
||||
li(class=(page === 'users'? 'active' : ''))
|
||||
li(class=(nav.active === 'users'? 'active' : ''))
|
||||
a(href='/users') Users
|
||||
li(class=(page === 'create_user'? 'active' : ''))
|
||||
li(class=(nav.active === 'create_user'? 'active' : ''))
|
||||
a(href='/users/create') Create user
|
||||
ul.nav.navbar-nav.navbar-right
|
||||
li
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
@ -1,6 +1,6 @@
|
||||
//-
|
||||
ztncui - ZeroTier network controller UI
|
||||
Copyright (C) 2017 Key Networks (https://key-networks.com)
|
||||
Copyright (C) 2017-2018 Key Networks (https://key-networks.com)
|
||||
Licensed under GPLv3 - see LICENSE for details.
|
||||
|
||||
extends network_layout
|
||||
|
Loading…
Reference in New Issue
Block a user