liuq преди 4 месеца
родител
ревизия
ab38e25ed7
променени са 1 файла, в които са добавени 120 реда и са изтрити 49 реда
  1. 120 49
      server.js

+ 120 - 49
server.js

@@ -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