File size: 3,416 Bytes
fb38ec5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { EventEmitter } from "events";
import { FastifyBaseLogger } from "fastify";
import { getProfilePath } from "../../utils/context.js";
import { ChromeLocalStorageReader } from "../leveldb/localstorage.js";
import { ChromeSessionStorageReader } from "../leveldb/sessionstorage.js";
import { SessionData } from "./types.js";

export class ChromeContextService extends EventEmitter {
  private logger: FastifyBaseLogger;

  constructor(logger: FastifyBaseLogger) {
    super();
    this.logger = logger;
  }

  /**
   * Get all session data from a Chrome user data directory
   * @param userDataDir Path to Chrome user data directory
   * @returns SessionData containing cookies, localStorage, sessionStorage, and more
   */
  public async getSessionData(userDataDir?: string): Promise<SessionData> {
    if (!userDataDir) {
      this.logger.warn("No userDataDir specified, returning empty session data");
      return {
        localStorage: {},
        sessionStorage: {},
        indexedDB: {},
        cookies: [],
      };
    }

    this.logger.info(`Extracting session data from Chrome user data directory: ${userDataDir}`);

    try {
      const sessionData: SessionData = {};

      const [localStorage, sessionStorage] = await Promise.all([
        this.extractLocalStorage(userDataDir),
        this.extractSessionStorage(userDataDir),
      ]);

      if (localStorage && Object.keys(localStorage).length > 0) {
        sessionData.localStorage = localStorage;
      }

      if (sessionStorage && Object.keys(sessionStorage).length > 0) {
        sessionData.sessionStorage = sessionStorage;
      }

      return sessionData;
    } catch (error: unknown) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.logger.error(`Error extracting session data: ${errorMessage}`);
      throw new Error(`Failed to extract session data: ${errorMessage}`);
    }
  }

  /**
   * Extract localStorage from Chrome's LevelDB database
   */
  private async extractLocalStorage(
    userDataDir: string,
  ): Promise<Record<string, Record<string, string>>> {
    const localStoragePath = getProfilePath(userDataDir, "Local Storage", "leveldb");
    this.logger.info(`Extracting localStorage from ${localStoragePath}`);

    try {
      this.logger.info(`Reading localStorage from ${localStoragePath}`);
      return await ChromeLocalStorageReader.readLocalStorage(localStoragePath);
    } catch (error: unknown) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.logger.error(`Error extracting localStorage: ${errorMessage}`);
      return {};
    }
  }

  /**
   * Extract sessionStorage from Chrome's Session Storage
   */
  private async extractSessionStorage(
    userDataDir: string,
  ): Promise<Record<string, Record<string, string>>> {
    // Normalize path for cross-platform compatibility
    const sessionStoragePath = getProfilePath(userDataDir, "Session Storage");

    try {
      this.logger.info(`Reading sessionStorage from ${sessionStoragePath}`);
      const sessionStorage =
        await ChromeSessionStorageReader.readSessionStorage(sessionStoragePath);
      return sessionStorage;
    } catch (error: unknown) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.logger.error(`Error extracting sessionStorage: ${errorMessage}`);
      return {};
    }
  }
}