From aaabff8db1ac463a2cbe40c28048a30c83c18c51 Mon Sep 17 00:00:00 2001
From: charlocharlie <charlielaabs@gmail.com>
Date: Sun, 8 Sep 2024 21:28:55 -0500
Subject: [PATCH] Cleanup puppeteer dev profiles on exit. Resolves #396

---
 src/common/puppeteer.ts | 18 ++++++++++++++++--
 src/index.ts            |  6 ++++--
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/src/common/puppeteer.ts b/src/common/puppeteer.ts
index db4a212..80a8f96 100644
--- a/src/common/puppeteer.ts
+++ b/src/common/puppeteer.ts
@@ -4,6 +4,10 @@ import StealthPlugin from 'puppeteer-extra-plugin-stealth';
 import { Logger } from 'pino';
 import pTimeout, { TimeoutError } from 'p-timeout';
 import psList from 'ps-list';
+import os from 'node:os';
+import fs from 'node:fs/promises';
+import fsx from 'fs-extra/esm';
+import path from 'node:path';
 
 import { ETCCookie, ToughCookieFileStore } from './cookie.js';
 import { config } from './config/index.js';
@@ -19,8 +23,8 @@ export default puppeteer;
 export function toughCookieFileStoreToPuppeteerCookie(tcfs: ToughCookieFileStore): CookieParam[] {
   const puppetCookies: CookieParam[] = [];
   Object.values(tcfs).forEach((domain) => {
-    Object.values(domain).forEach((path) => {
-      Object.values(path).forEach((tcfsCookie) => {
+    Object.values(domain).forEach((urlPath) => {
+      Object.values(urlPath).forEach((tcfsCookie) => {
         puppetCookies.push({
           name: tcfsCookie.key,
           value: tcfsCookie.value,
@@ -129,6 +133,16 @@ export const killBrowserProcesses = async (L: Logger) => {
   browserProcesses.forEach((p) => process.kill(p.pid));
 };
 
+export const cleanupDevProfiles = async (L: Logger) => {
+  if (!getCommitSha()) return; // Don't clear if not in docker
+  const tempDir = os.tmpdir();
+  const profileMatcher = /^puppeteer_dev_profile-\w+$/;
+  const tempFiles = await fs.readdir(tempDir);
+  const devProfiles = tempFiles.filter((file) => profileMatcher.test(file));
+  L.debug({ devProfiles }, 'Deleting temp puppeteer dev profile folders');
+  await Promise.all([devProfiles.map((file) => fsx.remove(path.join(tempDir, file)))]);
+};
+
 /**
  * Create a new page within a wrapper that will retry if it hangs for 30 seconds
  */
diff --git a/src/index.ts b/src/index.ts
index 8a44ecd..27827d6 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -5,7 +5,7 @@ import logger from './common/logger.js';
 import { sendNotification, testNotifiers } from './notify.js';
 import { checkForUpdate, logVersionOnError } from './version.js';
 import PuppetLogin from './puppet/login.js';
-import { killBrowserProcesses, safeLaunchBrowser } from './common/puppeteer.js';
+import { cleanupDevProfiles, killBrowserProcesses, safeLaunchBrowser } from './common/puppeteer.js';
 import PuppetFreeGames from './puppet/free-games.js';
 import { createServer } from './common/server.js';
 import { convertImportCookies } from './common/cookie.js';
@@ -85,6 +85,7 @@ export async function main(): Promise<void> {
     await Promise.all(accountPromises);
     server.close();
     await killBrowserProcesses(logger);
+    await cleanupDevProfiles(logger);
     logger.info('Exiting successfully');
     exit(0); // For some reason, puppeteer will keep a zombie promise alive and stop Node from exiting
   }
@@ -92,7 +93,8 @@ export async function main(): Promise<void> {
 
 main().catch(async (err) => {
   logger.error(err);
-  await killBrowserProcesses(logger);
   logVersionOnError();
+  await killBrowserProcesses(logger);
+  await cleanupDevProfiles(logger);
   exit(1);
 });