Compare commits

..

13 Commits

Author SHA1 Message Date
手瓜一十雪
4bd92a72bd fix: ua agent 2025-01-03 13:09:43 +08:00
手瓜一十雪
a3be26f3e4 fix: error 2025-01-03 12:44:55 +08:00
Mlikiowa
675c906cbf release: v4.2.64 2024-12-31 14:42:17 +00:00
手瓜一十雪
6be6023236 Merge pull request #679 from wu-yafeng/main
fix #678
2024-12-31 22:41:34 +08:00
WuYafeng
42cee0d018 在没有写入权限时记录warn日志 2024-12-31 22:38:01 +08:00
WuYafeng
041f725748 Update config.ts 2024-12-31 22:25:05 +08:00
WuYafeng
0594d61631 Update config.ts 2024-12-31 22:20:34 +08:00
Mlikiowa
15cae6b765 release: v4.2.63 2024-12-31 13:52:37 +00:00
pk5ls20
b984116c35 fix: #677 2024-12-31 21:34:45 +08:00
Mlikiowa
13bda6e3f4 release: v4.2.62 2024-12-31 08:35:55 +00:00
手瓜一十雪
c0d18549d1 fix 2024-12-31 15:09:08 +08:00
手瓜一十雪
3caff72fce fix: cache trace 2024-12-31 13:10:58 +08:00
Mlikiowa
1313e9c3f4 release: v4.2.61 2024-12-30 15:59:33 +00:00
9 changed files with 39 additions and 142 deletions

View File

