|
|
@@ -101,7 +101,8 @@ function parseCookies(setCookieHeaders) {
|
|
|
}
|
|
|
|
|
|
// 生成跳转 HTML
|
|
|
-function generateRedirectHTML(cookieData, targetHost, targetDomain, requestId = '') {
|
|
|
+function generateRedirectHTML(cookieData, targetHost, targetDomain, requestId = '', customUrl = null) {
|
|
|
+ const targetUrl = customUrl || `http://${targetHost}/`;
|
|
|
return `
|
|
|
<!DOCTYPE html>
|
|
|
<html lang="zh-CN">
|
|
|
@@ -151,7 +152,7 @@ function generateRedirectHTML(cookieData, targetHost, targetDomain, requestId =
|
|
|
(function() {
|
|
|
const requestId = '${requestId}';
|
|
|
const cookies = ${JSON.stringify(cookieData)};
|
|
|
- const targetUrl = 'http://${targetHost}/';
|
|
|
+ const targetUrl = '${targetUrl}';
|
|
|
const targetDomain = '${targetDomain}';
|
|
|
|
|
|
console.log('========================================');
|
|
|
@@ -163,49 +164,55 @@ function generateRedirectHTML(cookieData, targetHost, targetDomain, requestId =
|
|
|
console.log('[浏览器端] Cookie 详情:', cookies);
|
|
|
|
|
|
// 方法1: 尝试直接设置 Cookie(可能因为跨域限制而失败)
|
|
|
- console.log('[浏览器端] 开始尝试设置 Cookie...');
|
|
|
- let successCount = 0;
|
|
|
- let failCount = 0;
|
|
|
-
|
|
|
- cookies.forEach(function(cookie) {
|
|
|
- try {
|
|
|
- // 构建 Cookie 字符串
|
|
|
- let cookieStr = cookie.name + '=' + cookie.value;
|
|
|
- cookieStr += '; path=' + cookie.path;
|
|
|
- if (cookie.maxAge) {
|
|
|
- cookieStr += '; max-age=' + cookie.maxAge;
|
|
|
- }
|
|
|
- if (cookie.expires) {
|
|
|
- cookieStr += '; expires=' + cookie.expires;
|
|
|
- }
|
|
|
- if (cookie.secure) {
|
|
|
- cookieStr += '; secure';
|
|
|
- }
|
|
|
- if (cookie.sameSite) {
|
|
|
- cookieStr += '; samesite=' + cookie.sameSite;
|
|
|
- }
|
|
|
- // 注意:Domain 属性无法通过 JavaScript 设置跨域 Cookie
|
|
|
- // 但我们可以尝试设置(浏览器会忽略跨域的 Domain)
|
|
|
- cookieStr += '; domain=' + targetDomain;
|
|
|
-
|
|
|
- document.cookie = cookieStr;
|
|
|
- console.log('[浏览器端] ✓ 尝试设置 Cookie:', cookie.name);
|
|
|
- successCount++;
|
|
|
-
|
|
|
- // 验证 Cookie 是否设置成功
|
|
|
- const allCookies = document.cookie;
|
|
|
- if (allCookies.indexOf(cookie.name + '=') !== -1) {
|
|
|
- console.log('[浏览器端] ✓ Cookie 设置成功:', cookie.name);
|
|
|
- } else {
|
|
|
- console.warn('[浏览器端] ⚠ Cookie 可能未设置成功:', cookie.name, '(可能是跨域限制)');
|
|
|
+ if (cookies.length > 0) {
|
|
|
+ console.log('[浏览器端] 开始尝试设置 Cookie...');
|
|
|
+ let successCount = 0;
|
|
|
+ let failCount = 0;
|
|
|
+
|
|
|
+ cookies.forEach(function(cookie) {
|
|
|
+ try {
|
|
|
+ // 构建 Cookie 字符串
|
|
|
+ let cookieStr = cookie.name + '=' + cookie.value;
|
|
|
+ cookieStr += '; path=' + (cookie.path || '/');
|
|
|
+ if (cookie.maxAge) {
|
|
|
+ cookieStr += '; max-age=' + cookie.maxAge;
|
|
|
+ }
|
|
|
+ if (cookie.expires) {
|
|
|
+ cookieStr += '; expires=' + cookie.expires;
|
|
|
+ }
|
|
|
+ if (cookie.secure) {
|
|
|
+ cookieStr += '; secure';
|
|
|
+ }
|
|
|
+ if (cookie.sameSite) {
|
|
|
+ cookieStr += '; samesite=' + cookie.sameSite;
|
|
|
+ }
|
|
|
+ // 注意:Domain 属性无法通过 JavaScript 设置跨域 Cookie
|
|
|
+ // 但我们可以尝试设置(浏览器会忽略跨域的 Domain)
|
|
|
+ if (cookie.domain) {
|
|
|
+ cookieStr += '; domain=' + cookie.domain;
|
|
|
+ }
|
|
|
+
|
|
|
+ document.cookie = cookieStr;
|
|
|
+ console.log('[浏览器端] ✓ 尝试设置 Cookie:', cookie.name);
|
|
|
+ successCount++;
|
|
|
+
|
|
|
+ // 验证 Cookie 是否设置成功
|
|
|
+ const allCookies = document.cookie;
|
|
|
+ if (allCookies.indexOf(cookie.name + '=') !== -1) {
|
|
|
+ console.log('[浏览器端] ✓ Cookie 设置成功:', cookie.name);
|
|
|
+ } else {
|
|
|
+ console.warn('[浏览器端] ⚠ Cookie 可能未设置成功:', cookie.name, '(可能是跨域限制)');
|
|
|
+ }
|
|
|
+ } catch(e) {
|
|
|
+ console.error('[浏览器端] ✗ 设置 Cookie 失败:', cookie.name, e);
|
|
|
+ failCount++;
|
|
|
}
|
|
|
- } catch(e) {
|
|
|
- console.error('[浏览器端] ✗ 设置 Cookie 失败:', cookie.name, e);
|
|
|
- failCount++;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- console.log('[浏览器端] Cookie 设置结果: 成功 ' + successCount + ', 失败 ' + failCount);
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('[浏览器端] Cookie 设置结果: 成功 ' + successCount + ', 失败 ' + failCount);
|
|
|
+ } else {
|
|
|
+ console.log('[浏览器端] 没有 Cookie 需要设置,直接跳转');
|
|
|
+ }
|
|
|
|
|
|
// 方法2: 使用隐藏的 iframe 加载目标站点,让服务器设置 Cookie
|
|
|
// 然后跳转到目标站点
|
|
|
@@ -558,7 +565,7 @@ async function handleHomeAssistantLogin(config, credentials) {
|
|
|
|
|
|
console.log(`访问授权端点: ${authorizeUrl}`);
|
|
|
|
|
|
- // 使用 Cookie jar 的客户端访问授权端点
|
|
|
+ // 使用 Cookie jar 的客户端访问授权端点,跟随重定向
|
|
|
const authorizeResponse = await client.get(authorizeUrl, {
|
|
|
headers: {
|
|
|
'User-Agent': baseHeaders['User-Agent'],
|
|
|
@@ -566,14 +573,55 @@ async function handleHomeAssistantLogin(config, credentials) {
|
|
|
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
|
|
'Referer': `${targetBaseUrl}/`
|
|
|
},
|
|
|
- maxRedirects: 5,
|
|
|
+ maxRedirects: 10, // 增加重定向次数
|
|
|
validateStatus: function (status) {
|
|
|
return status >= 200 && status < 400;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
console.log(`授权响应状态码: ${authorizeResponse.status}`);
|
|
|
- console.log(`授权响应 URL: ${authorizeResponse.request?.res?.responseUrl || authorizeResponse.config?.url}`);
|
|
|
+ const finalUrl = authorizeResponse.request?.res?.responseUrl || authorizeResponse.config?.url || authorizeUrl;
|
|
|
+ console.log(`授权最终 URL: ${finalUrl}`);
|
|
|
+
|
|
|
+ // 检查是否是重定向到回调 URL
|
|
|
+ if (finalUrl.includes('auth_callback=1') || finalUrl.includes('code=')) {
|
|
|
+ console.log('检测到授权回调,访问回调 URL 获取 Cookie...');
|
|
|
+ try {
|
|
|
+ const callbackResponse = await client.get(finalUrl, {
|
|
|
+ headers: {
|
|
|
+ 'User-Agent': baseHeaders['User-Agent'],
|
|
|
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
|
|
+ 'Referer': authorizeUrl
|
|
|
+ },
|
|
|
+ maxRedirects: 5,
|
|
|
+ validateStatus: function (status) {
|
|
|
+ return status >= 200 && status < 400;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ console.log(`回调响应状态码: ${callbackResponse.status}`);
|
|
|
+ } catch (callbackError) {
|
|
|
+ console.log('访问回调 URL 失败:', callbackError.message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 尝试访问主页面来触发 Cookie 设置
|
|
|
+ console.log('访问主页面以触发 Cookie 设置...');
|
|
|
+ try {
|
|
|
+ const homePageResponse = await client.get(`${targetBaseUrl}/`, {
|
|
|
+ headers: {
|
|
|
+ 'User-Agent': baseHeaders['User-Agent'],
|
|
|
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
|
|
+ 'Referer': finalUrl
|
|
|
+ },
|
|
|
+ maxRedirects: 5,
|
|
|
+ validateStatus: function (status) {
|
|
|
+ return status >= 200 && status < 400;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ console.log(`主页面响应状态码: ${homePageResponse.status}`);
|
|
|
+ } catch (homeError) {
|
|
|
+ console.log('访问主页面失败:', homeError.message);
|
|
|
+ }
|
|
|
|
|
|
// 从 Cookie jar 中获取授权后的 Cookie
|
|
|
const authorizeJarCookies = await cookieJar.getCookies(targetBaseUrl);
|
|
|
@@ -605,6 +653,13 @@ async function handleHomeAssistantLogin(config, credentials) {
|
|
|
uniqueCookies = Array.from(cookieMap.values());
|
|
|
|
|
|
console.log(`授权完成!最终获取到 ${uniqueCookies.length} 个唯一 Cookie`);
|
|
|
+
|
|
|
+ // 如果还是没有 Cookie,尝试使用登录结果中的 token
|
|
|
+ if (uniqueCookies.length === 0 && responseData.result) {
|
|
|
+ console.log(`尝试使用登录结果中的 token: ${responseData.result}`);
|
|
|
+ // 这里可以尝试使用 token 来获取访问令牌
|
|
|
+ // 但 Home Assistant 的 token 通常需要通过浏览器来设置 Cookie
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
console.log('授权流程失败(可能不需要):', error.message);
|
|
|
if (error.response) {
|
|
|
@@ -886,12 +941,28 @@ app.get('/api/auto-login/:siteId', async (req, res) => {
|
|
|
});
|
|
|
|
|
|
// 生成跳转 HTML(添加更多调试信息)
|
|
|
- console.log(`[${requestId}] 生成跳转页面,目标: http://${config.targetHost}/`);
|
|
|
+ // 对于 Home Assistant,如果没有 Cookie,直接跳转到授权端点
|
|
|
+ let redirectUrl = `http://${config.targetHost}/`;
|
|
|
+ if (config.loginMethod === 'home-assistant' && cookieData.length === 0) {
|
|
|
+ // 构建授权 URL 让浏览器处理
|
|
|
+ const stateData = {
|
|
|
+ hassUrl: config.targetBaseUrl,
|
|
|
+ clientId: `${config.targetBaseUrl}/`
|
|
|
+ };
|
|
|
+ const state = Buffer.from(JSON.stringify(stateData)).toString('base64');
|
|
|
+ const redirectUri = `${config.targetBaseUrl}/?auth_callback=1`;
|
|
|
+ const clientId = `${config.targetBaseUrl}/`;
|
|
|
+ redirectUrl = `${config.targetBaseUrl}/auth/authorize?response_type=code&redirect_uri=${encodeURIComponent(redirectUri)}&client_id=${encodeURIComponent(clientId)}&state=${encodeURIComponent(state)}`;
|
|
|
+ console.log(`[${requestId}] Home Assistant 无 Cookie,跳转到授权端点: ${redirectUrl}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log(`[${requestId}] 生成跳转页面,目标: ${redirectUrl}`);
|
|
|
const html = generateRedirectHTML(
|
|
|
cookieData,
|
|
|
config.targetHost,
|
|
|
config.targetDomain,
|
|
|
- requestId
|
|
|
+ requestId,
|
|
|
+ redirectUrl
|
|
|
);
|
|
|
|
|
|
// 在响应头中设置 Cookie
|