File size: 3,586 Bytes
c015809 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | 'use strict';
import { getConnInfo } from 'hono/bun';
export var regexes = {
ipv4: /^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/,
ipv6: /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i,
};
export function isIpInCidr(ip, cidr) {
// Split IP and CIDR into parts
const [cidrIp, cidrBits] = cidr.split('/');
const mask = ~((1 << (32 - +cidrBits)) - 1) >>> 0;
// Convert IP addresses to numeric values
const ipNum = ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0) >>> 0;
const cidrIpNum = cidrIp.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0) >>> 0;
// Compare using bitwise operations
return (ipNum & mask) === (cidrIpNum & mask);
}
function existy(value) {
return value != null;
}
function ip(value) {
return (existy(value) && regexes.ipv4.test(value)) || regexes.ipv6.test(value);
}
function getClientIpFromXForwardedFor(value) {
if (!existy(value)) {
return null;
}
if (typeof value !== 'string') {
throw new TypeError('Expected a string, got "'.concat(typeof value, '"'));
}
var forwardedIps = value.split(',').map(function (e) {
var ip = e.trim();
if (ip.includes(':')) {
var splitted = ip.split(':');
if (splitted.length === 2) {
return splitted[0];
}
}
return ip;
});
for (var i = 0; i < forwardedIps.length; i++) {
if (ip(forwardedIps[i])) {
return forwardedIps[i];
}
}
return null;
}
/**
*
* @param {import('hono').Context} c
* @returns
*/
function getClientIp(c) {
// Get request headers
const headers = c.req.raw.headers;
const { remote } = getConnInfo(c)
// Check headers
if (headers) {
if (ip(headers.get('cf-connecting-ip'))) {
return headers.get('cf-connecting-ip');
}
if (ip(headers.get('cf-pseudo-ipv4'))) {
return headers.get('cf-pseudo-ipv4');
}
if (ip(headers.get('x-client-ip'))) {
return headers.get('x-client-ip');
}
const xForwardedFor = getClientIpFromXForwardedFor(headers.get('x-forwarded-for'));
if (ip(xForwardedFor)) {
return xForwardedFor;
}
if (ip(headers.get('fastly-client-ip'))) {
return headers.get('fastly-client-ip');
}
if (ip(headers.get('true-client-ip'))) {
return headers.get('true-client-ip');
}
if (ip(headers.get('x-real-ip'))) {
return headers.get('x-real-ip');
}
if (ip(headers.get('x-cluster-client-ip'))) {
return headers.get('x-cluster-client-ip');
}
if (ip(headers.get('x-forwarded'))) {
return headers.get('x-forwarded');
}
if (ip(headers.get('forwarded-for'))) {
return headers.get('forwarded-for');
}
if (ip(headers.get('forwarded'))) {
return headers.get('forwarded');
}
if (ip(headers.get('x-appengine-user-ip'))) {
return headers.get('x-appengine-user-ip');
}
}
// Check direct IP from Hono's request
if (ip(remote.address)) {
return remote.address.replaceAll(/:|ffff/g, '');
}
return null;
}
function mw(options) {
var configuration = typeof options !== 'object' ? {} : options;
if (typeof configuration !== 'object') {
throw new TypeError('Options must be an object!');
}
var attributeName = configuration.attributeName || 'clientIp';
return function (req, res, next) {
var ip = getClientIp(req);
Object.defineProperty(req, attributeName, {
get: function get() {
return ip;
},
configurable: true,
});
next();
};
}
export default getClientIp;
export { getClientIpFromXForwardedFor, getClientIp, mw, ip };
|