Lookup node via monitoring token only

This commit is contained in:
baldo 2016-05-23 22:36:27 +02:00
parent 001e7b59a3
commit cc0fadb7cd
9 changed files with 78 additions and 55 deletions

View file

@ -12,7 +12,7 @@ angular.module('ffffng')
$scope.monitoringInfo = {}; $scope.monitoringInfo = {};
$scope.monitoringStatus = 'loading'; $scope.monitoringStatus = 'loading';
MonitoringService.confirm($routeParams['mac'], $routeParams['token']) MonitoringService.confirm($routeParams['token'])
.then( .then(
function (response) { function (response) {
// success // success

View file

@ -12,7 +12,7 @@ angular.module('ffffng')
$scope.monitoringInfo = {}; $scope.monitoringInfo = {};
$scope.monitoringStatus = 'loading'; $scope.monitoringStatus = 'loading';
MonitoringService.disable($routeParams['mac'], $routeParams['token']) MonitoringService.disable($routeParams['token'])
.then( .then(
function (response) { function (response) {
// success // success

View file

@ -3,18 +3,18 @@
angular.module('ffffng') angular.module('ffffng')
.service('MonitoringService', function ($http, $q) { .service('MonitoringService', function ($http, $q) {
return { return {
'confirm': function (mac, token) { 'confirm': function (token) {
if (!mac || !token) { if (!token) {
return $q.reject({}); return $q.reject({});
} }
return $http.put('/api/monitoring/confirm/' + mac + '?token=' + token); return $http.put('/api/monitoring/confirm/' + token);
}, },
'disable': function (mac, token) { 'disable': function (token) {
if (!mac || !token) { if (!token) {
return $q.reject({}); return $q.reject({});
} }
return $http.put('/api/monitoring/disable/' + mac + '?token=' + token); return $http.put('/api/monitoring/disable/' + token);
} }
}; };
}); });

View file

@ -26,7 +26,7 @@ def normalizeMac(mac):
def toFilename(peer): def toFilename(peer):
filename = '' filename = ''
for field in ['name', 'mac', 'vpn', 'token']: for field in ['name', 'mac', 'vpn', 'token', 'monitoring-token']:
if peer.has_key(field): if peer.has_key(field):
filename = filename + peer[field] filename = filename + peer[field]
filename = filename + '@' filename = filename + '@'
@ -48,12 +48,17 @@ for filename in os.listdir(peersDir):
parts = line.split() parts = line.split()
if len(parts) > 0: if len(parts) > 0:
for i in range(0, 3 - len(parts)):
parts.append('')
if parts[1] == 'Knotenname:': if parts[1] == 'Knotenname:':
peer['name'] = parts[2].lower() peer['name'] = parts[2].lower()
elif parts[1] == 'MAC:': elif parts[1] == 'MAC:':
peer['mac'] = normalizeMac(parts[2]) peer['mac'] = normalizeMac(parts[2])
elif parts[1] == 'Token:': elif parts[1] == 'Token:':
peer['token'] = parts[2].lower() peer['token'] = parts[2].lower()
elif parts[1] == 'Monitoring-Token:':
peer['monitoring-token'] = parts[2].lower()
elif parts[0] == 'key': elif parts[0] == 'key':
peer['vpn'] = parts[1].split('"')[1].lower() peer['vpn'] = parts[1].split('"')[1].lower()

View file

@ -9,24 +9,18 @@ angular.module('ffffng').factory('MonitoringResource', function (
Resources, Resources,
ErrorTypes ErrorTypes
) { ) {
var isValidMac = Validator.forConstraint(Constraints.node.mac);
var isValidToken = Validator.forConstraint(Constraints.token); var isValidToken = Validator.forConstraint(Constraints.token);
return { return {
confirm: function (req, res) { confirm: function (req, res) {
var data = Resources.getData(req); var data = Resources.getData(req);
var mac = Strings.normalizeMac(data.mac);
if (!isValidMac(mac)) {
return Resources.error(res, {data: 'Invalid MAC.', type: ErrorTypes.badRequest});
}
var token = Strings.normalizeString(data.token); var token = Strings.normalizeString(data.token);
if (!isValidToken(token)) { if (!isValidToken(token)) {
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest}); return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
} }
return MonitoringService.confirm(mac, token, function (err, node) { return MonitoringService.confirm(token, function (err, node) {
if (err) { if (err) {
return Resources.error(res, err); return Resources.error(res, err);
} }
@ -43,17 +37,12 @@ angular.module('ffffng').factory('MonitoringResource', function (
disable: function (req, res) { disable: function (req, res) {
var data = Resources.getData(req); var data = Resources.getData(req);
var mac = Strings.normalizeMac(data.mac);
if (!isValidMac(mac)) {
return Resources.error(res, {data: 'Invalid MAC.', type: ErrorTypes.badRequest});
}
var token = Strings.normalizeString(data.token); var token = Strings.normalizeString(data.token);
if (!isValidToken(token)) { if (!isValidToken(token)) {
return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest}); return Resources.error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
} }
return MonitoringService.disable(mac, token, function (err, node) { return MonitoringService.disable(token, function (err, node) {
if (err) { if (err) {
return Resources.error(res, err); return Resources.error(res, err);
} }

View file

@ -8,8 +8,8 @@ angular.module('ffffng').factory('Router', function (app, NodeResource, Monitori
app.delete('/api/node/:token', NodeResource.delete); app.delete('/api/node/:token', NodeResource.delete);
app.get('/api/node/:token', NodeResource.get); app.get('/api/node/:token', NodeResource.get);
app.put('/api/monitoring/confirm/:mac', MonitoringResource.confirm); app.put('/api/monitoring/confirm/:token', MonitoringResource.confirm);
app.put('/api/monitoring/disable/:mac', MonitoringResource.disable); app.put('/api/monitoring/disable/:token', MonitoringResource.disable);
} }
}; };
}); });

View file

@ -3,8 +3,8 @@
angular.module('ffffng') angular.module('ffffng')
.service('MonitoringService', function (NodeService, ErrorTypes) { .service('MonitoringService', function (NodeService, ErrorTypes) {
return { return {
confirm: function (mac, token, callback) { confirm: function (token, callback) {
NodeService.getNodeDataByMac(mac, function (err, node, nodeSecrets) { NodeService.getNodeDataByMonitoringToken(token, function (err, node, nodeSecrets) {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@ -27,8 +27,8 @@ angular.module('ffffng')
}); });
}, },
disable: function (mac, token, callback) { disable: function (token, callback) {
NodeService.getNodeDataByMac(mac, function (err, node, nodeSecrets) { NodeService.getNodeDataByMonitoringToken(token, function (err, node, nodeSecrets) {
if (err) { if (err) {
return callback(err); return callback(err);
} }

View file

@ -23,48 +23,77 @@ angular.module('ffffng')
monitoringToken: '# Monitoring-Token: ' monitoringToken: '# Monitoring-Token: '
}; };
var filenameParts = ['hostname', 'mac', 'key', 'token', 'monitoringToken'];
function generateToken() { function generateToken() {
return crypto.randomBytes(8).toString('hex'); return crypto.randomBytes(8).toString('hex');
} }
function findNodeFiles(pattern) { function findNodeFiles(filter) {
var pattern = _.join(
_.map(filenameParts, function (field) {
return filter.hasOwnProperty(field) ? filter[field] : '*';
}),
'@'
);
return glob.sync(config.server.peersPath + '/' + pattern.toLowerCase()); return glob.sync(config.server.peersPath + '/' + pattern.toLowerCase());
} }
function isDuplicate(pattern, token) { function parseNodeFilename(filename) {
var files = findNodeFiles(pattern); var parts = _.split(filename, '@', filenameParts.length);
var parsed = {};
_.each(_.zip(filenameParts, parts), function (part) {
parsed[part[0]] = part[1];
});
return parsed;
}
function isDuplicate(filter, token) {
var files = findNodeFiles(filter);
if (files.length === 0) { if (files.length === 0) {
return false; return false;
} }
if (files.length > 1 || !token) { if (files.length > 1 || !token /* node is being created*/) {
return true; return true;
} }
var file = files[0]; return parseNodeFilename(files[0]).token !== token;
return file.substring(file.length - token.length, file.length) !== token;
} }
function checkNoDuplicates(token, node) { function checkNoDuplicates(token, node, nodeSecrets) {
if (isDuplicate(node.hostname + '@*@*@*', token)) { if (isDuplicate({ hostname: node.hostname }, token)) {
return {data: {msg: 'Already exists.', field: 'hostname'}, type: ErrorTypes.conflict}; return {data: {msg: 'Already exists.', field: 'hostname'}, type: ErrorTypes.conflict};
} }
if (node.key) { if (node.key) {
if (isDuplicate('*@*@' + node.key + '@*', token)) { if (isDuplicate({ key: node.key }, token)) {
return {data: {msg: 'Already exists.', field: 'key'}, type: ErrorTypes.conflict}; return {data: {msg: 'Already exists.', field: 'key'}, type: ErrorTypes.conflict};
} }
} }
if (isDuplicate('*@' + node.mac + '@*@*', token)) { if (isDuplicate({ mac: node.mac }, token)) {
return {data: {msg: 'Already exists.', field: 'mac'}, type: ErrorTypes.conflict}; return {data: {msg: 'Already exists.', field: 'mac'}, type: ErrorTypes.conflict};
} }
if (nodeSecrets.monitoringToken && isDuplicate({ monitoringToken: nodeSecrets.monitoringToken }, token)) {
return {data: {msg: 'Already exists.', field: 'monitoringToken'}, type: ErrorTypes.conflict};
}
return null; return null;
} }
function writeNodeFile(isUpdate, token, node, nodeSecrets, callback) { function writeNodeFile(isUpdate, token, node, nodeSecrets, callback) {
var filename = var filename =
config.server.peersPath + '/' + (node.hostname + '@' + node.mac + '@' + (node.key || '') + '@' + token).toLowerCase(); config.server.peersPath + '/' +
(
node.hostname + '@' +
node.mac + '@' +
(node.key || '') + '@' +
token + '@' +
nodeSecrets.monitoringToken
).toLowerCase();
var data = ''; var data = '';
_.each(linePrefixes, function (prefix, key) { _.each(linePrefixes, function (prefix, key) {
@ -102,12 +131,12 @@ angular.module('ffffng')
var error; var error;
if (isUpdate) { if (isUpdate) {
var files = findNodeFiles('*@*@*@' + token); var files = findNodeFiles({ token: token });
if (files.length !== 1) { if (files.length !== 1) {
return callback({data: 'Node not found.', type: ErrorTypes.notFound}); return callback({data: 'Node not found.', type: ErrorTypes.notFound});
} }
error = checkNoDuplicates(token, node); error = checkNoDuplicates(token, node, nodeSecrets);
if (error) { if (error) {
return callback(error); return callback(error);
} }
@ -121,7 +150,7 @@ angular.module('ffffng')
return callback({data: 'Could not remove old node data.', type: ErrorTypes.internalError}); return callback({data: 'Could not remove old node data.', type: ErrorTypes.internalError});
} }
} else { } else {
error = checkNoDuplicates(null, node); error = checkNoDuplicates(null, node, nodeSecrets);
if (error) { if (error) {
return callback(error); return callback(error);
} }
@ -139,7 +168,7 @@ angular.module('ffffng')
} }
function deleteNodeFile(token, callback) { function deleteNodeFile(token, callback) {
var files = findNodeFiles('*@*@*@' + token); var files = findNodeFiles({ token: token });
if (files.length !== 1) { if (files.length !== 1) {
return callback({data: 'Node not found.', type: ErrorTypes.notFound}); return callback({data: 'Node not found.', type: ErrorTypes.notFound});
} }
@ -195,8 +224,8 @@ angular.module('ffffng')
callback(null, node, nodeSecrets); callback(null, node, nodeSecrets);
} }
function getNodeDataByFilePattern(pattern, callback) { function getNodeDataByFilePattern(filter, callback) {
var files = findNodeFiles(pattern); var files = findNodeFiles(filter);
if (files.length !== 1) { if (files.length !== 1) {
return callback({data: 'Node not found.', type: ErrorTypes.notFound}); return callback({data: 'Node not found.', type: ErrorTypes.notFound});
@ -207,8 +236,8 @@ angular.module('ffffng')
} }
function sendMonitoringConfirmationMail(node, nodeSecrets, callback) { function sendMonitoringConfirmationMail(node, nodeSecrets, callback) {
var confirmUrl = UrlBuilder.monitoringConfirmUrl(node, nodeSecrets); var confirmUrl = UrlBuilder.monitoringConfirmUrl(nodeSecrets);
var disableUrl = UrlBuilder.monitoringDisableUrl(node, nodeSecrets); var disableUrl = UrlBuilder.monitoringDisableUrl(nodeSecrets);
MailService.enqueue( MailService.enqueue(
config.server.email.from, config.server.email.from,
@ -220,7 +249,7 @@ angular.module('ffffng')
disableUrl: disableUrl disableUrl: disableUrl
}, },
function (err) { function (err) {
if (err) { if (err) {checkNoDuplicates
console.error(err); console.error(err);
return callback({data: 'Internal error.', type: ErrorTypes.internalError}); return callback({data: 'Internal error.', type: ErrorTypes.internalError});
} }
@ -323,11 +352,11 @@ angular.module('ffffng')
}, },
getNodeDataByToken: function (token, callback) { getNodeDataByToken: function (token, callback) {
return getNodeDataByFilePattern('*@*@*@' + token, callback); return getNodeDataByFilePattern({ token: token }, callback);
}, },
getNodeDataByMac: function (mac, callback) { getNodeDataByMonitoringToken: function (monitoringToken, callback) {
return getNodeDataByFilePattern('*@' + mac + '@*@*', callback); return getNodeDataByFilePattern({ monitoringToken: monitoringToken }, callback);
} }
}; };
}); });

View file

@ -29,11 +29,11 @@ angular.module('ffffng').factory('UrlBuilder', function (_, config) {
return formUrl('update'); return formUrl('update');
}, },
monitoringConfirmUrl: function (node, nodeSecrets) { monitoringConfirmUrl: function (nodeSecrets) {
return formUrl('monitoring/confirm', { mac: node.mac, token: nodeSecrets.monitoringToken }); return formUrl('monitoring/confirm', { token: nodeSecrets.monitoringToken });
}, },
monitoringDisableUrl: function (node, nodeSecrets) { monitoringDisableUrl: function (nodeSecrets) {
return formUrl('monitoring/disable', { mac: node.mac, token: nodeSecrets.monitoringToken }); return formUrl('monitoring/disable', { token: nodeSecrets.monitoringToken });
} }
}; };
}); });