mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
Merge pull request #127 from glyptodon/filter-token
GUAC-1138: Add filter pattern tokenizer.
This commit is contained in:
@@ -23,8 +23,16 @@
|
||||
/**
|
||||
* A service for defining the FilterPattern class.
|
||||
*/
|
||||
angular.module('list').factory('FilterPattern', ['$parse',
|
||||
function defineFilterPattern($parse) {
|
||||
angular.module('list').factory('FilterPattern', ['$injector',
|
||||
function defineFilterPattern($injector) {
|
||||
|
||||
// Required types
|
||||
var FilterToken = $injector.get('FilterToken');
|
||||
var IPv4Network = $injector.get('IPv4Network');
|
||||
var IPv6Network = $injector.get('IPv6Network');
|
||||
|
||||
// Required services
|
||||
var $parse = $injector.get('$parse');
|
||||
|
||||
/**
|
||||
* Object which handles compilation of filtering predicates as used by
|
||||
@@ -69,6 +77,138 @@ angular.module('list').factory('FilterPattern', ['$parse',
|
||||
getters.push($parse(expression));
|
||||
});
|
||||
|
||||
/**
|
||||
* Determines whether the given object contains properties that match
|
||||
* the given string, according to the provided getters.
|
||||
*
|
||||
* @param {Object} object
|
||||
* The object to match against.
|
||||
*
|
||||
* @param {String} str
|
||||
* The string to match.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true if the object matches the given string, false otherwise.
|
||||
*/
|
||||
var matchesString = function matchesString(object, str) {
|
||||
|
||||
// For each defined getter
|
||||
for (var i=0; i < getters.length; i++) {
|
||||
|
||||
// Retrieve value of current getter
|
||||
var value = getters[i](object);
|
||||
|
||||
// If the value matches the pattern, the whole object matches
|
||||
if (String(value).toLowerCase().indexOf(str) !== -1)
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// No matches found
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether the given object contains properties that match
|
||||
* the given IPv4 network, according to the provided getters.
|
||||
*
|
||||
* @param {Object} object
|
||||
* The object to match against.
|
||||
*
|
||||
* @param {IPv4Network} network
|
||||
* The IPv4 network to match.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true if the object matches the given network, false otherwise.
|
||||
*/
|
||||
var matchesIPv4 = function matchesIPv4(object, network) {
|
||||
|
||||
// For each defined getter
|
||||
for (var i=0; i < getters.length; i++) {
|
||||
|
||||
// Test value against IPv4 network
|
||||
var value = IPv4Network.parse(String(getters[i](object)));
|
||||
if (value && network.contains(value))
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// No matches found
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether the given object contains properties that match
|
||||
* the given IPv6 network, according to the provided getters.
|
||||
*
|
||||
* @param {Object} object
|
||||
* The object to match against.
|
||||
*
|
||||
* @param {IPv6Network} network
|
||||
* The IPv6 network to match.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true if the object matches the given network, false otherwise.
|
||||
*/
|
||||
var matchesIPv6 = function matchesIPv6(object, network) {
|
||||
|
||||
// For each defined getter
|
||||
for (var i=0; i < getters.length; i++) {
|
||||
|
||||
// Test value against IPv6 network
|
||||
var value = IPv6Network.parse(String(getters[i](object)));
|
||||
if (value && network.contains(value))
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// No matches found
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the given object matches the given filter pattern
|
||||
* token.
|
||||
*
|
||||
* @param {Object} object
|
||||
* The object to match the token against.
|
||||
*
|
||||
* @param {FilterToken} token
|
||||
* The token from the tokenized filter pattern to match aginst the
|
||||
* given object.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true if the object matches the token, false otherwise.
|
||||
*/
|
||||
var matchesToken = function matchesToken(object, token) {
|
||||
|
||||
// Match depending on token type
|
||||
switch (token.type) {
|
||||
|
||||
// Simple string literal
|
||||
case 'LITERAL':
|
||||
return matchesString(object, token.value);
|
||||
|
||||
// IPv4 network address / subnet
|
||||
case 'IPV4_NETWORK':
|
||||
return matchesIPv4(object, token.value);
|
||||
|
||||
// IPv6 network address / subnet
|
||||
case 'IPV6_NETWORK':
|
||||
return matchesIPv6(object, token.value);
|
||||
|
||||
// Unsupported token type
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The current filtering predicate.
|
||||
*
|
||||
@@ -92,26 +232,20 @@ angular.module('list').factory('FilterPattern', ['$parse',
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert to lower case for case insensitive matching
|
||||
pattern = pattern.toLowerCase();
|
||||
// Tokenize pattern, converting to lower case for case-insensitive matching
|
||||
var tokens = FilterToken.tokenize(pattern.toLowerCase());
|
||||
|
||||
// Return predicate which matches against the value of any getter in the getters array
|
||||
filterPattern.predicate = function matchAny(object) {
|
||||
|
||||
// For each defined getter
|
||||
for (var i=0; i < getters.length; i++) {
|
||||
|
||||
// Retrieve value of current getter
|
||||
var value = getters[i](object);
|
||||
|
||||
// If the value matches the pattern, the whole object matches
|
||||
if (String(value).toLowerCase().indexOf(pattern) !== -1)
|
||||
return true;
|
||||
filterPattern.predicate = function matchesAllTokens(object) {
|
||||
|
||||
// False if any token does not match
|
||||
for (var i=0; i < tokens.length; i++) {
|
||||
if (!matchesToken(object, tokens[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
// No matches found
|
||||
return false;
|
||||
// True if all tokens matched
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
|
232
guacamole/src/main/webapp/app/list/types/FilterToken.js
Normal file
232
guacamole/src/main/webapp/app/list/types/FilterToken.js
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A service for defining the FilterToken class.
|
||||
*/
|
||||
angular.module('list').factory('FilterToken', ['$injector',
|
||||
function defineFilterToken($injector) {
|
||||
|
||||
// Required types
|
||||
var IPv4Network = $injector.get('IPv4Network');
|
||||
var IPv6Network = $injector.get('IPv6Network');
|
||||
|
||||
/**
|
||||
* An arbitrary token having an associated type and value.
|
||||
*
|
||||
* @constructor
|
||||
* @param {String} consumed
|
||||
* The input string consumed to produce this token.
|
||||
*
|
||||
* @param {String} type
|
||||
* The type of this token. Each legal type name is a property within
|
||||
* FilterToken.Types.
|
||||
*
|
||||
* @param {Object} value
|
||||
* The value of this token. The type of this value is determined by
|
||||
* the token type.
|
||||
*/
|
||||
var FilterToken = function FilterToken(consumed, type, value) {
|
||||
|
||||
/**
|
||||
* The input string that was consumed to produce this token.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
this.consumed = consumed;
|
||||
|
||||
/**
|
||||
* The type of this token. Each legal type name is a property within
|
||||
* FilterToken.Types.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* The value of this token.
|
||||
*
|
||||
* @type Object
|
||||
*/
|
||||
this.value = value;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* All legal token types, and corresponding functions which match them.
|
||||
* Each function returns the parsed token, or null if no such token was
|
||||
* found.
|
||||
*
|
||||
* @type Object.<String, Function>
|
||||
*/
|
||||
FilterToken.Types = {
|
||||
|
||||
/**
|
||||
* An IPv4 address or subnet. The value of an IPV4_NETWORK token is an
|
||||
* IPv4Network.
|
||||
*/
|
||||
IPV4_NETWORK: function parseIPv4(str) {
|
||||
|
||||
var pattern = /^\S+/;
|
||||
|
||||
// Read first word via regex
|
||||
var matches = pattern.exec(str);
|
||||
if (!matches)
|
||||
return null;
|
||||
|
||||
// Validate and parse as IPv4 address
|
||||
var network = IPv4Network.parse(matches[0]);
|
||||
if (!network)
|
||||
return null;
|
||||
|
||||
return new FilterToken(matches[0], 'IPV4_NETWORK', network);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* An IPv6 address or subnet. The value of an IPV6_NETWORK token is an
|
||||
* IPv6Network.
|
||||
*/
|
||||
IPV6_NETWORK: function parseIPv6(str) {
|
||||
|
||||
var pattern = /^\S+/;
|
||||
|
||||
// Read first word via regex
|
||||
var matches = pattern.exec(str);
|
||||
if (!matches)
|
||||
return null;
|
||||
|
||||
// Validate and parse as IPv6 address
|
||||
var network = IPv6Network.parse(matches[0]);
|
||||
if (!network)
|
||||
return null;
|
||||
|
||||
return new FilterToken(matches[0], 'IPV6_NETWORK', network);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* A string literal, which may be quoted. The value of a LITERAL token
|
||||
* is a String.
|
||||
*/
|
||||
LITERAL: function parseLiteral(str) {
|
||||
|
||||
var pattern = /^"([^"]*)"|^\S+/;
|
||||
|
||||
// Validate against pattern
|
||||
var matches = pattern.exec(str);
|
||||
if (!matches)
|
||||
return null;
|
||||
|
||||
// If literal is quoted, parse within the quotes
|
||||
if (matches[1])
|
||||
return new FilterToken(matches[0], 'LITERAL', matches[1]);
|
||||
|
||||
// Otherwise, literal is unquoted
|
||||
return new FilterToken(matches[0], 'LITERAL', matches[0]);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Arbitrary contiguous whitespace. The value of a WHITESPACE token is
|
||||
* a String.
|
||||
*/
|
||||
WHITESPACE: function parseWhitespace(str) {
|
||||
|
||||
var pattern = /^\s+/;
|
||||
|
||||
// Validate against pattern
|
||||
var matches = pattern.exec(str);
|
||||
if (!matches)
|
||||
return null;
|
||||
|
||||
// Generate token from matching whitespace
|
||||
return new FilterToken(matches[0], 'WHITESPACE', matches[0]);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Tokenizes the given string, returning an array of tokens. Whitespace
|
||||
* tokens are dropped.
|
||||
*
|
||||
* @param {String} str
|
||||
* The string to tokenize.
|
||||
*
|
||||
* @returns {FilterToken[]}
|
||||
* All tokens identified within the given string, in order.
|
||||
*/
|
||||
FilterToken.tokenize = function tokenize(str) {
|
||||
|
||||
var tokens = [];
|
||||
|
||||
/**
|
||||
* Returns the first token on the current string, removing the token
|
||||
* from that string.
|
||||
*
|
||||
* @returns FilterToken
|
||||
* The first token on the string, or null if no tokens match.
|
||||
*/
|
||||
var popToken = function popToken() {
|
||||
|
||||
// Attempt to find a matching token
|
||||
for (var type in FilterToken.Types) {
|
||||
|
||||
// Get matching function for current type
|
||||
var matcher = FilterToken.Types[type];
|
||||
|
||||
// If token matches, return the matching group
|
||||
var token = matcher(str);
|
||||
if (token) {
|
||||
str = str.substring(token.consumed.length);
|
||||
return token;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// No match
|
||||
return null;
|
||||
|
||||
};
|
||||
|
||||
// Tokenize input until no input remains
|
||||
while (str) {
|
||||
|
||||
// Remove first token
|
||||
var token = popToken();
|
||||
if (!token)
|
||||
break;
|
||||
|
||||
// Add token to tokens array, if not whitespace
|
||||
if (token.type !== 'WHITESPACE')
|
||||
tokens.push(token);
|
||||
|
||||
}
|
||||
|
||||
return tokens;
|
||||
|
||||
};
|
||||
|
||||
return FilterToken;
|
||||
|
||||
}]);
|
129
guacamole/src/main/webapp/app/list/types/IPv4Network.js
Normal file
129
guacamole/src/main/webapp/app/list/types/IPv4Network.js
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A service for defining the IPv4Network class.
|
||||
*/
|
||||
angular.module('list').factory('IPv4Network', [
|
||||
function defineIPv4Network() {
|
||||
|
||||
/**
|
||||
* Represents an IPv4 network as a pairing of base address and netmask,
|
||||
* both of which are in binary form. To obtain an IPv4Network from
|
||||
* standard CIDR or dot-decimal notation, use IPv4Network.parse().
|
||||
*
|
||||
* @constructor
|
||||
* @param {Number} address
|
||||
* The IPv4 address of the network in binary form.
|
||||
*
|
||||
* @param {Number} netmask
|
||||
* The IPv4 netmask of the network in binary form.
|
||||
*/
|
||||
var IPv4Network = function IPv4Network(address, netmask) {
|
||||
|
||||
/**
|
||||
* Reference to this IPv4Network.
|
||||
*
|
||||
* @type IPv4Network
|
||||
*/
|
||||
var network = this;
|
||||
|
||||
/**
|
||||
* The binary address of this network. This will be a 32-bit quantity.
|
||||
*
|
||||
* @type Number
|
||||
*/
|
||||
this.address = address;
|
||||
|
||||
/**
|
||||
* The binary netmask of this network. This will be a 32-bit quantity.
|
||||
*
|
||||
* @type Number
|
||||
*/
|
||||
this.netmask = netmask;
|
||||
|
||||
/**
|
||||
* Tests whether the given network is entirely within this network,
|
||||
* taking into account the base addresses and netmasks of both.
|
||||
*
|
||||
* @param {IPv4Network} other
|
||||
* The network to test.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true if the other network is entirely within this network, false
|
||||
* otherwise.
|
||||
*/
|
||||
this.contains = function contains(other) {
|
||||
return network.address === (other.address & other.netmask & network.netmask);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses the given string as an IPv4 address or subnet, returning an
|
||||
* IPv4Network object which describes that address or subnet.
|
||||
*
|
||||
* @param {String} str
|
||||
* The string to parse.
|
||||
*
|
||||
* @returns {IPv4Network}
|
||||
* The parsed network, or null if the given string is not valid.
|
||||
*/
|
||||
IPv4Network.parse = function parse(str) {
|
||||
|
||||
// Regex which matches the general form of IPv4 addresses
|
||||
var pattern = /^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(?:\/([0-9]{1,2}))?$/;
|
||||
|
||||
// Parse IPv4 address via regex
|
||||
var match = pattern.exec(str);
|
||||
if (!match)
|
||||
return null;
|
||||
|
||||
// Parse netmask, if given
|
||||
var netmask = 0xFFFFFFFF;
|
||||
if (match[5]) {
|
||||
var bits = parseInt(match[5]);
|
||||
if (bits > 0 && bits <= 32)
|
||||
netmask = 0xFFFFFFFF << (32 - bits);
|
||||
}
|
||||
|
||||
// Read each octet onto address
|
||||
var address = 0;
|
||||
for (var i=1; i <= 4; i++) {
|
||||
|
||||
// Validate octet range
|
||||
var octet = parseInt(match[i]);
|
||||
if (octet > 255)
|
||||
return null;
|
||||
|
||||
// Shift on octet
|
||||
address = (address << 8) | octet;
|
||||
|
||||
}
|
||||
|
||||
return new IPv4Network(address, netmask);
|
||||
|
||||
};
|
||||
|
||||
return IPv4Network;
|
||||
|
||||
}]);
|
230
guacamole/src/main/webapp/app/list/types/IPv6Network.js
Normal file
230
guacamole/src/main/webapp/app/list/types/IPv6Network.js
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A service for defining the IPv6Network class.
|
||||
*/
|
||||
angular.module('list').factory('IPv6Network', [
|
||||
function defineIPv6Network() {
|
||||
|
||||
/**
|
||||
* Represents an IPv6 network as a pairing of base address and netmask,
|
||||
* both of which are in binary form. To obtain an IPv6Network from
|
||||
* standard CIDR notation, use IPv6Network.parse().
|
||||
*
|
||||
* @constructor
|
||||
* @param {Number[]} addressGroups
|
||||
* Array of eight IPv6 address groups in binary form, each group being
|
||||
* 16-bit number.
|
||||
*
|
||||
* @param {Number[]} netmaskGroups
|
||||
* Array of eight IPv6 netmask groups in binary form, each group being
|
||||
* 16-bit number.
|
||||
*/
|
||||
var IPv6Network = function IPv6Network(addressGroups, netmaskGroups) {
|
||||
|
||||
/**
|
||||
* Reference to this IPv6Network.
|
||||
*
|
||||
* @type IPv6Network
|
||||
*/
|
||||
var network = this;
|
||||
|
||||
/**
|
||||
* The 128-bit binary address of this network as an array of eight
|
||||
* 16-bit numbers.
|
||||
*
|
||||
* @type Number[]
|
||||
*/
|
||||
this.addressGroups = addressGroups;
|
||||
|
||||
/**
|
||||
* The 128-bit binary netmask of this network as an array of eight
|
||||
* 16-bit numbers.
|
||||
*
|
||||
* @type Number
|
||||
*/
|
||||
this.netmaskGroups = netmaskGroups;
|
||||
|
||||
/**
|
||||
* Tests whether the given network is entirely within this network,
|
||||
* taking into account the base addresses and netmasks of both.
|
||||
*
|
||||
* @param {IPv6Network} other
|
||||
* The network to test.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true if the other network is entirely within this network, false
|
||||
* otherwise.
|
||||
*/
|
||||
this.contains = function contains(other) {
|
||||
|
||||
// Test that each masked 16-bit quantity matches the address
|
||||
for (var i=0; i < 8; i++) {
|
||||
if (network.addressGroups[i] !== (other.addressGroups[i]
|
||||
& other.netmaskGroups[i]
|
||||
& network.netmaskGroups[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
// All 16-bit numbers match
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a netmask having the given number of ones on the left side.
|
||||
* All other bits within the netmask will be zeroes. The resulting netmask
|
||||
* will be an array of eight numbers, where each number corresponds to a
|
||||
* 16-bit group of an IPv6 netmask.
|
||||
*
|
||||
* @param {Number} bits
|
||||
* The number of ones to include on the left side of the netmask. All
|
||||
* other bits will be zeroes.
|
||||
*
|
||||
* @returns {Number[]}
|
||||
* The generated netmask, having the given number of ones.
|
||||
*/
|
||||
var generateNetmask = function generateNetmask(bits) {
|
||||
|
||||
var netmask = [];
|
||||
|
||||
// Only generate up to 128 bits
|
||||
bits = Math.min(128, bits);
|
||||
|
||||
// Add any contiguous 16-bit sections of ones
|
||||
while (bits >= 16) {
|
||||
netmask.push(0xFFFF);
|
||||
bits -= 16;
|
||||
}
|
||||
|
||||
// Add remaining ones
|
||||
if (bits > 0 && bits <= 16)
|
||||
netmask.push(0xFFFF & (0xFFFF << (16 - bits)));
|
||||
|
||||
// Add remaining zeroes
|
||||
while (netmask.length < 8)
|
||||
netmask.push(0);
|
||||
|
||||
return netmask;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Splits the given IPv6 address or partial address into its corresponding
|
||||
* 16-bit groups.
|
||||
*
|
||||
* @param {String} str
|
||||
* The IPv6 address or partial address to split.
|
||||
*
|
||||
* @returns Number[]
|
||||
* The numeric values of all 16-bit groups within the given IPv6
|
||||
* address.
|
||||
*/
|
||||
var splitAddress = function splitAddress(str) {
|
||||
|
||||
var address = [];
|
||||
|
||||
// Split address into groups
|
||||
var groups = str.split(':');
|
||||
|
||||
// Parse the numeric value of each group
|
||||
angular.forEach(groups, function addGroup(group) {
|
||||
var value = parseInt(group || '0', 16);
|
||||
address.push(value);
|
||||
});
|
||||
|
||||
return address;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses the given string as an IPv6 address or subnet, returning an
|
||||
* IPv6Network object which describes that address or subnet.
|
||||
*
|
||||
* @param {String} str
|
||||
* The string to parse.
|
||||
*
|
||||
* @returns {IPv6Network}
|
||||
* The parsed network, or null if the given string is not valid.
|
||||
*/
|
||||
IPv6Network.parse = function parse(str) {
|
||||
|
||||
// Regex which matches the general form of IPv6 addresses
|
||||
var pattern = /^([0-9a-f]{0,4}(?::[0-9a-f]{0,4}){0,7})(?:\/([0-9]{1,3}))?$/;
|
||||
|
||||
// Parse rudimentary IPv6 address via regex
|
||||
var match = pattern.exec(str);
|
||||
if (!match)
|
||||
return null;
|
||||
|
||||
// Extract address and netmask from parse results
|
||||
var unparsedAddress = match[1];
|
||||
var unparsedNetmask = match[2];
|
||||
|
||||
// Parse netmask
|
||||
var netmask;
|
||||
if (unparsedNetmask)
|
||||
netmask = generateNetmask(parseInt(unparsedNetmask));
|
||||
else
|
||||
netmask = generateNetmask(128);
|
||||
|
||||
var address;
|
||||
|
||||
// Separate based on the double-colon, if present
|
||||
var doubleColon = unparsedAddress.indexOf('::');
|
||||
|
||||
// If no double colon, just split into groups
|
||||
if (doubleColon === -1)
|
||||
address = splitAddress(unparsedAddress);
|
||||
|
||||
// Otherwise, split either side of the double colon and pad with zeroes
|
||||
else {
|
||||
|
||||
// Parse either side of the double colon
|
||||
var leftAddress = splitAddress(unparsedAddress.substring(0, doubleColon));
|
||||
var rightAddress = splitAddress(unparsedAddress.substring(doubleColon + 2));
|
||||
|
||||
// Pad with zeroes up to address length
|
||||
var remaining = 8 - leftAddress.length - rightAddress.length;
|
||||
while (remaining > 0) {
|
||||
leftAddress.push(0);
|
||||
remaining--;
|
||||
}
|
||||
|
||||
address = leftAddress.concat(rightAddress);
|
||||
|
||||
}
|
||||
|
||||
// Validate length of address
|
||||
if (address.length !== 8)
|
||||
return null;
|
||||
|
||||
return new IPv6Network(address, netmask);
|
||||
|
||||
};
|
||||
|
||||
return IPv6Network;
|
||||
|
||||
}]);
|
Reference in New Issue
Block a user