diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 381755b606..7e3b820762 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,9 @@ on: branches: [develop, master] merge_group: types: [checks_requested] +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} # develop pushes and repository_dispatch handled in build_develop.yaml env: # These must be set for fetchdep.sh to get the right branch @@ -37,14 +40,38 @@ jobs: - uses: actions/setup-node@v4 with: - cache: "yarn" + # Disable cache on Windows as it is slower than not caching + # https://github.com/actions/setup-node/issues/975 + cache: ${{ runner.os != 'Windows' && 'yarn' || '' }} node-version: "lts/*" # Workaround for yarn install timeouts, especially on Windows - run: yarn config set network-timeout 300000 - - name: Install Dependencies - run: "./scripts/layered.sh" + - name: Fetch layered build + id: layered_build + env: + # tell layered.sh to check out the right sha of the JS-SDK & EW, if they were given one + JS_SDK_GITHUB_BASE_REF: ${{ inputs.matrix-js-sdk-sha }} + run: | + scripts/layered.sh + JSSDK_SHA=$(git -C matrix-js-sdk rev-parse --short=12 HEAD) + VECTOR_SHA=$(git rev-parse --short=12 HEAD) + echo "VERSION=$VECTOR_SHA--js-$JSSDK_SHA" >> $GITHUB_OUTPUT + + - name: Copy config + run: cp element.io/develop/config.json config.json - name: Build - run: "yarn build" + env: + CI_PACKAGE: true + VERSION: "${{ steps.layered_build.outputs.VERSION }}" + run: | + yarn build + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: webapp-${{ matrix.image }} + path: webapp + retention-days: 1 diff --git a/.github/workflows/dockerhub.yaml b/.github/workflows/dockerhub.yaml index 8dae6cf5ab..0146f41050 100644 --- a/.github/workflows/dockerhub.yaml +++ b/.github/workflows/dockerhub.yaml @@ -27,7 +27,7 @@ jobs: uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3 + uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 with: install: true diff --git a/.github/workflows/netlify.yaml b/.github/workflows/netlify.yaml index 63bac7d33f..cd03ca5140 100644 --- a/.github/workflows/netlify.yaml +++ b/.github/workflows/netlify.yaml @@ -3,7 +3,7 @@ name: Upload Preview Build to Netlify on: workflow_run: - workflows: ["End to End Tests"] + workflows: ["Build"] types: - completed jobs: @@ -32,7 +32,7 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} - name: webapp + name: webapp-ubuntu-24.04 path: webapp - name: šŸ“¤ Deploy to Netlify diff --git a/.github/workflows/playwright-image-updates.yaml b/.github/workflows/playwright-image-updates.yaml index 1613b42dfb..ef2dfa1132 100644 --- a/.github/workflows/playwright-image-updates.yaml +++ b/.github/workflows/playwright-image-updates.yaml @@ -23,7 +23,7 @@ jobs: - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7 + uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7 with: token: ${{ secrets.ELEMENT_BOT_TOKEN }} branch: actions/playwright-image-updates diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 35803a60f1..dfb92e8ba0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -104,7 +104,7 @@ jobs: - name: Skip SonarCloud in merge queue if: github.event_name == 'merge_group' || inputs.disable_coverage == 'true' - uses: guibranco/github-status-action-v2@d469d49426f5a7b8a1fbcac20ad274d3e4892321 + uses: guibranco/github-status-action-v2@56cd38caf0615dd03f49d42ed301f1469911ac61 with: authToken: ${{ secrets.GITHUB_TOKEN }} state: success diff --git a/.github/workflows/triage-stale-flaky-tests.yml b/.github/workflows/triage-stale-flaky-tests.yml index 90ba7c40f7..3d3bcb0b13 100644 --- a/.github/workflows/triage-stale-flaky-tests.yml +++ b/.github/workflows/triage-stale-flaky-tests.yml @@ -1,5 +1,6 @@ name: Close stale flaky issues on: + workflow_dispatch: {} schedule: - cron: "30 1 * * *" permissions: {} @@ -17,3 +18,4 @@ jobs: days-before-close: 0 close-issue-message: "This flaky test issue has not been updated in 14 days. It is being closed as presumed resolved." exempt-issue-labels: "Z-Flaky-Test-Disabled" + operations-per-run: 100 diff --git a/.github/workflows/update-jitsi.yml b/.github/workflows/update-jitsi.yml index bf0414e73a..a3abcb002f 100644 --- a/.github/workflows/update-jitsi.yml +++ b/.github/workflows/update-jitsi.yml @@ -23,7 +23,7 @@ jobs: run: "yarn update:jitsi" - name: Create Pull Request - uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7 + uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7 with: token: ${{ secrets.ELEMENT_BOT_TOKEN }} branch: actions/jitsi-update diff --git a/docs/playwright.md b/docs/playwright.md index 73ee77228b..fe44a06ff1 100644 --- a/docs/playwright.md +++ b/docs/playwright.md @@ -227,7 +227,11 @@ has to be disabled in Playwright on Firefox & Webkit to retain routing functiona Anything testing VoIP/microphone will need to have `@no-webkit` as fake microphone functionality is not available there at this time. -## Colima +## Supporter container runtimes + +We use testcontainers to spin up various instances of Synapse, Matrix Authentication Service, and more. +It supports Docker out of the box but also has support for Podman, Colima, Rancher, you just need to follow some instructions to achieve it: +https://node.testcontainers.org/supported-container-runtimes/ If you are running under Colima, you may need to set the environment variable `TMPDIR` to `/tmp/colima` or a path within `$HOME` to allow bind mounting temporary directories into the Docker containers. diff --git a/package.json b/package.json index 050e40079c..19023cfcba 100644 --- a/package.json +++ b/package.json @@ -71,9 +71,11 @@ "update:jitsi": "curl -s https://meet.element.io/libs/external_api.min.js > ./res/jitsi_external_api.min.js" }, "resolutions": { + "@types/react": "18.3.18", + "@types/react-dom": "18.3.5", "oidc-client-ts": "3.1.0", "jwt-decode": "4.0.0", - "caniuse-lite": "1.0.30001684", + "caniuse-lite": "1.0.30001690", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0", "wrap-ansi": "npm:wrap-ansi@^7.0.0" }, @@ -122,7 +124,7 @@ "linkify-string": "4.2.0", "linkifyjs": "4.2.0", "lodash": "^4.17.21", - "maplibre-gl": "^4.0.0", + "maplibre-gl": "^5.0.0", "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", @@ -135,7 +137,7 @@ "png-chunks-extract": "^1.0.0", "posthog-js": "1.157.2", "qrcode": "1.5.4", - "re-resizable": "6.10.1", + "re-resizable": "6.10.3", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.0", "react-blurhash": "^0.3.0", @@ -144,7 +146,7 @@ "react-transition-group": "^4.4.1", "rfc4648": "^1.4.0", "sanitize-filename": "^1.6.3", - "sanitize-html": "2.13.1", + "sanitize-html": "2.14.0", "tar-js": "^0.3.0", "temporal-polyfill": "^0.2.5", "ua-parser-js": "^1.0.2", @@ -180,6 +182,7 @@ "@sentry/webpack-plugin": "^2.7.1", "@stylistic/eslint-plugin": "^2.9.0", "@svgr/webpack": "^8.0.0", + "@testcontainers/postgresql": "^10.16.0", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.4.8", "@testing-library/react": "^16.0.0", @@ -191,7 +194,6 @@ "@types/escape-html": "^1.0.1", "@types/express": "^5.0.0", "@types/file-saver": "^2.0.3", - "@types/fs-extra": "^11.0.0", "@types/glob-to-regexp": "^0.4.1", "@types/jest": "29.5.12", "@types/jitsi-meet": "^2.0.2", @@ -204,17 +206,17 @@ "@types/node-fetch": "^2.6.2", "@types/pako": "^2.0.0", "@types/qrcode": "^1.3.5", - "@types/react": "18.3.3", + "@types/react": "18.3.18", "@types/react-beautiful-dnd": "^13.0.0", - "@types/react-dom": "18.3.1", + "@types/react-dom": "18.3.5", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "2.13.0", "@types/semver": "^7.5.8", "@types/tar-js": "^0.3.5", "@types/ua-parser-js": "^0.7.36", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "^8.0.0", - "@typescript-eslint/parser": "^8.0.0", + "@typescript-eslint/eslint-plugin": "^8.19.0", + "@typescript-eslint/parser": "^8.19.0", "babel-jest": "^29.0.0", "babel-loader": "^9.0.0", "babel-plugin-jsx-remove-data-test-id": "^3.0.0", @@ -243,7 +245,6 @@ "fetch-mock": "9.11.0", "fetch-mock-jest": "^1.5.1", "file-loader": "^6.0.0", - "fs-extra": "^11.0.0", "glob": "^11.0.0", "html-webpack-plugin": "^5.5.3", "husky": "^9.0.0", @@ -278,11 +279,13 @@ "rimraf": "^6.0.0", "semver": "^7.5.2", "source-map-loader": "^5.0.0", + "strip-ansi": "^7.1.0", "stylelint": "^16.1.0", "stylelint-config-standard": "^36.0.0", "stylelint-scss": "^6.0.0", "stylelint-value-no-unknown-custom-properties": "^6.0.1", "terser-webpack-plugin": "^5.3.9", + "testcontainers": "^10.16.0", "ts-node": "^10.9.1", "ts-prune": "^0.10.3", "typescript": "5.7.2", @@ -290,7 +293,7 @@ "web-streams-polyfill": "^4.0.0", "webpack": "^5.89.0", "webpack-bundle-analyzer": "^4.8.0", - "webpack-cli": "^5.0.0", + "webpack-cli": "^6.0.0", "webpack-dev-server": "^5.0.0", "webpack-version-file-plugin": "^0.5.0", "yaml": "^2.3.3" diff --git a/playwright/e2e/app-loading/guest-registration.spec.ts b/playwright/e2e/app-loading/guest-registration.spec.ts index 78ba57ad6b..1c38177ec7 100644 --- a/playwright/e2e/app-loading/guest-registration.spec.ts +++ b/playwright/e2e/app-loading/guest-registration.spec.ts @@ -13,13 +13,8 @@ Please see LICENSE files in the repository root for full details. import { expect, test } from "../../element-web-test"; test.use({ - startHomeserverOpts: "guest-enabled", - config: async ({ homeserver }, use) => { - await use({ - default_server_config: { - "m.homeserver": { base_url: homeserver.config.baseUrl }, - }, - }); + synapseConfigOptions: { + allow_guest_access: true, }, }); diff --git a/playwright/e2e/crypto/backups.spec.ts b/playwright/e2e/crypto/backups.spec.ts index 23a976bb1b..6e6c3e0491 100644 --- a/playwright/e2e/crypto/backups.spec.ts +++ b/playwright/e2e/crypto/backups.spec.ts @@ -9,9 +9,10 @@ Please see LICENSE files in the repository root for full details. import { type Page } from "@playwright/test"; import { test, expect } from "../../element-web-test"; -import { test as masTest, registerAccountMas } from "../oidc"; +import { registerAccountMas } from "../oidc"; import { isDendrite } from "../../plugins/homeserver/dendrite"; import { TestClientServerAPI } from "../csAPI"; +import { masHomeserver } from "../../plugins/homeserver/synapse/masHomeserver.ts"; async function expectBackupVersionToBe(page: Page, version: string) { await expect(page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(5) td")).toHaveText( @@ -24,22 +25,23 @@ async function expectBackupVersionToBe(page: Page, version: string) { // These tests register an account with MAS because then we go through the "normal" registration flow // and crypto gets set up. Using the 'user' fixture create a a user an synthesizes an existing login, // which is faster but leaves us without crypto set up. -masTest.describe("Encryption state after registration", () => { - masTest.skip(isDendrite, "does not yet support MAS"); +test.describe("Encryption state after registration", () => { + test.use(masHomeserver); + test.skip(isDendrite, "does not yet support MAS"); - masTest("Key backup is enabled by default", async ({ page, mailhog, app }) => { + test("Key backup is enabled by default", async ({ page, mailhogClient, app }) => { await page.goto("/#/login"); await page.getByRole("button", { name: "Continue" }).click(); - await registerAccountMas(page, mailhog.api, "alice", "alice@email.com", "Pa$sW0rD!"); + await registerAccountMas(page, mailhogClient, "alice", "alice@email.com", "Pa$sW0rD!"); await app.settings.openUserSettings("Security & Privacy"); await expect(page.getByText("This session is backing up your keys.")).toBeVisible(); }); - masTest("user is prompted to set up recovery", async ({ page, mailhog, app }) => { + test("user is prompted to set up recovery", async ({ page, mailhogClient, app }) => { await page.goto("/#/login"); await page.getByRole("button", { name: "Continue" }).click(); - await registerAccountMas(page, mailhog.api, "alice", "alice@email.com", "Pa$sW0rD!"); + await registerAccountMas(page, mailhogClient, "alice", "alice@email.com", "Pa$sW0rD!"); await page.getByRole("button", { name: "Add room" }).click(); await page.getByRole("menuitem", { name: "New room" }).click(); @@ -50,57 +52,53 @@ masTest.describe("Encryption state after registration", () => { }); }); -masTest.describe("Key backup reset from elsewhere", () => { - masTest.skip(isDendrite, "does not yet support MAS"); +test.describe("Key backup reset from elsewhere", () => { + test.use(masHomeserver); + test.skip(isDendrite, "does not yet support MAS"); - masTest( - "Key backup is disabled when reset from elsewhere", - async ({ page, mailhog, request, masPrepare, homeserver }) => { - const testUsername = "alice"; - const testPassword = "Pa$sW0rD!"; + test("Key backup is disabled when reset from elsewhere", async ({ page, mailhogClient, request, homeserver }) => { + const testUsername = "alice"; + const testPassword = "Pa$sW0rD!"; - // there's a delay before keys are uploaded so the error doesn't appear immediately: use a fake - // clock so we can skip the delay - await page.clock.install(); + // there's a delay before keys are uploaded so the error doesn't appear immediately: use a fake + // clock so we can skip the delay + await page.clock.install(); - await page.goto("/#/login"); - await page.getByRole("button", { name: "Continue" }).click(); - await registerAccountMas(page, mailhog.api, testUsername, "alice@email.com", testPassword); + await page.goto("/#/login"); + await page.getByRole("button", { name: "Continue" }).click(); + await registerAccountMas(page, mailhogClient, testUsername, "alice@email.com", testPassword); - await page.getByRole("button", { name: "Add room" }).click(); - await page.getByRole("menuitem", { name: "New room" }).click(); - await page.getByRole("textbox", { name: "Name" }).fill("test room"); - await page.getByRole("button", { name: "Create room" }).click(); + await page.getByRole("button", { name: "Add room" }).click(); + await page.getByRole("menuitem", { name: "New room" }).click(); + await page.getByRole("textbox", { name: "Name" }).fill("test room"); + await page.getByRole("button", { name: "Create room" }).click(); - // @ts-ignore - this runs in the browser scope where mxMatrixClientPeg is a thing. Here, it is not. - const accessToken = await page.evaluate(() => mxMatrixClientPeg.get().getAccessToken()); + // @ts-ignore - this runs in the browser scope where mxMatrixClientPeg is a thing. Here, it is not. + const accessToken = await page.evaluate(() => mxMatrixClientPeg.get().getAccessToken()); - const csAPI = new TestClientServerAPI(request, homeserver, accessToken); + const csAPI = new TestClientServerAPI(request, homeserver, accessToken); - const backupInfo = await csAPI.getCurrentBackupInfo(); + const backupInfo = await csAPI.getCurrentBackupInfo(); - await csAPI.deleteBackupVersion(backupInfo.version); + await csAPI.deleteBackupVersion(backupInfo.version); - await page.getByRole("textbox", { name: "Send an encrypted message…" }).fill("/discardsession"); - await page.getByRole("button", { name: "Send message" }).click(); + await page.getByRole("textbox", { name: "Send an encrypted message…" }).fill("/discardsession"); + await page.getByRole("button", { name: "Send message" }).click(); - await page - .getByRole("textbox", { name: "Send an encrypted message…" }) - .fill("Message with broken key backup"); - await page.getByRole("button", { name: "Send message" }).click(); + await page.getByRole("textbox", { name: "Send an encrypted message…" }).fill("Message with broken key backup"); + await page.getByRole("button", { name: "Send message" }).click(); - // Should be the message we sent plus the room creation event - await expect(page.locator(".mx_EventTile")).toHaveCount(2); - await expect( - page.locator(".mx_RoomView_MessageList > .mx_EventTile_last .mx_EventTile_receiptSent"), - ).toBeVisible(); + // Should be the message we sent plus the room creation event + await expect(page.locator(".mx_EventTile")).toHaveCount(2); + await expect( + page.locator(".mx_RoomView_MessageList > .mx_EventTile_last .mx_EventTile_receiptSent"), + ).toBeVisible(); - // Wait for it to try uploading the key - await page.clock.fastForward(20000); + // Wait for it to try uploading the key + await page.clock.fastForward(20000); - await expect(page.getByRole("heading", { level: 1, name: "New Recovery Method" })).toBeVisible(); - }, - ); + await expect(page.getByRole("heading", { level: 1, name: "New Recovery Method" })).toBeVisible(); + }); }); test.describe("Backups", () => { diff --git a/playwright/e2e/crypto/complete-security.spec.ts b/playwright/e2e/crypto/complete-security.spec.ts index 44eb70355c..da6974459c 100644 --- a/playwright/e2e/crypto/complete-security.spec.ts +++ b/playwright/e2e/crypto/complete-security.spec.ts @@ -19,9 +19,9 @@ test.describe("Complete security", () => { homeserver, credentials, }) => { - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); await expect(page.getByText("Welcome Jeff", { exact: true })).toBeVisible(); }); - // see also "Verify device during login with SAS" in `verifiction.spec.ts`. + // see also "Verify device during login with SAS" in `verification.spec.ts`. }); diff --git a/playwright/e2e/crypto/decryption-failure-messages.spec.ts b/playwright/e2e/crypto/decryption-failure-messages.spec.ts index b9199ef9fd..e1952bfec6 100644 --- a/playwright/e2e/crypto/decryption-failure-messages.spec.ts +++ b/playwright/e2e/crypto/decryption-failure-messages.spec.ts @@ -45,7 +45,7 @@ test.describe("Cryptography", function () { await logOutOfElement(page, true); // Log in again, and see how the message looks. - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); await app.viewRoomByName("Test room"); const lastTile = page.locator(".mx_EventTile").last(); await expect(lastTile).toContainText("Historical messages are not available on this device"); @@ -62,7 +62,7 @@ test.describe("Cryptography", function () { // Finally, log out again, and back in, skipping verification for now, and see what we see. await logOutOfElement(page); - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); await page.locator(".mx_AuthPage").getByRole("button", { name: "Skip verification for now" }).click(); await page.locator(".mx_AuthPage").getByRole("button", { name: "I'll verify later" }).click(); await app.viewRoomByName("Test room"); diff --git a/playwright/e2e/crypto/dehydration.spec.ts b/playwright/e2e/crypto/dehydration.spec.ts index 5a5b7f19d1..5bfcd1da28 100644 --- a/playwright/e2e/crypto/dehydration.spec.ts +++ b/playwright/e2e/crypto/dehydration.spec.ts @@ -8,33 +8,10 @@ Please see LICENSE files in the repository root for full details. import { Locator, type Page } from "@playwright/test"; -import { test as base, expect, Fixtures } from "../../element-web-test"; +import { test, expect } from "../../element-web-test"; import { viewRoomSummaryByName } from "../right-panel/utils"; import { isDendrite } from "../../plugins/homeserver/dendrite"; -const test = base.extend({ - // eslint-disable-next-line no-empty-pattern - startHomeserverOpts: async ({}, use) => { - await use("dehydration"); - }, - config: async ({ homeserver, context }, use) => { - const wellKnown = { - "m.homeserver": { - base_url: homeserver.config.baseUrl, - }, - "org.matrix.msc3814": true, - }; - - await context.route("https://localhost/.well-known/matrix/client", async (route) => { - await route.fulfill({ json: wellKnown }); - }); - - await use({ - default_server_config: wellKnown, - }); - }, -}); - const ROOM_NAME = "Test room"; const NAME = "Alice"; @@ -47,6 +24,24 @@ test.describe("Dehydration", () => { test.use({ displayName: NAME, + synapseConfigOptions: { + experimental_features: { + msc2697_enabled: false, + msc3814_enabled: true, + }, + }, + config: async ({ config, context }, use) => { + const wellKnown = { + ...config.default_server_config, + "org.matrix.msc3814": true, + }; + + await context.route("https://localhost/.well-known/matrix/client", async (route) => { + await route.fulfill({ json: wellKnown }); + }); + + await use(config); + }, }); test("Create dehydrated device", async ({ page, user, app }, workerInfo) => { diff --git a/playwright/e2e/crypto/device-verification.spec.ts b/playwright/e2e/crypto/device-verification.spec.ts index ddd564139f..a028bfb70c 100644 --- a/playwright/e2e/crypto/device-verification.spec.ts +++ b/playwright/e2e/crypto/device-verification.spec.ts @@ -66,7 +66,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { } test("Verify device with SAS during login", async ({ page, app, credentials, homeserver }) => { - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); // Launch the verification request between alice and the bot const verificationRequest = await initiateAliceVerificationRequest(page); @@ -93,7 +93,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { test("Verify device with QR code during login", async ({ page, app, credentials, homeserver }) => { // A mode 0x02 verification: "self-verifying in which the current device does not yet trust the master key" - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); // Launch the verification request between alice and the bot const verificationRequest = await initiateAliceVerificationRequest(page); @@ -137,7 +137,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { }); test("Verify device with Security Phrase during login", async ({ page, app, credentials, homeserver }) => { - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); // Select the security phrase await page.locator(".mx_AuthPage").getByRole("button", { name: "Verify with Security Key or Phrase" }).click(); @@ -158,7 +158,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { }); test("Verify device with Security Key during login", async ({ page, app, credentials, homeserver }) => { - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); // Select the security phrase await page.locator(".mx_AuthPage").getByRole("button", { name: "Verify with Security Key or Phrase" }).click(); @@ -181,7 +181,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { }); test("Handle incoming verification request with SAS", async ({ page, credentials, homeserver, toasts }) => { - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); /* Dismiss "Verify this device" */ const authPage = page.locator(".mx_AuthPage"); diff --git a/playwright/e2e/crypto/event-shields.spec.ts b/playwright/e2e/crypto/event-shields.spec.ts index f680f340c3..3811c2819e 100644 --- a/playwright/e2e/crypto/event-shields.spec.ts +++ b/playwright/e2e/crypto/event-shields.spec.ts @@ -207,7 +207,7 @@ test.describe("Cryptography", function () { window.localStorage.clear(); }); await page.reload(); - await logIntoElement(page, homeserver, aliceCredentials, securityKey); + await logIntoElement(page, aliceCredentials, securityKey); /* go back to the test room and find Bob's message again */ await app.viewRoomById(testRoomId); diff --git a/playwright/e2e/crypto/logout.spec.ts b/playwright/e2e/crypto/logout.spec.ts index 8e408dc634..2bafe0ece8 100644 --- a/playwright/e2e/crypto/logout.spec.ts +++ b/playwright/e2e/crypto/logout.spec.ts @@ -11,7 +11,7 @@ import { createRoom, enableKeyBackup, logIntoElement, sendMessageInCurrentRoom } test.describe("Logout tests", () => { test.beforeEach(async ({ page, homeserver, credentials }) => { - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); }); test("Ask to set up recovery on logout if not setup", async ({ page, app }) => { diff --git a/playwright/e2e/crypto/migration.spec.ts b/playwright/e2e/crypto/migration.spec.ts index c36cf2997e..86072fccc0 100644 --- a/playwright/e2e/crypto/migration.spec.ts +++ b/playwright/e2e/crypto/migration.spec.ts @@ -9,24 +9,24 @@ Please see LICENSE files in the repository root for full details. import path from "path"; import { readFile } from "node:fs/promises"; -import { expect, Fixtures, test as base } from "../../element-web-test"; - -const test = base.extend({ - // Replace the `user` fixture with one which populates the indexeddb data before starting the app. - user: async ({ context, pageWithCredentials: page, credentials }, use) => { - await page.route(`/test_indexeddb_cryptostore_dump/*`, async (route, request) => { - const resourcePath = path.join(__dirname, new URL(request.url()).pathname); - const body = await readFile(resourcePath, { encoding: "utf-8" }); - await route.fulfill({ body }); - }); - await page.goto("/test_indexeddb_cryptostore_dump/index.html"); - - await use(credentials); - }, -}); +import { expect, test } from "../../element-web-test"; test.describe("migration", { tag: "@no-webkit" }, function () { - test.use({ displayName: "Alice" }); + test.use({ + displayName: "Alice", + + // Replace the `user` fixture with one which populates the indexeddb data before starting the app. + user: async ({ context, pageWithCredentials: page, credentials }, use) => { + await page.route(`/test_indexeddb_cryptostore_dump/*`, async (route, request) => { + const resourcePath = path.join(__dirname, new URL(request.url()).pathname); + const body = await readFile(resourcePath, { encoding: "utf-8" }); + await route.fulfill({ body }); + }); + await page.goto("/test_indexeddb_cryptostore_dump/index.html"); + + await use(credentials); + }, + }); test("Should support migration from legacy crypto", async ({ context, user, page }, workerInfo) => { test.slow(); diff --git a/playwright/e2e/crypto/utils.ts b/playwright/e2e/crypto/utils.ts index b170b24d66..48da798f1a 100644 --- a/playwright/e2e/crypto/utils.ts +++ b/playwright/e2e/crypto/utils.ts @@ -138,22 +138,9 @@ export async function checkDeviceIsConnectedKeyBackup( * * If a `securityKey` is given, verifies the new device using the key. */ -export async function logIntoElement( - page: Page, - homeserver: HomeserverInstance, - credentials: Credentials, - securityKey?: string, -) { +export async function logIntoElement(page: Page, credentials: Credentials, securityKey?: string) { await page.goto("/#/login"); - // select homeserver - await page.getByRole("button", { name: "Edit" }).click(); - await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl); - await page.getByRole("button", { name: "Continue", exact: true }).click(); - - // wait for the dialog to go away - await expect(page.locator(".mx_ServerPickerDialog")).not.toBeVisible(); - await page.getByRole("textbox", { name: "Username" }).fill(credentials.userId); await page.getByPlaceholder("Password").fill(credentials.password); await page.getByRole("button", { name: "Sign in" }).click(); diff --git a/playwright/e2e/csAPI.ts b/playwright/e2e/csAPI.ts index 7fb7bece8d..d55816fb6a 100644 --- a/playwright/e2e/csAPI.ts +++ b/playwright/e2e/csAPI.ts @@ -22,7 +22,7 @@ export class TestClientServerAPI { ) {} public async getCurrentBackupInfo(): Promise { - const res = await this.request.get(`${this.homeserver.config.baseUrl}/_matrix/client/v3/room_keys/version`, { + const res = await this.request.get(`${this.homeserver.baseUrl}/_matrix/client/v3/room_keys/version`, { headers: { Authorization: `Bearer ${this.accessToken}` }, }); @@ -35,7 +35,7 @@ export class TestClientServerAPI { */ public async deleteBackupVersion(version: string): Promise { const res = await this.request.delete( - `${this.homeserver.config.baseUrl}/_matrix/client/v3/room_keys/version/${version}`, + `${this.homeserver.baseUrl}/_matrix/client/v3/room_keys/version/${version}`, { headers: { Authorization: `Bearer ${this.accessToken}` }, }, diff --git a/playwright/e2e/forgot-password/forgot-password.spec.ts b/playwright/e2e/forgot-password/forgot-password.spec.ts index 9ffacc8efc..621cf3fd3c 100644 --- a/playwright/e2e/forgot-password/forgot-password.spec.ts +++ b/playwright/e2e/forgot-password/forgot-password.spec.ts @@ -8,6 +8,8 @@ Please see LICENSE files in the repository root for full details. import { expect, test } from "../../element-web-test"; import { selectHomeserver } from "../utils"; +import { emailHomeserver } from "../../plugins/homeserver/synapse/emailHomeserver.ts"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; const username = "user1234"; // this has to be password-like enough to please zxcvbn. Needless to say it's just from pwgen. @@ -15,15 +17,18 @@ const password = "oETo7MPf0o"; const email = "user@nowhere.dummy"; test.describe("Forgot Password", () => { + test.skip(isDendrite, "not yet wired up"); + test.use(emailHomeserver); test.use({ - startHomeserverOpts: ({ mailhog }, use) => - use({ - template: "email", - variables: { - SMTP_HOST: "host.containers.internal", - SMTP_PORT: mailhog.instance.smtpPort, + config: { + // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver. + // We point that to a guaranteed-invalid domain. + default_server_config: { + "m.homeserver": { + base_url: "https://server.invalid", }, - }), + }, + }, }); test("renders properly", { tag: "@screenshot" }, async ({ page, homeserver }) => { @@ -32,7 +37,7 @@ test.describe("Forgot Password", () => { await page.getByRole("link", { name: "Sign in" }).click(); // need to select a homeserver at this stage, before entering the forgot password flow - await selectHomeserver(page, homeserver.config.baseUrl); + await selectHomeserver(page, homeserver.baseUrl); await page.getByRole("button", { name: "Forgot password?" }).click(); @@ -47,7 +52,7 @@ test.describe("Forgot Password", () => { await page.goto("/"); await page.getByRole("link", { name: "Sign in" }).click(); - await selectHomeserver(page, homeserver.config.baseUrl); + await selectHomeserver(page, homeserver.baseUrl); await page.getByRole("button", { name: "Forgot password?" }).click(); diff --git a/playwright/e2e/login/consent.spec.ts b/playwright/e2e/login/consent.spec.ts index e6c68669ec..9127ae54bb 100644 --- a/playwright/e2e/login/consent.spec.ts +++ b/playwright/e2e/login/consent.spec.ts @@ -7,10 +7,11 @@ Please see LICENSE files in the repository root for full details. */ import { test, expect } from "../../element-web-test"; +import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts"; test.describe("Consent", () => { + test.use(consentHomeserver); test.use({ - startHomeserverOpts: "consent", displayName: "Bob", }); diff --git a/playwright/e2e/login/login.spec.ts b/playwright/e2e/login/login.spec.ts index 864f41922a..24b23fdbd8 100644 --- a/playwright/e2e/login/login.spec.ts +++ b/playwright/e2e/login/login.spec.ts @@ -13,6 +13,8 @@ import { doTokenRegistration } from "./utils"; import { isDendrite } from "../../plugins/homeserver/dendrite"; import { selectHomeserver } from "../utils"; import { Credentials, HomeserverInstance } from "../../plugins/homeserver"; +import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts"; +import { legacyOAuthHomeserver } from "../../plugins/homeserver/synapse/legacyOAuthHomeserver.ts"; const username = "user1234"; const password = "p4s5W0rD"; @@ -70,7 +72,7 @@ const DEVICE_SIGNING_KEYS_BODY = { async function login(page: Page, homeserver: HomeserverInstance) { await page.getByRole("link", { name: "Sign in" }).click(); - await selectHomeserver(page, homeserver.config.baseUrl); + await selectHomeserver(page, homeserver.baseUrl); await page.getByRole("textbox", { name: "Username" }).fill(username); await page.getByPlaceholder("Password").fill(password); @@ -78,8 +80,20 @@ async function login(page: Page, homeserver: HomeserverInstance) { } test.describe("Login", () => { + test.use({ + config: { + // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver. + // We point that to a guaranteed-invalid domain. + default_server_config: { + "m.homeserver": { + base_url: "https://server.invalid", + }, + }, + }, + }); + test.describe("Password login", () => { - test.use({ startHomeserverOpts: "consent" }); + test.use(consentHomeserver); let creds: Credentials; @@ -101,7 +115,7 @@ test.describe("Login", () => { await page.getByRole("link", { name: "Sign in" }).click(); // first pick the homeserver, as otherwise the user picker won't be visible - await selectHomeserver(page, homeserver.config.baseUrl); + await selectHomeserver(page, homeserver.baseUrl); await page.getByRole("button", { name: "Edit" }).click(); @@ -114,7 +128,7 @@ test.describe("Login", () => { await expect(page.locator(".mx_ServerPicker_server")).toHaveText("server.invalid"); // switch back to the custom homeserver - await selectHomeserver(page, homeserver.config.baseUrl); + await selectHomeserver(page, homeserver.baseUrl); await expect(page.getByRole("textbox", { name: "Username" })).toBeVisible(); // Disabled because flaky - see https://github.com/vector-im/element-web/issues/24688 @@ -142,10 +156,10 @@ test.describe("Login", () => { homeserver, request, }) => { - const res = await request.post( - `${homeserver.config.baseUrl}/_matrix/client/v3/keys/device_signing/upload`, - { headers: { Authorization: `Bearer ${creds.accessToken}` }, data: DEVICE_SIGNING_KEYS_BODY }, - ); + const res = await request.post(`${homeserver.baseUrl}/_matrix/client/v3/keys/device_signing/upload`, { + headers: { Authorization: `Bearer ${creds.accessToken}` }, + data: DEVICE_SIGNING_KEYS_BODY, + }); if (res.status() / 100 !== 2) { console.log("Uploading dummy keys failed", await res.json()); } @@ -172,7 +186,7 @@ test.describe("Login", () => { request, }) => { const res = await request.post( - `${homeserver.config.baseUrl}/_matrix/client/v3/keys/device_signing/upload`, + `${homeserver.baseUrl}/_matrix/client/v3/keys/device_signing/upload`, { headers: { Authorization: `Bearer ${creds.accessToken}` }, data: DEVICE_SIGNING_KEYS_BODY }, ); if (res.status() / 100 !== 2) { @@ -203,7 +217,7 @@ test.describe("Login", () => { }) => { console.log(`uid ${creds.userId} body`, DEVICE_SIGNING_KEYS_BODY); const res = await request.post( - `${homeserver.config.baseUrl}/_matrix/client/v3/keys/device_signing/upload`, + `${homeserver.baseUrl}/_matrix/client/v3/keys/device_signing/upload`, { headers: { Authorization: `Bearer ${creds.accessToken}` }, data: DEVICE_SIGNING_KEYS_BODY }, ); if (res.status() / 100 !== 2) { @@ -226,14 +240,7 @@ test.describe("Login", () => { // tests for old-style SSO login, in which we exchange tokens with Synapse, and Synapse talks to an auth server test.describe("SSO login", () => { test.skip(isDendrite, "does not yet support SSO"); - - test.use({ - startHomeserverOpts: ({ oAuthServer }, use) => - use({ - template: "default", - oAuthServerPort: oAuthServer.port, - }), - }); + test.use(legacyOAuthHomeserver); test("logs in with SSO and lands on the home screen", async ({ page, homeserver }) => { // If this test fails with a screen showing "Timeout connecting to remote server", it is most likely due to @@ -247,7 +254,7 @@ test.describe("Login", () => { }); test.describe("logout", () => { - test.use({ startHomeserverOpts: "consent" }); + test.use(consentHomeserver); test("should go to login page on logout", async ({ page, user }) => { await page.getByRole("button", { name: "User menu" }).click(); @@ -262,8 +269,8 @@ test.describe("Login", () => { }); test.describe("logout with logout_redirect_url", () => { + test.use(consentHomeserver); test.use({ - startHomeserverOpts: "consent", config: { // We redirect to decoder-ring because it's a predictable page that isn't Element itself. // We could use example.org, matrix.org, or something else, however this puts dependency of external diff --git a/playwright/e2e/login/overwrite_login.spec.ts b/playwright/e2e/login/overwrite_login.spec.ts index 7d5ec6a649..4beed00d12 100644 --- a/playwright/e2e/login/overwrite_login.spec.ts +++ b/playwright/e2e/login/overwrite_login.spec.ts @@ -13,7 +13,7 @@ test.describe("Overwrite login action", () => { // This seems terminally flakey: https://github.com/element-hq/element-web/issues/27363 // I tried verious things to try & deflake it, to no avail: https://github.com/matrix-org/matrix-react-sdk/pull/12506 test.skip("Try replace existing login with new one", async ({ page, app, credentials, homeserver }) => { - await logIntoElement(page, homeserver, credentials); + await logIntoElement(page, credentials); const userMenu = await app.openUserMenu(); await expect(userMenu.getByText(credentials.userId)).toBeVisible(); @@ -24,7 +24,7 @@ test.describe("Overwrite login action", () => { expect(credentials.userId).not.toBe(bobRegister.userId); const clientCredentials /* IMatrixClientCreds */ = { - homeserverUrl: homeserver.config.baseUrl, + homeserverUrl: homeserver.baseUrl, ...bobRegister, }; diff --git a/playwright/e2e/login/soft_logout.spec.ts b/playwright/e2e/login/soft_logout.spec.ts index 884dd3fee6..6b4aa5a40d 100644 --- a/playwright/e2e/login/soft_logout.spec.ts +++ b/playwright/e2e/login/soft_logout.spec.ts @@ -11,16 +11,20 @@ import { Page } from "@playwright/test"; import { test, expect } from "../../element-web-test"; import { doTokenRegistration } from "./utils"; import { Credentials } from "../../plugins/homeserver"; -import { isDendrite } from "../../plugins/homeserver/dendrite"; +import { legacyOAuthHomeserver } from "../../plugins/homeserver/synapse/legacyOAuthHomeserver.ts"; test.describe("Soft logout", () => { test.use({ displayName: "Alice", - startHomeserverOpts: ({ oAuthServer }, use) => - use({ - template: "default", - oAuthServerPort: oAuthServer.port, - }), + config: { + // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver. + // We point that to a guaranteed-invalid domain. + default_server_config: { + "m.homeserver": { + base_url: "https://server.invalid", + }, + }, + }, }); test.describe("with password user", () => { @@ -49,8 +53,7 @@ test.describe("Soft logout", () => { }); test.describe("with SSO user", () => { - test.skip(isDendrite, "does not yet support SSO"); - + test.use(legacyOAuthHomeserver); test.use({ user: async ({ page, homeserver }, use) => { const user = await doTokenRegistration(page, homeserver); diff --git a/playwright/e2e/login/utils.ts b/playwright/e2e/login/utils.ts index 2c576dbea7..0a728faecc 100644 --- a/playwright/e2e/login/utils.ts +++ b/playwright/e2e/login/utils.ts @@ -19,7 +19,7 @@ export async function doTokenRegistration( await page.goto("/#/login"); await page.getByRole("button", { name: "Edit" }).click(); - await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl); + await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.baseUrl); await page.getByRole("button", { name: "Continue" }).click(); // wait for the dialog to go away await expect(page.locator(".mx_ServerPickerDialog")).toHaveCount(0); diff --git a/playwright/e2e/oidc/index.ts b/playwright/e2e/oidc/index.ts index 7a99677968..7e9b03ee6a 100644 --- a/playwright/e2e/oidc/index.ts +++ b/playwright/e2e/oidc/index.ts @@ -9,61 +9,7 @@ Please see LICENSE files in the repository root for full details. import { API, Messages } from "mailhog"; import { Page } from "@playwright/test"; -import { test as base, expect } from "../../element-web-test"; -import { MatrixAuthenticationService } from "../../plugins/matrix-authentication-service"; -import { StartHomeserverOpts } from "../../plugins/homeserver"; - -export const test = base.extend<{ - masPrepare: MatrixAuthenticationService; - mas: MatrixAuthenticationService; -}>({ - // There's a bit of a chicken and egg problem between MAS & Synapse where they each need to know how to reach each other - // so spinning up a MAS is split into the prepare & start stage: prepare mas -> homeserver -> start mas to disentangle this. - masPrepare: async ({ context }, use) => { - const mas = new MatrixAuthenticationService(context); - await mas.prepare(); - await use(mas); - }, - mas: [ - async ({ masPrepare: mas, homeserver, mailhog }, use, testInfo) => { - await mas.start(homeserver, mailhog.instance); - await use(mas); - await mas.stop(testInfo); - }, - { auto: true }, - ], - startHomeserverOpts: async ({ masPrepare }, use) => { - await use({ - template: "mas-oidc", - variables: { - MAS_PORT: masPrepare.port, - }, - }); - }, - config: async ({ homeserver, startHomeserverOpts, context }, use) => { - const issuer = `http://localhost:${(startHomeserverOpts as StartHomeserverOpts).variables["MAS_PORT"]}/`; - const wellKnown = { - "m.homeserver": { - base_url: homeserver.config.baseUrl, - }, - "org.matrix.msc2965.authentication": { - issuer, - account: `${issuer}account`, - }, - }; - - // Ensure org.matrix.msc2965.authentication is in well-known - await context.route("https://localhost/.well-known/matrix/client", async (route) => { - await route.fulfill({ json: wellKnown }); - }); - - await use({ - default_server_config: wellKnown, - }); - }, -}); - -export { expect }; +import { expect } from "../../element-web-test"; export async function registerAccountMas( page: Page, diff --git a/playwright/e2e/oidc/oidc-native.spec.ts b/playwright/e2e/oidc/oidc-native.spec.ts index e2e7a816dd..60c5bbf025 100644 --- a/playwright/e2e/oidc/oidc-native.spec.ts +++ b/playwright/e2e/oidc/oidc-native.spec.ts @@ -6,23 +6,26 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { test, expect, registerAccountMas } from "."; -import { isDendrite } from "../../plugins/homeserver/dendrite"; +import { test, expect } from "../../element-web-test.ts"; +import { registerAccountMas } from "."; import { ElementAppPage } from "../../pages/ElementAppPage.ts"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; +import { masHomeserver } from "../../plugins/homeserver/synapse/masHomeserver.ts"; test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => { + test.use(masHomeserver); test.skip(isDendrite, "does not yet support MAS"); test.slow(); // trace recording takes a while here - test("can register the oauth2 client and an account", async ({ context, page, homeserver, mailhog, mas }) => { - const tokenUri = `http://localhost:${mas.port}/oauth2/token`; + test("can register the oauth2 client and an account", async ({ context, page, homeserver, mailhogClient, mas }) => { + const tokenUri = `${mas.baseUrl}/oauth2/token`; const tokenApiPromise = page.waitForRequest( (request) => request.url() === tokenUri && request.postDataJSON()["grant_type"] === "authorization_code", ); await page.goto("/#/login"); await page.getByRole("button", { name: "Continue" }).click(); - await registerAccountMas(page, mailhog.api, "alice", "alice@email.com", "Pa$sW0rD!"); + await registerAccountMas(page, mailhogClient, "alice", "alice@email.com", "Pa$sW0rD!"); // Eventually, we should end up at the home screen. await expect(page).toHaveURL(/\/#\/home$/, { timeout: 10000 }); @@ -49,7 +52,7 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => { await newPage.close(); // Assert logging out revokes both tokens - const revokeUri = `http://localhost:${mas.port}/oauth2/revoke`; + const revokeUri = `${mas.baseUrl}/oauth2/revoke`; const revokeAccessTokenPromise = page.waitForRequest( (request) => request.url() === revokeUri && request.postDataJSON()["token_type_hint"] === "access_token", ); diff --git a/playwright/e2e/register/email.spec.ts b/playwright/e2e/register/email.spec.ts index 12d706ab3c..50cfb4297a 100644 --- a/playwright/e2e/register/email.spec.ts +++ b/playwright/e2e/register/email.spec.ts @@ -7,26 +7,18 @@ Please see LICENSE files in the repository root for full details. */ import { test, expect } from "../../element-web-test"; +import { emailHomeserver } from "../../plugins/homeserver/synapse/emailHomeserver.ts"; import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Email Registration", async () => { test.skip(isDendrite, "not yet wired up"); - + test.use(emailHomeserver); test.use({ - startHomeserverOpts: ({ mailhog }, use) => - use({ - template: "email", - variables: { - SMTP_HOST: "host.containers.internal", - SMTP_PORT: mailhog.instance.smtpPort, - }, - }), - config: ({ homeserver }, use) => + config: ({ config }, use) => use({ + ...config, default_server_config: { - "m.homeserver": { - base_url: homeserver.config.baseUrl, - }, + ...config.default_server_config, "m.identity_server": { base_url: "https://server.invalid", }, @@ -34,14 +26,14 @@ test.describe("Email Registration", async () => { }), }); - test.beforeEach(async ({ page }) => { + test.beforeEach(async ({ homeserver, page }) => { await page.goto("/#/register"); }); test( "registers an account and lands on the use case selection screen", { tag: "@screenshot" }, - async ({ page, mailhog, request, checkA11y }) => { + async ({ page, mailhogClient, request, checkA11y }) => { await expect(page.getByRole("textbox", { name: "Username" })).toBeVisible(); // Hide the server text as it contains the randomly allocated Homeserver port const screenshotOptions = { mask: [page.locator(".mx_ServerPicker_server")] }; @@ -58,7 +50,7 @@ test.describe("Email Registration", async () => { await expect(page.getByText("An error was encountered when sending the email")).not.toBeVisible(); - const messages = await mailhog.api.messages(); + const messages = await mailhogClient.messages(); expect(messages.items).toHaveLength(1); expect(messages.items[0].to).toEqual("alice@email.com"); const [emailLink] = messages.items[0].text.match(/http.+/); diff --git a/playwright/e2e/register/register.spec.ts b/playwright/e2e/register/register.spec.ts index 553972d6cf..7756fe53c5 100644 --- a/playwright/e2e/register/register.spec.ts +++ b/playwright/e2e/register/register.spec.ts @@ -7,10 +7,20 @@ Please see LICENSE files in the repository root for full details. */ import { test, expect } from "../../element-web-test"; +import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts"; test.describe("Registration", () => { + test.use(consentHomeserver); test.use({ - startHomeserverOpts: "consent", + config: { + // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver. + // We point that to a guaranteed-invalid domain. + default_server_config: { + "m.homeserver": { + base_url: "https://server.invalid", + }, + }, + }, }); test.beforeEach(async ({ page }) => { @@ -27,7 +37,7 @@ test.describe("Registration", () => { await expect(page.locator(".mx_Dialog")).toMatchScreenshot("server-picker.png"); await checkA11y(); - await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl); + await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.baseUrl); await page.getByRole("button", { name: "Continue", exact: true }).click(); // wait for the dialog to go away await expect(page.getByRole("dialog")).not.toBeVisible(); @@ -88,7 +98,7 @@ test.describe("Registration", () => { test("should require username to fulfil requirements and be available", async ({ homeserver, page }) => { await page.getByRole("button", { name: "Edit", exact: true }).click(); await expect(page.getByRole("button", { name: "Continue", exact: true })).toBeVisible(); - await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl); + await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.baseUrl); await page.getByRole("button", { name: "Continue", exact: true }).click(); // wait for the dialog to go away await expect(page.getByRole("dialog")).not.toBeVisible(); diff --git a/playwright/e2e/sliding-sync/sliding-sync.spec.ts b/playwright/e2e/sliding-sync/sliding-sync.spec.ts index 4a7fb9deed..35027746b0 100644 --- a/playwright/e2e/sliding-sync/sliding-sync.spec.ts +++ b/playwright/e2e/sliding-sync/sliding-sync.spec.ts @@ -7,21 +7,31 @@ Please see LICENSE files in the repository root for full details. */ import { Page, Request } from "@playwright/test"; +import { GenericContainer, StartedTestContainer, Wait } from "testcontainers"; import { test as base, expect } from "../../element-web-test"; import type { ElementAppPage } from "../../pages/ElementAppPage"; import type { Bot } from "../../pages/bot"; -import { ProxyInstance, SlidingSyncProxy } from "../../plugins/sliding-sync-proxy"; const test = base.extend<{ - slidingSyncProxy: ProxyInstance; + slidingSyncProxy: StartedTestContainer; testRoom: { roomId: string; name: string }; joinedBot: Bot; }>({ - slidingSyncProxy: async ({ context, page, homeserver }, use) => { - const proxy = new SlidingSyncProxy(homeserver.config.dockerUrl, context); - const proxyInstance = await proxy.start(); - const proxyAddress = `http://localhost:${proxyInstance.port}`; + slidingSyncProxy: async ({ logger, network, postgres, page, homeserver }, use, testInfo) => { + const container = await new GenericContainer("ghcr.io/matrix-org/sliding-sync:v0.99.3") + .withNetwork(network) + .withExposedPorts(8008) + .withLogConsumer(logger.getConsumer("sliding-sync-proxy")) + .withWaitStrategy(Wait.forHttp("/client/server.json", 8008)) + .withEnvironment({ + SYNCV3_SECRET: "bwahahaha", + SYNCV3_DB: `user=${postgres.getUsername()} dbname=postgres password=${postgres.getPassword()} host=postgres sslmode=disable`, + SYNCV3_SERVER: `http://homeserver:8008`, + }) + .start(); + + const proxyAddress = `http://${container.getHost()}:${container.getMappedPort(8008)}`; await page.addInitScript((proxyAddress) => { window.localStorage.setItem( "mx_local_settings", @@ -31,8 +41,8 @@ const test = base.extend<{ ); window.localStorage.setItem("mx_labs_feature_feature_sliding_sync", "true"); }, proxyAddress); - await use(proxyInstance); - await proxy.stop(); + await use(container); + await container.stop(); }, // Ensure slidingSyncProxy is set up before the user fixture as it relies on an init script credentials: async ({ slidingSyncProxy, credentials }, use) => { diff --git a/playwright/element-web-test.ts b/playwright/element-web-test.ts index 36b6941e26..af9c293a82 100644 --- a/playwright/element-web-test.ts +++ b/playwright/element-web-test.ts @@ -6,41 +6,27 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { test as base, expect as baseExpect, Locator, Page, ExpectMatcherState, ElementHandle } from "@playwright/test"; +import { expect as baseExpect, Locator, Page, ExpectMatcherState, ElementHandle } from "@playwright/test"; import { sanitizeForFilePath } from "playwright-core/lib/utils"; import AxeBuilder from "@axe-core/playwright"; import _ from "lodash"; -import { basename, extname } from "node:path"; +import { extname } from "node:path"; -import type mailhog from "mailhog"; import type { IConfigOptions } from "../src/IConfigOptions"; -import { Credentials, Homeserver, HomeserverInstance, StartHomeserverOpts } from "./plugins/homeserver"; -import { Synapse } from "./plugins/homeserver/synapse"; -import { Dendrite, Pinecone } from "./plugins/homeserver/dendrite"; -import { Instance, MailHogServer } from "./plugins/mailhog"; +import { Credentials } from "./plugins/homeserver"; import { ElementAppPage } from "./pages/ElementAppPage"; -import { OAuthServer } from "./plugins/oauth_server"; import { Crypto } from "./pages/crypto"; import { Toasts } from "./pages/toasts"; import { Bot, CreateBotOpts } from "./pages/bot"; import { Webserver } from "./plugins/webserver"; +import { test as base } from "./services.ts"; // Enable experimental service worker support // See https://playwright.dev/docs/service-workers-experimental#how-to-enable process.env["PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS"] = "1"; +// This is deliberately quite a minimal config.json, so that we can test that the default settings actually work. const CONFIG_JSON: Partial = { - // This is deliberately quite a minimal config.json, so that we can test that the default settings - // actually work. - // - // The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver. - // We point that to a guaranteed-invalid domain. - default_server_config: { - "m.homeserver": { - base_url: "https://server.invalid", - }, - }, - // The default language is set here for test consistency setting_defaults: { language: "en-GB", @@ -68,14 +54,6 @@ export interface Fixtures { */ config: typeof CONFIG_JSON; - /** - * The options with which to run the {@link #homeserver} fixture. - */ - startHomeserverOpts: StartHomeserverOpts | string; - - homeserver: HomeserverInstance; - oAuthServer: { port: number }; - /** * The displayname to use for the user registered in {@link #credentials}. * @@ -113,7 +91,6 @@ export interface Fixtures { */ app: ElementAppPage; - mailhog: { api: mailhog.API; instance: Instance }; crypto: Crypto; room?: { roomId: string }; toasts: Toasts; @@ -136,9 +113,18 @@ export const test = base.extend({ }, disablePresence: false, config: CONFIG_JSON, - page: async ({ context, page, config, labsFlags, disablePresence, homeserver }, use) => { + page: async ({ homeserver, context, page, config, labsFlags, disablePresence }, use) => { await context.route(`http://localhost:8080/config.json*`, async (route) => { - const json = { ...CONFIG_JSON, ...config }; + const json = { + ...CONFIG_JSON, + ...config, + default_server_config: { + "m.homeserver": { + base_url: homeserver.baseUrl, + }, + ...config.default_server_config, + }, + }; json["features"] = { ...json["features"], // Enable the lab features @@ -149,7 +135,7 @@ export const test = base.extend({ }; if (disablePresence) { json["enable_presence_by_hs_url"] = { - [homeserver.config.baseUrl]: false, + [homeserver.baseUrl]: false, }; } await route.fulfill({ json }); @@ -157,45 +143,6 @@ export const test = base.extend({ await use(page); }, - startHomeserverOpts: "default", - homeserver: async ({ request, startHomeserverOpts: opts }, use, testInfo) => { - if (typeof opts === "string") { - opts = { template: opts }; - } - - let server: Homeserver; - const homeserverName = process.env["PLAYWRIGHT_HOMESERVER"]; - switch (homeserverName) { - case "dendrite": - server = new Dendrite(request); - break; - case "pinecone": - server = new Pinecone(request); - break; - default: - server = new Synapse(request); - } - - await use(await server.start(opts)); - const logs = await server.stop(); - - if (testInfo.status !== "passed") { - for (const path of logs) { - await testInfo.attach(`homeserver-${basename(path)}`, { - path, - contentType: "text/plain", - }); - } - } - }, - // eslint-disable-next-line no-empty-pattern - oAuthServer: async ({}, use) => { - const server = new OAuthServer(); - const port = server.start(); - await use({ port }); - server.stop(); - }, - displayName: undefined, credentials: async ({ homeserver, displayName: testDisplayName }, use) => { const names = ["Alice", "Bob", "Charlie", "Daniel", "Eve", "Frank", "Grace", "Hannah", "Isaac", "Judy"]; @@ -224,10 +171,16 @@ export const test = base.extend({ window.localStorage.setItem("mx_has_pickle_key", "false"); window.localStorage.setItem("mx_has_access_token", "true"); - // Ensure the language is set to a consistent value - window.localStorage.setItem("mx_local_settings", '{"language":"en"}'); + window.localStorage.setItem( + "mx_local_settings", + JSON.stringify({ + ...JSON.parse(window.localStorage.getItem("mx_local_settings") || "{}"), + // Ensure the language is set to a consistent value + language: "en", + }), + ); }, - { baseUrl: homeserver.config.baseUrl, credentials }, + { baseUrl: homeserver.baseUrl, credentials }, ); await use(page); }, @@ -272,14 +225,6 @@ export const test = base.extend({ await use(bot); }, - // eslint-disable-next-line no-empty-pattern - mailhog: async ({}, use) => { - const mailhog = new MailHogServer(); - const instance = await mailhog.start(); - await use(instance); - await mailhog.stop(); - }, - // eslint-disable-next-line no-empty-pattern webserver: async ({}, use) => { const webserver = new Webserver(); diff --git a/playwright/pages/bot.ts b/playwright/pages/bot.ts index fbb7fd9010..1d414c7bf6 100644 --- a/playwright/pages/bot.ts +++ b/playwright/pages/bot.ts @@ -97,7 +97,7 @@ export class Bot extends Client { private async buildClient(): Promise> { const credentials = await this.getCredentials(); const clientHandle = await this.page.evaluateHandle( - async ({ homeserver, credentials, opts }) => { + async ({ baseUrl, credentials, opts }) => { function getLogger(loggerName: string): Logger { const logger = { getChild: (namespace: string) => getLogger(`${loggerName}:${namespace}`), @@ -157,7 +157,7 @@ export class Bot extends Client { }; const cli = new window.matrixcs.MatrixClient({ - baseUrl: homeserver.baseUrl, + baseUrl, userId: credentials.userId, deviceId: credentials.deviceId, accessToken: credentials.accessToken, @@ -179,7 +179,7 @@ export class Bot extends Client { return cli; }, { - homeserver: this.homeserver.config, + baseUrl: this.homeserver.baseUrl, credentials, opts: this.opts, }, diff --git a/playwright/pages/crypto.ts b/playwright/pages/crypto.ts index 934c81d7f6..c31e7fbedb 100644 --- a/playwright/pages/crypto.ts +++ b/playwright/pages/crypto.ts @@ -27,7 +27,7 @@ export class Crypto { accessToken: window.mxMatrixClientPeg.get().getAccessToken(), })); - const res = await this.request.post(`${this.homeserver.config.baseUrl}/_matrix/client/v3/keys/query`, { + const res = await this.request.post(`${this.homeserver.baseUrl}/_matrix/client/v3/keys/query`, { headers: { Authorization: `Bearer ${accessToken}` }, data: { device_keys: { [userId]: [] } }, }); diff --git a/playwright/plugins/docker/index.ts b/playwright/plugins/docker/index.ts deleted file mode 100644 index 667dbbe597..0000000000 --- a/playwright/plugins/docker/index.ts +++ /dev/null @@ -1,151 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 The Matrix.org Foundation C.I.C. - -SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial -Please see LICENSE files in the repository root for full details. -*/ - -import * as os from "os"; -import * as crypto from "crypto"; -import * as childProcess from "child_process"; -import * as fse from "fs-extra"; - -/** - * @param cmd - command to execute - * @param args - arguments to pass to executed command - * @param suppressOutput - whether to suppress the stdout and stderr resulting from this command. - * @return Promise which resolves to an object containing the string value of what was - * written to stdout and stderr by the executed command. - */ -const exec = (cmd: string, args: string[], suppressOutput = false): Promise<{ stdout: string; stderr: string }> => { - return new Promise((resolve, reject) => { - if (!suppressOutput) { - const log = ["Running command:", cmd, ...args, "\n"].join(" "); - // When in CI mode we combine reports from multiple runners into a single HTML report - // which has separate files for stdout and stderr, so we print the executed command to both - process.stdout.write(log); - if (process.env.CI) process.stderr.write(log); - } - const { stdout, stderr } = childProcess.execFile(cmd, args, { encoding: "utf8" }, (err, stdout, stderr) => { - if (err) reject(err); - resolve({ stdout, stderr }); - if (!suppressOutput) { - process.stdout.write("\n"); - if (process.env.CI) process.stderr.write("\n"); - } - }); - if (!suppressOutput) { - stdout.pipe(process.stdout); - stderr.pipe(process.stderr); - } - }); -}; - -export class Docker { - public id: string; - - async run(opts: { image: string; containerName: string; params?: string[]; cmd?: string[] }): Promise { - const userInfo = os.userInfo(); - const params = opts.params ?? []; - - const isPodman = await Docker.isPodman(); - if (params.includes("-v") && userInfo.uid >= 0) { - // Run the docker container as our uid:gid to prevent problems with permissions. - if (isPodman) { - // Note: this setup is for podman rootless containers. - - // In podman, run as root in the container, which maps to the current - // user on the host. This is probably the default since Synapse's - // Dockerfile doesn't specify, but we're being explicit here - // because it's important for the permissions to work. - params.push("-u", "0:0"); - - // Tell Synapse not to switch UID - params.push("-e", "UID=0"); - params.push("-e", "GID=0"); - } else { - params.push("-u", `${userInfo.uid}:${userInfo.gid}`); - } - } - - // Make host.containers.internal work to allow the container to talk to other services via host ports. - if (isPodman) { - params.push("--network"); - params.push("slirp4netns:allow_host_loopback=true"); - } else { - // Docker for Desktop includes a host-gateway mapping on host.docker.internal but to simplify the config - // we use the Podman variant host.containers.internal in all environments. - params.push("--add-host"); - params.push("host.containers.internal:host-gateway"); - } - - // Provided we are not running in CI, add a `--rm` parameter. - // There is no need to remove containers in CI (since they are automatically removed anyway), and - // `--rm` means that if a container crashes this means its logs are wiped out. - if (!process.env.CI) params.unshift("--rm"); - - const args = [ - "run", - "--name", - `${opts.containerName}-${crypto.randomBytes(4).toString("hex")}`, - "-d", - ...params, - opts.image, - ]; - - if (opts.cmd) args.push(...opts.cmd); - - const { stdout } = await exec("docker", args); - this.id = stdout.trim(); - return this.id; - } - - async stop(): Promise { - try { - await exec("docker", ["stop", this.id]); - } catch (err) { - console.error(`Failed to stop docker container`, this.id, err); - } - } - - /** - * @param params - list of parameters to pass to `docker exec` - * @param suppressOutput - whether to suppress the stdout and stderr resulting from this command. - */ - async exec(params: string[], suppressOutput = true): Promise { - await exec("docker", ["exec", this.id, ...params], suppressOutput); - } - - async getContainerIp(): Promise { - const { stdout } = await exec("docker", ["inspect", "-f", "{{ .NetworkSettings.IPAddress }}", this.id]); - return stdout.trim(); - } - - async persistLogsToFile(args: { stdoutFile?: string; stderrFile?: string }): Promise { - const stdoutFile = args.stdoutFile ? await fse.open(args.stdoutFile, "w") : "ignore"; - const stderrFile = args.stderrFile ? await fse.open(args.stderrFile, "w") : "ignore"; - await new Promise((resolve) => { - childProcess - .spawn("docker", ["logs", this.id], { - stdio: ["ignore", stdoutFile, stderrFile], - }) - .once("close", resolve); - }); - if (args.stdoutFile) await fse.close(stdoutFile); - if (args.stderrFile) await fse.close(stderrFile); - } - - /** - * Detects whether the docker command is actually podman. - * To do this, it looks for "podman" in the output of "docker --help". - */ - static _isPodman?: boolean; - static async isPodman(): Promise { - if (Docker._isPodman === undefined) { - const { stdout } = await exec("docker", ["--help"], true); - Docker._isPodman = stdout.toLowerCase().includes("podman"); - } - return Docker._isPodman; - } -} diff --git a/playwright/plugins/homeserver/dendrite/index.ts b/playwright/plugins/homeserver/dendrite/index.ts index 27215b05c9..c9cb3332eb 100644 --- a/playwright/plugins/homeserver/dendrite/index.ts +++ b/playwright/plugins/homeserver/dendrite/index.ts @@ -6,142 +6,32 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import * as path from "node:path"; -import * as os from "node:os"; -import * as fse from "fs-extra"; +import { Fixtures, PlaywrightTestArgs } from "@playwright/test"; -import { getFreePort } from "../../utils/port"; -import { Homeserver, HomeserverConfig, HomeserverInstance, StartHomeserverOpts } from "../"; -import { randB64Bytes } from "../../utils/rand"; -import { Synapse } from "../synapse"; -import { Docker } from "../../docker"; +import { Fixtures as BaseFixtures } from "../../../element-web-test.ts"; +import { DendriteContainer, PineconeContainer } from "../../../testcontainers/dendrite.ts"; +import { Services } from "../../../services.ts"; -const dockerConfigDir = "/etc/dendrite/"; -const dendriteConfigFile = "dendrite.yaml"; +type Fixture = PlaywrightTestArgs & Services & BaseFixtures; +export const dendriteHomeserver: Fixtures = { + _homeserver: async ({ request }, use) => { + const container = + process.env["PLAYWRIGHT_HOMESERVER"] === "dendrite" + ? new DendriteContainer(request) + : new PineconeContainer(request); + await use(container); + }, + homeserver: async ({ logger, network, _homeserver: homeserver }, use) => { + const container = await homeserver + .withNetwork(network) + .withNetworkAliases("homeserver") + .withLogConsumer(logger.getConsumer("dendrite")) + .start(); -// Surprisingly, Dendrite implements the same register user Admin API Synapse, so we can just extend it -export class Dendrite extends Synapse implements Homeserver, HomeserverInstance { - protected image = "matrixdotorg/dendrite-monolith:main"; - protected entrypoint = "/usr/bin/dendrite"; - - /** - * Start a dendrite instance: the template must be the name of one of the templates - * in the playwright/plugins/dendritedocker/templates directory - * @param opts - */ - public async start(opts: StartHomeserverOpts): Promise { - const denCfg = await cfgDirFromTemplate(this.image, opts); - - console.log(`Starting dendrite with config dir ${denCfg.configDir}...`); - - const dendriteId = await this.docker.run({ - image: this.image, - params: [ - "-v", - `${denCfg.configDir}:` + dockerConfigDir, - "-p", - `${denCfg.port}:8008/tcp`, - "--entrypoint", - this.entrypoint, - ], - containerName: `react-sdk-playwright-dendrite`, - cmd: ["--config", dockerConfigDir + dendriteConfigFile, "--really-enable-open-registration", "true", "run"], - }); - - console.log(`Started dendrite with id ${dendriteId} on port ${denCfg.port}.`); - - // Await Dendrite healthcheck - await this.docker.exec([ - "curl", - "--connect-timeout", - "30", - "--retry", - "30", - "--retry-delay", - "1", - "--retry-all-errors", - "--silent", - "http://localhost:8008/_matrix/client/versions", - ]); - - const dockerUrl = `http://${await this.docker.getContainerIp()}:8008`; - this.config = { - ...denCfg, - serverId: dendriteId, - dockerUrl, - }; - return this; - } - - public async stop(): Promise { - if (!this.config) throw new Error("Missing existing dendrite instance, did you call stop() before start()?"); - - const dendriteLogsPath = path.join("playwright", "dendritelogs", this.config.serverId); - await fse.ensureDir(dendriteLogsPath); - - await this.docker.persistLogsToFile({ - stdoutFile: path.join(dendriteLogsPath, "stdout.log"), - stderrFile: path.join(dendriteLogsPath, "stderr.log"), - }); - - await this.docker.stop(); - - await fse.remove(this.config.configDir); - - console.log(`Stopped dendrite id ${this.config.serverId}.`); - - return [path.join(dendriteLogsPath, "stdout.log"), path.join(dendriteLogsPath, "stderr.log")]; - } -} - -export class Pinecone extends Dendrite { - protected image = "matrixdotorg/dendrite-demo-pinecone:main"; - protected entrypoint = "/usr/bin/dendrite-demo-pinecone"; -} - -async function cfgDirFromTemplate( - dendriteImage: string, - opts: StartHomeserverOpts, -): Promise> { - const template = "default"; // XXX: for now we only have one template - const templateDir = path.join(__dirname, "templates", template); - - const stats = await fse.stat(templateDir); - if (!stats?.isDirectory) { - throw new Error(`No such template: ${template}`); - } - const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), "react-sdk-dendritedocker-")); - - // copy the contents of the template dir, omitting homeserver.yaml as we'll template that - console.log(`Copy ${templateDir} -> ${tempDir}`); - await fse.copy(templateDir, tempDir, { filter: (f) => path.basename(f) !== dendriteConfigFile }); - - const registrationSecret = randB64Bytes(16); - - const port = await getFreePort(); - const baseUrl = `http://localhost:${port}`; - - // now copy homeserver.yaml, applying substitutions - console.log(`Gen ${path.join(templateDir, dendriteConfigFile)}`); - let hsYaml = await fse.readFile(path.join(templateDir, dendriteConfigFile), "utf8"); - hsYaml = hsYaml.replace(/{{REGISTRATION_SECRET}}/g, registrationSecret); - await fse.writeFile(path.join(tempDir, dendriteConfigFile), hsYaml); - - const docker = new Docker(); - await docker.run({ - image: dendriteImage, - params: ["--entrypoint=", "-v", `${tempDir}:/mnt`], - containerName: `react-sdk-playwright-dendrite-keygen`, - cmd: ["/usr/bin/generate-keys", "-private-key", "/mnt/matrix_key.pem"], - }); - - return { - port, - baseUrl, - configDir: tempDir, - registrationSecret, - }; -} + await use(container); + await container.stop(); + }, +}; export function isDendrite(): boolean { return process.env["PLAYWRIGHT_HOMESERVER"] === "dendrite" || process.env["PLAYWRIGHT_HOMESERVER"] === "pinecone"; diff --git a/playwright/plugins/homeserver/dendrite/templates/default/dendrite.yaml b/playwright/plugins/homeserver/dendrite/templates/default/dendrite.yaml deleted file mode 100644 index 634cebbc87..0000000000 --- a/playwright/plugins/homeserver/dendrite/templates/default/dendrite.yaml +++ /dev/null @@ -1,378 +0,0 @@ -# This is the Dendrite configuration file. -# -# The configuration is split up into sections - each Dendrite component has a -# configuration section, in addition to the "global" section which applies to -# all components. - -# The version of the configuration file. -version: 2 - -# Global Matrix configuration. This configuration applies to all components. -global: - # The domain name of this homeserver. - server_name: localhost - - # The path to the signing private key file, used to sign requests and events. - # Note that this is NOT the same private key as used for TLS! To generate a - # signing key, use "./bin/generate-keys --private-key matrix_key.pem". - private_key: matrix_key.pem - - # The paths and expiry timestamps (as a UNIX timestamp in millisecond precision) - # to old signing keys that were formerly in use on this domain name. These - # keys will not be used for federation request or event signing, but will be - # provided to any other homeserver that asks when trying to verify old events. - old_private_keys: - # If the old private key file is available: - # - private_key: old_matrix_key.pem - # expired_at: 1601024554498 - # If only the public key (in base64 format) and key ID are known: - # - public_key: mn59Kxfdq9VziYHSBzI7+EDPDcBS2Xl7jeUdiiQcOnM= - # key_id: ed25519:mykeyid - # expired_at: 1601024554498 - - # How long a remote server can cache our server signing key before requesting it - # again. Increasing this number will reduce the number of requests made by other - # servers for our key but increases the period that a compromised key will be - # considered valid by other homeservers. - key_validity_period: 168h0m0s - - # Global database connection pool, for PostgreSQL monolith deployments only. If - # this section is populated then you can omit the "database" blocks in all other - # sections. For polylith deployments, or monolith deployments using SQLite databases, - # you must configure the "database" block for each component instead. - # database: - # connection_string: postgresql://username:password@hostname/dendrite?sslmode=disable - # max_open_conns: 90 - # max_idle_conns: 5 - # conn_max_lifetime: -1 - - # Configuration for in-memory caches. Caches can often improve performance by - # keeping frequently accessed items (like events, identifiers etc.) in memory - # rather than having to read them from the database. - cache: - # The estimated maximum size for the global cache in bytes, or in terabytes, - # gigabytes, megabytes or kilobytes when the appropriate 'tb', 'gb', 'mb' or - # 'kb' suffix is specified. Note that this is not a hard limit, nor is it a - # memory limit for the entire process. A cache that is too small may ultimately - # provide little or no benefit. - max_size_estimated: 1gb - - # The maximum amount of time that a cache entry can live for in memory before - # it will be evicted and/or refreshed from the database. Lower values result in - # easier admission of new cache entries but may also increase database load in - # comparison to higher values, so adjust conservatively. Higher values may make - # it harder for new items to make it into the cache, e.g. if new rooms suddenly - # become popular. - max_age: 1h - - # The server name to delegate server-server communications to, with optional port - # e.g. localhost:443 - well_known_server_name: "" - - # The server name to delegate client-server communications to, with optional port - # e.g. localhost:443 - well_known_client_name: "" - - # Lists of domains that the server will trust as identity servers to verify third - # party identifiers such as phone numbers and email addresses. - trusted_third_party_id_servers: - - matrix.org - - vector.im - - # Disables federation. Dendrite will not be able to communicate with other servers - # in the Matrix federation and the federation API will not be exposed. - disable_federation: false - - # Configures the handling of presence events. Inbound controls whether we receive - # presence events from other servers, outbound controls whether we send presence - # events for our local users to other servers. - presence: - enable_inbound: false - enable_outbound: false - - # Configures phone-home statistics reporting. These statistics contain the server - # name, number of active users and some information on your deployment config. - # We use this information to understand how Dendrite is being used in the wild. - report_stats: - enabled: false - endpoint: https://matrix.org/report-usage-stats/push - - # Server notices allows server admins to send messages to all users on the server. - server_notices: - enabled: false - # The local part, display name and avatar URL (as a mxc:// URL) for the user that - # will send the server notices. These are visible to all users on the deployment. - local_part: "_server" - display_name: "Server Alerts" - avatar_url: "" - # The room name to be used when sending server notices. This room name will - # appear in user clients. - room_name: "Server Alerts" - - # Configuration for NATS JetStream - jetstream: - # A list of NATS Server addresses to connect to. If none are specified, an - # internal NATS server will be started automatically when running Dendrite in - # monolith mode. For polylith deployments, it is required to specify the address - # of at least one NATS Server node. - addresses: - # - localhost:4222 - - # Disable the validation of TLS certificates of NATS. This is - # not recommended in production since it may allow NATS traffic - # to be sent to an insecure endpoint. - disable_tls_validation: false - - # Persistent directory to store JetStream streams in. This directory should be - # preserved across Dendrite restarts. - storage_path: ./ - - # The prefix to use for stream names for this homeserver - really only useful - # if you are running more than one Dendrite server on the same NATS deployment. - topic_prefix: Dendrite - - # Configuration for Prometheus metric collection. - metrics: - enabled: false - basic_auth: - username: metrics - password: metrics - - # Optional DNS cache. The DNS cache may reduce the load on DNS servers if there - # is no local caching resolver available for use. - dns_cache: - enabled: false - cache_size: 256 - cache_lifetime: "5m" # 5 minutes; https://pkg.go.dev/time@master#ParseDuration - -# Configuration for the Appservice API. -app_service_api: - # Disable the validation of TLS certificates of appservices. This is - # not recommended in production since it may allow appservice traffic - # to be sent to an insecure endpoint. - disable_tls_validation: false - - # Appservice configuration files to load into this homeserver. - config_files: - # - /path/to/appservice_registration.yaml - -# Configuration for the Client API. -client_api: - # Prevents new users from being able to register on this homeserver, except when - # using the registration shared secret below. - registration_disabled: false - - # Prevents new guest accounts from being created. Guest registration is also - # disabled implicitly by setting 'registration_disabled' above. - guests_disabled: true - - # If set, allows registration by anyone who knows the shared secret, regardless - # of whether registration is otherwise disabled. - registration_shared_secret: "{{REGISTRATION_SECRET}}" - - # Whether to require reCAPTCHA for registration. If you have enabled registration - # then this is HIGHLY RECOMMENDED to reduce the risk of your homeserver being used - # for coordinated spam attacks. - enable_registration_captcha: false - - # Settings for ReCAPTCHA. - recaptcha_public_key: "" - recaptcha_private_key: "" - recaptcha_bypass_secret: "" - - # To use hcaptcha.com instead of ReCAPTCHA, set the following parameters, otherwise just keep them empty. - # recaptcha_siteverify_api: "https://hcaptcha.com/siteverify" - # recaptcha_api_js_url: "https://js.hcaptcha.com/1/api.js" - # recaptcha_form_field: "h-captcha-response" - # recaptcha_sitekey_class: "h-captcha" - - # TURN server information that this homeserver should send to clients. - turn: - turn_user_lifetime: "5m" - turn_uris: - # - turn:turn.server.org?transport=udp - # - turn:turn.server.org?transport=tcp - turn_shared_secret: "" - # If your TURN server requires static credentials, then you will need to enter - # them here instead of supplying a shared secret. Note that these credentials - # will be visible to clients! - # turn_username: "" - # turn_password: "" - - # Settings for rate-limited endpoints. Rate limiting kicks in after the threshold - # number of "slots" have been taken by requests from a specific host. Each "slot" - # will be released after the cooloff time in milliseconds. Server administrators - # and appservice users are exempt from rate limiting by default. - rate_limiting: - enabled: true - threshold: 20 - cooloff_ms: 500 - exempt_user_ids: - # - "@user:domain.com" - -# Configuration for the Federation API. -federation_api: - # How many times we will try to resend a failed transaction to a specific server. The - # backoff is 2**x seconds, so 1 = 2 seconds, 2 = 4 seconds, 3 = 8 seconds etc. Once - # the max retries are exceeded, Dendrite will no longer try to send transactions to - # that server until it comes back to life and connects to us again. - send_max_retries: 16 - - # Disable the validation of TLS certificates of remote federated homeservers. Do not - # enable this option in production as it presents a security risk! - disable_tls_validation: false - - # Disable HTTP keepalives, which also prevents connection reuse. Dendrite will typically - # keep HTTP connections open to remote hosts for 5 minutes as they can be reused much - # more quickly than opening new connections each time. Disabling keepalives will close - # HTTP connections immediately after a successful request but may result in more CPU and - # memory being used on TLS handshakes for each new connection instead. - disable_http_keepalives: false - - # Perspective keyservers to use as a backup when direct key fetches fail. This may - # be required to satisfy key requests for servers that are no longer online when - # joining some rooms. - key_perspectives: - - server_name: matrix.org - keys: - - key_id: ed25519:auto - public_key: Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw - - key_id: ed25519:a_RXGa - public_key: l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ - - # This option will control whether Dendrite will prefer to look up keys directly - # or whether it should try perspective servers first, using direct fetches as a - # last resort. - prefer_direct_fetch: false - - database: - connection_string: file:dendrite-federationapi.db - -# Configuration for the Media API. -media_api: - # Storage path for uploaded media. May be relative or absolute. - base_path: ./media_store - - # The maximum allowed file size (in bytes) for media uploads to this homeserver - # (0 = unlimited). If using a reverse proxy, ensure it allows requests at least - #this large (e.g. the client_max_body_size setting in nginx). - max_file_size_bytes: 10485760 - - # Whether to dynamically generate thumbnails if needed. - dynamic_thumbnails: false - - # The maximum number of simultaneous thumbnail generators to run. - max_thumbnail_generators: 10 - - # A list of thumbnail sizes to be generated for media content. - thumbnail_sizes: - - width: 32 - height: 32 - method: crop - - width: 96 - height: 96 - method: crop - - width: 640 - height: 480 - method: scale - - database: - connection_string: file:dendrite-mediaapi.db - -# Configuration for enabling experimental MSCs on this homeserver. -mscs: - mscs: - # - msc2836 # (Threading, see https://github.com/matrix-org/matrix-doc/pull/2836) - # - msc2946 # (Spaces Summary, see https://github.com/matrix-org/matrix-doc/pull/2946) - - database: - connection_string: file:dendrite-msc.db - -# Configuration for the Sync API. -sync_api: - # This option controls which HTTP header to inspect to find the real remote IP - # address of the client. This is likely required if Dendrite is running behind - # a reverse proxy server. - # real_ip_header: X-Real-IP - - # Configuration for the full-text search engine. - search: - # Whether or not search is enabled. - enabled: false - - # The path where the search index will be created in. - index_path: "./searchindex" - - # The language most likely to be used on the server - used when indexing, to - # ensure the returned results match expectations. A full list of possible languages - # can be found at https://github.com/blevesearch/bleve/tree/master/analysis/lang - language: "en" - - database: - connection_string: file:dendrite-syncapi.db - -# Configuration for the User API. -user_api: - # The cost when hashing passwords on registration/login. Default: 10. Min: 4, Max: 31 - # See https://pkg.go.dev/golang.org/x/crypto/bcrypt for more information. - # Setting this lower makes registration/login consume less CPU resources at the cost - # of security should the database be compromised. Setting this higher makes registration/login - # consume more CPU resources but makes it harder to brute force password hashes. This value - # can be lowered if performing tests or on embedded Dendrite instances (e.g WASM builds). - bcrypt_cost: 10 - - # The length of time that a token issued for a relying party from - # /_matrix/client/r0/user/{userId}/openid/request_token endpoint - # is considered to be valid in milliseconds. - # The default lifetime is 3600000ms (60 minutes). - # openid_token_lifetime_ms: 3600000 - - # Users who register on this homeserver will automatically be joined to the rooms listed under "auto_join_rooms" option. - # By default, any room aliases included in this list will be created as a publicly joinable room - # when the first user registers for the homeserver. If the room already exists, - # make certain it is a publicly joinable room, i.e. the join rule of the room must be set to 'public'. - # As Spaces are just rooms under the hood, Space aliases may also be used. - auto_join_rooms: - # - "#main:matrix.org" - - account_database: - connection_string: file:dendrite-userapi.db - -room_server: - database: - connection_string: file:dendrite-roomserverapi.db - -key_server: - database: - connection_string: file:dendrite-keyserverapi.db - -relay_api: - database: - connection_string: file:dendrite-relayapi.db - -# Configuration for Opentracing. -# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on -# how this works and how to set it up. -tracing: - enabled: false - jaeger: - serviceName: "" - disabled: false - rpc_metrics: false - tags: [] - sampler: null - reporter: null - headers: null - baggage_restrictions: null - throttler: null - -# Logging configuration. The "std" logging type controls the logs being sent to -# stdout. The "file" logging type controls logs being written to a log folder on -# the disk. Supported log levels are "debug", "info", "warn", "error". -logging: - - type: std - level: debug - - type: file - level: debug - params: - path: ./logs diff --git a/playwright/plugins/homeserver/index.ts b/playwright/plugins/homeserver/index.ts index c6a09ceab7..c05a5c345e 100644 --- a/playwright/plugins/homeserver/index.ts +++ b/playwright/plugins/homeserver/index.ts @@ -6,16 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -export interface HomeserverConfig { - readonly configDir: string; - readonly baseUrl: string; - readonly port: number; - readonly registrationSecret: string; - readonly dockerUrl: string; -} - export interface HomeserverInstance { - readonly config: HomeserverConfig; + readonly baseUrl: string; /** * Register a user on the given Homeserver using the shared registration secret. @@ -42,27 +34,6 @@ export interface HomeserverInstance { setThreepid(userId: string, medium: string, address: string): Promise; } -export interface StartHomeserverOpts { - /** path to template within playwright/plugins/{homeserver}docker/template/ directory. */ - template: string; - - /** Port of an OAuth server to configure the homeserver to use */ - oAuthServerPort?: number; - - /** Additional variables to inject into the configuration template **/ - variables?: Record; -} - -export interface Homeserver { - start(opts: StartHomeserverOpts): Promise; - /** - * Stop this test homeserver instance. - * - * @returns A list of paths relative to the cwd for logfiles generated during this test run. - */ - stop(): Promise; -} - export interface Credentials { accessToken: string; userId: string; diff --git a/playwright/plugins/homeserver/synapse/consentHomeserver.ts b/playwright/plugins/homeserver/synapse/consentHomeserver.ts new file mode 100644 index 0000000000..07d1fbbec2 --- /dev/null +++ b/playwright/plugins/homeserver/synapse/consentHomeserver.ts @@ -0,0 +1,56 @@ +/* +Copyright 2024 New Vector Ltd. +Copyright 2023 The Matrix.org Foundation C.I.C. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { Fixtures } from "@playwright/test"; + +import { Services } from "../../../services.ts"; + +export const consentHomeserver: Fixtures = { + _homeserver: async ({ _homeserver: container, mailhog }, use) => { + container + .withCopyDirectoriesToContainer([ + { source: "playwright/plugins/homeserver/synapse/res", target: "/data/res" }, + ]) + .withConfig({ + email: { + enable_notifs: false, + smtp_host: "mailhog", + smtp_port: 1025, + smtp_user: "username", + smtp_pass: "password", + require_transport_security: false, + notif_from: "Your Friendly %(app)s homeserver ", + app_name: "Matrix", + notif_template_html: "notif_mail.html", + notif_template_text: "notif_mail.txt", + notif_for_new_users: true, + client_base_url: "http://localhost/element", + }, + user_consent: { + template_dir: "/data/res/templates/privacy", + version: "1.0", + server_notice_content: { + msgtype: "m.text", + body: "To continue using this homeserver you must review and agree to the terms and conditions at %(consent_uri)s", + }, + send_server_notice_to_guests: true, + block_events_error: + "To continue using this homeserver you must review and agree to the terms and conditions at %(consent_uri)s", + require_at_registration: true, + }, + server_notices: { + system_mxid_localpart: "notices", + system_mxid_display_name: "Server Notices", + system_mxid_avatar_url: "mxc://localhost/oumMVlgDnLYFaPVkExemNVVZ", + room_name: "Server Notices", + }, + }) + .withConfigField("listeners[0].resources[0].names", ["client", "consent"]); + await use(container); + }, +}; diff --git a/playwright/plugins/homeserver/synapse/emailHomeserver.ts b/playwright/plugins/homeserver/synapse/emailHomeserver.ts new file mode 100644 index 0000000000..ab7affdee5 --- /dev/null +++ b/playwright/plugins/homeserver/synapse/emailHomeserver.ts @@ -0,0 +1,28 @@ +/* +Copyright 2024 New Vector Ltd. +Copyright 2023 The Matrix.org Foundation C.I.C. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { Fixtures } from "@playwright/test"; + +import { Services } from "../../../services.ts"; + +export const emailHomeserver: Fixtures = { + _homeserver: async ({ _homeserver: container, mailhog }, use) => { + container.withConfig({ + enable_registration_without_verification: undefined, + disable_msisdn_registration: undefined, + registrations_require_3pid: ["email"], + email: { + smtp_host: "mailhog", + smtp_port: 1025, + notif_from: "Your Friendly %(app)s homeserver ", + app_name: "my_branded_matrix_server", + }, + }); + await use(container); + }, +}; diff --git a/playwright/plugins/homeserver/synapse/index.ts b/playwright/plugins/homeserver/synapse/index.ts deleted file mode 100644 index 574797ae75..0000000000 --- a/playwright/plugins/homeserver/synapse/index.ts +++ /dev/null @@ -1,239 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 The Matrix.org Foundation C.I.C. - -SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial -Please see LICENSE files in the repository root for full details. -*/ - -import * as path from "node:path"; -import * as os from "node:os"; -import * as crypto from "node:crypto"; -import * as fse from "fs-extra"; -import { APIRequestContext } from "@playwright/test"; - -import { getFreePort } from "../../utils/port"; -import { Docker } from "../../docker"; -import { HomeserverConfig, HomeserverInstance, Homeserver, StartHomeserverOpts, Credentials } from ".."; -import { randB64Bytes } from "../../utils/rand"; - -// Docker tag to use for synapse docker image. -// We target a specific digest as every now and then a Synapse update will break our CI. -// This digest is updated by the playwright-image-updates.yaml workflow periodically. -const DOCKER_TAG = "develop@sha256:39f94b005e87cd3042c2535c37d8d9f915a88072fe79f6283ac18977fe134321"; - -async function cfgDirFromTemplate(opts: StartHomeserverOpts): Promise> { - const templateDir = path.join(__dirname, "templates", opts.template); - - const stats = await fse.stat(templateDir); - if (!stats?.isDirectory) { - throw new Error(`No such template: ${opts.template}`); - } - const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), "react-sdk-synapsedocker-")); - - // copy the contents of the template dir, omitting homeserver.yaml as we'll template that - console.log(`Copy ${templateDir} -> ${tempDir}`); - await fse.copy(templateDir, tempDir, { filter: (f) => path.basename(f) !== "homeserver.yaml" }); - - const registrationSecret = randB64Bytes(16); - const macaroonSecret = randB64Bytes(16); - const formSecret = randB64Bytes(16); - - const port = await getFreePort(); - const baseUrl = `http://localhost:${port}`; - - // now copy homeserver.yaml, applying substitutions - const templateHomeserver = path.join(templateDir, "homeserver.yaml"); - const outputHomeserver = path.join(tempDir, "homeserver.yaml"); - console.log(`Gen ${templateHomeserver} -> ${outputHomeserver}`); - let hsYaml = await fse.readFile(templateHomeserver, "utf8"); - hsYaml = hsYaml.replace(/{{REGISTRATION_SECRET}}/g, registrationSecret); - hsYaml = hsYaml.replace(/{{MACAROON_SECRET_KEY}}/g, macaroonSecret); - hsYaml = hsYaml.replace(/{{FORM_SECRET}}/g, formSecret); - hsYaml = hsYaml.replace(/{{PUBLIC_BASEURL}}/g, baseUrl); - if (opts.oAuthServerPort) { - hsYaml = hsYaml.replace(/{{OAUTH_SERVER_PORT}}/g, opts.oAuthServerPort.toString()); - } - if (opts.variables) { - for (const key in opts.variables) { - hsYaml = hsYaml.replace(new RegExp("%" + key + "%", "g"), String(opts.variables[key])); - } - } - - await fse.writeFile(outputHomeserver, hsYaml); - - // now generate a signing key (we could use synapse's config generation for - // this, or we could just do this...) - // NB. This assumes the homeserver.yaml specifies the key in this location - const signingKey = randB64Bytes(32); - const outputSigningKey = path.join(tempDir, "localhost.signing.key"); - console.log(`Gen -> ${outputSigningKey}`); - await fse.writeFile(outputSigningKey, `ed25519 x ${signingKey}`); - - // Allow anyone to read, write and execute in the /temp/react-sdk-synapsedocker-xxx directory - // so that the DIND setup that we use to update the playwright screenshots work without any issues. - await fse.chmod(tempDir, 0o757); - - return { - port, - baseUrl, - configDir: tempDir, - registrationSecret, - }; -} - -export class Synapse implements Homeserver, HomeserverInstance { - protected docker: Docker = new Docker(); - public config: HomeserverConfig & { serverId: string }; - - private adminToken?: string; - - public constructor(private readonly request: APIRequestContext) {} - - /** - * Start a synapse instance: the template must be the name of - * one of the templates in the playwright/plugins/synapsedocker/templates - * directory. - */ - public async start(opts: StartHomeserverOpts): Promise { - if (this.config) await this.stop(); - - const synCfg = await cfgDirFromTemplate(opts); - console.log(`Starting synapse with config dir ${synCfg.configDir}...`); - const dockerSynapseParams = ["-v", `${synCfg.configDir}:/data`, "-p", `${synCfg.port}:8008/tcp`]; - const synapseId = await this.docker.run({ - image: `ghcr.io/element-hq/synapse:${DOCKER_TAG}`, - containerName: `react-sdk-playwright-synapse`, - params: dockerSynapseParams, - cmd: ["run"], - }); - console.log(`Started synapse with id ${synapseId} on port ${synCfg.port}.`); - // Await Synapse healthcheck - await this.docker.exec([ - "curl", - "--connect-timeout", - "30", - "--retry", - "30", - "--retry-delay", - "1", - "--retry-all-errors", - "--silent", - "http://localhost:8008/health", - ]); - const dockerUrl = `http://${await this.docker.getContainerIp()}:8008`; - this.config = { - ...synCfg, - serverId: synapseId, - dockerUrl, - }; - return this; - } - - public async stop(): Promise { - if (!this.config) throw new Error("Missing existing synapse instance, did you call stop() before start()?"); - const id = this.config.serverId; - const synapseLogsPath = path.join("playwright", "logs", "synapse", id); - await fse.ensureDir(synapseLogsPath); - await this.docker.persistLogsToFile({ - stdoutFile: path.join(synapseLogsPath, "stdout.log"), - stderrFile: path.join(synapseLogsPath, "stderr.log"), - }); - await this.docker.stop(); - await fse.remove(this.config.configDir); - console.log(`Stopped synapse id ${id}.`); - - return [path.join(synapseLogsPath, "stdout.log"), path.join(synapseLogsPath, "stderr.log")]; - } - - private async registerUserInternal( - username: string, - password: string, - displayName?: string, - admin = false, - ): Promise { - const url = `${this.config.baseUrl}/_synapse/admin/v1/register`; - const { nonce } = await this.request.get(url).then((r) => r.json()); - const mac = crypto - .createHmac("sha1", this.config.registrationSecret) - .update(`${nonce}\0${username}\0${password}\0${admin ? "" : "not"}admin`) - .digest("hex"); - const res = await this.request.post(url, { - data: { - nonce, - username, - password, - mac, - admin, - displayname: displayName, - }, - }); - - if (!res.ok()) { - throw await res.json(); - } - - const data = await res.json(); - return { - homeServer: data.home_server, - accessToken: data.access_token, - userId: data.user_id, - deviceId: data.device_id, - password, - displayName, - }; - } - - public registerUser(username: string, password: string, displayName?: string): Promise { - return this.registerUserInternal(username, password, displayName, false); - } - - public async loginUser(userId: string, password: string): Promise { - const url = `${this.config.baseUrl}/_matrix/client/v3/login`; - const res = await this.request.post(url, { - data: { - type: "m.login.password", - identifier: { - type: "m.id.user", - user: userId, - }, - password: password, - }, - }); - const json = await res.json(); - - return { - password, - accessToken: json.access_token, - userId: json.user_id, - deviceId: json.device_id, - homeServer: json.home_server, - }; - } - - public async setThreepid(userId: string, medium: string, address: string): Promise { - if (this.adminToken === undefined) { - const result = await this.registerUserInternal("admin", "totalyinsecureadminpassword", undefined, true); - this.adminToken = result.accessToken; - } - - const url = `${this.config.baseUrl}/_synapse/admin/v2/users/${userId}`; - const res = await this.request.put(url, { - data: { - threepids: [ - { - medium, - address, - }, - ], - }, - headers: { - Authorization: `Bearer ${this.adminToken}`, - }, - }); - - if (!res.ok()) { - throw await res.json(); - } - } -} diff --git a/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts b/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts new file mode 100644 index 0000000000..a6b39e0484 --- /dev/null +++ b/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts @@ -0,0 +1,48 @@ +/* +Copyright 2024 New Vector Ltd. +Copyright 2023 The Matrix.org Foundation C.I.C. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { Fixtures } from "@playwright/test"; +import { TestContainers } from "testcontainers"; + +import { Services } from "../../../services.ts"; +import { OAuthServer } from "../../oauth_server"; + +export const legacyOAuthHomeserver: Fixtures = { + _homeserver: async ({ _homeserver: container }, use) => { + const server = new OAuthServer(); + const port = server.start(); + + await TestContainers.exposeHostPorts(port); + container.withConfig({ + oidc_providers: [ + { + idp_id: "test", + idp_name: "OAuth test", + issuer: `http://localhost:${port}/oauth`, + authorization_endpoint: `http://localhost:${port}/oauth/auth.html`, + // the token endpoint receives requests from synapse, + // rather than the webapp, so needs to escape the docker container. + token_endpoint: `http://host.testcontainers.internal:${port}/oauth/token`, + userinfo_endpoint: `http://host.testcontainers.internal:${port}/oauth/userinfo`, + client_id: "synapse", + discover: false, + scopes: ["profile"], + skip_verification: true, + client_auth_method: "none", + user_mapping_provider: { + config: { + display_name_template: "{{ user.name }}", + }, + }, + }, + ], + }); + await use(container); + server.stop(); + }, +}; diff --git a/playwright/plugins/homeserver/synapse/masHomeserver.ts b/playwright/plugins/homeserver/synapse/masHomeserver.ts new file mode 100644 index 0000000000..cb144fcaee --- /dev/null +++ b/playwright/plugins/homeserver/synapse/masHomeserver.ts @@ -0,0 +1,83 @@ +/* +Copyright 2024 New Vector Ltd. +Copyright 2023 The Matrix.org Foundation C.I.C. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { Fixtures, PlaywrightTestArgs } from "@playwright/test"; + +import { Services } from "../../../services.ts"; +import { Fixtures as BaseFixtures } from "../../../element-web-test.ts"; +import { MatrixAuthenticationServiceContainer } from "../../../testcontainers/mas.ts"; + +type Fixture = PlaywrightTestArgs & Services & BaseFixtures; +export const masHomeserver: Fixtures = { + mas: async ({ _homeserver: homeserver, logger, network, postgres, mailhog }, use) => { + const config = { + clients: [ + { + client_id: "0000000000000000000SYNAPSE", + client_auth_method: "client_secret_basic", + client_secret: "SomeRandomSecret", + }, + ], + matrix: { + homeserver: "localhost", + secret: "AnotherRandomSecret", + endpoint: "http://homeserver:8008", + }, + }; + + const container = await new MatrixAuthenticationServiceContainer(postgres) + .withNetwork(network) + .withNetworkAliases("mas") + .withLogConsumer(logger.getConsumer("mas")) + .withConfig(config) + .start(); + + homeserver.withConfig({ + enable_registration: undefined, + enable_registration_without_verification: undefined, + disable_msisdn_registration: undefined, + password_config: undefined, + experimental_features: { + msc3861: { + enabled: true, + issuer: `http://mas:8080/`, + introspection_endpoint: "http://mas:8080/oauth2/introspect", + client_id: config.clients[0].client_id, + client_auth_method: config.clients[0].client_auth_method, + client_secret: config.clients[0].client_secret, + admin_token: config.matrix.secret, + }, + }, + }); + + await use(container); + await container.stop(); + }, + + config: async ({ homeserver, context, mas }, use) => { + const issuer = `${mas.baseUrl}/`; + const wellKnown = { + "m.homeserver": { + base_url: homeserver.baseUrl, + }, + "org.matrix.msc2965.authentication": { + issuer, + account: `${issuer}account`, + }, + }; + + // Ensure org.matrix.msc2965.authentication is in well-known + await context.route("https://localhost/.well-known/matrix/client", async (route) => { + await route.fulfill({ json: wellKnown }); + }); + + await use({ + default_server_config: wellKnown, + }); + }, +}; diff --git a/playwright/plugins/homeserver/synapse/templates/consent/res/templates/privacy/en/1.0.html b/playwright/plugins/homeserver/synapse/res/templates/privacy/en/1.0.html similarity index 100% rename from playwright/plugins/homeserver/synapse/templates/consent/res/templates/privacy/en/1.0.html rename to playwright/plugins/homeserver/synapse/res/templates/privacy/en/1.0.html diff --git a/playwright/plugins/homeserver/synapse/templates/consent/res/templates/privacy/en/success.html b/playwright/plugins/homeserver/synapse/res/templates/privacy/en/success.html similarity index 100% rename from playwright/plugins/homeserver/synapse/templates/consent/res/templates/privacy/en/success.html rename to playwright/plugins/homeserver/synapse/res/templates/privacy/en/success.html diff --git a/playwright/plugins/homeserver/synapse/templates/COPYME/README.md b/playwright/plugins/homeserver/synapse/templates/COPYME/README.md deleted file mode 100644 index df1ed89e6e..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/COPYME/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Meta-template for synapse templates - -To make another template, you can copy this directory diff --git a/playwright/plugins/homeserver/synapse/templates/COPYME/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/COPYME/homeserver.yaml deleted file mode 100644 index cb58dc8661..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/COPYME/homeserver.yaml +++ /dev/null @@ -1,72 +0,0 @@ -server_name: "localhost" -pid_file: /data/homeserver.pid -# XXX: This won't actually be right: it lets docker allocate an ephemeral port, -# so we have a chicken-and-egg problem -public_baseurl: http://localhost:8008/ -# Listener is always port 8008 (configured in the container) -listeners: - - port: 8008 - tls: false - bind_addresses: ["::"] - type: http - x_forwarded: true - - resources: - - names: [client, federation, consent] - compress: false - -# An sqlite in-memory database is fast & automatically wipes each time -database: - name: "sqlite3" - args: - database: ":memory:" - -# Needs to be configured to log to the console like a good docker process -log_config: "/data/log.config" - -rc_messages_per_second: 10000 -rc_message_burst_count: 10000 -rc_registration: - per_second: 10000 - burst_count: 10000 - -rc_login: - address: - per_second: 10000 - burst_count: 10000 - account: - per_second: 10000 - burst_count: 10000 - failed_attempts: - per_second: 10000 - burst_count: 10000 - -media_store_path: "/data/media_store" -uploads_path: "/data/uploads" -enable_registration: true -enable_registration_without_verification: true -disable_msisdn_registration: false -# These placeholders will be be replaced with values generated at start -registration_shared_secret: "{{REGISTRATION_SECRET}}" -report_stats: false -macaroon_secret_key: "{{MACAROON_SECRET_KEY}}" -form_secret: "{{FORM_SECRET}}" -# Signing key must be here: it will be generated to this file -signing_key_path: "/data/localhost.signing.key" -email: - enable_notifs: false - smtp_host: "localhost" - smtp_port: 25 - smtp_user: "exampleusername" - smtp_pass: "examplepassword" - require_transport_security: False - notif_from: "Your Friendly %(app)s homeserver " - app_name: Matrix - notif_template_html: notif_mail.html - notif_template_text: notif_mail.txt - notif_for_new_users: True - client_base_url: "http://localhost/element" - -trusted_key_servers: - - server_name: "matrix.org" -suppress_key_server_warning: true diff --git a/playwright/plugins/homeserver/synapse/templates/COPYME/log.config b/playwright/plugins/homeserver/synapse/templates/COPYME/log.config deleted file mode 100644 index ac232762da..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/COPYME/log.config +++ /dev/null @@ -1,50 +0,0 @@ -# Log configuration for Synapse. -# -# This is a YAML file containing a standard Python logging configuration -# dictionary. See [1] for details on the valid settings. -# -# Synapse also supports structured logging for machine readable logs which can -# be ingested by ELK stacks. See [2] for details. -# -# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema -# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html - -version: 1 - -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' - -handlers: - # A handler that writes logs to stderr. Unused by default, but can be used - # instead of "buffer" and "file" in the logger handlers. - console: - class: logging.StreamHandler - formatter: precise - -loggers: - synapse.storage.SQL: - # beware: increasing this to DEBUG will make synapse log sensitive - # information such as access tokens. - level: INFO - - twisted: - # We send the twisted logging directly to the file handler, - # to work around https://github.com/matrix-org/synapse/issues/3471 - # when using "buffer" logger. Use "console" to log to stderr instead. - handlers: [console] - propagate: false - -root: - level: INFO - - # Write logs to the `buffer` handler, which will buffer them together in memory, - # then write them to a file. - # - # Replace "buffer" with "console" to log to stderr instead. (Note that you'll - # also need to update the configuration for the `twisted` logger above, in - # this case.) - # - handlers: [console] - -disable_existing_loggers: false diff --git a/playwright/plugins/homeserver/synapse/templates/consent/README.md b/playwright/plugins/homeserver/synapse/templates/consent/README.md deleted file mode 100644 index 713e55f9d5..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/consent/README.md +++ /dev/null @@ -1 +0,0 @@ -A synapse configured with user privacy consent enabled diff --git a/playwright/plugins/homeserver/synapse/templates/consent/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/consent/homeserver.yaml deleted file mode 100644 index d3a4fa520c..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/consent/homeserver.yaml +++ /dev/null @@ -1,84 +0,0 @@ -server_name: "localhost" -pid_file: /data/homeserver.pid -public_baseurl: "{{PUBLIC_BASEURL}}" -listeners: - - port: 8008 - tls: false - bind_addresses: ["::"] - type: http - x_forwarded: true - - resources: - - names: [client, federation, consent] - compress: false - -database: - name: "sqlite3" - args: - database: ":memory:" - -log_config: "/data/log.config" - -rc_messages_per_second: 10000 -rc_message_burst_count: 10000 -rc_registration: - per_second: 10000 - burst_count: 10000 - -rc_login: - address: - per_second: 10000 - burst_count: 10000 - account: - per_second: 10000 - burst_count: 10000 - failed_attempts: - per_second: 10000 - burst_count: 10000 - -media_store_path: "/data/media_store" -uploads_path: "/data/uploads" -enable_registration: true -enable_registration_without_verification: true -disable_msisdn_registration: false -registration_shared_secret: "{{REGISTRATION_SECRET}}" -report_stats: false -macaroon_secret_key: "{{MACAROON_SECRET_KEY}}" -form_secret: "{{FORM_SECRET}}" -signing_key_path: "/data/localhost.signing.key" -email: - enable_notifs: false - smtp_host: "localhost" - smtp_port: 25 - smtp_user: "exampleusername" - smtp_pass: "examplepassword" - require_transport_security: False - notif_from: "Your Friendly %(app)s homeserver " - app_name: Matrix - notif_template_html: notif_mail.html - notif_template_text: notif_mail.txt - notif_for_new_users: True - client_base_url: "http://localhost/element" - -user_consent: - template_dir: /data/res/templates/privacy - version: 1.0 - server_notice_content: - msgtype: m.text - body: >- - To continue using this homeserver you must review and agree to the - terms and conditions at %(consent_uri)s - send_server_notice_to_guests: True - block_events_error: >- - To continue using this homeserver you must review and agree to the - terms and conditions at %(consent_uri)s - require_at_registration: true - -server_notices: - system_mxid_localpart: notices - system_mxid_display_name: "Server Notices" - system_mxid_avatar_url: "mxc://localhost:5005/oumMVlgDnLYFaPVkExemNVVZ" - room_name: "Server Notices" -trusted_key_servers: - - server_name: "matrix.org" -suppress_key_server_warning: true diff --git a/playwright/plugins/homeserver/synapse/templates/consent/log.config b/playwright/plugins/homeserver/synapse/templates/consent/log.config deleted file mode 100644 index b9123d0f5b..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/consent/log.config +++ /dev/null @@ -1,50 +0,0 @@ -# Log configuration for Synapse. -# -# This is a YAML file containing a standard Python logging configuration -# dictionary. See [1] for details on the valid settings. -# -# Synapse also supports structured logging for machine readable logs which can -# be ingested by ELK stacks. See [2] for details. -# -# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema -# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html - -version: 1 - -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' - -handlers: - # A handler that writes logs to stderr. Unused by default, but can be used - # instead of "buffer" and "file" in the logger handlers. - console: - class: logging.StreamHandler - formatter: precise - -loggers: - synapse.storage.SQL: - # beware: increasing this to DEBUG will make synapse log sensitive - # information such as access tokens. - level: DEBUG - - twisted: - # We send the twisted logging directly to the file handler, - # to work around https://github.com/matrix-org/synapse/issues/3471 - # when using "buffer" logger. Use "console" to log to stderr instead. - handlers: [console] - propagate: false - -root: - level: DEBUG - - # Write logs to the `buffer` handler, which will buffer them together in memory, - # then write them to a file. - # - # Replace "buffer" with "console" to log to stderr instead. (Note that you'll - # also need to update the configuration for the `twisted` logger above, in - # this case.) - # - handlers: [console] - -disable_existing_loggers: false diff --git a/playwright/plugins/homeserver/synapse/templates/default/README.md b/playwright/plugins/homeserver/synapse/templates/default/README.md deleted file mode 100644 index 8f6b11f999..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/default/README.md +++ /dev/null @@ -1 +0,0 @@ -A synapse configured with user privacy consent disabled diff --git a/playwright/plugins/homeserver/synapse/templates/default/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/default/homeserver.yaml deleted file mode 100644 index 539a917b20..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/default/homeserver.yaml +++ /dev/null @@ -1,106 +0,0 @@ -server_name: "localhost" -pid_file: /data/homeserver.pid -public_baseurl: "{{PUBLIC_BASEURL}}" -listeners: - - port: 8008 - tls: false - bind_addresses: ["::"] - type: http - x_forwarded: true - - resources: - - names: [client] - compress: false - -database: - name: "sqlite3" - args: - database: ":memory:" - -log_config: "/data/log.config" - -rc_messages_per_second: 10000 -rc_message_burst_count: 10000 -rc_registration: - per_second: 10000 - burst_count: 10000 -rc_joins: - local: - per_second: 9999 - burst_count: 9999 - remote: - per_second: 9999 - burst_count: 9999 -rc_joins_per_room: - per_second: 9999 - burst_count: 9999 -rc_3pid_validation: - per_second: 1000 - burst_count: 1000 - -rc_invites: - per_room: - per_second: 1000 - burst_count: 1000 - per_user: - per_second: 1000 - burst_count: 1000 - -rc_login: - address: - per_second: 10000 - burst_count: 10000 - account: - per_second: 10000 - burst_count: 10000 - failed_attempts: - per_second: 10000 - burst_count: 10000 - -media_store_path: "/data/media_store" -uploads_path: "/data/uploads" -enable_registration: true -enable_registration_without_verification: true -disable_msisdn_registration: false -registration_shared_secret: "{{REGISTRATION_SECRET}}" -report_stats: false -macaroon_secret_key: "{{MACAROON_SECRET_KEY}}" -form_secret: "{{FORM_SECRET}}" -signing_key_path: "/data/localhost.signing.key" - -trusted_key_servers: - - server_name: "matrix.org" -suppress_key_server_warning: true - -ui_auth: - session_timeout: "300s" - -oidc_providers: - - idp_id: test - idp_name: "OAuth test" - issuer: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth" - authorization_endpoint: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth/auth.html" - # the token endpoint receives requests from synapse, rather than the webapp, so needs to escape the docker container. - token_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/token" - userinfo_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/userinfo" - client_id: "synapse" - discover: false - scopes: ["profile"] - skip_verification: true - client_auth_method: none - user_mapping_provider: - config: - display_name_template: "{{ user.name }}" - -# Inhibit background updates as this Synapse isn't long-lived -background_updates: - min_batch_size: 100000 - sleep_duration_ms: 100000 - -experimental_features: - # Needed for e2e/crypto/crypto.spec.ts > Cryptography > decryption failure - # messages > non-joined historical messages. - # Can be removed after Synapse enables it by default - msc4115_membership_on_events: true - -enable_authenticated_media: true diff --git a/playwright/plugins/homeserver/synapse/templates/default/log.config b/playwright/plugins/homeserver/synapse/templates/default/log.config deleted file mode 100644 index b9123d0f5b..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/default/log.config +++ /dev/null @@ -1,50 +0,0 @@ -# Log configuration for Synapse. -# -# This is a YAML file containing a standard Python logging configuration -# dictionary. See [1] for details on the valid settings. -# -# Synapse also supports structured logging for machine readable logs which can -# be ingested by ELK stacks. See [2] for details. -# -# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema -# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html - -version: 1 - -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' - -handlers: - # A handler that writes logs to stderr. Unused by default, but can be used - # instead of "buffer" and "file" in the logger handlers. - console: - class: logging.StreamHandler - formatter: precise - -loggers: - synapse.storage.SQL: - # beware: increasing this to DEBUG will make synapse log sensitive - # information such as access tokens. - level: DEBUG - - twisted: - # We send the twisted logging directly to the file handler, - # to work around https://github.com/matrix-org/synapse/issues/3471 - # when using "buffer" logger. Use "console" to log to stderr instead. - handlers: [console] - propagate: false - -root: - level: DEBUG - - # Write logs to the `buffer` handler, which will buffer them together in memory, - # then write them to a file. - # - # Replace "buffer" with "console" to log to stderr instead. (Note that you'll - # also need to update the configuration for the `twisted` logger above, in - # this case.) - # - handlers: [console] - -disable_existing_loggers: false diff --git a/playwright/plugins/homeserver/synapse/templates/dehydration/README.md b/playwright/plugins/homeserver/synapse/templates/dehydration/README.md deleted file mode 100644 index 18f7923e6d..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/dehydration/README.md +++ /dev/null @@ -1 +0,0 @@ -A synapse configured with device dehydration v2 enabled diff --git a/playwright/plugins/homeserver/synapse/templates/dehydration/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/dehydration/homeserver.yaml deleted file mode 100644 index c3ac5d6536..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/dehydration/homeserver.yaml +++ /dev/null @@ -1,102 +0,0 @@ -server_name: "localhost" -pid_file: /data/homeserver.pid -public_baseurl: "{{PUBLIC_BASEURL}}" -listeners: - - port: 8008 - tls: false - bind_addresses: ["::"] - type: http - x_forwarded: true - - resources: - - names: [client] - compress: false - -database: - name: "sqlite3" - args: - database: ":memory:" - -log_config: "/data/log.config" - -rc_messages_per_second: 10000 -rc_message_burst_count: 10000 -rc_registration: - per_second: 10000 - burst_count: 10000 -rc_joins: - local: - per_second: 9999 - burst_count: 9999 - remote: - per_second: 9999 - burst_count: 9999 -rc_joins_per_room: - per_second: 9999 - burst_count: 9999 -rc_3pid_validation: - per_second: 1000 - burst_count: 1000 - -rc_invites: - per_room: - per_second: 1000 - burst_count: 1000 - per_user: - per_second: 1000 - burst_count: 1000 - -rc_login: - address: - per_second: 10000 - burst_count: 10000 - account: - per_second: 10000 - burst_count: 10000 - failed_attempts: - per_second: 10000 - burst_count: 10000 - -media_store_path: "/data/media_store" -uploads_path: "/data/uploads" -enable_registration: true -enable_registration_without_verification: true -disable_msisdn_registration: false -registration_shared_secret: "{{REGISTRATION_SECRET}}" -report_stats: false -macaroon_secret_key: "{{MACAROON_SECRET_KEY}}" -form_secret: "{{FORM_SECRET}}" -signing_key_path: "/data/localhost.signing.key" - -trusted_key_servers: - - server_name: "matrix.org" -suppress_key_server_warning: true - -ui_auth: - session_timeout: "300s" - -oidc_providers: - - idp_id: test - idp_name: "OAuth test" - issuer: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth" - authorization_endpoint: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth/auth.html" - # the token endpoint receives requests from synapse, rather than the webapp, so needs to escape the docker container. - token_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/token" - userinfo_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/userinfo" - client_id: "synapse" - discover: false - scopes: ["profile"] - skip_verification: true - client_auth_method: none - user_mapping_provider: - config: - display_name_template: "{{ user.name }}" - -# Inhibit background updates as this Synapse isn't long-lived -background_updates: - min_batch_size: 100000 - sleep_duration_ms: 100000 - -experimental_features: - msc2697_enabled: false - msc3814_enabled: true diff --git a/playwright/plugins/homeserver/synapse/templates/dehydration/log.config b/playwright/plugins/homeserver/synapse/templates/dehydration/log.config deleted file mode 100644 index b9123d0f5b..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/dehydration/log.config +++ /dev/null @@ -1,50 +0,0 @@ -# Log configuration for Synapse. -# -# This is a YAML file containing a standard Python logging configuration -# dictionary. See [1] for details on the valid settings. -# -# Synapse also supports structured logging for machine readable logs which can -# be ingested by ELK stacks. See [2] for details. -# -# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema -# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html - -version: 1 - -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' - -handlers: - # A handler that writes logs to stderr. Unused by default, but can be used - # instead of "buffer" and "file" in the logger handlers. - console: - class: logging.StreamHandler - formatter: precise - -loggers: - synapse.storage.SQL: - # beware: increasing this to DEBUG will make synapse log sensitive - # information such as access tokens. - level: DEBUG - - twisted: - # We send the twisted logging directly to the file handler, - # to work around https://github.com/matrix-org/synapse/issues/3471 - # when using "buffer" logger. Use "console" to log to stderr instead. - handlers: [console] - propagate: false - -root: - level: DEBUG - - # Write logs to the `buffer` handler, which will buffer them together in memory, - # then write them to a file. - # - # Replace "buffer" with "console" to log to stderr instead. (Note that you'll - # also need to update the configuration for the `twisted` logger above, in - # this case.) - # - handlers: [console] - -disable_existing_loggers: false diff --git a/playwright/plugins/homeserver/synapse/templates/email/README.md b/playwright/plugins/homeserver/synapse/templates/email/README.md deleted file mode 100644 index 40c23ba0be..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/email/README.md +++ /dev/null @@ -1 +0,0 @@ -A synapse configured to require an email for registration diff --git a/playwright/plugins/homeserver/synapse/templates/email/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/email/homeserver.yaml deleted file mode 100644 index fc20641ab4..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/email/homeserver.yaml +++ /dev/null @@ -1,44 +0,0 @@ -server_name: "localhost" -pid_file: /data/homeserver.pid -public_baseurl: "{{PUBLIC_BASEURL}}" -listeners: - - port: 8008 - tls: false - bind_addresses: ["::"] - type: http - x_forwarded: true - - resources: - - names: [client] - compress: false - -database: - name: "sqlite3" - args: - database: ":memory:" - -log_config: "/data/log.config" - -media_store_path: "/data/media_store" -uploads_path: "/data/uploads" -enable_registration: true -registrations_require_3pid: - - email -registration_shared_secret: "{{REGISTRATION_SECRET}}" -report_stats: false -macaroon_secret_key: "{{MACAROON_SECRET_KEY}}" -form_secret: "{{FORM_SECRET}}" -signing_key_path: "/data/localhost.signing.key" - -trusted_key_servers: - - server_name: "matrix.org" -suppress_key_server_warning: true - -ui_auth: - session_timeout: "300s" - -email: - smtp_host: "%SMTP_HOST%" - smtp_port: %SMTP_PORT% - notif_from: "Your Friendly %(app)s homeserver " - app_name: my_branded_matrix_server diff --git a/playwright/plugins/homeserver/synapse/templates/email/log.config b/playwright/plugins/homeserver/synapse/templates/email/log.config deleted file mode 100644 index ac232762da..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/email/log.config +++ /dev/null @@ -1,50 +0,0 @@ -# Log configuration for Synapse. -# -# This is a YAML file containing a standard Python logging configuration -# dictionary. See [1] for details on the valid settings. -# -# Synapse also supports structured logging for machine readable logs which can -# be ingested by ELK stacks. See [2] for details. -# -# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema -# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html - -version: 1 - -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' - -handlers: - # A handler that writes logs to stderr. Unused by default, but can be used - # instead of "buffer" and "file" in the logger handlers. - console: - class: logging.StreamHandler - formatter: precise - -loggers: - synapse.storage.SQL: - # beware: increasing this to DEBUG will make synapse log sensitive - # information such as access tokens. - level: INFO - - twisted: - # We send the twisted logging directly to the file handler, - # to work around https://github.com/matrix-org/synapse/issues/3471 - # when using "buffer" logger. Use "console" to log to stderr instead. - handlers: [console] - propagate: false - -root: - level: INFO - - # Write logs to the `buffer` handler, which will buffer them together in memory, - # then write them to a file. - # - # Replace "buffer" with "console" to log to stderr instead. (Note that you'll - # also need to update the configuration for the `twisted` logger above, in - # this case.) - # - handlers: [console] - -disable_existing_loggers: false diff --git a/playwright/plugins/homeserver/synapse/templates/guest-enabled/README.md b/playwright/plugins/homeserver/synapse/templates/guest-enabled/README.md deleted file mode 100644 index e1fef0b9d4..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/guest-enabled/README.md +++ /dev/null @@ -1 +0,0 @@ -A synapse configured with guest registration enabled. diff --git a/playwright/plugins/homeserver/synapse/templates/guest-enabled/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/guest-enabled/homeserver.yaml deleted file mode 100644 index 1faa39c3a7..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/guest-enabled/homeserver.yaml +++ /dev/null @@ -1,105 +0,0 @@ -server_name: "localhost" -pid_file: /data/homeserver.pid -public_baseurl: "{{PUBLIC_BASEURL}}" -listeners: - - port: 8008 - tls: false - bind_addresses: ["::"] - type: http - x_forwarded: true - - resources: - - names: [client] - compress: false - -database: - name: "sqlite3" - args: - database: ":memory:" - -log_config: "/data/log.config" - -rc_messages_per_second: 10000 -rc_message_burst_count: 10000 -rc_registration: - per_second: 10000 - burst_count: 10000 -rc_joins: - local: - per_second: 9999 - burst_count: 9999 - remote: - per_second: 9999 - burst_count: 9999 -rc_joins_per_room: - per_second: 9999 - burst_count: 9999 -rc_3pid_validation: - per_second: 1000 - burst_count: 1000 - -rc_invites: - per_room: - per_second: 1000 - burst_count: 1000 - per_user: - per_second: 1000 - burst_count: 1000 - -rc_login: - address: - per_second: 10000 - burst_count: 10000 - account: - per_second: 10000 - burst_count: 10000 - failed_attempts: - per_second: 10000 - burst_count: 10000 - -media_store_path: "/data/media_store" -uploads_path: "/data/uploads" -allow_guest_access: true -enable_registration: true -enable_registration_without_verification: true -disable_msisdn_registration: false -registration_shared_secret: "{{REGISTRATION_SECRET}}" -report_stats: false -macaroon_secret_key: "{{MACAROON_SECRET_KEY}}" -form_secret: "{{FORM_SECRET}}" -signing_key_path: "/data/localhost.signing.key" - -trusted_key_servers: - - server_name: "matrix.org" -suppress_key_server_warning: true - -ui_auth: - session_timeout: "300s" - -oidc_providers: - - idp_id: test - idp_name: "OAuth test" - issuer: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth" - authorization_endpoint: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth/auth.html" - # the token endpoint receives requests from synapse, rather than the webapp, so needs to escape the docker container. - token_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/token" - userinfo_endpoint: "http://host.containers.internal:{{OAUTH_SERVER_PORT}}/oauth/userinfo" - client_id: "synapse" - discover: false - scopes: ["profile"] - skip_verification: true - client_auth_method: none - user_mapping_provider: - config: - display_name_template: "{{ user.name }}" - -# Inhibit background updates as this Synapse isn't long-lived -background_updates: - min_batch_size: 100000 - sleep_duration_ms: 100000 - -experimental_features: - # Needed for e2e/crypto/crypto.spec.ts > Cryptography > decryption failure - # messages > non-joined historical messages. - # Can be removed after Synapse enables it by default - msc4115_membership_on_events: true diff --git a/playwright/plugins/homeserver/synapse/templates/guest-enabled/log.config b/playwright/plugins/homeserver/synapse/templates/guest-enabled/log.config deleted file mode 100644 index ac232762da..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/guest-enabled/log.config +++ /dev/null @@ -1,50 +0,0 @@ -# Log configuration for Synapse. -# -# This is a YAML file containing a standard Python logging configuration -# dictionary. See [1] for details on the valid settings. -# -# Synapse also supports structured logging for machine readable logs which can -# be ingested by ELK stacks. See [2] for details. -# -# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema -# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html - -version: 1 - -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' - -handlers: - # A handler that writes logs to stderr. Unused by default, but can be used - # instead of "buffer" and "file" in the logger handlers. - console: - class: logging.StreamHandler - formatter: precise - -loggers: - synapse.storage.SQL: - # beware: increasing this to DEBUG will make synapse log sensitive - # information such as access tokens. - level: INFO - - twisted: - # We send the twisted logging directly to the file handler, - # to work around https://github.com/matrix-org/synapse/issues/3471 - # when using "buffer" logger. Use "console" to log to stderr instead. - handlers: [console] - propagate: false - -root: - level: INFO - - # Write logs to the `buffer` handler, which will buffer them together in memory, - # then write them to a file. - # - # Replace "buffer" with "console" to log to stderr instead. (Note that you'll - # also need to update the configuration for the `twisted` logger above, in - # this case.) - # - handlers: [console] - -disable_existing_loggers: false diff --git a/playwright/plugins/homeserver/synapse/templates/mas-oidc/README.md b/playwright/plugins/homeserver/synapse/templates/mas-oidc/README.md deleted file mode 100644 index 223ff436a8..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/mas-oidc/README.md +++ /dev/null @@ -1 +0,0 @@ -A synapse configured with auth delegated to via matrix authentication service diff --git a/playwright/plugins/homeserver/synapse/templates/mas-oidc/homeserver.yaml b/playwright/plugins/homeserver/synapse/templates/mas-oidc/homeserver.yaml deleted file mode 100644 index 64fea9a5a9..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/mas-oidc/homeserver.yaml +++ /dev/null @@ -1,96 +0,0 @@ -server_name: "localhost" -pid_file: /data/homeserver.pid -public_baseurl: "{{PUBLIC_BASEURL}}" -listeners: - - port: 8008 - tls: false - bind_addresses: ["::"] - type: http - x_forwarded: true - - resources: - - names: [client] - compress: false - -database: - name: "sqlite3" - args: - database: ":memory:" - -log_config: "/data/log.config" - -rc_messages_per_second: 10000 -rc_message_burst_count: 10000 -rc_registration: - per_second: 10000 - burst_count: 10000 -rc_joins: - local: - per_second: 9999 - burst_count: 9999 - remote: - per_second: 9999 - burst_count: 9999 -rc_joins_per_room: - per_second: 9999 - burst_count: 9999 -rc_3pid_validation: - per_second: 1000 - burst_count: 1000 - -rc_invites: - per_room: - per_second: 1000 - burst_count: 1000 - per_user: - per_second: 1000 - burst_count: 1000 - -rc_login: - address: - per_second: 10000 - burst_count: 10000 - account: - per_second: 10000 - burst_count: 10000 - failed_attempts: - per_second: 10000 - burst_count: 10000 - -media_store_path: "/data/media_store" -uploads_path: "/data/uploads" -registration_shared_secret: "{{REGISTRATION_SECRET}}" -report_stats: false -macaroon_secret_key: "{{MACAROON_SECRET_KEY}}" -form_secret: "{{FORM_SECRET}}" -signing_key_path: "/data/localhost.signing.key" - -trusted_key_servers: - - server_name: "matrix.org" -suppress_key_server_warning: true - -ui_auth: - session_timeout: "300s" - -# Inhibit background updates as this Synapse isn't long-lived -background_updates: - min_batch_size: 100000 - sleep_duration_ms: 100000 - -serve_server_wellknown: true -experimental_features: - msc3861: - enabled: true - - issuer: http://host.containers.internal:%MAS_PORT%/ - introspection_endpoint: http://host.containers.internal:%MAS_PORT%/oauth2/introspect - - # Matches the `client_id` in the auth service config - client_id: 0000000000000000000SYNAPSE - # Matches the `client_auth_method` in the auth service config - client_auth_method: client_secret_basic - # Matches the `client_secret` in the auth service config - client_secret: "SomeRandomSecret" - - # Matches the `matrix.secret` in the auth service config - admin_token: "AnotherRandomSecret" diff --git a/playwright/plugins/homeserver/synapse/templates/mas-oidc/log.config b/playwright/plugins/homeserver/synapse/templates/mas-oidc/log.config deleted file mode 100644 index b9123d0f5b..0000000000 --- a/playwright/plugins/homeserver/synapse/templates/mas-oidc/log.config +++ /dev/null @@ -1,50 +0,0 @@ -# Log configuration for Synapse. -# -# This is a YAML file containing a standard Python logging configuration -# dictionary. See [1] for details on the valid settings. -# -# Synapse also supports structured logging for machine readable logs which can -# be ingested by ELK stacks. See [2] for details. -# -# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema -# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html - -version: 1 - -formatters: - precise: - format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' - -handlers: - # A handler that writes logs to stderr. Unused by default, but can be used - # instead of "buffer" and "file" in the logger handlers. - console: - class: logging.StreamHandler - formatter: precise - -loggers: - synapse.storage.SQL: - # beware: increasing this to DEBUG will make synapse log sensitive - # information such as access tokens. - level: DEBUG - - twisted: - # We send the twisted logging directly to the file handler, - # to work around https://github.com/matrix-org/synapse/issues/3471 - # when using "buffer" logger. Use "console" to log to stderr instead. - handlers: [console] - propagate: false - -root: - level: DEBUG - - # Write logs to the `buffer` handler, which will buffer them together in memory, - # then write them to a file. - # - # Replace "buffer" with "console" to log to stderr instead. (Note that you'll - # also need to update the configuration for the `twisted` logger above, in - # this case.) - # - handlers: [console] - -disable_existing_loggers: false diff --git a/playwright/plugins/mailhog/index.ts b/playwright/plugins/mailhog/index.ts deleted file mode 100644 index 967d2cb806..0000000000 --- a/playwright/plugins/mailhog/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 The Matrix.org Foundation C.I.C. - -SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial -Please see LICENSE files in the repository root for full details. -*/ - -import mailhog from "mailhog"; - -import { getFreePort } from "../utils/port"; -import { Docker } from "../docker"; - -export interface Instance { - host: string; - smtpPort: number; - httpPort: number; - containerId: string; -} - -export class MailHogServer { - private readonly docker: Docker = new Docker(); - private instance?: Instance; - - async start(): Promise<{ api: mailhog.API; instance: Instance }> { - if (this.instance) throw new Error("Mailhog server is already running!"); - const smtpPort = await getFreePort(); - const httpPort = await getFreePort(); - console.log(`Starting mailhog...`); - const containerId = await this.docker.run({ - image: "mailhog/mailhog:latest", - containerName: `react-sdk-playwright-mailhog`, - params: ["-p", `${smtpPort}:1025/tcp`, "-p", `${httpPort}:8025/tcp`], - }); - console.log(`Started mailhog on ports smtp=${smtpPort} http=${httpPort}.`); - const host = await this.docker.getContainerIp(); - this.instance = { smtpPort, httpPort, containerId, host }; - return { api: mailhog({ host: "localhost", port: httpPort }), instance: this.instance }; - } - - async stop(): Promise { - if (!this.instance) throw new Error("Missing existing mailhog instance, did you call stop() before start()?"); - await this.docker.stop(); - console.log(`Stopped mailhog id ${this.instance.containerId}.`); - this.instance = undefined; - } -} diff --git a/playwright/plugins/matrix-authentication-service/config.yaml b/playwright/plugins/matrix-authentication-service/config.yaml deleted file mode 100644 index 5ee69bdec5..0000000000 --- a/playwright/plugins/matrix-authentication-service/config.yaml +++ /dev/null @@ -1,156 +0,0 @@ -clients: - - client_id: 0000000000000000000SYNAPSE - client_auth_method: client_secret_basic - client_secret: "SomeRandomSecret" -http: - listeners: - - name: web - resources: - - name: discovery - - name: human - - name: oauth - - name: compat - - name: graphql - playground: true - - name: assets - path: /usr/local/share/mas-cli/assets/ - binds: - - address: "[::]:8080" - proxy_protocol: false - - name: internal - resources: - - name: health - binds: - - host: localhost - port: 8081 - proxy_protocol: false - trusted_proxies: - - 192.128.0.0/16 - - 172.16.0.0/12 - - 10.0.0.0/10 - - 127.0.0.1/8 - - fd00::/8 - - ::1/128 - public_base: "http://localhost:{{MAS_PORT}}/" - issuer: http://localhost:{{MAS_PORT}}/ -database: - host: "{{POSTGRES_HOST}}" - port: 5432 - database: postgres - username: postgres - password: "{{POSTGRES_PASSWORD}}" - max_connections: 10 - min_connections: 0 - connect_timeout: 30 - idle_timeout: 600 - max_lifetime: 1800 -telemetry: - tracing: - exporter: none - propagators: [] - metrics: - exporter: none - sentry: - dsn: null -templates: - path: /usr/local/share/mas-cli/templates/ - assets_manifest: /usr/local/share/mas-cli/manifest.json - translations_path: /usr/local/share/mas-cli/translations/ -email: - from: '"Authentication Service" ' - reply_to: '"Authentication Service" ' - transport: smtp - mode: plain - hostname: "host.containers.internal" - port: %{{SMTP_PORT}} - username: username - password: password - -secrets: - encryption: 984b18e207c55ad5fbb2a49b217481a722917ee87b2308d4cf314c83fed8e3b5 - keys: - - kid: YEAhzrKipJ - key: | - -----BEGIN RSA PRIVATE KEY----- - MIIEowIBAAKCAQEAuIV+AW5vx52I4CuumgSxp6yvKfIAnRdALeZZCoFkIGxUli1B - S79NJ3ls46oLh1pSD9RrhaMp6HTNoi4K3hnP9Q9v77pD7KwdFKG3UdG1zksIB0s/ - +/Ey/DmX4LPluwBBS7r/LkQ1jk745lENA++oiDqZf2D/uP8jCHlvaSNyVKTqi1ki - OXPd4T4xBUjzuas9ze5jQVSYtfOidgnv1EzUipbIxgvH1jNt4raRlmP8mOq7xEnW - R+cF5x6n/g17PdSEfrwO4kz6aKGZuMP5lVlDEEnMHKabFSQDBl7+Mpok6jXutbtA - uiBnsKEahF9eoj4na4fpbRNPdIVyoaN5eGvm5wIDAQABAoIBAApyFCYEmHNWaa83 - CdVSOrRhRDE9r+c0r79pcNT1ajOjrk4qFa4yEC4R46YntCtfY5Hd1pBkIjU0l4d8 - z8Su9WTMEOwjQUEepS7L0NLi6kXZXYT8L40VpGs+32grBvBFHW0qEtQNrHJ36gMv - x2rXoFTF7HaXiSJx3wvVxAbRqOE9tBXLsmNHaWaAdWQG5o77V9+zvMri3cAeEg2w - VkKokb0dza7es7xG3tqS26k69SrwGeeuKo7qCHPH2cfyWmY5Yhv8iOoA59JzzbiK - UdxyzCHskrPSpRKVkVVwmY3RBt282TmSRG7td7e5ESSj50P2e5BI5uu1Hp/dvU4F - vYjV7kECgYEA6WqYoUpVsgQiqhvJwJIc/8gRm0mUy8TenI36z4Iim01Nt7fibWH7 - XnsFqLGjXtYNVWvBcCrUl9doEnRbJeG2eRGbGKYAWVrOeFvwM4fYvw9GoOiJdDj4 - cgWDe7eHbHE+UTqR7Nnr/UBfipoNWDh6X68HRBuXowh0Q6tOfxsrRFECgYEAyl/V - 4b8bFp3pKZZCb+KPSYsQf793cRmrBexPcLWcDPYbMZQADEZ/VLjbrNrpTOWxUWJT - hr8MrWswnHO+l5AFu5CNO+QgV2dHLk+2w8qpdpFRPJCfXfo2D3wZ0c4cv3VCwv1V - 5y7f6XWVjDWZYV4wj6c3shxZJjZ+9Hbhf3/twbcCgYA6fuRRR3fCbRbi2qPtBrEN - yO3gpMgNaQEA6vP4HPzfPrhDWmn8T5nXS61XYW03zxz4U1De81zj0K/cMBzHmZFJ - NghQXQmpWwBzWVcREvJWr1Vb7erEnaJlsMwKrSvbGWYspSj82oAxr3hCG+lMOpsw - b4S6pM+TpAK/EqdRY1WsgQKBgQCGoMaaTRXqL9bC0bEU2XVVCWxKb8c3uEmrwQ7/ - /fD4NmjUzI5TnDps1CVfkqoNe+hAKddDFqmKXHqUOfOaxDbsFje+lf5l5tDVoDYH - fjTKKdYPIm7CiAeauYY7qpA5Vfq52Opixy4yEwUPp0CII67OggFtPaqY3zwJyWQt - +57hdQKBgGCXM/KKt7ceUDcNJxSGjvu0zD9D5Sv2ihYlEBT/JLaTCCJdvzREevaJ - 1d+mpUAt0Lq6A8NWOMq8HPaxAik3rMQ0WtM5iG+XgsUqvTSb7NcshArDLuWGnW3m - MC4rM0UBYAS4QweduUSH1imrwH/1Gu5+PxbiecceRMMggWpzu0Bq - -----END RSA PRIVATE KEY----- - - kid: 8J1AxrlNZT - key: | - -----BEGIN EC PRIVATE KEY----- - MHcCAQEEIF1cjfIOEdy3BXJ72x6fKpEB8WP1ddZAUJAaqqr/6CpToAoGCCqGSM49 - AwEHoUQDQgAEfHdNuI1Yeh3/uOq2PlnW2vymloOVpwBYebbw4VVsna9xhnutIdQW - dE8hkX8Yb0pIDasrDiwllVLzSvsWJAI0Kw== - -----END EC PRIVATE KEY----- - - kid: 3BW6un1EBi - key: | - -----BEGIN EC PRIVATE KEY----- - MIGkAgEBBDA+3ZV17r8TsiMdw1cpbTSNbyEd5SMy3VS1Mk/kz6O2Ev/3QZut8GE2 - q3eGtLBoVQigBwYFK4EEACKhZANiAASs8Wxjk/uRimRKXnPr2/wDaXkN9wMDjYQK - mZULb+0ZP1/cXmuXuri8hUGhQvIU8KWY9PkpV+LMPEdpE54mHPKSLjq5CDXoSZ/P - 9f7cdRaOZ000KQPZfIFR9ujJTtDN7Vs= - -----END EC PRIVATE KEY----- - - kid: pkZ0pTKK0X - key: | - -----BEGIN EC PRIVATE KEY----- - MHQCAQEEIHenfsXYPc5yzjZKUfvmydDR1YRwdsfZYvwHf/2wsYxooAcGBSuBBAAK - oUQDQgAEON1x7Vlu+nA0KvC5vYSOHhDUkfLYNZwYSLPFVT02h9E13yFFMIJegIBl - Aer+6PMZpPc8ycyeH9N+U9NAyliBhQ== - -----END EC PRIVATE KEY----- -passwords: - enabled: true - schemes: - - version: 1 - algorithm: argon2id - minimum_complexity: 0 -matrix: - homeserver: localhost - secret: AnotherRandomSecret - endpoint: "{{SYNAPSE_URL}}" -policy: - wasm_module: /usr/local/share/mas-cli/policy.wasm - client_registration_entrypoint: client_registration/violation - register_entrypoint: register/violation - authorization_grant_entrypoint: authorization_grant/violation - password_entrypoint: password/violation - email_entrypoint: email/violation - data: - client_registration: - allow_insecure_uris: true # allow non-SSL and localhost URIs - allow_missing_contacts: true # EW doesn't have contacts at this time -upstream_oauth2: - providers: [] -branding: - service_name: null - policy_uri: null - tos_uri: null - imprint: null - logo_uri: null -account: - password_registration_enabled: true -experimental: - access_token_ttl: 300 - compat_token_ttl: 300 diff --git a/playwright/plugins/matrix-authentication-service/index.ts b/playwright/plugins/matrix-authentication-service/index.ts deleted file mode 100644 index 775497ed96..0000000000 --- a/playwright/plugins/matrix-authentication-service/index.ts +++ /dev/null @@ -1,145 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 The Matrix.org Foundation C.I.C. - -SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial -Please see LICENSE files in the repository root for full details. -*/ - -import path, { basename } from "node:path"; -import os from "node:os"; -import * as fse from "fs-extra"; -import { BrowserContext, TestInfo } from "@playwright/test"; - -import { getFreePort } from "../utils/port"; -import { Docker } from "../docker"; -import { PG_PASSWORD, PostgresDocker } from "../postgres"; -import { HomeserverInstance } from "../homeserver"; -import { Instance as MailhogInstance } from "../mailhog"; - -// Docker tag to use for `ghcr.io/matrix-org/matrix-authentication-service` image. -const TAG = "0.12.0"; - -interface Instance { - containerId: string; - postgresId: string; - configDir: string; - port: number; -} - -async function cfgDirFromTemplate(opts: { - postgresHost: string; - synapseUrl: string; - masPort: string; - smtpPort: string; -}): Promise<{ - configDir: string; -}> { - const configPath = path.join(__dirname, "config.yaml"); - const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), "react-sdk-mas-")); - - const outputHomeserver = path.join(tempDir, "config.yaml"); - console.log(`Gen ${configPath} -> ${outputHomeserver}`); - let config = await fse.readFile(configPath, "utf8"); - config = config.replace(/{{MAS_PORT}}/g, opts.masPort); - config = config.replace(/{{POSTGRES_HOST}}/g, opts.postgresHost); - config = config.replace(/{{POSTGRES_PASSWORD}}/g, PG_PASSWORD); - config = config.replace(/%{{SMTP_PORT}}/g, opts.smtpPort); - config = config.replace(/{{SYNAPSE_URL}}/g, opts.synapseUrl); - - await fse.writeFile(outputHomeserver, config); - - // Allow anyone to read, write and execute in the temp directory - // so that the DIND setup that we use to update the playwright screenshots work without any issues. - await fse.chmod(tempDir, 0o757); - - return { - configDir: tempDir, - }; -} - -export class MatrixAuthenticationService { - private readonly masDocker = new Docker(); - private readonly postgresDocker = new PostgresDocker("mas"); - private instance: Instance; - public port: number; - - constructor(private context: BrowserContext) {} - - async prepare(): Promise<{ port: number }> { - this.port = await getFreePort(); - return { port: this.port }; - } - - async start(homeserver: HomeserverInstance, mailhog: MailhogInstance): Promise { - console.log(new Date(), "Starting mas..."); - - if (!this.port) await this.prepare(); - const port = this.port; - const { containerId: postgresId, ipAddress: postgresIp } = await this.postgresDocker.start(); - const { configDir } = await cfgDirFromTemplate({ - masPort: port.toString(), - postgresHost: postgresIp, - synapseUrl: homeserver.config.dockerUrl, - smtpPort: mailhog.smtpPort.toString(), - }); - - console.log(new Date(), "starting mas container...", TAG); - const containerId = await this.masDocker.run({ - image: "ghcr.io/element-hq/matrix-authentication-service:" + TAG, - containerName: "react-sdk-playwright-mas", - params: ["-p", `${port}:8080/tcp`, "-v", `${configDir}:/config`], - cmd: ["server", "--config", "/config/config.yaml"], - }); - console.log(new Date(), "started!"); - - // Set up redirects - const baseUrl = `http://localhost:${port}`; - for (const path of [ - "**/_matrix/client/*/login", - "**/_matrix/client/*/login/**", - "**/_matrix/client/*/logout", - "**/_matrix/client/*/refresh", - ]) { - await this.context.route(path, async (route) => { - await route.continue({ - url: new URL(route.request().url().split("/").slice(3).join("/"), baseUrl).href, - }); - }); - } - - this.instance = { containerId, postgresId, port, configDir }; - return this.instance; - } - - async stop(testInfo: TestInfo): Promise { - if (!this.instance) return; // nothing to stop - const id = this.instance.containerId; - const logPath = path.join("playwright", "logs", "matrix-authentication-service", id); - await fse.ensureDir(logPath); - await this.masDocker.persistLogsToFile({ - stdoutFile: path.join(logPath, "stdout.log"), - stderrFile: path.join(logPath, "stderr.log"), - }); - - await this.masDocker.stop(); - await this.postgresDocker.stop(); - - if (testInfo.status !== "passed") { - const logs = [path.join(logPath, "stdout.log"), path.join(logPath, "stderr.log")]; - for (const path of logs) { - await testInfo.attach(`mas-${basename(path)}`, { - path, - contentType: "text/plain", - }); - } - await testInfo.attach("mas-config.yaml", { - path: path.join(this.instance.configDir, "config.yaml"), - contentType: "text/plain", - }); - } - - await fse.remove(this.instance.configDir); - console.log(new Date(), "Stopped mas."); - } -} diff --git a/playwright/plugins/postgres/index.ts b/playwright/plugins/postgres/index.ts deleted file mode 100644 index 52f682c4b4..0000000000 --- a/playwright/plugins/postgres/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 The Matrix.org Foundation C.I.C. - -SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial -Please see LICENSE files in the repository root for full details. -*/ - -import { Docker } from "../docker"; - -export const PG_PASSWORD = "p4S5w0rD"; - -/** - * Class to manage a postgres database in docker - */ -export class PostgresDocker extends Docker { - /** - * @param key an opaque string to use when naming the docker containers instantiated by this class - */ - public constructor(private key: string) { - super(); - } - - private async waitForPostgresReady(ipAddress: string): Promise { - const waitTimeMillis = 30000; - const startTime = new Date().getTime(); - let lastErr: Error | null = null; - while (new Date().getTime() - startTime < waitTimeMillis) { - try { - // Note that we specify the IP address rather than letting it connect to the local - // socket: that's the listener we care about and empirically it matters. - await this.exec(["pg_isready", "-h", ipAddress, "-U", "postgres"], true); - lastErr = null; - break; - } catch (err) { - console.log("pg_isready: failed"); - lastErr = err; - } - } - if (lastErr) { - console.log("rethrowing"); - throw lastErr; - } - } - - public async start(): Promise<{ - ipAddress: string; - containerId: string; - }> { - console.log(new Date(), "starting postgres container"); - const containerId = await this.run({ - image: "postgres", - containerName: `react-sdk-playwright-postgres-${this.key}`, - params: ["--tmpfs=/pgtmpfs", "-e", "PGDATA=/pgtmpfs", "-e", `POSTGRES_PASSWORD=${PG_PASSWORD}`], - // Optimise for testing - https://www.postgresql.org/docs/current/non-durability.html - cmd: ["-c", `fsync=off`, "-c", `synchronous_commit=off`, "-c", `full_page_writes=off`], - }); - - const ipAddress = await this.getContainerIp(); - console.log(new Date(), "postgres container up"); - - await this.waitForPostgresReady(ipAddress); - console.log(new Date(), "postgres container ready"); - return { ipAddress, containerId }; - } -} diff --git a/playwright/plugins/sliding-sync-proxy/index.ts b/playwright/plugins/sliding-sync-proxy/index.ts deleted file mode 100644 index 166729df2d..0000000000 --- a/playwright/plugins/sliding-sync-proxy/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 The Matrix.org Foundation C.I.C. - -SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial -Please see LICENSE files in the repository root for full details. -*/ - -import type { BrowserContext, Route } from "@playwright/test"; -import { getFreePort } from "../utils/port"; -import { Docker } from "../docker"; -import { PG_PASSWORD, PostgresDocker } from "../postgres"; - -// Docker tag to use for `ghcr.io/matrix-org/sliding-sync` image. -const SLIDING_SYNC_PROXY_TAG = "v0.99.3"; - -export interface ProxyInstance { - containerId: string; - postgresId: string; - port: number; -} - -export class SlidingSyncProxy { - private readonly proxyDocker = new Docker(); - private readonly postgresDocker = new PostgresDocker("sliding-sync"); - private instance: ProxyInstance; - - constructor( - private synapseIp: string, - private context: BrowserContext, - ) {} - - private syncHandler = async (route: Route) => { - if (!this.instance) return route.abort("blockedbyclient"); - - const baseUrl = `http://localhost:${this.instance.port}`; - await route.continue({ - url: new URL(route.request().url().split("/").slice(3).join("/"), baseUrl).href, - }); - }; - - async start(): Promise { - console.log(new Date(), "Starting sliding sync proxy..."); - - const { ipAddress: postgresIp, containerId: postgresId } = await this.postgresDocker.start(); - - const port = await getFreePort(); - console.log(new Date(), "starting proxy container...", SLIDING_SYNC_PROXY_TAG); - const containerId = await this.proxyDocker.run({ - image: "ghcr.io/matrix-org/sliding-sync:" + SLIDING_SYNC_PROXY_TAG, - containerName: "react-sdk-playwright-sliding-sync-proxy", - params: [ - "-p", - `${port}:8008/tcp`, - "-e", - "SYNCV3_SECRET=bwahahaha", - "-e", - `SYNCV3_SERVER=${this.synapseIp}`, - "-e", - `SYNCV3_DB=user=postgres dbname=postgres password=${PG_PASSWORD} host=${postgresIp} sslmode=disable`, - ], - }); - console.log(new Date(), "started!"); - - this.instance = { containerId, postgresId, port }; - await this.context.route("**/_matrix/client/unstable/org.matrix.msc3575/sync*", this.syncHandler); - return this.instance; - } - - async stop(): Promise { - await this.context.unroute("**/_matrix/client/unstable/org.matrix.msc3575/sync*", this.syncHandler); - - await this.postgresDocker.stop(); - await this.proxyDocker.stop(); - console.log(new Date(), "Stopped sliding sync proxy."); - } -} diff --git a/playwright/plugins/utils/object.ts b/playwright/plugins/utils/object.ts new file mode 100644 index 0000000000..bfb92fecec --- /dev/null +++ b/playwright/plugins/utils/object.ts @@ -0,0 +1,16 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only +Please see LICENSE files in the repository root for full details. +*/ + +/** + * Deep copy the given object. The object MUST NOT have circular references and + * MUST NOT have functions. + * @param obj - The object to deep copy. + * @returns A copy of the object without any references to the original. + */ +export function deepCopy(obj: T): T { + return JSON.parse(JSON.stringify(obj)); +} diff --git a/playwright/services.ts b/playwright/services.ts new file mode 100644 index 0000000000..58fc21775e --- /dev/null +++ b/playwright/services.ts @@ -0,0 +1,109 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { test as base } from "@playwright/test"; +import mailhog from "mailhog"; +import { GenericContainer, Network, StartedNetwork, StartedTestContainer, Wait } from "testcontainers"; +import { PostgreSqlContainer, StartedPostgreSqlContainer } from "@testcontainers/postgresql"; + +import { SynapseConfigOptions, SynapseContainer } from "./testcontainers/synapse.ts"; +import { ContainerLogger } from "./testcontainers/utils.ts"; +import { StartedMatrixAuthenticationServiceContainer } from "./testcontainers/mas.ts"; +import { HomeserverContainer, StartedHomeserverContainer } from "./testcontainers/HomeserverContainer.ts"; + +export interface Services { + logger: ContainerLogger; + + network: StartedNetwork; + postgres: StartedPostgreSqlContainer; + + mailhog: StartedTestContainer; + mailhogClient: mailhog.API; + + synapseConfigOptions: SynapseConfigOptions; + _homeserver: HomeserverContainer; + homeserver: StartedHomeserverContainer; + mas?: StartedMatrixAuthenticationServiceContainer; +} + +export const test = base.extend({ + // eslint-disable-next-line no-empty-pattern + logger: async ({}, use, testInfo) => { + const logger = new ContainerLogger(); + await use(logger); + await logger.testFinished(testInfo); + }, + // eslint-disable-next-line no-empty-pattern + network: async ({}, use) => { + const network = await new Network().start(); + await use(network); + await network.stop(); + }, + postgres: async ({ logger, network }, use) => { + const container = await new PostgreSqlContainer() + .withNetwork(network) + .withNetworkAliases("postgres") + .withLogConsumer(logger.getConsumer("postgres")) + .withTmpFs({ + "/dev/shm/pgdata/data": "", + }) + .withEnvironment({ + PG_DATA: "/dev/shm/pgdata/data", + }) + .withCommand([ + "-c", + "shared_buffers=128MB", + "-c", + `fsync=off`, + "-c", + `synchronous_commit=off`, + "-c", + "full_page_writes=off", + ]) + .start(); + await use(container); + await container.stop(); + }, + + mailhog: async ({ logger, network }, use) => { + const container = await new GenericContainer("mailhog/mailhog:latest") + .withNetwork(network) + .withNetworkAliases("mailhog") + .withExposedPorts(8025) + .withLogConsumer(logger.getConsumer("mailhog")) + .withWaitStrategy(Wait.forListeningPorts()) + .start(); + await use(container); + await container.stop(); + }, + mailhogClient: async ({ mailhog: container }, use) => { + await use(mailhog({ host: container.getHost(), port: container.getMappedPort(8025) })); + }, + + synapseConfigOptions: [{}, { option: true }], + _homeserver: async ({ request }, use) => { + const container = new SynapseContainer(request); + await use(container); + }, + homeserver: async ({ logger, network, _homeserver: homeserver, synapseConfigOptions, mas }, use) => { + const container = await homeserver + .withNetwork(network) + .withNetworkAliases("homeserver") + .withLogConsumer(logger.getConsumer("synapse")) + .withConfig(synapseConfigOptions) + .start(); + + await use(container); + await container.stop(); + }, + // eslint-disable-next-line no-empty-pattern + mas: async ({}, use) => { + // we stub the mas fixture to allow `homeserver` to depend on it to ensure + // when it is specified by `masHomeserver` it is started before the homeserver + await use(undefined); + }, +}); diff --git a/playwright/testcontainers/HomeserverContainer.ts b/playwright/testcontainers/HomeserverContainer.ts new file mode 100644 index 0000000000..bbe075f2c9 --- /dev/null +++ b/playwright/testcontainers/HomeserverContainer.ts @@ -0,0 +1,19 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { AbstractStartedContainer, GenericContainer } from "testcontainers"; + +import { StartedSynapseContainer } from "./synapse.ts"; +import { HomeserverInstance } from "../plugins/homeserver"; + +export interface HomeserverContainer extends GenericContainer { + withConfigField(key: string, value: any): this; + withConfig(config: Partial): this; + start(): Promise; +} + +export interface StartedHomeserverContainer extends AbstractStartedContainer, HomeserverInstance {} diff --git a/playwright/testcontainers/dendrite.ts b/playwright/testcontainers/dendrite.ts new file mode 100644 index 0000000000..484b828b52 --- /dev/null +++ b/playwright/testcontainers/dendrite.ts @@ -0,0 +1,266 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { GenericContainer, Wait } from "testcontainers"; +import { APIRequestContext } from "@playwright/test"; +import * as YAML from "yaml"; +import { set } from "lodash"; + +import { randB64Bytes } from "../plugins/utils/rand.ts"; +import { StartedSynapseContainer } from "./synapse.ts"; +import { deepCopy } from "../plugins/utils/object.ts"; +import { HomeserverContainer } from "./HomeserverContainer.ts"; + +const DEFAULT_CONFIG = { + version: 2, + global: { + server_name: "localhost", + private_key: "matrix_key.pem", + old_private_keys: null, + key_validity_period: "168h0m0s", + cache: { + max_size_estimated: "1gb", + max_age: "1h", + }, + well_known_server_name: "", + well_known_client_name: "", + trusted_third_party_id_servers: ["matrix.org", "vector.im"], + disable_federation: false, + presence: { + enable_inbound: false, + enable_outbound: false, + }, + report_stats: { + enabled: false, + endpoint: "https://matrix.org/report-usage-stats/push", + }, + server_notices: { + enabled: false, + local_part: "_server", + display_name: "Server Alerts", + avatar_url: "", + room_name: "Server Alerts", + }, + jetstream: { + addresses: null, + disable_tls_validation: false, + storage_path: "./", + topic_prefix: "Dendrite", + }, + metrics: { + enabled: false, + basic_auth: { + username: "metrics", + password: "metrics", + }, + }, + dns_cache: { + enabled: false, + cache_size: 256, + cache_lifetime: "5m", + }, + }, + app_service_api: { + disable_tls_validation: false, + config_files: null, + }, + client_api: { + registration_disabled: false, + guests_disabled: true, + registration_shared_secret: "secret", + enable_registration_captcha: false, + recaptcha_public_key: "", + recaptcha_private_key: "", + recaptcha_bypass_secret: "", + turn: { + turn_user_lifetime: "5m", + turn_uris: null, + turn_shared_secret: "", + }, + rate_limiting: { + enabled: true, + threshold: 20, + cooloff_ms: 500, + exempt_user_ids: null, + }, + }, + federation_api: { + send_max_retries: 16, + disable_tls_validation: false, + disable_http_keepalives: false, + key_perspectives: [ + { + server_name: "matrix.org", + keys: [ + { + key_id: "ed25519:auto", + public_key: "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw", + }, + { + key_id: "ed25519:a_RXGa", + public_key: "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ", + }, + ], + }, + ], + prefer_direct_fetch: false, + database: { + connection_string: "file:dendrite-federationapi.db", + }, + }, + media_api: { + base_path: "./media_store", + max_file_size_bytes: 10485760, + dynamic_thumbnails: false, + max_thumbnail_generators: 10, + thumbnail_sizes: [ + { + width: 32, + height: 32, + method: "crop", + }, + { + width: 96, + height: 96, + method: "crop", + }, + { + width: 640, + height: 480, + method: "scale", + }, + ], + database: { + connection_string: "file:dendrite-mediaapi.db", + }, + }, + mscs: { + mscs: null, + database: { + connection_string: "file:dendrite-msc.db", + }, + }, + sync_api: { + search: { + enabled: false, + index_path: "./searchindex", + language: "en", + }, + database: { + connection_string: "file:dendrite-syncapi.db", + }, + }, + user_api: { + bcrypt_cost: 10, + auto_join_rooms: null, + account_database: { + connection_string: "file:dendrite-userapi.db", + }, + }, + room_server: { + database: { + connection_string: "file:dendrite-roomserverapi.db", + }, + }, + key_server: { + database: { + connection_string: "file:dendrite-keyserverapi.db", + }, + }, + relay_api: { + database: { + connection_string: "file:dendrite-relayapi.db", + }, + }, + tracing: { + enabled: false, + jaeger: { + serviceName: "", + disabled: false, + rpc_metrics: false, + tags: [], + sampler: null, + reporter: null, + headers: null, + baggage_restrictions: null, + throttler: null, + }, + }, + logging: [ + { + type: "std", + level: "debug", + }, + { + type: "file", + level: "debug", + params: { + path: "./logs", + }, + }, + ], +}; + +export class DendriteContainer extends GenericContainer implements HomeserverContainer { + private config: typeof DEFAULT_CONFIG; + + constructor( + private request: APIRequestContext, + image = "matrixdotorg/dendrite-monolith:main", + binary = "/usr/bin/dendrite", + ) { + super(image); + + this.config = deepCopy(DEFAULT_CONFIG); + this.config.client_api.registration_shared_secret = randB64Bytes(16); + + this.withEntrypoint(["/bin/sh"]) + .withCommand([ + "-c", + `/usr/bin/generate-keys -private-key /etc/dendrite/matrix_key.pem && ${binary} --config /etc/dendrite/dendrite.yaml --really-enable-open-registration true run`, + ]) + .withExposedPorts(8008) + .withWaitStrategy(Wait.forHttp("/_matrix/client/versions", 8008)); + } + + public withConfigField(key: string, value: any): this { + set(this.config, key, value); + return this; + } + + public withConfig(config: Partial): this { + this.config = { + ...this.config, + ...config, + }; + return this; + } + + public override async start(): Promise { + this.withCopyContentToContainer([ + { + target: "/etc/dendrite/dendrite.yaml", + content: YAML.stringify(this.config), + }, + ]); + + const container = await super.start(); + // Surprisingly, Dendrite implements the same register user Admin API Synapse, so we can just extend it + return new StartedSynapseContainer( + container, + `http://${container.getHost()}:${container.getMappedPort(8008)}`, + this.config.client_api.registration_shared_secret, + this.request, + ); + } +} + +export class PineconeContainer extends DendriteContainer { + constructor(request: APIRequestContext) { + super(request, "matrixdotorg/dendrite-demo-pinecone:main", "/usr/bin/dendrite-demo-pinecone"); + } +} diff --git a/playwright/testcontainers/mas.ts b/playwright/testcontainers/mas.ts new file mode 100644 index 0000000000..d15f619dbc --- /dev/null +++ b/playwright/testcontainers/mas.ts @@ -0,0 +1,224 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { AbstractStartedContainer, GenericContainer, StartedTestContainer, Wait } from "testcontainers"; +import { StartedPostgreSqlContainer } from "@testcontainers/postgresql"; +import * as YAML from "yaml"; + +import { getFreePort } from "../plugins/utils/port.ts"; +import { deepCopy } from "../plugins/utils/object.ts"; + +const DEFAULT_CONFIG = { + http: { + listeners: [ + { + name: "web", + resources: [ + { + name: "discovery", + }, + { + name: "human", + }, + { + name: "oauth", + }, + { + name: "compat", + }, + { + name: "graphql", + playground: true, + }, + { + name: "assets", + path: "/usr/local/share/mas-cli/assets/", + }, + ], + binds: [ + { + address: "[::]:8080", + }, + ], + proxy_protocol: false, + }, + { + name: "internal", + resources: [ + { + name: "health", + }, + ], + binds: [ + { + address: "[::]:8081", + }, + ], + proxy_protocol: false, + }, + ], + trusted_proxies: ["192.128.0.0/16", "172.16.0.0/12", "10.0.0.0/10", "127.0.0.1/8", "fd00::/8", "::1/128"], + public_base: "", // Needs to be set + issuer: "", // Needs to be set + }, + database: { + host: "postgres", + port: 5432, + database: "postgres", + username: "postgres", + password: "p4S5w0rD", + max_connections: 10, + min_connections: 0, + connect_timeout: 30, + idle_timeout: 600, + max_lifetime: 1800, + }, + telemetry: { + tracing: { + exporter: "none", + propagators: [], + }, + metrics: { + exporter: "none", + }, + sentry: { + dsn: null, + }, + }, + templates: { + path: "/usr/local/share/mas-cli/templates/", + assets_manifest: "/usr/local/share/mas-cli/manifest.json", + translations_path: "/usr/local/share/mas-cli/translations/", + }, + email: { + from: '"Authentication Service" ', + reply_to: '"Authentication Service" ', + transport: "smtp", + mode: "plain", + hostname: "mailhog", + port: 1025, + username: "username", + password: "password", + }, + secrets: { + encryption: "984b18e207c55ad5fbb2a49b217481a722917ee87b2308d4cf314c83fed8e3b5", + keys: [ + { + kid: "YEAhzrKipJ", + key: "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAuIV+AW5vx52I4CuumgSxp6yvKfIAnRdALeZZCoFkIGxUli1B\nS79NJ3ls46oLh1pSD9RrhaMp6HTNoi4K3hnP9Q9v77pD7KwdFKG3UdG1zksIB0s/\n+/Ey/DmX4LPluwBBS7r/LkQ1jk745lENA++oiDqZf2D/uP8jCHlvaSNyVKTqi1ki\nOXPd4T4xBUjzuas9ze5jQVSYtfOidgnv1EzUipbIxgvH1jNt4raRlmP8mOq7xEnW\nR+cF5x6n/g17PdSEfrwO4kz6aKGZuMP5lVlDEEnMHKabFSQDBl7+Mpok6jXutbtA\nuiBnsKEahF9eoj4na4fpbRNPdIVyoaN5eGvm5wIDAQABAoIBAApyFCYEmHNWaa83\nCdVSOrRhRDE9r+c0r79pcNT1ajOjrk4qFa4yEC4R46YntCtfY5Hd1pBkIjU0l4d8\nz8Su9WTMEOwjQUEepS7L0NLi6kXZXYT8L40VpGs+32grBvBFHW0qEtQNrHJ36gMv\nx2rXoFTF7HaXiSJx3wvVxAbRqOE9tBXLsmNHaWaAdWQG5o77V9+zvMri3cAeEg2w\nVkKokb0dza7es7xG3tqS26k69SrwGeeuKo7qCHPH2cfyWmY5Yhv8iOoA59JzzbiK\nUdxyzCHskrPSpRKVkVVwmY3RBt282TmSRG7td7e5ESSj50P2e5BI5uu1Hp/dvU4F\nvYjV7kECgYEA6WqYoUpVsgQiqhvJwJIc/8gRm0mUy8TenI36z4Iim01Nt7fibWH7\nXnsFqLGjXtYNVWvBcCrUl9doEnRbJeG2eRGbGKYAWVrOeFvwM4fYvw9GoOiJdDj4\ncgWDe7eHbHE+UTqR7Nnr/UBfipoNWDh6X68HRBuXowh0Q6tOfxsrRFECgYEAyl/V\n4b8bFp3pKZZCb+KPSYsQf793cRmrBexPcLWcDPYbMZQADEZ/VLjbrNrpTOWxUWJT\nhr8MrWswnHO+l5AFu5CNO+QgV2dHLk+2w8qpdpFRPJCfXfo2D3wZ0c4cv3VCwv1V\n5y7f6XWVjDWZYV4wj6c3shxZJjZ+9Hbhf3/twbcCgYA6fuRRR3fCbRbi2qPtBrEN\nyO3gpMgNaQEA6vP4HPzfPrhDWmn8T5nXS61XYW03zxz4U1De81zj0K/cMBzHmZFJ\nNghQXQmpWwBzWVcREvJWr1Vb7erEnaJlsMwKrSvbGWYspSj82oAxr3hCG+lMOpsw\nb4S6pM+TpAK/EqdRY1WsgQKBgQCGoMaaTRXqL9bC0bEU2XVVCWxKb8c3uEmrwQ7/\n/fD4NmjUzI5TnDps1CVfkqoNe+hAKddDFqmKXHqUOfOaxDbsFje+lf5l5tDVoDYH\nfjTKKdYPIm7CiAeauYY7qpA5Vfq52Opixy4yEwUPp0CII67OggFtPaqY3zwJyWQt\n+57hdQKBgGCXM/KKt7ceUDcNJxSGjvu0zD9D5Sv2ihYlEBT/JLaTCCJdvzREevaJ\n1d+mpUAt0Lq6A8NWOMq8HPaxAik3rMQ0WtM5iG+XgsUqvTSb7NcshArDLuWGnW3m\nMC4rM0UBYAS4QweduUSH1imrwH/1Gu5+PxbiecceRMMggWpzu0Bq\n-----END RSA PRIVATE KEY-----\n", + }, + { + kid: "8J1AxrlNZT", + key: "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIF1cjfIOEdy3BXJ72x6fKpEB8WP1ddZAUJAaqqr/6CpToAoGCCqGSM49\nAwEHoUQDQgAEfHdNuI1Yeh3/uOq2PlnW2vymloOVpwBYebbw4VVsna9xhnutIdQW\ndE8hkX8Yb0pIDasrDiwllVLzSvsWJAI0Kw==\n-----END EC PRIVATE KEY-----\n", + }, + { + kid: "3BW6un1EBi", + key: "-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDA+3ZV17r8TsiMdw1cpbTSNbyEd5SMy3VS1Mk/kz6O2Ev/3QZut8GE2\nq3eGtLBoVQigBwYFK4EEACKhZANiAASs8Wxjk/uRimRKXnPr2/wDaXkN9wMDjYQK\nmZULb+0ZP1/cXmuXuri8hUGhQvIU8KWY9PkpV+LMPEdpE54mHPKSLjq5CDXoSZ/P\n9f7cdRaOZ000KQPZfIFR9ujJTtDN7Vs=\n-----END EC PRIVATE KEY-----\n", + }, + { + kid: "pkZ0pTKK0X", + key: "-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIHenfsXYPc5yzjZKUfvmydDR1YRwdsfZYvwHf/2wsYxooAcGBSuBBAAK\noUQDQgAEON1x7Vlu+nA0KvC5vYSOHhDUkfLYNZwYSLPFVT02h9E13yFFMIJegIBl\nAer+6PMZpPc8ycyeH9N+U9NAyliBhQ==\n-----END EC PRIVATE KEY-----\n", + }, + ], + }, + passwords: { + enabled: true, + schemes: [ + { + version: 1, + algorithm: "argon2id", + }, + ], + minimum_complexity: 0, + }, + policy: { + wasm_module: "/usr/local/share/mas-cli/policy.wasm", + client_registration_entrypoint: "client_registration/violation", + register_entrypoint: "register/violation", + authorization_grant_entrypoint: "authorization_grant/violation", + password_entrypoint: "password/violation", + email_entrypoint: "email/violation", + data: { + client_registration: { + // allow non-SSL and localhost URIs + allow_insecure_uris: true, + // EW doesn't have contacts at this time + allow_missing_contacts: true, + }, + }, + }, + upstream_oauth2: { + providers: [], + }, + branding: { + service_name: null, + policy_uri: null, + tos_uri: null, + imprint: null, + logo_uri: null, + }, + account: { + password_registration_enabled: true, + }, + experimental: { + access_token_ttl: 300, + compat_token_ttl: 300, + }, +}; + +export class MatrixAuthenticationServiceContainer extends GenericContainer { + private config: typeof DEFAULT_CONFIG; + + constructor(db: StartedPostgreSqlContainer) { + super("ghcr.io/element-hq/matrix-authentication-service:0.12.0"); + + this.config = deepCopy(DEFAULT_CONFIG); + this.config.database.username = db.getUsername(); + this.config.database.password = db.getPassword(); + + this.withExposedPorts(8080, 8081) + .withWaitStrategy(Wait.forHttp("/health", 8081)) + .withCommand(["server", "--config", "/config/config.yaml"]); + } + + public withConfig(config: object): this { + this.config = { + ...this.config, + ...config, + }; + return this; + } + + public override async start(): Promise { + // MAS config issuer needs to know what URL it'll be accessed from, so we have to map the port manually + const port = await getFreePort(); + + this.config.http.public_base = `http://localhost:${port}/`; + this.config.http.issuer = `http://localhost:${port}/`; + + this.withExposedPorts({ + container: 8080, + host: port, + }).withCopyContentToContainer([ + { + target: "/config/config.yaml", + content: YAML.stringify(this.config), + }, + ]); + + return new StartedMatrixAuthenticationServiceContainer(await super.start(), `http://localhost:${port}`); + } +} + +export class StartedMatrixAuthenticationServiceContainer extends AbstractStartedContainer { + constructor( + container: StartedTestContainer, + public readonly baseUrl: string, + ) { + super(container); + } +} diff --git a/playwright/testcontainers/synapse.ts b/playwright/testcontainers/synapse.ts new file mode 100644 index 0000000000..46a4bcb415 --- /dev/null +++ b/playwright/testcontainers/synapse.ts @@ -0,0 +1,331 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { AbstractStartedContainer, GenericContainer, StartedTestContainer, Wait } from "testcontainers"; +import { APIRequestContext } from "@playwright/test"; +import crypto from "node:crypto"; +import * as YAML from "yaml"; +import { set } from "lodash"; + +import { getFreePort } from "../plugins/utils/port.ts"; +import { randB64Bytes } from "../plugins/utils/rand.ts"; +import { Credentials } from "../plugins/homeserver"; +import { deepCopy } from "../plugins/utils/object.ts"; +import { HomeserverContainer, StartedHomeserverContainer } from "./HomeserverContainer.ts"; + +const TAG = "develop@sha256:17cc0a301447430624afb860276e5c13270ddeb99a3f6d1c6d519a20b1a8f650"; + +const DEFAULT_CONFIG = { + server_name: "localhost", + public_baseurl: "", // set by start method + pid_file: "/homeserver.pid", + web_client: false, + soft_file_limit: 0, + // Needs to be configured to log to the console like a good docker process + log_config: "/data/log.config", + listeners: [ + { + // Listener is always port 8008 (configured in the container) + port: 8008, + tls: false, + bind_addresses: ["::"], + type: "http", + x_forwarded: true, + resources: [ + { + names: ["client"], + compress: false, + }, + ], + }, + ], + database: { + // An sqlite in-memory database is fast & automatically wipes each time + name: "sqlite3", + args: { + database: ":memory:", + }, + }, + rc_messages_per_second: 10000, + rc_message_burst_count: 10000, + rc_registration: { + per_second: 10000, + burst_count: 10000, + }, + rc_joins: { + local: { + per_second: 9999, + burst_count: 9999, + }, + remote: { + per_second: 9999, + burst_count: 9999, + }, + }, + rc_joins_per_room: { + per_second: 9999, + burst_count: 9999, + }, + rc_3pid_validation: { + per_second: 1000, + burst_count: 1000, + }, + rc_invites: { + per_room: { + per_second: 1000, + burst_count: 1000, + }, + per_user: { + per_second: 1000, + burst_count: 1000, + }, + }, + rc_login: { + address: { + per_second: 10000, + burst_count: 10000, + }, + account: { + per_second: 10000, + burst_count: 10000, + }, + failed_attempts: { + per_second: 10000, + burst_count: 10000, + }, + }, + media_store_path: "/tmp/media_store", + max_upload_size: "50M", + max_image_pixels: "32M", + dynamic_thumbnails: false, + enable_registration: true, + enable_registration_without_verification: true, + disable_msisdn_registration: false, + registrations_require_3pid: [], + enable_metrics: false, + report_stats: false, + // These placeholders will be replaced with values generated at start + registration_shared_secret: "secret", + macaroon_secret_key: "secret", + form_secret: "secret", + // Signing key must be here: it will be generated to this file + signing_key_path: "/data/localhost.signing.key", + trusted_key_servers: [], + password_config: { + enabled: true, + }, + ui_auth: { + session_timeout: "300s", + }, + background_updates: { + // Inhibit background updates as this Synapse isn't long-lived + min_batch_size: 100000, + sleep_duration_ms: 100000, + }, + enable_authenticated_media: true, + email: undefined, + user_consent: undefined, + server_notices: undefined, + allow_guest_access: false, + experimental_features: {}, + oidc_providers: [], + serve_server_wellknown: true, +}; + +export type SynapseConfigOptions = Partial; + +export class SynapseContainer extends GenericContainer implements HomeserverContainer { + private config: typeof DEFAULT_CONFIG; + + constructor(private readonly request: APIRequestContext) { + super(`ghcr.io/element-hq/synapse:${TAG}`); + + this.config = deepCopy(DEFAULT_CONFIG); + this.config.registration_shared_secret = randB64Bytes(16); + this.config.macaroon_secret_key = randB64Bytes(16); + this.config.form_secret = randB64Bytes(16); + + const signingKey = randB64Bytes(32); + this.withWaitStrategy(Wait.forHttp("/health", 8008)).withCopyContentToContainer([ + { target: this.config.signing_key_path, content: `ed25519 x ${signingKey}` }, + { + target: this.config.log_config, + content: YAML.stringify({ + version: 1, + formatters: { + precise: { + format: "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s", + }, + }, + handlers: { + console: { + class: "logging.StreamHandler", + formatter: "precise", + }, + }, + loggers: { + "synapse.storage.SQL": { + level: "DEBUG", + }, + "twisted": { + handlers: ["console"], + propagate: false, + }, + }, + root: { + level: "DEBUG", + handlers: ["console"], + }, + disable_existing_loggers: false, + }), + }, + ]); + } + + public withConfigField(key: string, value: any): this { + set(this.config, key, value); + return this; + } + + public withConfig(config: Partial): this { + this.config = { + ...this.config, + ...config, + }; + return this; + } + + public override async start(): Promise { + // Synapse config public_baseurl needs to know what URL it'll be accessed from, so we have to map the port manually + const port = await getFreePort(); + + this.withExposedPorts({ + container: 8008, + host: port, + }) + .withConfig({ + public_baseurl: `http://localhost:${port}`, + }) + .withCopyContentToContainer([ + { + target: "/data/homeserver.yaml", + content: YAML.stringify(this.config), + }, + ]); + + return new StartedSynapseContainer( + await super.start(), + `http://localhost:${port}`, + this.config.registration_shared_secret, + this.request, + ); + } +} + +export class StartedSynapseContainer extends AbstractStartedContainer implements StartedHomeserverContainer { + private adminToken?: string; + + constructor( + container: StartedTestContainer, + public readonly baseUrl: string, + private readonly registrationSharedSecret: string, + private readonly request: APIRequestContext, + ) { + super(container); + } + + private async registerUserInternal( + username: string, + password: string, + displayName?: string, + admin = false, + ): Promise { + const url = `${this.baseUrl}/_synapse/admin/v1/register`; + const { nonce } = await this.request.get(url).then((r) => r.json()); + const mac = crypto + .createHmac("sha1", this.registrationSharedSecret) + .update(`${nonce}\0${username}\0${password}\0${admin ? "" : "not"}admin`) + .digest("hex"); + const res = await this.request.post(url, { + data: { + nonce, + username, + password, + mac, + admin, + displayname: displayName, + }, + }); + + if (!res.ok()) { + throw await res.json(); + } + + const data = await res.json(); + return { + homeServer: data.home_server, + accessToken: data.access_token, + userId: data.user_id, + deviceId: data.device_id, + password, + displayName, + }; + } + + public registerUser(username: string, password: string, displayName?: string): Promise { + return this.registerUserInternal(username, password, displayName, false); + } + + public async loginUser(userId: string, password: string): Promise { + const url = `${this.baseUrl}/_matrix/client/v3/login`; + const res = await this.request.post(url, { + data: { + type: "m.login.password", + identifier: { + type: "m.id.user", + user: userId, + }, + password: password, + }, + }); + const json = await res.json(); + + return { + password, + accessToken: json.access_token, + userId: json.user_id, + deviceId: json.device_id, + homeServer: json.home_server, + }; + } + + public async setThreepid(userId: string, medium: string, address: string): Promise { + if (this.adminToken === undefined) { + const result = await this.registerUserInternal("admin", "totalyinsecureadminpassword", undefined, true); + this.adminToken = result.accessToken; + } + + const url = `${this.baseUrl}/_synapse/admin/v2/users/${userId}`; + const res = await this.request.put(url, { + data: { + threepids: [ + { + medium, + address, + }, + ], + }, + headers: { + Authorization: `Bearer ${this.adminToken}`, + }, + }); + + if (!res.ok()) { + throw await res.json(); + } + } +} diff --git a/playwright/testcontainers/utils.ts b/playwright/testcontainers/utils.ts new file mode 100644 index 0000000000..36b8d8aabf --- /dev/null +++ b/playwright/testcontainers/utils.ts @@ -0,0 +1,37 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { TestInfo } from "@playwright/test"; +import { Readable } from "stream"; +import stripAnsi from "strip-ansi"; + +export class ContainerLogger { + private logs: Record = {}; + + public getConsumer(container: string) { + this.logs[container] = ""; + return (stream: Readable) => { + stream.on("data", (chunk) => { + this.logs[container] += chunk.toString(); + }); + stream.on("err", (chunk) => { + this.logs[container] += "ERR " + chunk.toString(); + }); + }; + } + + public async testFinished(testInfo: TestInfo) { + if (testInfo.status !== "passed") { + for (const container in this.logs) { + await testInfo.attach(container, { + body: stripAnsi(this.logs[container]), + contentType: "text/plain", + }); + } + } + } +} diff --git a/scripts/copy-res.ts b/scripts/copy-res.ts index 956dedc2a3..905372cb0a 100755 --- a/scripts/copy-res.ts +++ b/scripts/copy-res.ts @@ -19,9 +19,9 @@ const argv = parseArgs(process.argv.slice(2), {}); const watch = argv.w; const verbose = argv.v; -function errCheck(err?: Error): void { +function errCheck(err: unknown): void { if (err) { - console.error(err.message); + console.error(err instanceof Error ? err.message : err); process.exit(1); } } diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index efe3a4e75a..642ae1e567 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -1276,7 +1276,7 @@ "error_already_invited_space": "Die Person wurde bereits eingeladen", "error_already_joined_room": "Die Person ist bereits im Raum", "error_already_joined_space": "Die Person ist bereits im Space", - "error_bad_state": "Verbannte Nutzer kƶnnen nicht eingeladen werden.", + "error_bad_state": "Gesperrte Benutzer kƶnnen nicht eingeladen werden.", "error_dm": "Wir konnten deine Direktnachricht nicht erstellen.", "error_find_room": "Beim Einladen der Nutzer lief etwas schief.", "error_find_user_description": "Folgende Nutzer konnten nicht eingeladen werden, da sie nicht existieren oder ungültig sind: %(csvNames)s", @@ -1317,7 +1317,7 @@ "unable_find_profiles_invite_label_default": "Dennoch einladen", "unable_find_profiles_invite_never_warn_label_default": "Trotzdem einladen und mich nicht mehr warnen", "unable_find_profiles_title": "Eventuell existieren folgende Benutzer nicht", - "unban_first_title": "Benutzer kann nicht eingeladen werden, solange er nicht entbannt ist" + "unban_first_title": "Benutzer kann nicht eingeladen werden, solange die Sperre nicht aufgehoben worden ist." }, "inviting_user1_and_user2": "Lade %(user1)s und %(user2)s ein", "inviting_user_and_n_others": { @@ -3732,8 +3732,8 @@ "ban_button_room": "Bannen", "ban_button_space": "Bannen", "ban_room_confirm_title": "Aus %(roomName)s verbannen", - "ban_space_everything": "Überall wo ich die Rechte dazu habe bannen", - "ban_space_specific": "In ausgewƤhlten RƤumen und Spaces bannen", + "ban_space_everything": "Überall sperren, wo ich die Rechte dazu habe", + "ban_space_specific": "Sperre sie in ausgewƤhlten Chatrooms und Spaces", "count_of_sessions": { "other": "%(count)s Sitzungen", "one": "%(count)s Sitzung" @@ -3798,11 +3798,11 @@ "room_unencrypted_detail": "Nachrichten in verschlüsselten RƤumen kƶnnen nur von dir und vom EmpfƤnger gelesen werden.", "send_message": "Nachricht senden", "share_button": "Profil teilen", - "unban_button_room": "Entbannen", - "unban_button_space": "Entbannen", - "unban_room_confirm_title": "Von %(roomName)s entbannen", - "unban_space_everything": "Überall wo ich die Rechte dazu habe, entbannen", - "unban_space_specific": "In ausgewƤhlten RƤumen und Spaces entbannen", + "unban_button_room": "Sperrung für den Chatroom aufheben", + "unban_button_space": "Sperrung aus Space aufheben", + "unban_room_confirm_title": "Sperrung für %(roomName)s aufheben", + "unban_space_everything": "Die Verbannung überall aufheben wo ich die Rechte dazu habe", + "unban_space_specific": "In ausgewƤhlten Chatrooms und Spaces die Sperrung für sie aufheben", "unban_space_warning": "Die Person wird keinen Zutritt zu Bereichen haben, in denen du nicht administrierst.", "unignore_button": "Nicht mehr ignorieren", "verify_button": "Nutzer verifizieren", diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 14f611b138..937a6c1867 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -438,6 +438,7 @@ export function replaceByRegexes(text: string, mapping: IVariables | Tags): stri if (shouldWrapInSpan) { return React.createElement("span", null, ...(output as Array)); } else { + // eslint-disable-next-line @typescript-eslint/no-base-to-string return output.join(""); } } diff --git a/test/unit-tests/SupportedBrowser-test.ts b/test/unit-tests/SupportedBrowser-test.ts index d759ac4bd9..d3fa2803ea 100644 --- a/test/unit-tests/SupportedBrowser-test.ts +++ b/test/unit-tests/SupportedBrowser-test.ts @@ -61,21 +61,22 @@ describe("SupportedBrowser", () => { testUserAgentFactory("Browser unsupported, unsupported user agent"), ); + // Grabbed from https://www.whatismybrowser.com/guides/the-latest-user-agent/ it.each([ // Safari 18.0 on macOS Sonoma "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15", - // Firefox 131 on macOS Sonoma - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0", + // Latest Firefox on macOS Sonoma + "Mozilla/5.0 (Macintosh; Intel Mac OS X 14.7; rv:133.0) Gecko/20100101 Firefox/133.0", // Edge 131 on Windows "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.2903.70", // Edge 131 on macOS "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.2903.70", - // Firefox 131 on Windows - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0", - // Firefox 131 on Linux - "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:131.0) Gecko/20100101 Firefox/131.0", - // Chrome 130 on Windows - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36", + // Latest Firefox on Windows + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0", + // Latest Firefox on Linux + "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0", + // Latest Chrome on Windows + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", ])("should not warn for supported browsers", testUserAgentFactory()); it.each([ diff --git a/yarn.lock b/yarn.lock index 7b026cc33f..0c9b386330 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1165,6 +1165,11 @@ "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" +"@balena/dockerignore@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" + integrity sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q== + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -1209,26 +1214,36 @@ "@csstools/color-helpers" "^5.0.1" "@csstools/css-calc" "^2.0.2" -"@csstools/css-parser-algorithms@^3.0.1", "@csstools/css-parser-algorithms@^3.0.2": +"@csstools/css-parser-algorithms@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.2.tgz#be03c710a60b34f95ea62e332c9ca0c2674f6d5f" integrity sha512-6tC/MnlEvs5suR4Ahef4YlBccJDHZuxGsAlxXmybWjZ5jPxlzLSMlRZ9mVHSRvlD+CmtE7+hJ+UQbfXrws/rUQ== -"@csstools/css-tokenizer@^3.0.1", "@csstools/css-tokenizer@^3.0.2": +"@csstools/css-parser-algorithms@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz#74426e93bd1c4dcab3e441f5cc7ba4fb35d94356" + integrity sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A== + +"@csstools/css-tokenizer@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.2.tgz#1c1d7298f6a7b3db94afe53d949b9a7d6a8ebc57" integrity sha512-IuTRcD53WHsXPCZ6W7ubfGqReTJ9Ra0yRRFmXYP/Re8hFYYfoIYIK4080X5luslVLWimhIeFq0hj09urVMQzTw== -"@csstools/media-query-list-parser@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz#9474e08e6d7767cf68c56bf1581b59d203360cb0" - integrity sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw== +"@csstools/css-tokenizer@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz#a5502c8539265fecbd873c1e395a890339f119c2" + integrity sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw== "@csstools/media-query-list-parser@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.0.tgz#d32a27f1d95f77c2a62c0f21f12a9e84b944bf5f" integrity sha512-nUfbCGeqCju55Po8ujRNQ8DjuKYth5UcsDj5HsVzSfqnaFdpOwYCUAhRJ2grfwrXhb9+KuRXHQ6JHzaI0Qhu8Q== +"@csstools/media-query-list-parser@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz#e80e17eba1693fceafb8d6f2cfc68c0e7a9ab78a" + integrity sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A== + "@csstools/postcss-cascade-layers@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.0.tgz#ad9985c2d273554552a546f6b1584d03d8886a8d" @@ -1490,16 +1505,26 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz#7dfccb9df5499e627e7bfdbb4021a06813a45dba" integrity sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ== +"@csstools/selector-specificity@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz#037817b574262134cabd68fc4ec1a454f168407b" + integrity sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw== + "@csstools/utilities@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@csstools/utilities/-/utilities-2.0.0.tgz#f7ff0fee38c9ffb5646d47b6906e0bc8868bde60" integrity sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ== -"@discoveryjs/json-ext@0.5.7", "@discoveryjs/json-ext@^0.5.0": +"@discoveryjs/json-ext@0.5.7": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@discoveryjs/json-ext@^0.6.1": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz#f13c7c205915eb91ae54c557f5e92bddd8be0e83" + integrity sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ== + "@dual-bundle/import-meta-resolve@^4.1.0": version "4.1.0" resolved "https://registry.yarnpkg.com/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#519c1549b0e147759e7825701ecffd25e5819f7b" @@ -1549,6 +1574,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== +"@fastify/busboy@^2.0.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" + integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== + "@floating-ui/core@^1.6.0": version "1.6.8" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.8.tgz#aa43561be075815879305965020f492cdb43da12" @@ -1586,46 +1616,46 @@ integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== "@fontsource/inconsolata@^5": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@fontsource/inconsolata/-/inconsolata-5.1.0.tgz#f6a76680173336d02d2ce4009699821a6be239ce" - integrity sha512-vYPdG3R46MhK+99De8e8MMyNad5BAb1oTnHMpojlctZyWJIcin8bKHFPUpQSNRhZ4HQL/+DCW+RTiG2RbnweTw== + version "5.1.1" + resolved "https://registry.yarnpkg.com/@fontsource/inconsolata/-/inconsolata-5.1.1.tgz#bc5cc74d04dee8b2cb4e706cc33ac3dc50100191" + integrity sha512-jLLMagEJURTae5J30gehIsXRv96vjQ0XlALGxZC7DERWPqsJTa0oSsZR8k6IJfizU4ZeRl/aKWpZca2Lo3TvSg== "@fontsource/inter@^5": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.1.0.tgz#ab629b2c662457022d2d6a29854b8dc8ba538c47" - integrity sha512-zKZR3kf1G0noIes1frLfOHP5EXVVm0M7sV/l9f/AaYf+M/DId35FO4LkigWjqWYjTJZGgplhdv4cB+ssvCqr5A== + version "5.1.1" + resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.1.1.tgz#401803b6ac4c877f5be94088aa89147ed5a2bd85" + integrity sha512-weN3E+rq0Xb3Z93VHJ+Rc7WOQX9ETJPTAJ+gDcaMHtjft67L58sfS65rAjC5tZUXQ2FdZ/V1/sSzCwZ6v05kJw== -"@formatjs/ecma402-abstract@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.1.tgz#cdeb3ffe1aeea9c4284b85b7e37e8e8615314c39" - integrity sha512-Ip9uV+/MpLXWRk03U/GzeJMuPeOXpJBSB5V1tjA6kJhvqssye5J5LoYLc7Z5IAHb7nR62sRoguzrFiVCP/hnzw== +"@formatjs/ecma402-abstract@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.2.tgz#0ee291effe7ee2c340742a6c95d92eacb5e6c00a" + integrity sha512-6sE5nyvDloULiyOMbOTJEEgWL32w+VHkZQs8S02Lnn8Y/O5aQhjOEXwWzvR7SsBE/exxlSpY2EsWZgqHbtLatg== dependencies: - "@formatjs/fast-memoize" "2.2.5" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/fast-memoize" "2.2.6" + "@formatjs/intl-localematcher" "0.5.10" decimal.js "10" tslib "2" -"@formatjs/fast-memoize@2.2.5": - version "2.2.5" - resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.5.tgz#54a4a1793d773b72c372d3dcab3595149aee7880" - integrity sha512-6PoewUMrrcqxSoBXAOJDiW1m+AmkrAj0RiXnOMD59GRaswjXhm3MDhgepXPBgonc09oSirAJTsAggzAGQf6A6g== +"@formatjs/fast-memoize@2.2.6": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.6.tgz#fac0a84207a1396be1f1aa4ee2805b179e9343d1" + integrity sha512-luIXeE2LJbQnnzotY1f2U2m7xuQNj2DA8Vq4ce1BY9ebRZaoPB1+8eZ6nXpLzsxuW5spQxr7LdCg+CApZwkqkw== dependencies: tslib "2" -"@formatjs/intl-localematcher@0.5.9": - version "0.5.9" - resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.9.tgz#43c6ee22be85b83340bcb09bdfed53657a2720db" - integrity sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA== +"@formatjs/intl-localematcher@0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz#1e0bd3fc1332c1fe4540cfa28f07e9227b659a58" + integrity sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q== dependencies: tslib "2" "@formatjs/intl-segmenter@^11.5.7": - version "11.7.7" - resolved "https://registry.yarnpkg.com/@formatjs/intl-segmenter/-/intl-segmenter-11.7.7.tgz#8a5aaa316e11ca2d31b99222e6fcf1ab539b085e" - integrity sha512-610J5xz5DxtEpa16zNR89CrvA9qWHxQFkUB3FKiGao0Nwn7i8cl+oyBhuH9SvtXF9j2LUOM9VMdVCMzJkVANNw== + version "11.7.8" + resolved "https://registry.yarnpkg.com/@formatjs/intl-segmenter/-/intl-segmenter-11.7.8.tgz#85990c7e3961ef686ed78b8cacb216852cadb061" + integrity sha512-+nqMCJ6LNLl+qXldE2uthF82O/2Yo6GZlyWbOY25fe3066iaHjmrR4nXd6AKRMCHNeBBx3rANFLm2B5cNTBzTQ== dependencies: - "@formatjs/ecma402-abstract" "2.3.1" - "@formatjs/intl-localematcher" "0.5.9" + "@formatjs/ecma402-abstract" "2.3.2" + "@formatjs/intl-localematcher" "0.5.10" tslib "2" "@humanwhocodes/config-array@^0.13.0": @@ -1980,16 +2010,16 @@ resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe" integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q== -"@maplibre/maplibre-gl-style-spec@^20.3.1": - version "20.4.0" - resolved "https://registry.yarnpkg.com/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz#408339e051fb51e022b40af2235e0beb037937ea" - integrity sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw== +"@maplibre/maplibre-gl-style-spec@^22.0.1": + version "22.0.1" + resolved "https://registry.yarnpkg.com/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-22.0.1.tgz#49210dd9c08853130c453b2acb9439216ab81402" + integrity sha512-V7bSw7Ui6+NhpeeuYqGoqamvKuy+3+uCvQ/t4ZJkwN8cx527CAlQQQ2kp+w5R9q+Tw6bUAH+fsq+mPEkicgT8g== dependencies: "@mapbox/jsonlint-lines-primitives" "~2.0.2" "@mapbox/unitbezier" "^0.0.1" json-stringify-pretty-compact "^4.0.0" minimist "^1.2.8" - quickselect "^2.0.0" + quickselect "^3.0.0" rw "^1.3.3" tinyqueue "^3.0.0" @@ -2024,9 +2054,9 @@ "@babel/runtime" "^7.17.9" "@matrix-org/spec@^1.7.0": - version "1.12.0" - resolved "https://registry.yarnpkg.com/@matrix-org/spec/-/spec-1.12.0.tgz#9e8d37f65dc8029ceeac1da47556e6ba59d44733" - integrity sha512-QHUQ79dMtd0eKQgebRye8li1y/S1172T6fXhu10dsFKtirSWblneoeFnCUR8hsUSBGWLtqBFcryVGa9uoBhqxg== + version "1.13.0" + resolved "https://registry.yarnpkg.com/@matrix-org/spec/-/spec-1.13.0.tgz#30c6c1e6993a93139f49d43e0c8fb9880f2f99ac" + integrity sha512-rvBRT3MRZXhPPclAbDY5L4x6xJbi7yqRAOvD11QWwu/RzFra8DYf58GSy45Kw70QyfyyRMBvKMil8zzY0+LMfA== "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" @@ -2083,6 +2113,11 @@ tslib "^2.6.2" webcrypto-core "^1.8.0" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@playwright/test@^1.40.1": version "1.49.1" resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.1.tgz#55fa360658b3187bfb6371e2f8a64f50ef80c827" @@ -2386,35 +2421,35 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@sentry-internal/browser-utils@8.43.0": - version "8.43.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.43.0.tgz#b064908a537d1cc17d8ddaf0f4c5d712557cbf40" - integrity sha512-5WhJZ3SA5sZVDBwOsChDd5JCzYcwBX7sEqBqEcm3pFru6TUihEnFIJmDIbreIyrQMwUhs3dTxnfnidgjr5z1Ag== +"@sentry-internal/browser-utils@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.48.0.tgz#320713e29566929894de42d54152064ec19cc9b3" + integrity sha512-pLtu0Fa1Ou0v3M1OEO1MB1EONJVmXEGtoTwFRCO1RPQI2ulmkG6BikINClFG5IBpoYKZ33WkEXuM6U5xh+pdZg== dependencies: - "@sentry/core" "8.43.0" + "@sentry/core" "8.48.0" -"@sentry-internal/feedback@8.43.0": - version "8.43.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.43.0.tgz#9477b999c9bca62335eb944a6f7246a96beb0111" - integrity sha512-rcGR2kzFu4vLXBQbI9eGJwjyToyjl36O2q/UKbiZBNJ5IFtDvKRLke6jIHq/YqiHPfFGpVtq5M/lYduDfA/eaQ== +"@sentry-internal/feedback@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.48.0.tgz#92d2301b0e7379716efae6c05bc4a4740687921a" + integrity sha512-6PwcJNHVPg0EfZxmN+XxVOClfQpv7MBAweV8t9i5l7VFr8sM/7wPNSeU/cG7iK19Ug9ZEkBpzMOe3G4GXJ5bpw== dependencies: - "@sentry/core" "8.43.0" + "@sentry/core" "8.48.0" -"@sentry-internal/replay-canvas@8.43.0": - version "8.43.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.43.0.tgz#f5672a08c9eb588afa0bf36f07b9f5c29b5c9920" - integrity sha512-rL8G7E1GtozH8VNalRrBQNjYDJ5ChWS/vpQI5hUG11PZfvQFXEVatLvT3uO2l0xIlHm4idTsHOSLTe/usxnogQ== +"@sentry-internal/replay-canvas@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.48.0.tgz#f88282b0594751407ca3016d0a63b133c2e37ac3" + integrity sha512-LdivLfBXXB9us1aAc6XaL7/L2Ob4vi3C/fEOXElehg3qHjX6q6pewiv5wBvVXGX1NfZTRvu+X11k6TZoxKsezw== dependencies: - "@sentry-internal/replay" "8.43.0" - "@sentry/core" "8.43.0" + "@sentry-internal/replay" "8.48.0" + "@sentry/core" "8.48.0" -"@sentry-internal/replay@8.43.0": - version "8.43.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.43.0.tgz#4e2e3844f52b47b16bf816d21857921bbfe85d62" - integrity sha512-geV5/zejLfGGwWHjylzrb1w8NI3U37GMG9/53nmv13FmTXUDF5XF2lh41KXFVYwvp7Ha4bd1FRQ9IU9YtBWskw== +"@sentry-internal/replay@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.48.0.tgz#2cc802178f6b0185581b61058f2541b9f3384a8b" + integrity sha512-csILVupc5RkrsTrncuUTGmlB56FQSFjXPYWG8I8yBTGlXEJ+o8oTuF6+55R4vbw3EIzBveXWi4kEBbnQlXW/eg== dependencies: - "@sentry-internal/browser-utils" "8.43.0" - "@sentry/core" "8.43.0" + "@sentry-internal/browser-utils" "8.48.0" + "@sentry/core" "8.48.0" "@sentry/babel-plugin-component-annotate@2.22.7": version "2.22.7" @@ -2422,15 +2457,15 @@ integrity sha512-aa7XKgZMVl6l04NY+3X7BP7yvQ/s8scn8KzQfTLrGRarziTlMGrsCOBQtCNWXOPEbtxAIHpZ9dsrAn5EJSivOQ== "@sentry/browser@^8.0.0": - version "8.43.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.43.0.tgz#4eec67bc6fb278727304045b612ac392674cade6" - integrity sha512-LGvLLnfmR8+AEgFmd7Q7KHiOTiV0P1Lvio2ENDELhEqJOIiICauttibVmig+AW02qg4kMeywvleMsUYaZv2RVA== + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.48.0.tgz#bdd7793ddd3ae7a65d595066bde93fbb63ce8b9d" + integrity sha512-fuuVULB5/1vI8NoIwXwR3xwhJJqk+y4RdSdajExGF7nnUDBpwUJyXsmYJnOkBO+oLeEs58xaCpotCKiPUNnE3g== dependencies: - "@sentry-internal/browser-utils" "8.43.0" - "@sentry-internal/feedback" "8.43.0" - "@sentry-internal/replay" "8.43.0" - "@sentry-internal/replay-canvas" "8.43.0" - "@sentry/core" "8.43.0" + "@sentry-internal/browser-utils" "8.48.0" + "@sentry-internal/feedback" "8.48.0" + "@sentry-internal/replay" "8.48.0" + "@sentry-internal/replay-canvas" "8.48.0" + "@sentry/core" "8.48.0" "@sentry/bundler-plugin-core@2.22.7": version "2.22.7" @@ -2500,10 +2535,10 @@ "@sentry/cli-win32-i686" "2.39.1" "@sentry/cli-win32-x64" "2.39.1" -"@sentry/core@8.43.0": - version "8.43.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.43.0.tgz#e96a489e87a9999199f5ac27d8860da37c1fa8b4" - integrity sha512-ktyovtjkTMNud+kC/XfqHVCoQKreIKgx/hgeRvzPwuPyd1t1KzYmRL3DBkbcWVnyOPpVTHn+RsEI1eRcVYHtvw== +"@sentry/core@8.48.0": + version "8.48.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.48.0.tgz#3bb8d06305f0ec7c873453844687deafdeab168b" + integrity sha512-VGwYgTfLpvJ5LRO5A+qWo1gpo6SfqaGXL9TOzVgBucAdpzbrYHpZ87sEarDVq/4275uk1b0S293/mfsskFczyw== "@sentry/webpack-plugin@^2.7.1": version "2.22.7" @@ -2548,9 +2583,9 @@ p-map "^4.0.0" "@stylistic/eslint-plugin@^2.9.0": - version "2.11.0" - resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-2.11.0.tgz#50d0289f36f7201055b7fa1729fdc1d8c46e93fa" - integrity sha512-PNRHbydNG5EH8NK4c+izdJlxajIR6GxcUhzsYNRsn6Myep4dsZt0qFCz3rCPnkvgO5FYibDcMqgNHUT+zvjYZw== + version "2.12.1" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-2.12.1.tgz#e341beb4e4315084d8be20bceeeda7d8a46f079f" + integrity sha512-fubZKIHSPuo07FgRTn6S4Nl0uXPRPYVNpyZzIDGfp7Fny6JjNus6kReLD7NI380JXi4HtUTSOZ34LBuNPO1XLQ== dependencies: "@typescript-eslint/utils" "^8.13.0" eslint-visitor-keys "^4.2.0" @@ -2664,6 +2699,13 @@ "@svgr/plugin-jsx" "8.1.0" "@svgr/plugin-svgo" "8.1.0" +"@testcontainers/postgresql@^10.16.0": + version "10.16.0" + resolved "https://registry.yarnpkg.com/@testcontainers/postgresql/-/postgresql-10.16.0.tgz#0437a9b426d64ea958e745a0e2ae19462b786f81" + integrity sha512-zWFQI+3QxlEELRvVv27i6zlVEPNUz9zKaSh7iWmFlCdfhcyr78daS0FG8FIfdQ79VK7YXA4jv+dTYXa2SwXu/w== + dependencies: + testcontainers "^10.16.0" + "@testing-library/dom@^10.4.0": version "10.4.0" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.0.tgz#82a9d9462f11d240ecadbf406607c6ceeeff43a8" @@ -2822,15 +2864,32 @@ integrity sha512-aqBg5oAGo/qh/+wxUfuMadDu2WO0MEWOblyzwaM1Ske2xilUxBfgPqapAFVAfrVTDMVwa0UMarzGot8m64IAzA== "@types/css-tree@^2.3.8": - version "2.3.9" - resolved "https://registry.yarnpkg.com/@types/css-tree/-/css-tree-2.3.9.tgz#54c404e0a803e7e660fdc08c84fe73ee5266cece" - integrity sha512-g1FE6xkPDP4tsccmTd6jIugjKZdxIDqAf9h2pc+4LsGgYbOyfa9phNjBHYbm6FtwIlNfT1NBx3f2zSeqO7aRAw== + version "2.3.10" + resolved "https://registry.yarnpkg.com/@types/css-tree/-/css-tree-2.3.10.tgz#b96abb37c1b51b03fe16054c186130c6ab69fef7" + integrity sha512-WcaBazJ84RxABvRttQjjFWgTcHvZR9jGr0Y3hccPkHjFyk/a3N8EuxjKr+QfrwjoM5b1yI1Uj1i7EzOAAwBwag== "@types/diff-match-patch@^1.0.32": version "1.0.36" resolved "https://registry.yarnpkg.com/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz#dcef10a69d357fe9d43ac4ff2eca6b85dbf466af" integrity sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg== +"@types/docker-modem@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/docker-modem/-/docker-modem-3.0.6.tgz#1f9262fcf85425b158ca725699a03eb23cddbf87" + integrity sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg== + dependencies: + "@types/node" "*" + "@types/ssh2" "*" + +"@types/dockerode@^3.3.29": + version "3.3.33" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.33.tgz#67d9b4223caf41a0735695abe89c292e05d305c9" + integrity sha512-7av8lVOhkW7Xd11aZTSq5zhdpyNraldXwQR0pxUCiSNTvIzsP86KrFrmrZgxtrXD2Zrtzwt4H6OYLbATONWzWg== + dependencies: + "@types/docker-modem" "*" + "@types/node" "*" + "@types/ssh2" "*" + "@types/escape-html@^1.0.1": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.4.tgz#dc7c166b76c7b03b27e32f80edf01d91eb5d9af2" @@ -2907,14 +2966,6 @@ resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.7.tgz#8dbb2f24bdc7486c54aa854eb414940bbd056f7d" integrity sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A== -"@types/fs-extra@^11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-11.0.4.tgz#e16a863bb8843fba8c5004362b5a73e17becca45" - integrity sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ== - dependencies: - "@types/jsonfile" "*" - "@types/node" "*" - "@types/geojson-vt@3.2.5": version "3.2.5" resolved "https://registry.yarnpkg.com/@types/geojson-vt/-/geojson-vt-3.2.5.tgz#b6c356874991d9ab4207533476dfbcdb21e38408" @@ -2922,11 +2973,16 @@ dependencies: "@types/geojson" "*" -"@types/geojson@*", "@types/geojson@^7946.0.14": +"@types/geojson@*": version "7946.0.14" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613" integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg== +"@types/geojson@^7946.0.15": + version "7946.0.15" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.15.tgz#f9d55fd5a0aa2de9dc80b1b04e437538b7298868" + integrity sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA== + "@types/glob-to-regexp@^0.4.1": version "0.4.4" resolved "https://registry.yarnpkg.com/@types/glob-to-regexp/-/glob-to-regexp-0.4.4.tgz#409e71290253203185b1ea8a3d6ea406a4bdc902" @@ -3015,13 +3071,6 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/jsonfile@*": - version "6.1.4" - resolved "https://registry.yarnpkg.com/@types/jsonfile/-/jsonfile-6.1.4.tgz#614afec1a1164e7d670b4a7ad64df3e7beb7b702" - integrity sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ== - dependencies: - "@types/node" "*" - "@types/jsrsasign@^10.5.4": version "10.5.15" resolved "https://registry.yarnpkg.com/@types/jsrsasign/-/jsrsasign-10.5.15.tgz#5cf1ee506b2fa2435b6e1786a873285c7110eb82" @@ -3033,9 +3082,9 @@ integrity sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ== "@types/lodash@^4.14.168": - version "4.17.13" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb" - integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg== + version "4.17.14" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.14.tgz#bafc053533f4cdc5fcc9635af46a963c1f3deaff" + integrity sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A== "@types/mapbox__point-geometry@*", "@types/mapbox__point-geometry@^0.1.4": version "0.1.4" @@ -3089,9 +3138,16 @@ undici-types "~6.20.0" "@types/node@18": - version "18.19.68" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.68.tgz#f4f10d9927a7eaf3568c46a6d739cc0967ccb701" - integrity sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw== + version "18.19.70" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.70.tgz#5a77508f5568d16fcd3b711c8102d7a430a04df7" + integrity sha512-RE+K0+KZoEpDUbGGctnGdkrLFwi1eYKTlIHNl2Um98mUkGsm1u2Ff6Ltd0e8DktTtC98uy7rSj+hO8t/QuLoVQ== + dependencies: + undici-types "~5.26.4" + +"@types/node@^18.11.18": + version "18.19.69" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.69.tgz#748d301818ba4b238854c53d290257a70aae7d01" + integrity sha512-ECPdY1nlaiO/Y6GUnwgtAAhLNaQ53AyIVz+eILxpEo5OvuqE6yWkqWBIb5dU0DqhKQtMeny+FBD3PK6lm7L5xQ== dependencies: undici-types "~5.26.4" @@ -3149,12 +3205,10 @@ dependencies: "@types/react" "*" -"@types/react-dom@18.3.1": - version "18.3.1" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.1.tgz#1e4654c08a9cdcfb6594c780ac59b55aad42fe07" - integrity sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ== - dependencies: - "@types/react" "*" +"@types/react-dom@18.3.5": + version "18.3.5" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.5.tgz#45f9f87398c5dcea085b715c58ddcf1faf65f716" + integrity sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q== "@types/react-redux@^7.1.20": version "7.1.34" @@ -3167,24 +3221,22 @@ redux "^4.0.0" "@types/react-transition-group@^4.4.0": - version "4.4.11" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.11.tgz#d963253a611d757de01ebb241143b1017d5d63d5" - integrity sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA== - dependencies: - "@types/react" "*" + version "4.4.12" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" + integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== "@types/react-virtualized@^9.21.30": - version "9.21.30" - resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.30.tgz#ba39821bcb2487512a8a2cdd9fbdb5e6fc87fedb" - integrity sha512-4l2TFLQ8BCjNDQlvH85tU6gctuZoEdgYzENQyZHpgTHU7hoLzYgPSOALMAeA58LOWua8AzC6wBivPj1lfl6JgQ== + version "9.22.0" + resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.22.0.tgz#2ff9b3692fa04a429df24ffc7d181d9f33b3831d" + integrity sha512-JL/YCCFZ123za//cj10Apk54F0UGFMrjOE0QHTuXt1KBMFrzLOGv9/x6Uc/pZ0Gaf4o6w61Fostvlw0DwuPXig== dependencies: "@types/prop-types" "*" "@types/react" "*" -"@types/react@*", "@types/react@18.3.3": - version "18.3.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" - integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== +"@types/react@*", "@types/react@18.3.18": + version "18.3.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.18.tgz#9b382c4cd32e13e463f97df07c2ee3bbcd26904b" + integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ== dependencies: "@types/prop-types" "*" csstype "^3.0.2" @@ -3247,6 +3299,28 @@ dependencies: "@types/node" "*" +"@types/ssh2-streams@*": + version "0.1.12" + resolved "https://registry.yarnpkg.com/@types/ssh2-streams/-/ssh2-streams-0.1.12.tgz#e68795ba2bf01c76b93f9c9809e1f42f0eaaec5f" + integrity sha512-Sy8tpEmCce4Tq0oSOYdfqaBpA3hDM8SoxoFh5vzFsu2oL+znzGz8oVWW7xb4K920yYMUY+PIG31qZnFMfPWNCg== + dependencies: + "@types/node" "*" + +"@types/ssh2@*": + version "1.15.1" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.15.1.tgz#4db4b6864abca09eb299fe5354fa591add412223" + integrity sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA== + dependencies: + "@types/node" "^18.11.18" + +"@types/ssh2@^0.5.48": + version "0.5.52" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-0.5.52.tgz#9dbd8084e2a976e551d5e5e70b978ed8b5965741" + integrity sha512-lbLLlXxdCZOSJMCInKH2+9V/77ET2J6NPQHpFI0kda61Dd1KglJs+fPQBchizmzYSOJBgdTajhPqBO1xxLywvg== + dependencies: + "@types/node" "*" + "@types/ssh2-streams" "*" + "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" @@ -3298,30 +3372,30 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^8.0.0": - version "8.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz#ac56825bcdf3b392fc76a94b1315d4a162f201a6" - integrity sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q== +"@typescript-eslint/eslint-plugin@^8.19.0": + version "8.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz#5f26c0a833b27bcb1aa402b82e76d3b8dda0b247" + integrity sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "8.16.0" - "@typescript-eslint/type-utils" "8.16.0" - "@typescript-eslint/utils" "8.16.0" - "@typescript-eslint/visitor-keys" "8.16.0" + "@typescript-eslint/scope-manager" "8.19.1" + "@typescript-eslint/type-utils" "8.19.1" + "@typescript-eslint/utils" "8.19.1" + "@typescript-eslint/visitor-keys" "8.19.1" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" - ts-api-utils "^1.3.0" + ts-api-utils "^2.0.0" -"@typescript-eslint/parser@^8.0.0": - version "8.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.16.0.tgz#ee5b2d6241c1ab3e2e53f03fd5a32d8e266d8e06" - integrity sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w== +"@typescript-eslint/parser@^8.19.0": + version "8.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.19.1.tgz#b836fcfe7a704c8c65f5a50e5b0ff8acfca5c21b" + integrity sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw== dependencies: - "@typescript-eslint/scope-manager" "8.16.0" - "@typescript-eslint/types" "8.16.0" - "@typescript-eslint/typescript-estree" "8.16.0" - "@typescript-eslint/visitor-keys" "8.16.0" + "@typescript-eslint/scope-manager" "8.19.1" + "@typescript-eslint/types" "8.19.1" + "@typescript-eslint/typescript-estree" "8.19.1" + "@typescript-eslint/visitor-keys" "8.19.1" debug "^4.3.4" "@typescript-eslint/scope-manager@8.16.0": @@ -3332,21 +3406,34 @@ "@typescript-eslint/types" "8.16.0" "@typescript-eslint/visitor-keys" "8.16.0" -"@typescript-eslint/type-utils@8.16.0": - version "8.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz#585388735f7ac390f07c885845c3d185d1b64740" - integrity sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg== +"@typescript-eslint/scope-manager@8.19.1": + version "8.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz#794cfc8add4f373b9cd6fa32e367e7565a0e231b" + integrity sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q== dependencies: - "@typescript-eslint/typescript-estree" "8.16.0" - "@typescript-eslint/utils" "8.16.0" + "@typescript-eslint/types" "8.19.1" + "@typescript-eslint/visitor-keys" "8.19.1" + +"@typescript-eslint/type-utils@8.19.1": + version "8.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz#23710ab52643c19f74601b3f4a076c98f4e159aa" + integrity sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw== + dependencies: + "@typescript-eslint/typescript-estree" "8.19.1" + "@typescript-eslint/utils" "8.19.1" debug "^4.3.4" - ts-api-utils "^1.3.0" + ts-api-utils "^2.0.0" "@typescript-eslint/types@8.16.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.16.0.tgz#49c92ae1b57942458ab83d9ec7ccab3005e64737" integrity sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ== +"@typescript-eslint/types@8.19.1": + version "8.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.19.1.tgz#015a991281754ed986f2e549263a1188d6ed0a8c" + integrity sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA== + "@typescript-eslint/typescript-estree@8.16.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz#9d741e56e5b13469b5190e763432ce5551a9300c" @@ -3361,7 +3448,31 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@8.16.0", "@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/utils@^8.13.0": +"@typescript-eslint/typescript-estree@8.19.1": + version "8.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz#c1094bb00bc251ac76cf215569ca27236435036b" + integrity sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q== + dependencies: + "@typescript-eslint/types" "8.19.1" + "@typescript-eslint/visitor-keys" "8.19.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.0.0" + +"@typescript-eslint/utils@8.19.1", "@typescript-eslint/utils@^8.13.0": + version "8.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.19.1.tgz#dd8eabd46b92bf61e573286e1c0ba6bd243a185b" + integrity sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.19.1" + "@typescript-eslint/types" "8.19.1" + "@typescript-eslint/typescript-estree" "8.19.1" + +"@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.16.0.tgz#c71264c437157feaa97842809836254a6fc833c3" integrity sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA== @@ -3379,6 +3490,14 @@ "@typescript-eslint/types" "8.16.0" eslint-visitor-keys "^4.2.0" +"@typescript-eslint/visitor-keys@8.19.1": + version "8.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz#fce54d7cfa5351a92387d6c0c5be598caee072e0" + integrity sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q== + dependencies: + "@typescript-eslint/types" "8.19.1" + eslint-visitor-keys "^4.2.0" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -3405,7 +3524,7 @@ ts-xor "^1.3.0" vaul "^1.0.0" -"@vector-im/matrix-wysiwyg-wasm@link:../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.0-af862ffd231dc0a6b8d6f2cb3601e68456c0ff24-integrity/node_modules/bindings/wysiwyg-wasm": +"@vector-im/matrix-wysiwyg-wasm@link:../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.0-af862ffd231dc0a6b8d6f2cb3601e68456c0ff24-integrity/node_modules/bindings/wysiwyg-wasm": version "0.0.0" uid "" @@ -3537,20 +3656,20 @@ "@webassemblyjs/ast" "1.14.1" "@xtuc/long" "4.2.2" -"@webpack-cli/configtest@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" - integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== +"@webpack-cli/configtest@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-3.0.1.tgz#76ac285b9658fa642ce238c276264589aa2b6b57" + integrity sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA== -"@webpack-cli/info@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" - integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== +"@webpack-cli/info@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-3.0.1.tgz#3cff37fabb7d4ecaab6a8a4757d3826cf5888c63" + integrity sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ== -"@webpack-cli/serve@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" - integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== +"@webpack-cli/serve@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-3.0.1.tgz#bd8b1f824d57e30faa19eb78e4c0951056f72f00" + integrity sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -3584,6 +3703,13 @@ abab@^2.0.6: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -3742,6 +3868,32 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +archiver-utils@^5.0.0, archiver-utils@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-5.0.2.tgz#63bc719d951803efc72cf961a56ef810760dd14d" + integrity sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA== + dependencies: + glob "^10.0.0" + graceful-fs "^4.2.0" + is-stream "^2.0.1" + lazystream "^1.0.0" + lodash "^4.17.15" + normalize-path "^3.0.0" + readable-stream "^4.0.0" + +archiver@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-7.0.1.tgz#c9d91c350362040b8927379c7aa69c0655122f61" + integrity sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ== + dependencies: + archiver-utils "^5.0.2" + async "^3.2.4" + buffer-crc32 "^1.0.0" + readable-stream "^4.0.0" + readdir-glob "^1.1.2" + tar-stream "^3.0.0" + zip-stream "^6.0.1" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -3877,6 +4029,13 @@ arraybuffer.prototype.slice@^1.0.3: is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" +asn1@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + asn1js@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" @@ -3896,7 +4055,12 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async@^3.2.3: +async-lock@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.4.1.tgz#56b8718915a9b68b10fce2f2a9a3dddf765ef53f" + integrity sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ== + +async@^3.2.3, async@^3.2.4: version "3.2.6" resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== @@ -3940,6 +4104,11 @@ axobject-query@^4.1.0: resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== +b4a@^1.6.4: + version "1.6.7" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.7.tgz#a99587d4ebbfbd5a6e3b21bdb5d5fa385767abe4" + integrity sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg== + babel-jest@^29.0.0, babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -4050,6 +4219,39 @@ balanced-match@^2.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== +bare-events@^2.0.0, bare-events@^2.2.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.0.tgz#305b511e262ffd8b9d5616b056464f8e1b3329cc" + integrity sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A== + +bare-fs@^2.1.1: + version "2.3.5" + resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-2.3.5.tgz#05daa8e8206aeb46d13c2fe25a2cd3797b0d284a" + integrity sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw== + dependencies: + bare-events "^2.0.0" + bare-path "^2.0.0" + bare-stream "^2.0.0" + +bare-os@^2.1.0: + version "2.4.4" + resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-2.4.4.tgz#01243392eb0a6e947177bb7c8a45123d45c9b1a9" + integrity sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ== + +bare-path@^2.0.0, bare-path@^2.1.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-2.1.3.tgz#594104c829ef660e43b5589ec8daef7df6cedb3e" + integrity sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA== + dependencies: + bare-os "^2.1.0" + +bare-stream@^2.0.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.6.1.tgz#b3b9874fab05b662c9aea2706a12fb0698c46836" + integrity sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g== + dependencies: + streamx "^2.21.0" + base-x@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.0.tgz#6d835ceae379130e1a4cb846a70ac4746f28ea9b" @@ -4060,11 +4262,23 @@ base64-arraybuffer@^1.0.2: resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc" integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== +bcrypt-pbkdf@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -4075,6 +4289,15 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + blob-polyfill@^9.0.0: version "9.0.20240710" resolved "https://registry.yarnpkg.com/blob-polyfill/-/blob-polyfill-9.0.20240710.tgz#2ef075a207311ea327704f04dc4a98cbefe4143b" @@ -4153,13 +4376,13 @@ braces@^3.0.3, braces@~3.0.2: fill-range "^7.1.1" browserslist@^4.0.0, browserslist@^4.23.1, browserslist@^4.23.2, browserslist@^4.23.3, browserslist@^4.24.0, browserslist@^4.24.2: - version "4.24.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" - integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== + version "4.24.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2" + integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA== dependencies: - caniuse-lite "^1.0.30001669" - electron-to-chromium "^1.5.41" - node-releases "^2.0.18" + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" update-browserslist-db "^1.1.1" bs58@^6.0.0: @@ -4176,11 +4399,37 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +buffer-crc32@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405" + integrity sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +buildcheck@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.6.tgz#89aa6e417cfd1e2196e3f8fe915eb709d2fe4238" + integrity sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A== + builtin-modules@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" @@ -4193,6 +4442,11 @@ bundle-name@^4.1.0: dependencies: run-applescript "^7.0.0" +byline@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + integrity sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q== + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -4270,10 +4524,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@1.0.30001684, caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669: - version "1.0.30001684" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz#0eca437bab7d5f03452ff0ef9de8299be6b08e16" - integrity sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ== +caniuse-lite@1.0.30001690, caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001688: + version "1.0.30001690" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8" + integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w== chalk@5.2.0: version "5.2.0" @@ -4337,6 +4591,11 @@ chokidar@^4.0.0: dependencies: readdirp "^4.0.1" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + chrome-trace-event@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" @@ -4489,10 +4748,10 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" - integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +commander@^12.1.0, commander@~12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== commander@^2.20.0: version "2.20.3" @@ -4519,11 +4778,6 @@ commander@^8.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== -commander@~12.1.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" - integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== - common-path-prefix@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" @@ -4538,6 +4792,17 @@ commonmark@^0.31.0: mdurl "~1.0.1" minimist "~1.2.8" +compress-commons@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-6.0.2.tgz#26d31251a66b9d6ba23a84064ecd3a6a71d2609e" + integrity sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg== + dependencies: + crc-32 "^1.2.0" + crc32-stream "^6.0.0" + is-stream "^2.0.1" + normalize-path "^3.0.0" + readable-stream "^4.0.0" + compressible@~2.0.16: version "2.0.18" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" @@ -4679,11 +4944,32 @@ counterpart@^0.18.6: pluralizers "^0.1.7" sprintf-js "^1.0.3" +cpu-features@~0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.10.tgz#9aae536db2710c7254d7ed67cb3cbc7d29ad79c5" + integrity sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA== + dependencies: + buildcheck "~0.0.6" + nan "^2.19.0" + crc-32@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-0.3.0.tgz#6a3d3687f5baec41f7e9b99fe1953a2e5d19775e" integrity sha512-kucVIjOmMc1f0tv53BJ/5WIX+MGLcKuoBhnGqQrgKJNqLByb/sVMWfW/Aw6hw0jgcqjJ2pi9E5y32zOIpaUlsA== +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +crc32-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-6.0.0.tgz#8529a3868f8b27abb915f6c3617c0fadedbf9430" + integrity sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g== + dependencies: + crc-32 "^1.2.0" + readable-stream "^4.0.0" + create-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" @@ -4992,7 +5278,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.3.1: +debug@4, debug@^4.1.0, debug@^4.3.1, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== @@ -5006,7 +5292,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@~4.3.6: +debug@^4.1.1, debug@^4.3.2, debug@~4.3.6: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -5160,6 +5446,32 @@ dns-packet@^5.2.2: dependencies: "@leichtgewicht/ip-codec" "^2.0.1" +docker-compose@^0.24.8: + version "0.24.8" + resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.24.8.tgz#6c125e6b9e04cf68ced47e2596ef2bb93ee9694e" + integrity sha512-plizRs/Vf15H+GCVxq2EUvyPK7ei9b/cVesHvjnX4xaXjM9spHe2Ytq0BitndFgvTJ3E3NljPNUEl7BAN43iZw== + dependencies: + yaml "^2.2.2" + +docker-modem@^3.0.0: + version "3.0.8" + resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-3.0.8.tgz#ef62c8bdff6e8a7d12f0160988c295ea8705e77a" + integrity sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ== + dependencies: + debug "^4.1.1" + readable-stream "^3.5.0" + split-ca "^1.0.1" + ssh2 "^1.11.0" + +dockerode@^3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-3.3.5.tgz#7ae3f40f2bec53ae5e9a741ce655fff459745629" + integrity sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA== + dependencies: + "@balena/dockerignore" "^1.0.2" + docker-modem "^3.0.0" + tar-fs "~2.0.1" + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -5288,10 +5600,10 @@ duplexer@^0.1.2: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -earcut@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/earcut/-/earcut-3.0.0.tgz#a8d5bf891224eaea8287201b5e787c6c0318af89" - integrity sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg== +earcut@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/earcut/-/earcut-3.0.1.tgz#f60b3f671c5657cca9d3e131c5527c5dde00ef38" + integrity sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw== eastasianwidth@^0.2.0: version "0.2.0" @@ -5319,10 +5631,10 @@ ejs@^3.1.8: dependencies: jake "^10.8.5" -electron-to-chromium@^1.5.41: - version "1.5.72" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.72.tgz#a732805986d3a5b5fedd438ddf4616c7d78ac2df" - integrity sha512-ZpSAUOZ2Izby7qnZluSrAlGgGQzucmFbN0n64dYzocYxnxV5ufurpj3VgEe4cUp7ir9LmeLxNYo8bVnlM8bQHw== +electron-to-chromium@^1.5.73: + version "1.5.78" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.78.tgz#223cdc76a5d15ac731136e68430e92cb8d612d13" + integrity sha512-UmwIt7HRKN1rsJfddG5UG7rCTCTAKoS9JeOy/R0zSenAyaZ8SU3RuXlwcratxhdxGRNpk03iq8O7BA3W7ibLVw== emittery@^0.13.1: version "0.13.1" @@ -5374,6 +5686,13 @@ encodeurl@~2.0.0: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== +end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + enhanced-resolve@^5.17.1: version "5.17.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" @@ -5402,7 +5721,7 @@ env-paths@^2.2.1: resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -envinfo@^7.7.3: +envinfo@^7.14.0: version "7.14.0" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.14.0.tgz#26dac5db54418f2a4c1159153a0b2ae980838aae" integrity sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg== @@ -5852,6 +6171,11 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -5862,7 +6186,7 @@ eventemitter3@^5.0.1: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -events@^3.2.0: +events@^3.2.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -5972,7 +6296,12 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.2: +fast-fifo@^1.2.0, fast-fifo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + +fast-glob@^3.2.7: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -5983,6 +6312,17 @@ fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.2: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.2.9, fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -5994,9 +6334,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fast-uri@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.3.tgz#892a1c91802d5d7860de728f18608a0573142241" - integrity sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw== + version "3.0.5" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.5.tgz#19f5f9691d0dab9b85861a7bb5d98fca961da9cd" + integrity sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q== fastest-levenshtein@1.0.16, fastest-levenshtein@^1.0.12, fastest-levenshtein@^1.0.16: version "1.0.16" @@ -6004,9 +6344,9 @@ fastest-levenshtein@1.0.16, fastest-levenshtein@^1.0.12, fastest-levenshtein@^1. integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + version "1.18.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.18.0.tgz#d631d7e25faffea81887fe5ea8c9010e1b36fee0" + integrity sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw== dependencies: reusify "^1.0.4" @@ -6175,11 +6515,16 @@ flat@^5.0.2: resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^3.2.9, flatted@^3.3.1: +flatted@^3.2.9: version "3.3.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== +flatted@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + focus-lock@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-1.3.5.tgz#aa644576e5ec47d227b57eb14e1efb2abf33914c" @@ -6236,14 +6581,10 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -fs-extra@^11.0.0: - version "11.2.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" - integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs.realpath@^1.0.0: version "1.0.0" @@ -6340,6 +6681,11 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -6388,6 +6734,18 @@ glob-to-regexp@^0.4.0, glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@^10.0.0: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e" @@ -6513,7 +6871,7 @@ gopd@^1.1.0: dependencies: get-intrinsic "^1.2.4" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.2, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -6800,7 +7158,7 @@ icss-utils@^5.0.0, icss-utils@^5.1.0: resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== -ieee754@^1.1.12: +ieee754@^1.1.12, ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -6859,7 +7217,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -7147,7 +7505,7 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: dependencies: call-bind "^1.0.7" -is-stream@^2.0.0: +is-stream@^2.0.0, is-stream@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== @@ -7300,6 +7658,15 @@ iterator.prototype@^1.1.3: reflect.getprototypeof "^1.0.4" set-function-name "^2.0.1" +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jackspeak@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.2.tgz#11f9468a3730c6ff6f56823a820d7e3be9bef015" @@ -7835,15 +8202,6 @@ json5@^2.1.2, json5@^2.1.3, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - jsqr@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-1.4.0.tgz#8efb8d0a7cc6863cb6d95116b9069123ce9eb2d1" @@ -7930,11 +8288,6 @@ knip@^5.36.2: zod "^3.22.4" zod-validation-error "^3.0.3" -known-css-properties@^0.34.0: - version "0.34.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.34.0.tgz#ccd7e9f4388302231b3f174a8b1d5b1f7b576cea" - integrity sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ== - known-css-properties@^0.35.0: version "0.35.0" resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.35.0.tgz#f6f8e40ab4e5700fa32f5b2ef5218a56bc853bd6" @@ -7960,6 +8313,13 @@ launch-editor@^2.6.1: picocolors "^1.0.0" shell-quote "^1.8.1" +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== + dependencies: + readable-stream "^2.0.5" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -8115,7 +8475,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.20, lodash@^4.17.21: +lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -8210,10 +8570,10 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -maplibre-gl@^4.0.0: - version "4.7.1" - resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-4.7.1.tgz#06a524438ee2aafbe8bcd91002a4e01468ea5486" - integrity sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA== +maplibre-gl@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-5.0.0.tgz#d9120b6ced7df5d1c791497f25bbe4edd5039d96" + integrity sha512-WG8IYFK2gfJYXvWjlqg1yavo/YO/JlNkblAJMt19sjIafP5oJzTgXFiOLUIYkjtrv5pKiAWuSYsx4CD3ithJqw== dependencies: "@mapbox/geojson-rewind" "^0.5.2" "@mapbox/jsonlint-lines-primitives" "^2.0.2" @@ -8222,14 +8582,14 @@ maplibre-gl@^4.0.0: "@mapbox/unitbezier" "^0.0.1" "@mapbox/vector-tile" "^1.3.1" "@mapbox/whoots-js" "^3.1.0" - "@maplibre/maplibre-gl-style-spec" "^20.3.1" - "@types/geojson" "^7946.0.14" + "@maplibre/maplibre-gl-style-spec" "^22.0.1" + "@types/geojson" "^7946.0.15" "@types/geojson-vt" "3.2.5" "@types/mapbox__point-geometry" "^0.1.4" "@types/mapbox__vector-tile" "^1.3.4" "@types/pbf" "^3.0.5" "@types/supercluster" "^7.1.3" - earcut "^3.0.0" + earcut "^3.0.1" geojson-vt "^4.0.2" gl-matrix "^3.4.3" global-prefix "^4.0.0" @@ -8299,7 +8659,7 @@ matrix-web-i18n@^3.2.1: minimist "^1.2.8" walk "^2.3.15" -matrix-widget-api@^1.10.0, matrix-widget-api@^1.8.2: +matrix-widget-api@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.10.0.tgz#d31ea073a5871a1fb1a511ef900b0c125a37bf55" integrity sha512-rkAJ29briYV7TJnfBVLVSKtpeBrBju15JZFSDP6wj8YdbCu1bdmlplJayQ+vYaw1x4fzI49Q+Nz3E85s46sRDw== @@ -8459,7 +8819,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1: +minimatch@^5.0.1, minimatch@^5.1.0: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== @@ -8495,6 +8855,11 @@ minipass@^4.2.4: resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -8555,6 +8920,11 @@ murmurhash-js@^1.0.0: resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51" integrity sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw== +nan@^2.19.0, nan@^2.20.0: + version "2.22.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3" + integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw== + nanoid@^3.3.7: version "3.3.8" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" @@ -8600,7 +8970,7 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.18: +node-releases@^2.0.19: version "2.0.19" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== @@ -8737,7 +9107,7 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== @@ -8973,7 +9343,7 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.6.1: +path-scurry@^1.11.1, path-scurry@^1.6.1: version "1.11.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== @@ -9017,7 +9387,7 @@ pbf@^3.2.1, pbf@^3.3.0: ieee754 "^1.1.12" resolve-protobuf-schema "^2.1.0" -picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0: +picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== @@ -9697,7 +10067,7 @@ postcss@8.4.38: picocolors "^1.0.0" source-map-js "^1.2.0" -postcss@^8.3.11, postcss@^8.4.33, postcss@^8.4.38, postcss@^8.4.47: +postcss@^8.3.11, postcss@^8.4.33, postcss@^8.4.38: version "8.4.47" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== @@ -9706,6 +10076,15 @@ postcss@^8.3.11, postcss@^8.4.33, postcss@^8.4.38, postcss@^8.4.47: picocolors "^1.1.0" source-map-js "^1.2.1" +postcss@^8.4.49: + version "8.4.49" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" + integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.1" + source-map-js "^1.2.1" + posthog-js@1.157.2: version "1.157.2" resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.157.2.tgz#dc2515818ead408aefb900e90c535fb57beb1f59" @@ -9800,6 +10179,22 @@ prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +proper-lockfile@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + +properties-reader@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/properties-reader/-/properties-reader-2.3.0.tgz#f3ab84224c9535a7a36e011ae489a79a13b472b2" + integrity sha512-z597WicA7nDZxK12kZqHr2TcvwNU1GCfA5UwfDY/HDp3hXPoPlb5rlEx9bwGTiJnc0OqbBTkU975jDToth8Gxw== + dependencies: + mkdirp "^1.0.4" + protocol-buffers-schema@^3.3.1: version "3.6.0" resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03" @@ -9823,6 +10218,14 @@ psl@^1.1.33: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +pump@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@^2.1.0, punycode@^2.1.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -9876,10 +10279,10 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -quickselect@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" - integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw== +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== quickselect@^3.0.0: version "3.0.0" @@ -9921,10 +10324,10 @@ raw-loader@^4.0.2: loader-utils "^2.0.0" schema-utils "^3.0.0" -re-resizable@6.10.1: - version "6.10.1" - resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.1.tgz#d062ca50bbc4ec7ae940f756cba36479e9015bc5" - integrity sha512-m33nSWRH57UZLmep5M/LatkZ2NRqimVD/bOOpvymw5Zf33+eTSEixsUugscOZzAtK0/nx+OSuOf8VbKJx/4ptw== +re-resizable@6.10.3: + version "6.10.3" + resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.3.tgz#72c42532ede0cbcaf93308bcbfed782abbf97e79" + integrity sha512-zvWb7X3RJMA4cuSrqoxgs3KR+D+pEXnGrD2FAD6BMYAULnZsSF4b7AOVyG6pC3VVNVOtlagGDCDmZSwWLjjBBw== react-beautiful-dnd@^13.1.0: version "13.1.1" @@ -10086,7 +10489,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^2.0.1, readable-stream@~2.3.6: +readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -10099,7 +10502,7 @@ readable-stream@^2.0.1, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6: +readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -10108,6 +10511,24 @@ readable-stream@^3.0.6: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^4.0.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.6.0.tgz#ce412dfb19c04efde1c5936d99c27f37a1ff94c9" + integrity sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + string_decoder "^1.3.0" + +readdir-glob@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" + integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== + dependencies: + minimatch "^5.1.0" + readdirp@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a" @@ -10326,6 +10747,11 @@ restore-cursor@^5.0.0: onetime "^7.0.0" signal-exit "^4.1.0" +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + retry@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" @@ -10414,7 +10840,7 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -10426,10 +10852,10 @@ sanitize-filename@^1.6.3: dependencies: truncate-utf8-bytes "^1.0.0" -sanitize-html@2.13.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.13.1.tgz#b4639b0a09574ab62b1b353cb99b1b87af742834" - integrity sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg== +sanitize-html@2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.14.0.tgz#bd2a7b97ee1d86a7f0e0babf3a4468f639c3a429" + integrity sha512-CafX+IUPxZshXqqRaG9ZClSlfPVjSxI0td7n07hk8QO2oO+9JDnlcL8iM8TWeOXOIBFgIOx6zioTzM53AOMn3g== dependencies: deepmerge "^4.2.2" escape-string-regexp "^4.0.0" @@ -10634,7 +11060,7 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -10798,6 +11224,11 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" +split-ca@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" + integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== + sprintf-js@^1.0.3: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" @@ -10808,6 +11239,25 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +ssh-remote-port-forward@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/ssh-remote-port-forward/-/ssh-remote-port-forward-1.0.4.tgz#72b0c5df8ec27ca300c75805cc6b266dee07e298" + integrity sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ== + dependencies: + "@types/ssh2" "^0.5.48" + ssh2 "^1.4.0" + +ssh2@^1.11.0, ssh2@^1.4.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.16.0.tgz#79221d40cbf4d03d07fe881149de0a9de928c9f0" + integrity sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg== + dependencies: + asn1 "^0.2.6" + bcrypt-pbkdf "^1.0.2" + optionalDependencies: + cpu-features "~0.0.10" + nan "^2.20.0" + stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -10825,6 +11275,17 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== +streamx@^2.15.0, streamx@^2.21.0: + version "2.21.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.21.1.tgz#f02979d8395b6b637d08a589fb514498bed55845" + integrity sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw== + dependencies: + fast-fifo "^1.3.2" + queue-tick "^1.0.1" + text-decoder "^1.1.0" + optionalDependencies: + bare-events "^2.2.0" + string-argv@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" @@ -10937,7 +11398,7 @@ string.prototype.trimstart@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.0" -string_decoder@^1.1.1: +string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -11052,20 +11513,20 @@ stylelint-value-no-unknown-custom-properties@^6.0.1: resolve "^1.22.8" stylelint@^16.1.0: - version "16.10.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.10.0.tgz#452b42a5d82f2ad910954eb2ba2b3a2ec583cd75" - integrity sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ== + version "16.12.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.12.0.tgz#13532dcbaed21348da0e9e0fb9a4e1e7f6dab2b8" + integrity sha512-F8zZ3L/rBpuoBZRvI4JVT20ZanPLXfQLzMOZg1tzPflRVh9mKpOZ8qcSIhh1my3FjAjZWG4T2POwGnmn6a6hbg== dependencies: - "@csstools/css-parser-algorithms" "^3.0.1" - "@csstools/css-tokenizer" "^3.0.1" - "@csstools/media-query-list-parser" "^3.0.1" - "@csstools/selector-specificity" "^4.0.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/media-query-list-parser" "^4.0.2" + "@csstools/selector-specificity" "^5.0.0" "@dual-bundle/import-meta-resolve" "^4.1.0" balanced-match "^2.0.0" colord "^2.9.3" cosmiconfig "^9.0.0" css-functions-list "^3.2.3" - css-tree "^3.0.0" + css-tree "^3.0.1" debug "^4.3.7" fast-glob "^3.3.2" fastest-levenshtein "^1.0.16" @@ -11077,22 +11538,22 @@ stylelint@^16.1.0: ignore "^6.0.2" imurmurhash "^0.1.4" is-plain-object "^5.0.0" - known-css-properties "^0.34.0" + known-css-properties "^0.35.0" mathml-tag-names "^2.1.3" meow "^13.2.0" micromatch "^4.0.8" normalize-path "^3.0.0" - picocolors "^1.0.1" - postcss "^8.4.47" + picocolors "^1.1.1" + postcss "^8.4.49" postcss-resolve-nested-selector "^0.1.6" postcss-safe-parser "^7.0.1" - postcss-selector-parser "^6.1.2" + postcss-selector-parser "^7.0.0" postcss-value-parser "^4.2.0" resolve-from "^5.0.0" string-width "^4.2.3" supports-hyperlinks "^3.1.0" svg-tags "^1.0.0" - table "^6.8.2" + table "^6.9.0" write-file-atomic "^5.0.1" sugarss@^4.0.1: @@ -11179,10 +11640,10 @@ tabbable@^6.0.0: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== -table@^6.8.2: - version "6.8.2" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58" - integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== +table@^6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.9.0.tgz#50040afa6264141c7566b3b81d4d82c47a8668f5" + integrity sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -11195,11 +11656,52 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== +tar-fs@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.6.tgz#eaccd3a67d5672f09ca8e8f9c3d2b89fa173f217" + integrity sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w== + dependencies: + pump "^3.0.0" + tar-stream "^3.1.5" + optionalDependencies: + bare-fs "^2.1.1" + bare-path "^2.1.0" + +tar-fs@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" + integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.0.0" + tar-js@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/tar-js/-/tar-js-0.3.0.tgz#6949aabfb0ba18bb1562ae51a439fd0f30183a17" integrity sha512-9uqP2hJUZNKRkwPDe5nXxXdzo6w+BFBPq9x/tyi5/U/DneuSesO/HMb0y5TeWpfcv49YDJTs7SrrZeeu8ZHWDA== +tar-stream@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +tar-stream@^3.0.0, tar-stream@^3.1.5: + version "3.1.7" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" + integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + temporal-polyfill@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/temporal-polyfill/-/temporal-polyfill-0.2.5.tgz#0796c40a50754c69ec0f9a2db3f6c582b9721aaf" @@ -11252,6 +11754,34 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +testcontainers@^10.16.0: + version "10.16.0" + resolved "https://registry.yarnpkg.com/testcontainers/-/testcontainers-10.16.0.tgz#8a7e69ada5cd2c6cce1c6db72b3a3e8e412fcaf6" + integrity sha512-oxPLuOtrRWS11A+Yn0+zXB7GkmNarflWqmy6CQJk8KJ75LZs2/zlUXDpizTbPpCGtk4kE2EQYwFZjrE967F8Wg== + dependencies: + "@balena/dockerignore" "^1.0.2" + "@types/dockerode" "^3.3.29" + archiver "^7.0.1" + async-lock "^1.4.1" + byline "^5.0.0" + debug "^4.3.5" + docker-compose "^0.24.8" + dockerode "^3.3.5" + get-port "^5.1.1" + proper-lockfile "^4.1.2" + properties-reader "^2.3.0" + ssh-remote-port-forward "^1.0.4" + tar-fs "^3.0.6" + tmp "^0.2.3" + undici "^5.28.4" + +text-decoder@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.3.tgz#b19da364d981b2326d5f43099c310cc80d770c65" + integrity sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA== + dependencies: + b4a "^1.6.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -11285,6 +11815,11 @@ tinyqueue@^3.0.0: resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-3.0.0.tgz#101ea761ccc81f979e29200929e78f1556e3661e" integrity sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g== +tmp@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -11368,6 +11903,11 @@ ts-api-utils@^1.3.0: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== +ts-api-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.0.tgz#b9d7d5f7ec9f736f4d0f09758b8607979044a900" + integrity sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ== + ts-morph@^13.0.1: version "13.0.3" resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-13.0.3.tgz#c0c51d1273ae2edb46d76f65161eb9d763444c1d" @@ -11432,6 +11972,11 @@ tslib@^2.0.0, tslib@^2.4.0, tslib@^2.6.1, tslib@^2.6.2, tslib@^2.7.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.0.tgz#d124c86c3c05a40a91e6fdea4021bd31d377971b" integrity sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA== +tweetnacl@^0.14.3: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -11557,6 +12102,13 @@ undici-types@~6.20.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== +undici@^5.28.4: + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== + dependencies: + "@fastify/busboy" "^2.0.0" + unhomoglyph@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/unhomoglyph/-/unhomoglyph-1.0.6.tgz#ea41f926d0fcf598e3b8bb2980c2ddac66b081d3" @@ -11595,11 +12147,6 @@ universalify@^0.2.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -11844,24 +12391,24 @@ webpack-bundle-analyzer@^4.8.0: sirv "^2.0.3" ws "^7.3.1" -webpack-cli@^5.0.0: - version "5.1.4" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" - integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== +webpack-cli@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-6.0.1.tgz#a1ce25da5ba077151afd73adfa12e208e5089207" + integrity sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw== dependencies: - "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^2.1.1" - "@webpack-cli/info" "^2.0.2" - "@webpack-cli/serve" "^2.0.5" + "@discoveryjs/json-ext" "^0.6.1" + "@webpack-cli/configtest" "^3.0.1" + "@webpack-cli/info" "^3.0.1" + "@webpack-cli/serve" "^3.0.1" colorette "^2.0.14" - commander "^10.0.1" + commander "^12.1.0" cross-spawn "^7.0.3" - envinfo "^7.7.3" + envinfo "^7.14.0" fastest-levenshtein "^1.0.12" import-local "^3.0.2" interpret "^3.1.1" rechoir "^0.8.0" - webpack-merge "^5.7.3" + webpack-merge "^6.0.1" webpack-dev-middleware@^7.4.2: version "7.4.2" @@ -11909,14 +12456,14 @@ webpack-dev-server@^5.0.0: webpack-dev-middleware "^7.4.2" ws "^8.18.0" -webpack-merge@^5.7.3: - version "5.10.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" - integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== +webpack-merge@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-6.0.1.tgz#50c776868e080574725abc5869bd6e4ef0a16c6a" + integrity sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg== dependencies: clone-deep "^4.0.1" flat "^5.0.2" - wildcard "^2.0.0" + wildcard "^2.0.1" webpack-sources@^3.2.3: version "3.2.3" @@ -12110,7 +12657,7 @@ which@^4.0.0: dependencies: isexe "^3.1.1" -wildcard@^2.0.0: +wildcard@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== @@ -12211,6 +12758,11 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.2.2: + version "2.7.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.0.tgz#aef9bb617a64c937a9a748803786ad8d3ffe1e98" + integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== + yaml@^2.3.3: version "2.6.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773" @@ -12279,6 +12831,15 @@ yocto-queue@^1.0.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.1.1.tgz#fef65ce3ac9f8a32ceac5a634f74e17e5b232110" integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g== +zip-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-6.0.1.tgz#e141b930ed60ccaf5d7fa9c8260e0d1748a2bbfb" + integrity sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA== + dependencies: + archiver-utils "^5.0.0" + compress-commons "^6.0.2" + readable-stream "^4.0.0" + zod-validation-error@^3.0.3: version "3.4.0" resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.4.0.tgz#3a8a1f55c65579822d7faa190b51336c61bee2a6"