opusdev/vector-similarity-api
1
1/*!2 * proxy-addr3 * Copyright(c) 2014-2016 Douglas Christopher Wilson4 * MIT Licensed5 */6 7'use strict'8 9/**10 * Module exports.11 * @public12 */13 14module.exports = proxyaddr15module.exports.all = alladdrs16module.exports.compile = compile17 18/**19 * Module dependencies.20 * @private21 */22 23var forwarded = require('forwarded')24var ipaddr = require('ipaddr.js')25 26/**27 * Variables.28 * @private29 */30 31var DIGIT_REGEXP = /^[0-9]+$/32var isip = ipaddr.isValid33var parseip = ipaddr.parse34 35/**36 * Pre-defined IP ranges.37 * @private38 */39 40var IP_RANGES = {41 linklocal: ['169.254.0.0/16', 'fe80::/10'],42 loopback: ['127.0.0.1/8', '::1/128'],43 uniquelocal: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', 'fc00::/7']44}45 46/**47 * Get all addresses in the request, optionally stopping48 * at the first untrusted.49 *50 * @param {Object} request51 * @param {Function|Array|String} [trust]52 * @public53 */54 55function alladdrs (req, trust) {56 // get addresses57 var addrs = forwarded(req)58 59 if (!trust) {60 // Return all addresses61 return addrs62 }63 64 if (typeof trust !== 'function') {65 trust = compile(trust)66 }67 68 for (var i = 0; i < addrs.length - 1; i++) {69 if (trust(addrs[i], i)) continue70 71 addrs.length = i + 172 }73 74 return addrs75}76 77/**78 * Compile argument into trust function.79 *80 * @param {Array|String} val81 * @private82 */83 84function compile (val) {85 if (!val) {86 throw new TypeError('argument is required')87 }88 89 var trust90 91 if (typeof val === 'string') {92 trust = [val]93 } else if (Array.isArray(val)) {94 trust = val.slice()95 } else {96 throw new TypeError('unsupported trust argument')97 }98 99 for (var i = 0; i < trust.length; i++) {100 val = trust[i]101 102 if (!Object.prototype.hasOwnProperty.call(IP_RANGES, val)) {103 continue104 }105 106 // Splice in pre-defined range107 val = IP_RANGES[val]108 trust.splice.apply(trust, [i, 1].concat(val))109 i += val.length - 1110 }111 112 return compileTrust(compileRangeSubnets(trust))113}114 115/**116 * Compile `arr` elements into range subnets.117 *118 * @param {Array} arr119 * @private120 */121 122function compileRangeSubnets (arr) {123 var rangeSubnets = new Array(arr.length)124 125 for (var i = 0; i < arr.length; i++) {126 rangeSubnets[i] = parseipNotation(arr[i])127 }128 129 return rangeSubnets130}131 132/**133 * Compile range subnet array into trust function.134 *135 * @param {Array} rangeSubnets136 * @private137 */138 139function compileTrust (rangeSubnets) {140 // Return optimized function based on length141 var len = rangeSubnets.length142 return len === 0143 ? trustNone144 : len === 1145 ? trustSingle(rangeSubnets[0])146 : trustMulti(rangeSubnets)147}148 149/**150 * Parse IP notation string into range subnet.151 *152 * @param {String} note153 * @private154 */155 156function parseipNotation (note) {157 var pos = note.lastIndexOf('/')158 var str = pos !== -1159 ? note.substring(0, pos)160 : note161 162 if (!isip(str)) {163 throw new TypeError('invalid IP address: ' + str)164 }165 166 var ip = parseip(str)167 168 if (pos === -1 && ip.kind() === 'ipv6' && ip.isIPv4MappedAddress()) {169 // Store as IPv4170 ip = ip.toIPv4Address()171 }172 173 var max = ip.kind() === 'ipv6'174 ? 128175 : 32176 177 var range = pos !== -1178 ? note.substring(pos + 1, note.length)179 : null180 181 if (range === null) {182 range = max183 } else if (DIGIT_REGEXP.test(range)) {184 range = parseInt(range, 10)185 } else if (ip.kind() === 'ipv4' && isip(range)) {186 range = parseNetmask(range)187 } else {188 range = null189 }190 191 if (range <= 0 || range > max) {192 throw new TypeError('invalid range on address: ' + note)193 }194 195 return [ip, range]196}197 198/**199 * Parse netmask string into CIDR range.200 *201 * @param {String} netmask202 * @private203 */204 205function parseNetmask (netmask) {206 var ip = parseip(netmask)207 var kind = ip.kind()208 209 return kind === 'ipv4'210 ? ip.prefixLengthFromSubnetMask()211 : null212}213 214/**215 * Determine address of proxied request.216 *217 * @param {Object} request218 * @param {Function|Array|String} trust219 * @public220 */221 222function proxyaddr (req, trust) {223 if (!req) {224 throw new TypeError('req argument is required')225 }226 227 if (!trust) {228 throw new TypeError('trust argument is required')229 }230 231 var addrs = alladdrs(req, trust)232 var addr = addrs[addrs.length - 1]233 234 return addr235}236 237/**238 * Static trust function to trust nothing.239 *240 * @private241 */242 243function trustNone () {244 return false245}246 247/**248 * Compile trust function for multiple subnets.249 *250 * @param {Array} subnets251 * @private252 */253 254function trustMulti (subnets) {255 return function trust (addr) {256 if (!isip(addr)) return false257 258 var ip = parseip(addr)259 var ipconv260 var kind = ip.kind()261 262 for (var i = 0; i < subnets.length; i++) {263 var subnet = subnets[i]264 var subnetip = subnet[0]265 var subnetkind = subnetip.kind()266 var subnetrange = subnet[1]267 var trusted = ip268 269 if (kind !== subnetkind) {270 if (subnetkind === 'ipv4' && !ip.isIPv4MappedAddress()) {271 // Incompatible IP addresses272 continue273 }274 275 if (!ipconv) {276 // Convert IP to match subnet IP kind277 ipconv = subnetkind === 'ipv4'278 ? ip.toIPv4Address()279 : ip.toIPv4MappedAddress()280 }281 282 trusted = ipconv283 }284 285 if (trusted.match(subnetip, subnetrange)) {286 return true287 }288 }289 290 return false291 }292}293 294/**295 * Compile trust function for single subnet.296 *297 * @param {Object} subnet298 * @private299 */300 301function trustSingle (subnet) {302 var subnetip = subnet[0]303 var subnetkind = subnetip.kind()304 var subnetisipv4 = subnetkind === 'ipv4'305 var subnetrange = subnet[1]306 307 return function trust (addr) {308 if (!isip(addr)) return false309 310 var ip = parseip(addr)311 var kind = ip.kind()312 313 if (kind !== subnetkind) {314 if (subnetisipv4 && !ip.isIPv4MappedAddress()) {315 // Incompatible IP addresses316 return false317 }318 319 // Convert IP to match subnet IP kind320 ip = subnetisipv4321 ? ip.toIPv4Address()322 : ip.toIPv4MappedAddress()323 }324 325 return ip.match(subnetip, subnetrange)326 }327}328 