diff --git a/deploy/playbooks/setup.yml b/deploy/playbooks/setup.yml index 9279d5b..e2c8196 100644 --- a/deploy/playbooks/setup.yml +++ b/deploy/playbooks/setup.yml @@ -267,6 +267,55 @@ - libgif-dev - librsvg2-dev + - name: Install Playwright system dependencies + # NOTE: I copied the package list from the source list for + # `npx playwright install-deps`, which I couldn't get running in + # Ansible as root, and besides, I prefer manually managing the + # package list over running an npm script as root! + become: yes + apt: + update_cache: yes + name: + # Tools + - xvfb + - fonts-noto-color-emoji + - ttf-unifont + - libfontconfig + - libfreetype6 + - xfonts-cyrillic + - xfonts-scalable + - fonts-liberation + - fonts-ipafont-gothic + - fonts-wqy-zenhei + - fonts-tlwg-loma-otf + - ttf-ubuntu-font-family + # Chromium + - fonts-liberation + - libasound2 + - libatk-bridge2.0-0 + - libatk1.0-0 + - libatspi2.0-0 + - libcairo2 + - libcups2 + - libdbus-1-3 + - libdrm2 + - libegl1 + - libgbm1 + - libglib2.0-0 + - libgtk-3-0 + - libnspr4 + - libnss3 + - libpango-1.0-0 + - libx11-6 + - libx11-xcb1 + - libxcb1 + - libxcomposite1 + - libxdamage1 + - libxext6 + - libxfixes3 + - libxrandr2 + - libxshmfence1 + handlers: - name: Restart nginx become: yes diff --git a/package.json b/package.json index b0dea43..28078d6 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "mysql2": "^2.1.0", "next": "12.0.2", "node-fetch": "^2.6.0", - "playwright-core": "^1.14.0", + "playwright": "^1.16.3", "react": "^17.0.1", "react-autosuggest": "^10.0.2", "react-dom": "^17.0.1", @@ -112,7 +112,6 @@ "inquirer": "^7.3.3", "jest-image-snapshot": "^4.3.0", "lint-staged": "^10.5.4", - "playwright": "^1.14.0", "prettier": "^2.0.5", "react-is": "^16.13.1", "ts-node": "^9.1.1", diff --git a/pages/api/assetImage.js b/pages/api/assetImage.js index 1a13c08..0c285ea 100644 --- a/pages/api/assetImage.js +++ b/pages/api/assetImage.js @@ -22,6 +22,8 @@ const beeline = require("honeycomb-beeline")({ disableInstrumentationOnLoad: true, }); +const playwright = require("playwright"); + // To render the image, we load the /internal/assetImage page in the web app, // a simple page specifically designed for this API endpoint! const ASSET_IMAGE_PAGE_BASE_URL = process.env.VERCEL_URL @@ -30,25 +32,21 @@ const ASSET_IMAGE_PAGE_BASE_URL = process.env.VERCEL_URL ? "http://localhost:3000/internal/assetImage" : "https://impress-2020.openneo.net/internal/assetImage"; -// TODO: We used to share a browser instamce, but we couldn't get it to reload -// correctly after accidental closes, so we're just gonna always load a -// new one now. What are the perf implications of this? Does it slow down -// response time substantially? -async function getBrowser() { - if (process.env["NODE_ENV"] === "production") { - // In production, we use a special chrome-aws-lambda Chromium. - const chromium = require("chrome-aws-lambda"); - const playwright = require("playwright-core"); - return await playwright.chromium.launch({ - args: chromium.args, - executablePath: await chromium.executablePath, - headless: true, - }); - } else { - // In development, we use the standard playwright Chromium. - const playwright = require("playwright"); - return await playwright.chromium.launch({ headless: true }); +// We share one browser instance, but create a new independent "context" for +// each request, as a security hedge. (The intent is for the user to request +// very little from the browser, so it shouldn't matter, but it's just an extra +// layer to reduce the risk of what an attack could do!) +// +// TODO: We're probably going to need to limit the number of concurrent browser +// sessions here, right? I don't actually know how the Next.js server +// handles concurrency though, let's pressure-test and find out before +// building a solution. +let SHARED_BROWSER = null; +async function getBrowserContext() { + if (SHARED_BROWSER == null) { + SHARED_BROWSER = await playwright.chromium.launch({ headless: true }); } + return await SHARED_BROWSER.newContext(); } async function handle(req, res) { @@ -93,8 +91,8 @@ async function loadAndScreenshotImage(libraryUrl, size) { }).toString(); console.debug("Opening browser page"); - const browser = await getBrowser(); - const page = await browser.newPage(); + const context = await getBrowserContext(); + const page = await context.newPage(); console.debug("Page opened, navigating to: " + assetImagePageUrl.toString()); try { @@ -130,7 +128,7 @@ async function loadAndScreenshotImage(libraryUrl, size) { console.warn("Error closing page after image finished", e); } try { - await browser.close(); + await context.close(); } catch (e) { console.warn("Error closing browser after image finished", e); } diff --git a/yarn.lock b/yarn.lock index 5277daf..ae5a791 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3523,7 +3523,7 @@ agent-base@4, agent-base@^4.2.0, agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -4961,11 +4961,16 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commander@^6.1.0, commander@^6.2.0: +commander@^6.2.0: version "6.2.1" resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== +commander@^8.2.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + common-tags@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" @@ -9675,12 +9680,12 @@ platform@1.3.6: resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== -playwright-core@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.14.0.tgz#af51da7b201c11eeda780e2db3f05c8bca74c8be" - integrity sha512-n6NdknezSfRgB6LkLwcrbm5orRQZSpbd8LZmlc4YrIXV0VEvJr5tzP3xlHXpiFBfTr3yoFuagldI3T7bD/8H3w== +playwright-core@=1.16.3: + version "1.16.3" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.16.3.tgz#f466be9acaffb698654adfb0a17a4906ba936895" + integrity sha512-16hF27IvQheJee+DbhC941AUZLjbJgfZFWi9YPS4LKEk/lKFhZI+9TiFD0sboYqb9eaEWvul47uR5xxTVbE4iw== dependencies: - commander "^6.1.0" + commander "^8.2.0" debug "^4.1.1" extract-zip "^2.0.1" https-proxy-agent "^5.0.0" @@ -9691,29 +9696,18 @@ playwright-core@^1.14.0: proper-lockfile "^4.1.1" proxy-from-env "^1.1.0" rimraf "^3.0.2" + socks-proxy-agent "^6.1.0" stack-utils "^2.0.3" ws "^7.4.6" + yauzl "^2.10.0" yazl "^2.5.1" -playwright@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.14.0.tgz#18301b11f5278a446d36b5cf96f67db36ce2cd20" - integrity sha512-aR5oZ1iVsjQkGfYCjgYAmyMAVu0MQ0i8MgdnfdqDu9EVLfbnpuuFmTv/Rb7/Yjno1kOrDUP9+RyNC+zfG3wozA== +playwright@^1.16.3: + version "1.16.3" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.16.3.tgz#27a292d9fa54fbac923998d3af58cd2b691f5ebe" + integrity sha512-nfJx/OpIb/8OexL3rYGxNN687hGyaM3XNpfuMzoPlrekURItyuiHHsNhC9oQCx3JDmCn5O3EyyyFCnrZjH6MpA== dependencies: - commander "^6.1.0" - debug "^4.1.1" - extract-zip "^2.0.1" - https-proxy-agent "^5.0.0" - jpeg-js "^0.4.2" - mime "^2.4.6" - pngjs "^5.0.0" - progress "^2.0.3" - proper-lockfile "^4.1.1" - proxy-from-env "^1.1.0" - rimraf "^3.0.2" - stack-utils "^2.0.3" - ws "^7.4.6" - yazl "^2.5.1" + playwright-core "=1.16.3" please-upgrade-node@^3.2.0: version "3.2.0" @@ -10928,6 +10922,23 @@ socks-proxy-agent@^4.0.1: agent-base "~4.2.1" socks "~2.3.2" +socks-proxy-agent@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" + integrity sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg== + dependencies: + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" + +socks@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" + integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.1.0" + socks@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.3.tgz#01129f0a5d534d2b897712ed8aceab7ee65d78e3"