mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2024-11-16 13:01:14 +00:00
refactor: nc shell login
This commit is contained in:
parent
6a08b15095
commit
96003724ab
@ -34,54 +34,46 @@ program.option('-q, --qq [number]', 'QQ号').parse(process.argv);
|
|||||||
const cmdOptions = program.opts();
|
const cmdOptions = program.opts();
|
||||||
|
|
||||||
// NapCat Shell App ES 入口文件
|
// NapCat Shell App ES 入口文件
|
||||||
export async function NCoreInitShell() {
|
async function handleUncaughtExceptions(logger: LogWrapper) {
|
||||||
console.log('NapCat Shell App Loading...');
|
|
||||||
process.on('uncaughtException', (err) => {
|
process.on('uncaughtException', (err) => {
|
||||||
console.log('[NapCat] [Error] Unhandled Exception:', err.message);
|
logger.logError('[NapCat] [Error] Unhandled Exception:', err.message);
|
||||||
});
|
});
|
||||||
process.on('unhandledRejection', (reason, promise) => {
|
process.on('unhandledRejection', (reason, promise) => {
|
||||||
console.log('[NapCat] [Error] unhandledRejection:', reason);
|
logger.logError('[NapCat] [Error] unhandledRejection:', reason);
|
||||||
});
|
});
|
||||||
const pathWrapper = new NapCatPathWrapper();
|
}
|
||||||
const logger = new LogWrapper(pathWrapper.logsPath);
|
|
||||||
const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
|
|
||||||
const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion());
|
|
||||||
|
|
||||||
const o3Service = wrapper.NodeIO3MiscService.get();
|
function getDataPaths(wrapper: WrapperNodeApi): [string, string] {
|
||||||
o3Service.addO3MiscListener(new NodeIO3MiscListener());
|
if (os.platform() === 'darwin') {
|
||||||
|
const userPath = os.homedir();
|
||||||
|
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
|
||||||
|
return [appDataPath, path.join(appDataPath, 'global')];
|
||||||
|
}
|
||||||
|
let dataPath = wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
|
||||||
|
if (!dataPath) {
|
||||||
|
dataPath = path.resolve(os.homedir(), './.config/QQ');
|
||||||
|
fs.mkdirSync(dataPath, { recursive: true });
|
||||||
|
}
|
||||||
|
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
|
||||||
|
return [dataPath, dataPathGlobal];
|
||||||
|
}
|
||||||
|
|
||||||
logger.log(`[NapCat] [Core] NapCat.Core Version: ` + napCatVersion);
|
function getPlatformType(): PlatformType {
|
||||||
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
|
|
||||||
|
|
||||||
// from constructor
|
|
||||||
const engine = wrapper.NodeIQQNTWrapperEngine.get();
|
|
||||||
//const util = wrapper.NodeQQNTWrapperUtil.get();
|
|
||||||
const loginService = wrapper.NodeIKernelLoginService.get();
|
|
||||||
|
|
||||||
const session = wrapper.NodeIQQNTWrapperSession.create();
|
|
||||||
// from get dataPath
|
|
||||||
const [dataPath, dataPathGlobal] = (() => {
|
|
||||||
if (os.platform() === 'darwin') {
|
|
||||||
const userPath = os.homedir();
|
|
||||||
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
|
|
||||||
return [appDataPath, path.join(appDataPath, 'global')];
|
|
||||||
}
|
|
||||||
let dataPath = wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
|
|
||||||
if (!dataPath) {
|
|
||||||
dataPath = path.resolve(os.homedir(), './.config/QQ');
|
|
||||||
fs.mkdirSync(dataPath, { recursive: true });
|
|
||||||
}
|
|
||||||
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
|
|
||||||
return [dataPath, dataPathGlobal];
|
|
||||||
})();
|
|
||||||
const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = {
|
const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = {
|
||||||
win32: PlatformType.KWINDOWS,
|
win32: PlatformType.KWINDOWS,
|
||||||
darwin: PlatformType.KMAC,
|
darwin: PlatformType.KMAC,
|
||||||
linux: PlatformType.KLINUX,
|
linux: PlatformType.KLINUX,
|
||||||
};
|
};
|
||||||
const systemPlatform = platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
|
return platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
|
||||||
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined');
|
}
|
||||||
// from initConfig
|
|
||||||
|
async function initializeEngine(
|
||||||
|
engine: any,
|
||||||
|
basicInfoWrapper: QQBasicInfoWrapper,
|
||||||
|
dataPathGlobal: string,
|
||||||
|
systemPlatform: PlatformType,
|
||||||
|
systemVersion: string
|
||||||
|
) {
|
||||||
engine.initWithDeskTopConfig(
|
engine.initWithDeskTopConfig(
|
||||||
{
|
{
|
||||||
base_path_prefix: '',
|
base_path_prefix: '',
|
||||||
@ -98,33 +90,41 @@ export async function NCoreInitShell() {
|
|||||||
},
|
},
|
||||||
new NodeIGlobalAdapter(),
|
new NodeIGlobalAdapter(),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initializeLoginService(
|
||||||
|
loginService: NodeIKernelLoginService,
|
||||||
|
basicInfoWrapper: QQBasicInfoWrapper,
|
||||||
|
dataPathGlobal: string,
|
||||||
|
systemVersion: string,
|
||||||
|
hostname: string
|
||||||
|
) {
|
||||||
loginService.initConfig({
|
loginService.initConfig({
|
||||||
machineId: '',
|
machineId: '',
|
||||||
appid: basicInfoWrapper.QQVersionAppid,
|
appid: basicInfoWrapper.QQVersionAppid ?? '',
|
||||||
platVer: systemVersion,
|
platVer: systemVersion,
|
||||||
commonPath: dataPathGlobal,
|
commonPath: dataPathGlobal,
|
||||||
clientVer: basicInfoWrapper.getFullQQVesion(),
|
clientVer: basicInfoWrapper.getFullQQVesion(),
|
||||||
hostName: hostname,
|
hostName: hostname,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let quickLoginUin = cmdOptions.qq; // undefined | 'true' | string
|
async function handleLogin(
|
||||||
const historyLoginList = (await loginService.getLoginList()).LocalLoginInfoList;
|
loginService: NodeIKernelLoginService,
|
||||||
if (quickLoginUin == 'true') {
|
logger: LogWrapper,
|
||||||
if (historyLoginList.length > 0) {
|
pathWrapper: NapCatPathWrapper,
|
||||||
quickLoginUin = historyLoginList[0].uin;
|
quickLoginUin: string | undefined,
|
||||||
logger.log(`-q 指令指定使用最近的 QQ ${quickLoginUin} 进行快速登录`);
|
historyLoginList: any[],
|
||||||
} else {
|
basicInfoWrapper: QQBasicInfoWrapper,
|
||||||
quickLoginUin = '';
|
o3Service: any,
|
||||||
}
|
dataTimestape: string
|
||||||
}
|
): Promise<SelfInfo> {
|
||||||
const dataTimestape = new Date().getTime().toString();
|
return new Promise<SelfInfo>((resolve) => {
|
||||||
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
|
|
||||||
const selfInfo = await new Promise<SelfInfo>((resolve) => {
|
|
||||||
const loginListener = new NodeIKernelLoginListener();
|
const loginListener = new NodeIKernelLoginListener();
|
||||||
let isLogined = false;
|
let isLogined = false;
|
||||||
// from constructor
|
|
||||||
loginListener.onUserLoggedIn = (userid: string) => {
|
loginListener.onUserLoggedIn = (userid: string) => {
|
||||||
logger.logError.bind(logger)(`当前账号(${userid})已登录,无法重复登录`);
|
logger.logError(`当前账号(${userid})已登录,无法重复登录`);
|
||||||
};
|
};
|
||||||
|
|
||||||
loginListener.onQRCodeLoginSucceed = async (loginResult) => {
|
loginListener.onQRCodeLoginSucceed = async (loginResult) => {
|
||||||
@ -132,13 +132,12 @@ export async function NCoreInitShell() {
|
|||||||
resolve({
|
resolve({
|
||||||
uid: loginResult.uid,
|
uid: loginResult.uid,
|
||||||
uin: loginResult.uin,
|
uin: loginResult.uin,
|
||||||
nick: '', // 获取不到
|
nick: '',
|
||||||
online: true,
|
online: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
loginListener.onQRCodeGetPicture = ({ pngBase64QrcodeData, qrcodeUrl }) => {
|
loginListener.onQRCodeGetPicture = ({ pngBase64QrcodeData, qrcodeUrl }) => {
|
||||||
//设置WebuiQrcode
|
|
||||||
WebUiDataRuntime.setQQLoginQrcodeURL(qrcodeUrl);
|
WebUiDataRuntime.setQQLoginQrcodeURL(qrcodeUrl);
|
||||||
|
|
||||||
const realBase64 = pngBase64QrcodeData.replace(/^data:image\/\w+;base64,/, '');
|
const realBase64 = pngBase64QrcodeData.replace(/^data:image\/\w+;base64,/, '');
|
||||||
@ -157,50 +156,46 @@ export async function NCoreInitShell() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
loginListener.onQRCodeSessionFailed = (errType: number, errCode: number, errMsg: string) => {
|
loginListener.onQRCodeSessionFailed = (errType: number, errCode: number, errMsg: string) => {
|
||||||
if (!isLogined) {
|
if (!isLogined) {
|
||||||
logger.logError.bind(logger)('[Core] [Login] Login Error,ErrCode: ', errCode, ' ErrMsg:', errMsg);
|
logger.logError('[Core] [Login] Login Error,ErrCode: ', errCode, ' ErrMsg:', errMsg);
|
||||||
if (errType == 1 && errCode == 3) {
|
if (errType == 1 && errCode == 3) {
|
||||||
// 二维码过期刷新
|
// 二维码过期刷新
|
||||||
}
|
}
|
||||||
loginService.getQRCodePicture();
|
loginService.getQRCodePicture();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
loginListener.onLoginFailed = (args) => {
|
loginListener.onLoginFailed = (args) => {
|
||||||
logger.logError.bind(logger)('[Core] [Login] Login Error , ErrInfo: ', args);
|
logger.logError('[Core] [Login] Login Error , ErrInfo: ', args);
|
||||||
};
|
};
|
||||||
|
|
||||||
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger));
|
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger));
|
||||||
const isConnect = loginService.connect();
|
const isConnect = loginService.connect();
|
||||||
if (!isConnect) {
|
if (!isConnect) {
|
||||||
logger.logError.bind(logger)('核心登录服务连接失败!');
|
logger.logError('核心登录服务连接失败!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log('核心登录服务连接成功!');
|
logger.log('核心登录服务连接成功!');
|
||||||
// 实现WebUi快速登录
|
|
||||||
loginService.getLoginList().then((res) => {
|
loginService.getLoginList().then((res) => {
|
||||||
// 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList
|
// 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList
|
||||||
WebUiDataRuntime.setQQQuickLoginList(res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin.toString()));
|
WebUiDataRuntime.setQQQuickLoginList(res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin.toString()));
|
||||||
});
|
});
|
||||||
if (basicInfoWrapper.QQVersionConfig?.curVersion) {
|
|
||||||
loginService.getLoginMiscData('hotUpdateSign').then((res) => {
|
|
||||||
if (res.result === 0) {
|
|
||||||
loginService.setLoginMiscData('hotUpdateSign', res.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
session.getNodeMiscService().writeVersionToRegistry(basicInfoWrapper.QQVersionConfig?.curVersion);
|
|
||||||
}
|
|
||||||
WebUiDataRuntime.setQuickLoginCall(async (uin: string) => {
|
WebUiDataRuntime.setQuickLoginCall(async (uin: string) => {
|
||||||
return await new Promise((resolve) => {
|
return await new Promise((resolve) => {
|
||||||
if (uin) {
|
if (uin) {
|
||||||
logger.log.bind(logger)('正在快速登录 ', uin);
|
logger.log('正在快速登录 ', uin);
|
||||||
loginService.quickLoginWithUin(uin).then(res => {
|
loginService.quickLoginWithUin(uin).then(res => {
|
||||||
if (res.loginErrorInfo.errMsg) {
|
if (res.loginErrorInfo.errMsg) {
|
||||||
resolve({ result: false, message: res.loginErrorInfo.errMsg });
|
resolve({ result: false, message: res.loginErrorInfo.errMsg });
|
||||||
}
|
}
|
||||||
resolve({ result: true, message: '' });
|
resolve({ result: true, message: '' });
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
logger.logError.bind(logger)(e);
|
logger.logError(e);
|
||||||
resolve({ result: false, message: '快速登录发生错误' });
|
resolve({ result: false, message: '快速登录发生错误' });
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -216,14 +211,14 @@ export async function NCoreInitShell() {
|
|||||||
loginService.quickLoginWithUin(quickLoginUin)
|
loginService.quickLoginWithUin(quickLoginUin)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (result.loginErrorInfo.errMsg) {
|
if (result.loginErrorInfo.errMsg) {
|
||||||
logger.logError.bind(logger)('快速登录错误:', result.loginErrorInfo.errMsg);
|
logger.logError('快速登录错误:', result.loginErrorInfo.errMsg);
|
||||||
if (!isLogined) loginService.getQRCodePicture();
|
if (!isLogined) loginService.getQRCodePicture();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch();
|
.catch();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
logger.logError.bind(logger)('快速登录失败,未找到该 QQ 历史登录记录,将使用二维码登录方式');
|
logger.logError('快速登录失败,未找到该 QQ 历史登录记录,将使用二维码登录方式');
|
||||||
if (!isLogined) loginService.getQRCodePicture();
|
if (!isLogined) loginService.getQRCodePicture();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -237,31 +232,14 @@ export async function NCoreInitShell() {
|
|||||||
loginService.getQRCodePicture();
|
loginService.getQRCodePicture();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// BEFORE LOGGING IN
|
}
|
||||||
const amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
|
|
||||||
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));
|
|
||||||
// AFTER LOGGING IN
|
|
||||||
//99b15bdb4c984fc69d5aa1feb9aa16xx --> 99b15bdb-4c98-4fc6-9d5a-a1feb9aa16xx
|
|
||||||
//把guid从左向右转换为guid格式 loginService.getMachineGuid()
|
|
||||||
|
|
||||||
let guid = loginService.getMachineGuid();
|
async function initializeSession(
|
||||||
guid = guid.slice(0, 8) + '-' + guid.slice(8, 12) + '-' + guid.slice(12, 16) + '-' + guid.slice(16, 20) + '-' + guid.slice(20);
|
session: NodeIQQNTWrapperSession,
|
||||||
//console.log('guid:', guid);
|
sessionConfig: any,
|
||||||
//NodeIO3MiscService/reportAmgomWeather login a6 [ '1726748166943', '184', '329' ]
|
logger: LogWrapper
|
||||||
o3Service.reportAmgomWeather('login', 'a6', [dataTimestape, '184', '329']);
|
) {
|
||||||
// if(session.getUnitedConfigService()){
|
return new Promise<void>((resolve, reject) => {
|
||||||
// session.getUnitedConfigService().fetchUnitedCommendConfig([]);
|
|
||||||
// }
|
|
||||||
// from initSession
|
|
||||||
const sessionConfig = await genSessionConfig(
|
|
||||||
guid,
|
|
||||||
basicInfoWrapper.QQVersionAppid,
|
|
||||||
basicInfoWrapper.getFullQQVesion(),
|
|
||||||
selfInfo.uin,
|
|
||||||
selfInfo.uid,
|
|
||||||
dataPath,
|
|
||||||
);
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
|
||||||
const sessionListener = new NodeIKernelSessionListener();
|
const sessionListener = new NodeIKernelSessionListener();
|
||||||
sessionListener.onSessionInitComplete = (r: unknown) => {
|
sessionListener.onSessionInitComplete = (r: unknown) => {
|
||||||
if (r === 0) {
|
if (r === 0) {
|
||||||
@ -278,7 +256,7 @@ export async function NCoreInitShell() {
|
|||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
session.startNT(0);
|
session.startNT(0);
|
||||||
} catch (_) { /* Empty */
|
} catch (_) {
|
||||||
try {
|
try {
|
||||||
session.startNT();
|
session.startNT();
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
@ -286,7 +264,60 @@ export async function NCoreInitShell() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Initialization end!
|
}
|
||||||
|
|
||||||
|
export async function NCoreInitShell() {
|
||||||
|
console.log('NapCat Shell App Loading...');
|
||||||
|
const pathWrapper = new NapCatPathWrapper();
|
||||||
|
const logger = new LogWrapper(pathWrapper.logsPath);
|
||||||
|
handleUncaughtExceptions(logger);
|
||||||
|
|
||||||
|
const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
|
||||||
|
const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion());
|
||||||
|
|
||||||
|
const o3Service = wrapper.NodeIO3MiscService.get();
|
||||||
|
o3Service.addO3MiscListener(new NodeIO3MiscListener());
|
||||||
|
|
||||||
|
logger.log(`[NapCat] [Core] NapCat.Core Version: ` + napCatVersion);
|
||||||
|
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
|
||||||
|
|
||||||
|
const engine = wrapper.NodeIQQNTWrapperEngine.get();
|
||||||
|
const loginService = wrapper.NodeIKernelLoginService.get();
|
||||||
|
const session = wrapper.NodeIQQNTWrapperSession.create();
|
||||||
|
|
||||||
|
const [dataPath, dataPathGlobal] = getDataPaths(wrapper);
|
||||||
|
const systemPlatform = getPlatformType();
|
||||||
|
|
||||||
|
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined');
|
||||||
|
|
||||||
|
await initializeEngine(engine, basicInfoWrapper, dataPathGlobal, systemPlatform, systemVersion);
|
||||||
|
await initializeLoginService(loginService, basicInfoWrapper, dataPathGlobal, systemVersion, hostname);
|
||||||
|
|
||||||
|
let quickLoginUin = cmdOptions.qq;
|
||||||
|
const historyLoginList = (await loginService.getLoginList()).LocalLoginInfoList;
|
||||||
|
|
||||||
|
const dataTimestape = new Date().getTime().toString();
|
||||||
|
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
|
||||||
|
|
||||||
|
const selfInfo = await handleLogin(loginService, logger, pathWrapper, quickLoginUin, historyLoginList, basicInfoWrapper, o3Service, dataTimestape);
|
||||||
|
|
||||||
|
const amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
|
||||||
|
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));
|
||||||
|
|
||||||
|
let guid = loginService.getMachineGuid();
|
||||||
|
guid = guid.slice(0, 8) + '-' + guid.slice(8, 12) + '-' + guid.slice(12, 16) + '-' + guid.slice(16, 20) + '-' + guid.slice(20);
|
||||||
|
o3Service.reportAmgomWeather('login', 'a6', [dataTimestape, '184', '329']);
|
||||||
|
|
||||||
|
const sessionConfig = await genSessionConfig(
|
||||||
|
guid,
|
||||||
|
basicInfoWrapper.QQVersionAppid,
|
||||||
|
basicInfoWrapper.getFullQQVesion(),
|
||||||
|
selfInfo.uin,
|
||||||
|
selfInfo.uid,
|
||||||
|
dataPath,
|
||||||
|
);
|
||||||
|
|
||||||
|
await initializeSession(session, sessionConfig, logger);
|
||||||
|
|
||||||
const accountDataPath = path.resolve(dataPath, './NapCat/data');
|
const accountDataPath = path.resolve(dataPath, './NapCat/data');
|
||||||
fs.mkdirSync(dataPath, { recursive: true });
|
fs.mkdirSync(dataPath, { recursive: true });
|
||||||
@ -303,6 +334,7 @@ export async function NCoreInitShell() {
|
|||||||
).InitNapCat();
|
).InitNapCat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class NapCatShell {
|
export class NapCatShell {
|
||||||
readonly core: NapCatCore;
|
readonly core: NapCatCore;
|
||||||
readonly context: InstanceContext;
|
readonly context: InstanceContext;
|
||||||
|
Loading…
Reference in New Issue
Block a user