diff --git a/package.json b/package.json index 3a30a35c..3bd306a2 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "author": "Karishma Shukla", "license": "", "dependencies": { + "@cliqz/adblocker-playwright": "^1.30.0", "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", "@mui/icons-material": "^5.5.1", @@ -21,15 +22,17 @@ "axios": "^0.26.0", "buffer": "^6.0.3", "cors": "^2.8.5", + "cross-fetch": "^4.0.0", "dotenv": "^16.0.0", "express": "^4.17.2", "fortawesome": "^0.0.1-security", - "html2canvas-pro": "^1.5.3", "joi": "^17.6.0", "loglevel": "^1.8.0", "loglevel-plugin-remote": "^0.6.8", "playwright": "^1.18.1", + "playwright-extra": "^4.3.6", "prismjs": "^1.28.0", + "puppeteer-extra-plugin-stealth": "^2.11.2", "react": "^18.0.0", "react-dom": "^18.0.0", "react-highlight": "^0.14.0", diff --git a/server/src/browser-management/classes/BrowserPool.ts b/server/src/browser-management/classes/BrowserPool.ts index 736189db..cd4962a1 100644 --- a/server/src/browser-management/classes/BrowserPool.ts +++ b/server/src/browser-management/classes/BrowserPool.ts @@ -38,7 +38,7 @@ export class BrowserPool { /** * Holds all the instances of remote browsers. */ - private pool : PoolDictionary = {}; + private pool: PoolDictionary = {}; /** * Adds a remote browser instance to the pool indexed by the id. @@ -62,12 +62,12 @@ export class BrowserPool { * @param id remote browser instance's id * @returns true if the browser was removed successfully, false otherwise */ - public deleteRemoteBrowser = (id: string) : boolean => { + public deleteRemoteBrowser = (id: string): boolean => { if (!this.pool[id]) { logger.log('warn', `Remote browser with id: ${id} does not exist in the pool`); return false; } - delete(this.pool[id]); + delete (this.pool[id]); logger.log('debug', `Remote browser with id: ${id} deleted from the pool`); return true; }; @@ -77,7 +77,7 @@ export class BrowserPool { * @param id remote browser instance's id * @returns remote browser instance or undefined if it does not exist in the pool */ - public getRemoteBrowser = (id: string) : RemoteBrowser | undefined => { + public getRemoteBrowser = (id: string): RemoteBrowser | undefined => { logger.log('debug', `Remote browser with id: ${id} retrieved from the pool`); return this.pool[id]?.browser; }; @@ -88,7 +88,7 @@ export class BrowserPool { * If there are multiple active browsers, it returns the first one. * @returns the first remote active browser instance's id from the pool */ - public getActiveBrowserId = () : string | null => { + public getActiveBrowserId = (): string | null => { for (const id of Object.keys(this.pool)) { if (this.pool[id].active) { return id; diff --git a/server/src/browser-management/classes/RemoteBrowser.ts b/server/src/browser-management/classes/RemoteBrowser.ts index d7376537..04facda6 100644 --- a/server/src/browser-management/classes/RemoteBrowser.ts +++ b/server/src/browser-management/classes/RemoteBrowser.ts @@ -5,12 +5,16 @@ import { BrowserContext, } from 'playwright'; import { Socket } from "socket.io"; +import { fullLists, PlaywrightBlocker, Request } from '@cliqz/adblocker-playwright'; +import fetch from 'cross-fetch'; import logger from '../../logger'; import { InterpreterSettings, RemoteBrowserOptions } from "../../types"; import { WorkflowGenerator } from "../../workflow-management/classes/Generator"; import { WorkflowInterpreter } from "../../workflow-management/classes/Interpreter"; + + /** * This class represents a remote browser instance. * It is used to allow a variety of interaction with the Playwright's browser instance. @@ -88,7 +92,10 @@ export class RemoteBrowser { this.browser = (await options.browser.launch(options.launchOptions)); const context = await this.browser.newContext(); this.currentPage = await context.newPage(); + const blocker = await PlaywrightBlocker.fromPrebuiltAdsAndTracking(fetch); + await blocker.enableBlockingInPage(this.currentPage); this.client = await this.currentPage.context().newCDPSession(this.currentPage); + await blocker.disableBlockingInPage(this.currentPage); }; /** diff --git a/server/src/routes/record.ts b/server/src/routes/record.ts index 0a20f66c..0f12f5c9 100644 --- a/server/src/routes/record.ts +++ b/server/src/routes/record.ts @@ -11,10 +11,12 @@ import { stopRunningInterpretation, getRemoteBrowserCurrentUrl, getRemoteBrowserCurrentTabs, } from '../browser-management/controller' -import { chromium } from "playwright"; +import { chromium } from 'playwright-extra'; +import stealthPlugin from 'puppeteer-extra-plugin-stealth'; import logger from "../logger"; export const router = Router(); +chromium.use(stealthPlugin()); /** * Logs information about remote browser recording session. diff --git a/server/src/workflow-management/utils.ts b/server/src/workflow-management/utils.ts index 775a0b55..c10d2c13 100644 --- a/server/src/workflow-management/utils.ts +++ b/server/src/workflow-management/utils.ts @@ -89,4 +89,4 @@ export const getBestSelectorForAction = (action: Action) => { break; } return null; -} +} \ No newline at end of file diff --git a/src/App.test.tsx b/src/App.test.tsx new file mode 100644 index 00000000..2a68616d --- /dev/null +++ b/src/App.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +});