添加项目文件。

This commit is contained in:
2023-03-13 15:00:34 +08:00
parent 42bf06ca3e
commit 1d73df3235
1205 changed files with 185078 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace JNPF.Common.Net;
public interface IUserAgent
{
string RawValue { get; set; }
UserAgentInfo userAgent { get; }
DeviceInfo Device { get; }
OSInfo OS { get; }
/// <summary>
/// 是否移动端.
/// </summary>
bool IsMobileDevice { get; }
/// <summary>
/// 是否平板.
/// </summary>
bool IsTablet { get; }
}
public sealed class DeviceInfo
{
public DeviceInfo(string family, bool isBot)
{
this.Family = family;
this.IsBot = isBot;
}
public override string ToString()
{
return this.Family;
}
public string Family { get; private set; }
public bool IsBot { get; private set; }
}
public sealed class OSInfo
{
public OSInfo(string family, string major, string minor, string patch, string patchMinor)
{
this.Family = family;
this.Major = major;
this.Minor = minor;
this.Patch = patch;
this.PatchMinor = patchMinor;
}
public override string ToString()
{
var str = VersionString.Format(Major, Minor, Patch, PatchMinor);
return (this.Family + (!string.IsNullOrEmpty(str) ? (" " + str) : null));
}
public string Family { get; private set; }
public string Major { get; private set; }
public string Minor { get; private set; }
public string Patch { get; private set; }
public string PatchMinor { get; private set; }
private static string FormatVersionString(params string[] parts)
{
return string.Join(".", (from v in parts
where !string.IsNullOrEmpty(v)
select v).ToArray<string>());
}
}
public sealed class UserAgentInfo
{
public UserAgentInfo(string family, string major, string minor, string patch)
{
this.Family = family;
this.Major = major;
this.Minor = minor;
this.Patch = patch;
}
public override string ToString()
{
var str = VersionString.Format(Major, Minor, Patch);
return (this.Family + (!string.IsNullOrEmpty(str) ? (" " + str) : null));
}
public string Family { get; private set; }
public string Major { get; private set; }
public string Minor { get; private set; }
public string Patch { get; private set; }
}
internal static class VersionString
{
public static string Format(params string[] parts)
{
return string.Join(".", (from v in parts
where !string.IsNullOrEmpty(v)
select v).ToArray<string>());
}
}

View File

@@ -0,0 +1,25 @@
using JNPF.DependencyInjection;
namespace JNPF.Common.Net;
/// <summary>
/// IP位置信息类.
/// </summary>
[SuppressSniffer]
public class IpLocation
{
/// <summary>
/// IP地址.
/// </summary>
public string? Ip { get; set; }
/// <summary>
/// IP地址所属国家.
/// </summary>
public string? Country { get; set; }
/// <summary>
/// 位置信息.
/// </summary>
public string? Local { get; set; }
}

View File

@@ -0,0 +1,296 @@
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using JNPF.DependencyInjection;
namespace JNPF.Common.Net
{
/// <summary>
/// IP位置查找操作类.
/// </summary>
[SuppressSniffer]
public class IpLocator
{
private readonly byte[] _data;
private readonly long _firstStartIpOffset;
private static readonly Regex Regex = new Regex(@"^(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))$");
/// <summary>
/// 初始化一个IP位置查找操作类的实例.
/// </summary>
/// <param name="dataPath"> IP信息数据文件路径.</param>
/// <exception cref="ArgumentException"></exception>
public IpLocator(string dataPath)
{
using (FileStream fs = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
_data = new byte[fs.Length];
fs.Read(_data, 0, _data.Length);
}
byte[] buffer = new byte[8];
Array.Copy(_data, 0, buffer, 0, 8);
_firstStartIpOffset = ((buffer[0] + (buffer[1] * 0x100)) + ((buffer[2] * 0x100) * 0x100)) + (((buffer[3] * 0x100) * 0x100) * 0x100);
long lastStartIpOffset = ((buffer[4] + (buffer[5] * 0x100)) + ((buffer[6] * 0x100) * 0x100)) + (((buffer[7] * 0x100) * 0x100) * 0x100);
Count = Convert.ToInt64((lastStartIpOffset - _firstStartIpOffset) / 7.0);
if (Count <= 1L)
throw new ArgumentException("IP信息数据文件异常。");
}
/// <summary>
/// 数据文件中信息数量.
/// </summary>
public long Count { get; private set; }
/// <summary>
/// IP地址转化成整数.
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static long IpToInt(string ip)
{
char[] separator = new[] { '.' };
if (ip.Split(separator).Length == 3)
{
ip = ip + ".0";
}
if (!Regex.Match(ip).Success)
throw new ArgumentException("IP格式错误");
string[] nums = ip.Split(separator);
long num1 = ((long.Parse(nums[0]) * 0x100L) * 0x100L) * 0x100L;
long num2 = (long.Parse(nums[1]) * 0x100L) * 0x100L;
long num3 = long.Parse(nums[2]) * 0x100L;
long num4 = long.Parse(nums[3]);
return ((num1 + num2) + num3) + num4;
}
/// <summary>
/// IP地址从整数类型转化为正常IP类型.
/// </summary>
/// <param name="ipInt"></param>
/// <returns></returns>
public static string IntToIp(long ipInt)
{
long num1 = (ipInt & 0xff000000L) >> 0x18;
if (num1 < 0L)
num1 += 0x100L;
long num2 = (ipInt & 0xff0000L) >> 0x10;
if (num2 < 0L)
num2 += 0x100L;
long num3 = (ipInt & 0xff00L) >> 8;
if (num3 < 0L)
num3 += 0x100L;
long num4 = ipInt & 0xffL;
if (num4 < 0L)
num4 += 0x100L;
string ip = string.Concat(new[]
{
num1.ToString(CultureInfo.InvariantCulture),
".",
num2.ToString(CultureInfo.InvariantCulture),
".",
num3.ToString(CultureInfo.InvariantCulture),
".",
num4.ToString(CultureInfo.InvariantCulture)
});
if (!Regex.Match(ip).Success)
throw new ArgumentException("IP格式错误");
return ip;
}
/// <summary>
/// 由IP地址查找对应的位置信息.
/// </summary>
/// <param name="ip"> 要查找的IP地址. </param>
/// <returns> </returns>
/// <exception cref="ArgumentException"></exception>
public IpLocation Query(string ip)
{
if (ip == "::1")
ip = "127.0.0.1";
if (!Regex.Match(ip).Success)
throw new ArgumentException("IP格式错误");
IpLocation ipLocation = new IpLocation { Ip = ip };
long intIp = IpToInt(ip);
if (intIp >= IpToInt("127.0.0.1") && (intIp <= IpToInt("127.255.255.255")))
{
ipLocation.Country = "本机内部环回地址";
ipLocation.Local = string.Empty;
}
else
{
if (((intIp >= IpToInt("0.0.0.0")) && (intIp <= IpToInt("2.255.255.255"))) ||
((intIp >= IpToInt("64.0.0.0")) && (intIp <= IpToInt("126.255.255.255"))) ||
((intIp >= IpToInt("58.0.0.0")) && (intIp <= IpToInt("60.255.255.255"))))
{
ipLocation.Country = "网络保留地址";
ipLocation.Local = string.Empty;
}
}
long right = Count;
long left = 0L;
long startIp;
long endIpOff;
int countryFlag;
while (left < (right - 1L))
{
long middle = (right + left) / 2L;
startIp = GetStartIp(middle, out endIpOff);
if (intIp == startIp)
{
left = middle;
break;
}
if (intIp > startIp)
{
left = middle;
}
else
{
right = middle;
}
}
startIp = GetStartIp(left, out endIpOff);
long endIp = GetEndIp(endIpOff, out countryFlag);
if ((startIp <= intIp) && (endIp >= intIp))
{
string local;
ipLocation.Country = GetCountry(endIpOff, countryFlag, out local);
ipLocation.Local = local.Replace("(我们一定要解放台湾!!!)", string.Empty);
}
else
{
ipLocation.Country = "未知";
ipLocation.Local = string.Empty;
}
return ipLocation;
}
/// <summary>
/// 由IP地址查找对应的位置信息的字符串.
/// </summary>
public string Query2(string ip)
{
IpLocation result = Query(ip);
return (result.Country + result.Local).Replace("CZ88.NET", string.Empty);
}
private long GetStartIp(long left, out long endIpOff)
{
long leftOffset = _firstStartIpOffset + (left * 7L);
byte[] buffer = new byte[7];
Array.Copy(_data, leftOffset, buffer, 0, 7);
endIpOff = (Convert.ToInt64(buffer[4].ToString(CultureInfo.InvariantCulture)) +
(Convert.ToInt64(buffer[5].ToString(CultureInfo.InvariantCulture)) * 0x100L)) +
((Convert.ToInt64(buffer[6].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L);
return ((Convert.ToInt64(buffer[0].ToString(CultureInfo.InvariantCulture)) +
(Convert.ToInt64(buffer[1].ToString(CultureInfo.InvariantCulture)) * 0x100L)) +
((Convert.ToInt64(buffer[2].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L)) +
(((Convert.ToInt64(buffer[3].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L) * 0x100L);
}
private long GetEndIp(long endIpOff, out int countryFlag)
{
byte[] buffer = new byte[5];
Array.Copy(_data, endIpOff, buffer, 0, 5);
countryFlag = buffer[4];
return ((Convert.ToInt64(buffer[0].ToString(CultureInfo.InvariantCulture)) +
(Convert.ToInt64(buffer[1].ToString(CultureInfo.InvariantCulture)) * 0x100L)) +
((Convert.ToInt64(buffer[2].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L)) +
(((Convert.ToInt64(buffer[3].ToString(CultureInfo.InvariantCulture)) * 0x100L) * 0x100L) * 0x100L);
}
/// <summary>
/// Gets the country.
/// </summary>
/// <param name="endIpOff"> The end ip off. </param>
/// <param name="countryFlag"> The country flag. </param>
/// <param name="local"> The local. </param>
/// <returns> country.</returns>
private string GetCountry(long endIpOff, int countryFlag, out string local)
{
string country;
long offset = endIpOff + 4L;
switch (countryFlag)
{
case 1:
case 2:
country = GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
offset = endIpOff + 8L;
local = (countryFlag == 1) ? string.Empty : GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
break;
default:
country = GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
local = GetFlagStr(ref offset, ref countryFlag, ref endIpOff);
break;
}
return country;
}
private string GetFlagStr(ref long offset, ref int countryFlag, ref long endIpOff)
{
byte[] buffer = new byte[3];
while (true)
{
// 用于向前累加偏移量
long forwardOffset = offset;
int flag = _data[forwardOffset++];
// 没有重定向
if (flag != 1 && flag != 2)
break;
Array.Copy(_data, forwardOffset, buffer, 0, 3);
if (flag == 2)
{
countryFlag = 2;
endIpOff = offset - 4L;
}
offset = (Convert.ToInt64(buffer[0].ToString()) + (Convert.ToInt64(buffer[1].ToString()) * 0x100L)) +
((Convert.ToInt64(buffer[2].ToString()) * 0x100L) * 0x100L);
}
if (offset < 12L)
{
return string.Empty;
}
return GetStr(ref offset);
}
private string GetStr(ref long offset)
{
StringBuilder stringBuilder = new StringBuilder();
byte[] bytes = new byte[2];
Encoding encoding = Encoding.GetEncoding("GB2312");
while (true)
{
byte lowByte = _data[offset++];
if (lowByte == 0)
return stringBuilder.ToString();
if (lowByte > 0x7f)
{
byte highByte = _data[offset++];
bytes[0] = lowByte;
bytes[1] = highByte;
if (highByte == 0)
return stringBuilder.ToString();
stringBuilder.Append(encoding.GetString(bytes));
}
else
{
stringBuilder.Append((char)lowByte);
}
}
}
}
}

View File

@@ -0,0 +1,229 @@
using System.Text.RegularExpressions;
using JNPF.DependencyInjection;
using Microsoft.AspNetCore.Http;
using UAParser;
namespace JNPF.Common.Net;
/// <summary>
/// UserAgent操作类.
/// </summary>
[SuppressSniffer]
public class UserAgent : IUserAgent
{
private readonly static Parser s_uap;
#region Mobile UAs, OS & Devices
private static readonly HashSet<string> s_MobileOS = new HashSet<string>
{
"Android",
"iOS",
"Windows Mobile",
"Windows Phone",
"Windows CE",
"Symbian OS",
"BlackBerry OS",
"BlackBerry Tablet OS",
"Firefox OS",
"Brew MP",
"webOS",
"Bada",
"Kindle",
"Maemo"
};
private static readonly HashSet<string> s_MobileBrowsers = new HashSet<string>
{
"Android",
"Firefox Mobile",
"Opera Mobile",
"Opera Mini",
"Mobile Safari",
"Amazon Silk",
"webOS Browser",
"MicroB",
"Ovi Browser",
"NetFront",
"NetFront NX",
"Chrome Mobile",
"Chrome Mobile iOS",
"UC Browser",
"Tizen Browser",
"Baidu Explorer",
"QQ Browser Mini",
"QQ Browser Mobile",
"IE Mobile",
"Polaris",
"ONE Browser",
"iBrowser Mini",
"Nokia Services (WAP) Browser",
"Nokia Browser",
"Nokia OSS Browser",
"BlackBerry WebKit",
"BlackBerry",
"Palm",
"Palm Blazer",
"Palm Pre",
"Teleca Browser",
"SEMC-Browser",
"PlayStation Portable",
"Nokia",
"Maemo Browser",
"Obigo",
"Bolt",
"Iris",
"UP.Browser",
"Minimo",
"Bunjaloo",
"Jasmine",
"Dolfin",
"Polaris",
"Skyfire"
};
private static readonly HashSet<string> s_MobileDevices = new HashSet<string>
{
"BlackBerry",
"MI PAD",
"iPhone",
"iPad",
"iPod",
"Kindle",
"Kindle Fire",
"Nokia",
"Lumia",
"Palm",
"DoCoMo",
"HP TouchPad",
"Xoom",
"Motorola",
"Generic Feature Phone",
"Generic Smartphone"
};
#endregion
private readonly HttpContext _httpContext;
private string _rawValue;
private UserAgentInfo _userAgent;
private DeviceInfo _device;
private OSInfo _os;
private bool? _isBot;
private bool? _isMobileDevice;
private bool? _isTablet;
private bool? _isPdfConverter;
static UserAgent()
{
s_uap = Parser.GetDefault();
}
public UserAgent(HttpContext httpContext)
{
this._httpContext = httpContext;
}
public string RawValue
{
get
{
if (_rawValue == null)
{
if (_httpContext.Request != null)
{
_rawValue = _httpContext.Request?.Headers["User-Agent"];
}
else
{
_rawValue = "";
}
}
return _rawValue;
}
set
{
_rawValue = value;
_userAgent = null;
_device = null;
_os = null;
_isBot = null;
_isMobileDevice = null;
_isTablet = null;
_isPdfConverter = null;
}
}
public virtual UserAgentInfo userAgent
{
get
{
if (_userAgent == null)
{
var tmp = s_uap.ParseUserAgent(this.RawValue);
_userAgent = new UserAgentInfo(tmp.Family, tmp.Major, tmp.Minor, tmp.Patch);
}
return _userAgent;
}
}
public virtual DeviceInfo Device
{
get
{
if (_device == null)
{
var tmp = s_uap.ParseDevice(this.RawValue);
_device = new DeviceInfo(tmp.Family, tmp.IsSpider);
}
return _device;
}
}
public virtual OSInfo OS
{
get
{
if (_os == null)
{
var tmp = s_uap.ParseOS(this.RawValue);
_os = new OSInfo(tmp.Family, tmp.Major, tmp.Minor, tmp.Patch, tmp.PatchMinor);
}
return _os;
}
}
public virtual bool IsMobileDevice
{
get
{
if (!_isMobileDevice.HasValue)
{
_isMobileDevice =
s_MobileOS.Contains(this.OS.Family) ||
s_MobileBrowsers.Contains(this.userAgent.Family) ||
s_MobileDevices.Contains(this.Device.Family);
}
return _isMobileDevice.Value;
}
}
public virtual bool IsTablet
{
get
{
if (!_isTablet.HasValue)
{
_isTablet =
Regex.IsMatch(this.Device.Family, "iPad|Kindle Fire|Nexus 10|Xoom|Transformer|MI PAD|IdeaTab", RegexOptions.CultureInvariant) ||
this.OS.Family == "BlackBerry Tablet OS";
}
return _isTablet.Value;
}
}
}