@@ -4,7 +4,7 @@
"name": "NapCatQQ",
"slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现",
"version": "4.2.60",
"version": "4.2.64",
"icon": "./logo.png",
"authors": [
{

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "4.2.60",
"version": "4.2.64",
"scripts": {
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",

View File

@@ -1,116 +0,0 @@
import * as net from 'net';
import * as https from 'https';
export const cloudflareIps = [
'103.21.244.0/22',
'103.22.200.0/22',
'103.31.4.0/22',
'104.16.0.0/13',
'104.24.0.0/14',
'108.162.192.0/18',
'131.0.72.0/22',
'141.101.64.0/18',
'162.158.0.0/15',
'172.64.0.0/13',
'173.245.48.0/20',
'188.114.96.0/20',
'190.93.240.0/20',
'197.234.240.0/22',
'198.41.128.0/17'
];
// 将IP地址转换为整数
const ipToInt = (ip: string): number => ip.split('.').reduce((acc, octet) => (acc << 8) + Number(octet), 0) >>> 0;
// 将整数转换为IP地址
const intToIp = (int: number): string => `${(int >>> 24) & 0xFF}.${(int >>> 16) & 0xFF}.${(int >>> 8) & 0xFF}.${int & 0xFF}`;
// 解析CIDR范围
const parseCIDR = (cidr: string): string[] => {
const [base, maskLength] = cidr.split('/');
const baseIP = ipToInt(base);
return Array.from({ length: 1 << (32 - Number(maskLength)) }, (_, i) => intToIp(baseIP + i))
.filter(ip => !ip.endsWith('.0')); // 排除以 .0 结尾的 IP 地址
}
// 解析IP地址和IP范围
const parseIPs = (ipList: string[]): string[] => ipList.flatMap(ip => ip.includes('/') ? parseCIDR(ip) : net.isIP(ip) ? [ip] : []);
// 检查URL的HTTP连接性
const checkUrl = (ip: string, domain: string): Promise<boolean> => new Promise((resolve) => {
const options = {
hostname: ip,
port: 443,
method: 'GET',
path: '/',
timeout: 2000,
headers: {
'Host': domain,
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.2128.93 Safari/537.36'
}
};
const req = https.request(options, (res) => {
res.on('data', (data) => {
//console.log('[NetWork] [Scan] Checking Data! ', domain, ' --> ', ip, data.toString());
});
if (res.statusCode && res.statusCode > 0 && res.statusCode < 500) {
console.log('[NetWork] [Scan] Checking Connect! ', domain, ' --> ', ip);
resolve(true);
} else {
console.log('[NetWork] [Scan] Checking Failed! ', domain, ' --> ', ip, ' Status Code: ', res.statusCode);
resolve(false);
}
});
req.on('error', () => {
console.log('[NetWork] [Scan] Checking Error! ', domain, ' --> ', ip);
resolve(false);
});
req.on('timeout', () => {
req.destroy();
console.log('[NetWork] [Scan] Checking Timeout! ', domain, ' --> ', ip);
resolve(false);
});
req.end();
});
// 检查特定域名的HTTP连接性
const checkDomainConnectivity = async (ip: string, domains: string[]): Promise<boolean> => {
const checkPromises = domains.map(domain => checkUrl(ip, domain));
const results = await Promise.all(checkPromises);
return results.some(result => result);
}
export const optimizeCloudflareIPs = async (ipList: string[], domains: string[]): Promise<string | undefined> => {
if ((await Promise.all(domains.map(domain => checkUrl(domain, domain)))).every(result => result)) return undefined;
for (const ip of parseIPs(ipList)) {
if (await checkDomainConnectivity(ip, domains)) return ip;
}
return undefined;
}
export const findRealHost = async () => {
const domains = ['umami.napneko.icu', 'rkey.napneko.icu'];
const ip = await optimizeCloudflareIPs(cloudflareIps, domains);
return {
'umami.napneko.icu': ip ?? 'umami.napneko.icu',
'rkey.napneko.icu': ip ?? 'rkey.napneko.icu'
};
}
type Cache = {
[key: string]: string;
};
let cache: Cache = {
'cached': '',
'umami.napneko.icu': 'umami.napneko.icu',
'rkey.napneko.icu': 'rkey.napneko.icu'
};
export const getDomainIp = async (domain: string) => {
if (!cache.cached) {
cache = { cached: 'cached', ...(await findRealHost()) };
}
console.log('[NetWork] [Cache] ', domain, ' --> ', cache[domain] ?? domain);
return cache[domain] ?? domain;
}

View File

@@ -1,6 +1,7 @@
import https from 'node:https';
import { napCatVersion } from './version';
import os from 'node:os';
export class UmamiTraceCore {
napcatVersion = napCatVersion;
qqversion = '1.0.0';
@@ -12,20 +13,23 @@ export class UmamiTraceCore {
ua: string = '';
workname: string = 'default';
bootTime = Date.now();
cache: string = '';
platform = process.platform;
init(qqversion: string, guid: string, workname: string) {
this.qqversion = qqversion;
this.workname = workname;
let UaList = {
'linux': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/124.0.0.0 Safari/537.36 PTST/240508.140043',
'win32': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.2128.93 Safari/537.36',
'darwin': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36',
const UaList = {
linux: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36',
win32: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.2128.93 Safari/537.36',
darwin: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36',
};
try {
if (process.platform === 'win32') {
if (this.platform === 'win32') {
const ntVersion = os.release();
UaList.win32 = `Mozilla/5.0 (Windows NT ${ntVersion}; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.2128.93 Safari/537.36`;
} else if (process.platform === 'darwin') {
} else if (this.platform === 'darwin') {
const macVersion = os.release();
UaList.darwin = `Mozilla/5.0 (Macintosh; Intel Mac OS X ${macVersion}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36`;
}
@@ -33,7 +37,7 @@ export class UmamiTraceCore {
this.ua = UaList.win32;
}
this.ua = UaList[process.platform as keyof typeof UaList] || UaList.win32;
this.ua = UaList[this.platform as keyof typeof UaList] || UaList.win32;
this.identifyUser(guid);
this.startHeartbeat();
@@ -46,17 +50,17 @@ export class UmamiTraceCore {
qq_version: this.qqversion,
napcat_working: this.workname,
device_guid: this.guid,
device_platform: os.platform(),
device_platform: this.platform,
device_arch: os.arch(),
boot_time: new Date(this.bootTime + 8 * 60 * 60 * 1000).toISOString().replace('T', ' ').substring(0, 19),
sys_time: new Date(Date.now() - os.uptime() * 1000 + 8 * 60 * 60 * 1000).toISOString().replace('T', ' ').substring(0, 19)
sys_time: new Date(Date.now() - os.uptime() * 1000 + 8 * 60 * 60 * 1000).toISOString().replace('T', ' ').substring(0, 19),
};
this.sendEvent(
{
website: this.website,
hostname: this.hostname,
referrer: this.referrer,
tittle: 'NapCat ' + this.napcatVersion,
title: 'NapCat ' + this.napcatVersion,
url: `/${this.qqversion}/${this.napcatVersion}/${this.workname}/identify`,
},
data,
@@ -75,8 +79,8 @@ export class UmamiTraceCore {
language: language || 'en-US',
screen: '1920x1080',
data: {
...data
}
...data,
},
};
this.sendRequest(payload, type);
}
@@ -86,7 +90,7 @@ export class UmamiTraceCore {
website: this.website,
hostname: this.hostname,
title: 'NapCat ' + this.napcatVersion,
url: `/${this.qqversion}/${this.napcatVersion}/${this.workname}/${eventName}` + (!!data ? `/${data}` : ''),
url: `/${this.qqversion}/${this.napcatVersion}/${this.workname}/${eventName}` + (data ? `/${data}` : ''),
referrer: this.referrer,
};
this.sendRequest(payload);
@@ -101,7 +105,8 @@ export class UmamiTraceCore {
headers: {
"Host": "umami.napneko.icu",
"Content-Type": "application/json",
"User-Agent": this.ua
"User-Agent": this.ua,
...(this.cache ? { 'x-umami-cache': this.cache } : {})
}
};
@@ -110,9 +115,11 @@ export class UmamiTraceCore {
});
res.on('data', (data) => {
if (!this.cache) {
this.cache = data.toString();
}
});
}).on('error', () => {} );
}).on('error', () => { });
request.write(JSON.stringify({ type, payload }));
request.end();
@@ -138,4 +145,5 @@ export class UmamiTraceCore {
}
}
}
export const UmamiTrace = new UmamiTraceCore();

View File

@@ -1 +1 @@
export const napCatVersion = '4.2.60';
export const napCatVersion = '4.2.64';

View File

@@ -21,7 +21,7 @@ export class PacketOperationContext {
}
async GroupPoke(groupUin: number, uin: number) {
const req = trans.SendPoke.build(groupUin, uin);
const req = trans.SendPoke.build(uin, groupUin);
await this.context.client.sendOidbPacket(req);
}

View File

@@ -14,6 +14,6 @@ export class GroupPoke extends GetPacketStatusDepends<Payload, any> {
payloadSchema = SchemaData;
async _handle(payload: Payload) {
await this.core.apis.PacketApi.pkt.operation.GroupPoke(+payload.user_id, +payload.group_id);
await this.core.apis.PacketApi.pkt.operation.GroupPoke(+payload.group_id, +payload.user_id);
}
}

View File

@@ -15,9 +15,9 @@ export class SendPoke extends GetPacketStatusDepends<Payload, any> {
async _handle(payload: Payload) {
if (payload.group_id) {
this.core.apis.PacketApi.pkt.operation.GroupPoke(+payload.group_id, +payload.user_id);
await this.core.apis.PacketApi.pkt.operation.GroupPoke(+payload.group_id, +payload.user_id);
} else {
this.core.apis.PacketApi.pkt.operation.FriendPoke(+payload.user_id);
await this.core.apis.PacketApi.pkt.operation.FriendPoke(+payload.user_id);
}
}
}
}

