Lookup node via monitoring token only
This commit is contained in:
parent
001e7b59a3
commit
cc0fadb7cd
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue