소스 검색

更新依赖项版本,简化自动登录服务,添加自动登录页面

wuyi 4 달 전
부모
커밋
bb4cdf0bf7
5개의 변경된 파일244개의 추가작업 그리고 309개의 파일을 삭제
  1. 7 7
      package.json
  2. 12 12
      pnpm-lock.yaml
  3. 7 17
      src/index.ts
  4. 2 273
      src/lib/api/sessionAutoLoginService.ts
  5. 216 0
      src/pages/pageAutoLogin.ts

+ 7 - 7
package.json

@@ -30,8 +30,8 @@
     "@cryptography/aes": "^0.1.1",
     "@cryptography/sha1": "^0.2.0",
     "@cryptography/sha256": "^0.2.0",
-    "@eslint/eslintrc": "^3.2.0",
-    "@eslint/js": "^9.20.0",
+    "@eslint/eslintrc": "^3.3.1",
+    "@eslint/js": "^9.23.0",
     "@peculiar/webcrypto": "^1.4.3",
     "@solid-primitives/refs": "^1.0.5",
     "@solid-primitives/transition-group": "^1.0.3",
@@ -39,18 +39,18 @@
     "@types/dom-webcodecs": "^0.1.13",
     "@types/express": "^4.17.21",
     "@types/prismjs": "^1.26.3",
-    "@typescript-eslint/eslint-plugin": "^8.24.0",
-    "@typescript-eslint/parser": "^8.24.0",
+    "@typescript-eslint/eslint-plugin": "^8.29.0",
+    "@typescript-eslint/parser": "^8.29.0",
     "@vitejs/plugin-basic-ssl": "^1.1.0",
     "autoprefixer": "^10.4.16",
     "big-integer": "^1.6.52",
     "browserslist": "^4.22.2",
     "compression": "^1.7.4",
     "csstype": "^3.1.3",
-    "eslint": "^9.20.0",
+    "eslint": "^9.23.0",
     "express": "^4.18.2",
     "fast-png": "^6.2.0",
-    "globals": "^15.14.0",
+    "globals": "^15.15.0",
     "hls.js": "^1.5.18",
     "http-proxy": "^1.18.1",
     "js-md5": "^0.8.3",
@@ -64,7 +64,7 @@
     "rollup-plugin-visualizer": "^5.12.0",
     "sass": "^1.69.6",
     "tinyld": "^1.3.4",
-    "typescript": "^5.7.3",
+    "typescript": "^5.8.2",
     "vite": "^5.2.10",
     "vite-plugin-checker": "^0.8.0",
     "vite-plugin-handlebars": "^1.6.0",

+ 12 - 12
pnpm-lock.yaml

@@ -27,10 +27,10 @@ importers:
         specifier: ^0.2.0
         version: 0.2.0
       '@eslint/eslintrc':
-        specifier: ^3.2.0
+        specifier: ^3.3.1
         version: 3.3.1
       '@eslint/js':
-        specifier: ^9.20.0
+        specifier: ^9.23.0
         version: 9.23.0
       '@peculiar/webcrypto':
         specifier: ^1.4.3
@@ -54,10 +54,10 @@ importers:
         specifier: ^1.26.3
         version: 1.26.3
       '@typescript-eslint/eslint-plugin':
-        specifier: ^8.24.0
+        specifier: ^8.29.0
         version: 8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0)(typescript@5.8.2))(eslint@9.23.0)(typescript@5.8.2)
       '@typescript-eslint/parser':
-        specifier: ^8.24.0
+        specifier: ^8.29.0
         version: 8.29.0(eslint@9.23.0)(typescript@5.8.2)
       '@vitejs/plugin-basic-ssl':
         specifier: ^1.1.0
@@ -78,7 +78,7 @@ importers:
         specifier: ^3.1.3
         version: 3.1.3
       eslint:
-        specifier: ^9.20.0
+        specifier: ^9.23.0
         version: 9.23.0
       express:
         specifier: ^4.18.2
@@ -87,7 +87,7 @@ importers:
         specifier: ^6.2.0
         version: 6.2.0
       globals:
-        specifier: ^15.14.0
+        specifier: ^15.15.0
         version: 15.15.0
       hls.js:
         specifier: ^1.5.18
@@ -129,7 +129,7 @@ importers:
         specifier: ^1.3.4
         version: 1.3.4
       typescript:
-        specifier: ^5.7.3
+        specifier: ^5.8.2
         version: 5.8.2
       vite:
         specifier: ^5.2.10
@@ -1457,8 +1457,8 @@ packages:
     resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
     engines: {node: '>=6'}
 
-  caniuse-lite@1.0.30001572:
-    resolution: {integrity: sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==}
+  caniuse-lite@1.0.30001741:
+    resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==}
 
   chai@4.3.10:
     resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==}
@@ -4358,7 +4358,7 @@ snapshots:
   autoprefixer@10.4.16(postcss@8.4.38):
     dependencies:
       browserslist: 4.22.2
-      caniuse-lite: 1.0.30001572
+      caniuse-lite: 1.0.30001741
       fraction.js: 4.3.7
       normalize-range: 0.1.2
       picocolors: 1.0.0
@@ -4445,7 +4445,7 @@ snapshots:
 
   browserslist@4.22.2:
     dependencies:
-      caniuse-lite: 1.0.30001572
+      caniuse-lite: 1.0.30001741
       electron-to-chromium: 1.4.616
       node-releases: 2.0.14
       update-browserslist-db: 1.0.13(browserslist@4.22.2)
@@ -4467,7 +4467,7 @@ snapshots:
 
   callsites@3.1.0: {}
 
-  caniuse-lite@1.0.30001572: {}
+  caniuse-lite@1.0.30001741: {}
 
   chai@4.3.10:
     dependencies:

+ 7 - 17
src/index.ts

@@ -450,25 +450,15 @@ function setDocumentLangPackProperties(langPack: LangPackDifference.langPackDiff
 
   let authState = stateResult.state.authState;
 
-  // 检查URL中的session数据并尝试导入
+  // 检查URL中的session数据,如果有则跳转到自动登录页面
   const hasSessionData = sessionAutoLoginService.parseUrlParams();
   if(hasSessionData) {
-    try {
-      const sessionDataImported = await sessionAutoLoginService.performAutoLogin();
-      if(sessionDataImported) {
-        // 清除URL参数
-        sessionAutoLoginService.clearUrlParams();
-        console.log('Session data imported successfully, refreshing page to apply changes');
-
-        // 刷新页面,让系统自动检测session数据
-        window.location.reload();
-        return; // 阻止后续代码执行
-      }
-    } catch(error) {
-      console.error('Error importing session data:', error);
-      // 清除可能已保存的无效session数据
-      await sessionAutoLoginService.clearInvalidSessionData();
-    }
+    console.log('Found session data parameter, redirecting to auto login page');
+    // 跳转到自动登录页面
+    const PageAutoLogin = (await import('./pages/pageAutoLogin')).default;
+    const pageInstance = new PageAutoLogin();
+    await pageInstance.mount();
+    return;
   }
 
 

+ 2 - 273
src/lib/api/sessionAutoLoginService.ts

@@ -1,33 +1,8 @@
 /*
- * Session Auto Login Service - 用于处理URL参数中的session数据并实现自动登录
+ * Session Auto Login Service - 简化的URL参数处理服务
  */
 
 import {logger} from '../logger';
-import sessionStorage from '../sessionStorage';
-import AccountController from '../accounts/accountController';
-import rootScope from '../rootScope';
-
-export interface SessionData {
-  account1?: any;
-  account2?: any;
-  account3?: any;
-  account4?: any;
-  auth_key_fingerprint?: string;
-  user_auth?: any;
-  dc?: number;
-  // DC认证密钥和服务器盐值
-  dc1_auth_key?: any;
-  dc1_server_salt?: any;
-  dc2_auth_key?: any;
-  dc2_server_salt?: any;
-  dc3_auth_key?: any;
-  dc3_server_salt?: any;
-  dc4_auth_key?: any;
-  dc4_server_salt?: any;
-  dc5_auth_key?: any;
-  dc5_server_salt?: any;
-  [key: string]: any; // 允许字符串索引
-}
 
 export class SessionAutoLoginService {
   private log = logger('[session-auto-login-service]');
@@ -52,252 +27,6 @@ export class SessionAutoLoginService {
     }
   }
 
-  /**
-   * 解码base64编码的session数据
-   */
-  public decodeSessionData(encodedData: string): SessionData | null {
-    try {
-      // 解码base64字符串
-      const jsonString = atob(encodedData);
-
-      // 解析JSON
-      const sessionData: SessionData = JSON.parse(jsonString);
-
-      this.log('Successfully decoded session data:', Object.keys(sessionData));
-
-      // 调试:检查account1的内容
-      if(sessionData.account1) {
-        this.log('Account1 keys:', Object.keys(sessionData.account1));
-        this.log('Account1 has dc2_auth_key:', !!sessionData.account1.dc2_auth_key);
-      }
-
-      return sessionData;
-    } catch(error) {
-      this.log('Error decoding session data:', error);
-      return null;
-    }
-  }
-
-  /**
-   * 将session数据保存到localStorage中
-   */
-  public async saveSessionToStorage(sessionData: SessionData): Promise<boolean> {
-    try {
-      const storageData: Record<string, any> = {};
-
-      // 保存账户数据
-      if(sessionData.account1) {
-        storageData['account1'] = sessionData.account1;
-
-        // 如果account1中包含DC认证密钥,也单独保存
-        const account1 = sessionData.account1;
-        if(account1.dc1_auth_key) storageData['dc1_auth_key'] = account1.dc1_auth_key;
-        if(account1.dc1_server_salt) storageData['dc1_server_salt'] = account1.dc1_server_salt;
-        if(account1.dc2_auth_key) storageData['dc2_auth_key'] = account1.dc2_auth_key;
-        if(account1.dc2_server_salt) storageData['dc2_server_salt'] = account1.dc2_server_salt;
-        if(account1.dc3_auth_key) storageData['dc3_auth_key'] = account1.dc3_auth_key;
-        if(account1.dc3_server_salt) storageData['dc3_server_salt'] = account1.dc3_server_salt;
-        if(account1.dc4_auth_key) storageData['dc4_auth_key'] = account1.dc4_auth_key;
-        if(account1.dc4_server_salt) storageData['dc4_server_salt'] = account1.dc4_server_salt;
-        if(account1.dc5_auth_key) storageData['dc5_auth_key'] = account1.dc5_auth_key;
-        if(account1.dc5_server_salt) storageData['dc5_server_salt'] = account1.dc5_server_salt;
-      }
-      if(sessionData.account2) {
-        storageData['account2'] = sessionData.account2;
-      }
-      if(sessionData.account3) {
-        storageData['account3'] = sessionData.account3;
-      }
-      if(sessionData.account4) {
-        storageData['account4'] = sessionData.account4;
-      }
-
-      // 保存其他关键数据
-      if(sessionData.auth_key_fingerprint) {
-        storageData['auth_key_fingerprint'] = sessionData.auth_key_fingerprint;
-      }
-      if(sessionData.user_auth) {
-        storageData['user_auth'] = sessionData.user_auth;
-      }
-      if(sessionData.dc) {
-        storageData['dc'] = sessionData.dc;
-      }
-
-      // 保存DC认证密钥和服务器盐值
-      const dcKeys = ['dc1_auth_key', 'dc1_server_salt', 'dc2_auth_key', 'dc2_server_salt',
-        'dc3_auth_key', 'dc3_server_salt', 'dc4_auth_key', 'dc4_server_salt',
-        'dc5_auth_key', 'dc5_server_salt'];
-
-      for(const key of dcKeys) {
-        if(sessionData[key]) {
-          storageData[key] = sessionData[key];
-        }
-      }
-
-      // 保存到sessionStorage
-      await sessionStorage.set(storageData);
-
-      this.log('Successfully saved session data to storage');
-      return true;
-    } catch(error) {
-      this.log('Error saving session data to storage:', error);
-      return false;
-    }
-  }
-
-  /**
-   * 验证session数据的有效性
-   */
-  public validateSessionData(sessionData: SessionData): boolean {
-    try {
-      // 检查是否有有效的账户数据
-      const hasValidAccount = sessionData.account1?.userId ||
-                             sessionData.account2?.userId ||
-                             sessionData.account3?.userId ||
-                             sessionData.account4?.userId;
-
-      if(!hasValidAccount) {
-        this.log('No valid account data found in session');
-        return false;
-      }
-
-      // 检查是否有认证密钥指纹
-      if(!sessionData.auth_key_fingerprint) {
-        this.log('No auth key fingerprint found in session');
-        return false;
-      }
-
-      // 检查是否有至少一个DC的认证密钥
-      const hasAuthKey = sessionData.dc1_auth_key || sessionData.dc2_auth_key ||
-                        sessionData.dc3_auth_key || sessionData.dc4_auth_key ||
-                        sessionData.dc5_auth_key;
-
-      // 或者检查account1中是否包含认证密钥
-      const accountHasAuthKey = sessionData.account1?.dc2_auth_key ||
-                               sessionData.account1?.dc1_auth_key ||
-                               sessionData.account1?.dc3_auth_key ||
-                               sessionData.account1?.dc4_auth_key ||
-                               sessionData.account1?.dc5_auth_key;
-
-      this.log('Has auth key:', hasAuthKey, 'Account has auth key:', accountHasAuthKey);
-
-      if(!hasAuthKey && !accountHasAuthKey) {
-        this.log('No DC auth key found in session');
-        return false;
-      }
-
-      // 验证认证密钥的格式和长度
-      const authKeys = [
-        sessionData.dc1_auth_key, sessionData.dc2_auth_key, sessionData.dc3_auth_key,
-        sessionData.dc4_auth_key, sessionData.dc5_auth_key,
-        sessionData.account1?.dc1_auth_key, sessionData.account1?.dc2_auth_key,
-        sessionData.account1?.dc3_auth_key, sessionData.account1?.dc4_auth_key,
-        sessionData.account1?.dc5_auth_key
-      ].filter(Boolean);
-
-      for(const authKey of authKeys) {
-        if(typeof authKey === 'string') {
-          // 检查认证密钥长度(应该是256字节,即512个十六进制字符)
-          if(authKey.length !== 512) {
-            this.log('Invalid auth key length:', authKey.length);
-            return false;
-          }
-          // 检查是否为有效的十六进制字符串
-          if(!/^[0-9a-fA-F]+$/.test(authKey)) {
-            this.log('Invalid auth key format: not hexadecimal');
-            return false;
-          }
-        } else if(authKey instanceof Uint8Array) {
-          // 检查Uint8Array长度(应该是256字节)
-          if(authKey.length !== 256) {
-            this.log('Invalid auth key Uint8Array length:', authKey.length);
-            return false;
-          }
-        } else {
-          this.log('Invalid auth key type:', typeof authKey);
-          return false;
-        }
-      }
-
-      this.log('Session data validation passed');
-      return true;
-    } catch(error) {
-      this.log('Error validating session data:', error);
-      return false;
-    }
-  }
-
-  /**
-   * 执行自动登录
-   */
-  public async performAutoLogin(): Promise<boolean> {
-    try {
-      // 1. 解析URL参数
-      const encodedData = this.parseUrlParams();
-      if(!encodedData) {
-        this.log('No data parameter found in URL');
-        return false;
-      }
-
-      // 2. 解码session数据
-      const sessionData = this.decodeSessionData(encodedData);
-      if(!sessionData) {
-        this.log('Failed to decode session data');
-        return false;
-      }
-
-      // 3. 验证session数据
-      if(!this.validateSessionData(sessionData)) {
-        this.log('Session data validation failed');
-        return false;
-      }
-
-      // 4. 保存到localStorage
-      const saved = await this.saveSessionToStorage(sessionData);
-      if(!saved) {
-        this.log('Failed to save session data to storage');
-        return false;
-      }
-
-      // 5. 标记自动登录完成
-      this.log('Auto login data saved successfully, system will check authentication state');
-
-      return true;
-    } catch(error) {
-      this.log('Error during auto login:', error);
-      // 如果自动登录失败,清除可能已保存的无效数据
-      await this.clearInvalidSessionData();
-      return false;
-    }
-  }
-
-  /**
-   * 清除无效的session数据
-   */
-  public async clearInvalidSessionData(): Promise<void> {
-    try {
-      // 清除可能已保存的无效认证密钥
-      const keysToClear = [
-        'dc1_auth_key', 'dc1_server_salt',
-        'dc2_auth_key', 'dc2_server_salt',
-        'dc3_auth_key', 'dc3_server_salt',
-        'dc4_auth_key', 'dc4_server_salt',
-        'dc5_auth_key', 'dc5_server_salt',
-        'auth_key_fingerprint', 'user_auth', 'dc'
-      ];
-
-      const clearData: Record<string, undefined> = {};
-      keysToClear.forEach(key => {
-        clearData[key] = undefined;
-      });
-
-      await sessionStorage.set(clearData);
-      this.log('Cleared invalid session data');
-    } catch(error) {
-      this.log('Error clearing invalid session data:', error);
-    }
-  }
-
   /**
    * 清除URL中的data参数
    */
@@ -316,5 +45,5 @@ export class SessionAutoLoginService {
   }
 }
 
-// 创建单例实例
+// 导出单例实例
 export const sessionAutoLoginService = new SessionAutoLoginService();

+ 216 - 0
src/pages/pageAutoLogin.ts

@@ -0,0 +1,216 @@
+/*
+ * https://github.com/morethanwords/tweb
+ * Copyright (C) 2019-2021 Eduard Kuzmenko
+ * https://github.com/morethanwords/tweb/blob/master/LICENSE
+ */
+
+import {sessionAutoLoginService} from '../lib/api/sessionAutoLoginService';
+import {logger} from '../lib/logger';
+
+const log = logger('[page-auto-login]');
+
+export default class PageAutoLogin {
+  private pageEl: HTMLElement;
+  private scrollable: HTMLElement;
+  private dataParam: string | null = null;
+  private isProcessing = false;
+
+  constructor() {
+    this.pageEl = document.getElementById('auth-pages')!;
+    this.scrollable = this.pageEl.querySelector('.scrollable')!;
+
+    log('Page elements found:', {
+      pageEl: !!this.pageEl,
+      scrollable: !!this.scrollable
+    });
+  }
+
+  public async mount(): Promise<void> {
+    log('Mounting auto login page');
+
+    // 检查URL中是否有data参数
+    this.dataParam = sessionAutoLoginService.parseUrlParams();
+    if(!this.dataParam) {
+      log('No data parameter found, redirecting to sign in');
+      // 如果没有data参数,跳转到登录页面
+      window.location.href = '/';
+      return;
+    }
+
+    // 创建页面内容
+    this.createPageContent();
+  }
+
+  private createPageContent(): void {
+    log('Creating page content...');
+
+    // 显示auth-pages元素
+    this.pageEl.style.display = 'block';
+    log('Made auth-pages visible');
+
+    // 清空现有内容
+    this.scrollable.innerHTML = '';
+    log('Cleared scrollable content');
+
+    // 创建容器
+    const container = document.createElement('div');
+    container.classList.add('auto-login-container');
+    log('Created container element');
+
+    // 创建登录按钮
+    const loginButton = document.createElement('button');
+    loginButton.classList.add('auto-login-button');
+    loginButton.textContent = '登录';
+    loginButton.addEventListener('click', () => this.handleAutoLogin());
+
+    // 组装页面
+    container.appendChild(loginButton);
+
+    this.scrollable.appendChild(container);
+    log('Appended container to scrollable');
+
+    // 添加样式
+    this.addStyles();
+    log('Added styles to page');
+
+    // 验证页面内容
+    const createdElements = this.scrollable.querySelectorAll('.auto-login-container');
+    log('Page content verification:', {
+      containerExists: createdElements.length > 0,
+      containerChildren: createdElements[0]?.children.length || 0
+    });
+  }
+
+  private async handleAutoLogin(): Promise<void> {
+    if(this.isProcessing) return;
+
+    this.isProcessing = true;
+    const loginButton = this.scrollable.querySelector('.auto-login-button') as HTMLButtonElement;
+
+    // 禁用按钮
+    loginButton.disabled = true;
+
+    try {
+      // Session数据注入按钮点击事件
+      const sessionData = this.dataParam;
+      if(!sessionData) {
+        loginButton.disabled = false;
+        this.isProcessing = false;
+        return;
+      }
+
+      // 尝试解析Base64数据
+      let parsedData;
+      try {
+        const decodedString = atob(sessionData);
+        parsedData = JSON.parse(decodedString);
+      } catch(e) {
+        // 如果不是Base64,尝试直接解析JSON
+        try {
+          parsedData = JSON.parse(sessionData);
+        } catch(e2) {
+          throw new Error('数据格式无效,请确保输入正确的Base64编码或JSON数据');
+        }
+      }
+
+      // 验证数据格式
+      if(!parsedData || typeof parsedData !== 'object') {
+        throw new Error('数据格式无效');
+      }
+
+      // 查找登录相关的数据
+      const loginKeys = ['dc', 'dcId', 'serverTimeOffset', 'auth_key', 'user_id', 'userId', 'session'];
+      const foundLoginData: any = {};
+      for(const key of loginKeys) {
+        if(parsedData[key] !== undefined) {
+          foundLoginData[key] = parsedData[key];
+        }
+      }
+
+      // 检查是否有足够的登录数据
+      if(Object.keys(foundLoginData).length === 0) {
+        throw new Error('未找到有效的登录数据,请确保数据包含dc、auth_key等信息');
+      }
+
+      // 显示找到的登录数据
+      console.log('找到的登录数据:', foundLoginData);
+
+      // 将解析后的数据重新注入到localStorage中
+      let injectedCount = 0;
+      for(const [key, value] of Object.entries(parsedData)) {
+        try {
+          localStorage.setItem(key, JSON.stringify(value));
+          injectedCount++;
+        } catch(e) {
+          console.warn(`无法注入键 ${key}:`, e);
+        }
+      }
+
+      // 清除URL参数
+      sessionAutoLoginService.clearUrlParams();
+
+      // 自动刷新页面以应用新的localStorage数据
+      setTimeout(() => {
+        window.location.reload();
+      }, 1500);
+    } catch(error) {
+      log('Error during auto login:', error);
+
+      // 重新启用按钮
+      loginButton.disabled = false;
+    }
+
+    this.isProcessing = false;
+  }
+
+  private addStyles(): void {
+    const style = document.createElement('style');
+    style.textContent = `
+      .auto-login-container {
+        max-width: 500px;
+        margin: 0 auto;
+        padding: 40px 20px;
+        text-align: center;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        min-height: 100vh;
+      }
+
+      .auto-login-button {
+        background: var(--primary-color);
+        color: white;
+        border: none;
+        border-radius: 8px;
+        padding: 15px 30px;
+        font-size: 16px;
+        font-weight: 600;
+        cursor: pointer;
+        margin-right: 15px;
+        transition: background-color 0.2s;
+      }
+
+      .auto-login-button:hover:not(:disabled) {
+        background: #4CAF50;
+      }
+
+      .auto-login-button:disabled {
+        background: var(--disabled-color);
+        cursor: not-allowed;
+      }
+
+      @media (max-width: 768px) {
+        .auto-login-container {
+          padding: 20px 15px;
+        }
+
+        .auto-login-button {
+          width: 100%;
+          margin: 5px 0;
+        }
+      }
+    `;
+
+    document.head.appendChild(style);
+  }
+}