View File

@@ -90,7 +90,7 @@ export class WebUiConfigWrapper {
try {
const configPath = resolve(webUiPathWrapper.configPath, './webui.json');
if (!await fs.access(configPath, constants.R_OK).then(() => true).catch(() => false)) {
if (!await fs.access(configPath, constants.F_OK).then(() => true).catch(() => false)) {
await fs.writeFile(configPath, JSON.stringify(defaultconfig, null, 4));
}
@@ -101,7 +101,12 @@ export class WebUiConfigWrapper {
if (!parsedConfig.prefix.startsWith('/')) parsedConfig.prefix = '/' + parsedConfig.prefix;
if (parsedConfig.prefix.endsWith('/')) parsedConfig.prefix = parsedConfig.prefix.slice(0, -1);
// 配置已经被操作过了,还是回写一下吧,不然新配置不会出现在配置文件里
await fs.writeFile(configPath, JSON.stringify(parsedConfig, null, 4));
if (await fs.access(configPath, constants.W_OK).then(() => true).catch(() => false)) {
await fs.writeFile(configPath, JSON.stringify(parsedConfig, null, 4));
}
else {
console.warn(`文件: ${configPath} 没有写入权限, 配置的更改部分可能会在重启后还原.`);
}
// 不希望回写的配置放后面
// 查询主机地址是否可用