diff --git a/.github/workflows/cherry-pick-release-to-dev.yml b/.github/workflows/cherry-pick-release-to-dev.yml index 8330dd64e1b9..d97a158a8c95 100644 --- a/.github/workflows/cherry-pick-release-to-dev.yml +++ b/.github/workflows/cherry-pick-release-to-dev.yml @@ -5,16 +5,23 @@ on: push: branches: - release/* + +permissions: + pull-requests: write + contents: write + jobs: cherry_pick: runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Create PR to branch uses: gorillio/github-action-cherry-pick@master with: pr_branch: 'dev' env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{secrets.OTTO_THE_BOT_GH_TOKEN}} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a998bd4e05ef..39982d97c55d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ name: CI on: pull_request: # we want to run the CI on every PR targetting those branches - branches: [master, dev] + branches: [master, dev, release/*] push: # We also run CI on dev in order to update the coverage monitoring @@ -37,7 +37,7 @@ jobs: run: yarn test --coverage --coverage-reporters=lcov --detectOpenHandles=false - name: Monitor coverage - uses: codecov/codecov-action@v3.1.4 + uses: codecov/codecov-action@v3.1.5 with: fail_ci_if_error: false files: ./coverage/lcov.info diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml deleted file mode 100644 index 83c72972ffd1..000000000000 --- a/.github/workflows/dependabot-auto-merge.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Dependabot auto-merge -on: pull_request_target - -permissions: - pull-requests: write - contents: write - -jobs: - activate-auto-merge: - runs-on: ubuntu-latest - if: ${{github.actor == 'dependabot[bot]'}} - steps: - - name: Dependabot metadata - id: metadata - uses: dependabot/fetch-metadata@v1.6.0 - with: - github-token: '${{secrets.WEBTEAM_AUTOMERGE_TOKEN}}' - - - name: Approve a PR - run: gh pr review --approve "$PR_URL" - env: - PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.WEBTEAM_AUTOMERGE_TOKEN}} - - - name: Enable auto-merge for Dependabot PRs - if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch'}} - run: gh pr merge --auto --squash "$PR_URL" - env: - PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.WEBTEAM_AUTOMERGE_TOKEN}} diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index a9b8d46d944f..9a9dcfebb75f 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,4 +17,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@v4 - name: 'Dependency Review' - uses: actions/dependency-review-action@v3 + uses: actions/dependency-review-action@v4 diff --git a/.github/workflows/jira-lint-and-link.yml b/.github/workflows/jira-lint-and-link.yml index 06c40a2750e5..e3feb664e0c1 100644 --- a/.github/workflows/jira-lint-and-link.yml +++ b/.github/workflows/jira-lint-and-link.yml @@ -4,6 +4,8 @@ on: types: [opened, edited, synchronize] jobs: add-jira-description: + # avoid triggering this action on dependabot PRs + if: ${{ github.actor != 'dependabot[bot]' }} runs-on: ubuntu-latest steps: - uses: cakeinpanic/jira-description-action@v0.7.0 @@ -12,5 +14,5 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} jira-token: ${{ secrets.JIRA_TOKEN }} jira-base-url: https://wearezeta.atlassian.net - skip-branches: '^(production-release|main|master|release\/v\d+)$' #optional + skip-branches: '^(dev|master|release\/*)$' fail-when-jira-issue-not-found: false diff --git a/.github/workflows/pr-auto-merge.yml b/.github/workflows/pr-auto-merge.yml new file mode 100644 index 000000000000..756dc3af5f95 --- /dev/null +++ b/.github/workflows/pr-auto-merge.yml @@ -0,0 +1,22 @@ +name: auto-merge PR +on: pull_request + +permissions: + pull-requests: write + contents: write + +# This job will enable auto merge on dependabots and otto-the-bot's PRs +jobs: + activate-auto-merge: + runs-on: ubuntu-latest + if: ${{github.actor == 'dependabot[bot]' || github.actor == 'otto-the-bot'}} + steps: + - name: Approve PR + run: gh pr review --approve ${{github.event.pull_request.html_url}} + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Enable auto-merge + run: gh pr merge --auto --squash ${{github.event.pull_request.html_url}} + env: + GITHUB_TOKEN: ${{secrets.OTTO_THE_BOT_GH_TOKEN}} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index aafc7499e5b3..344fa2131d31 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,7 +2,7 @@ name: Publish on: push: - branches: [master, dev] + branches: [master, dev, release/*] tags: - '*staging*' - '*production*' @@ -77,6 +77,10 @@ jobs: wire_builds_target_branches='["dev"]' fi + if [ "$version_tag" == "release/q1-2024" ]; then + wire_builds_target_branches='["q1-2024"]' + fi + echo "wire_builds_target_branches: $wire_builds_target_branches" echo "wire_builds_target_branches=$wire_builds_target_branches" >> $GITHUB_OUTPUT @@ -201,20 +205,48 @@ jobs: - name: Create new build in wire-build shell: bash run: | - git fetch --depth 1 origin "${{ matrix.target_branch }}" - git checkout "${{ matrix.target_branch }}" + set -eo pipefail chart_version="${{needs.build.outputs.chart_version}}" - build_json=$(cat ./build.json | ./bin/bump-chart webapp "$chart_version" | ./bin/bump-prerelease ) - echo "$build_json" > ./build.json + image_tag="${{needs.build.outputs.image_tag}}" - git add build.json git config --global user.email "zebot@users.noreply.github.com" git config --global user.name "Zebot" - git commit -m "Bump webapp to $chart_version" - git push origin "${{ matrix.target_branch }}" + for retry in $(seq 3); do + ( + set -e + + if (( retry > 1 )); then + echo "Retrying..." + fi + + git fetch --depth 1 origin "${{ matrix.target_branch }}" + git checkout "${{ matrix.target_branch }}" + git reset --hard @{upstream} + + build_json=$(cat ./build.json | \ + ./bin/set-chart-fields webapp \ + "version=$chart_version" \ + "repo=https://s3-eu-west-1.amazonaws.com/public.wire.com/charts-webapp" \ + "meta.appVersion=$image_tag" \ + "meta.commitURL=${{github.event.head_commit.url}}" \ + "meta.commit=${{github.event.head_commit.id}}" \ + | ./bin/bump-prerelease ) + echo "$build_json" > ./build.json + + git add build.json + git commit -m "Bump webapp to $chart_version" + + git push origin "${{ matrix.target_branch }}" + + ) && break + done + if (( $? != 0 )); then + echo "Retrying didn't help. Failing the step." + exit 1 + fi #FUTUREWORK: Remove this job once production builds are based on wireapp/wire-builds update_helm_chart: diff --git a/.github/workflows/pull_translations.yml b/.github/workflows/pull_translations.yml new file mode 100644 index 000000000000..db3daa09f26e --- /dev/null +++ b/.github/workflows/pull_translations.yml @@ -0,0 +1,49 @@ +name: Pull translations from crowdin + +on: + workflow_dispatch: + +jobs: + sync_translations: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.12.1 + with: + access_token: ${{github.token}} + + - name: Yarn cache + uses: c-hive/gha-yarn-cache@v2 + + - name: Authenticate git clone + env: + GH_TOKEN: ${{secrets.OTTO_THE_BOT_GH_TOKEN}} + run: echo -e "machine github.com\n login ${GH_TOKEN}" > ~/.netrc + + - name: Install JS dependencies + run: yarn --immutable + + - name: Sync translations + uses: crowdin/github-action@v1.16.1 + env: + GITHUB_TOKEN: ${{secrets.OTTO_THE_BOT_GH_TOKEN}} + GITHUB_ACTOR: otto-the-bot + CROWDIN_PROJECT_ID: 342359 + INPUT_DEBUG_MODE: true + with: + upload_sources: false + upload_translations: false + download_translations: true + push_translations: true + create_pull_request: true + localization_branch_name: 'pull_translations' + pull_request_title: 'chore: Pull translations' + commit_message: 'chore: Pull translations' + token: ${{secrets.WEBTEAM_CROWDIN_TOKEN}} + source: '/src/i18n/en-US.json' + translation: '/src/i18n/%locale%.json' + base_path: '.' diff --git a/.github/workflows/rename-cherry-pick-pr.yml b/.github/workflows/rename-cherry-pick-pr.yml new file mode 100644 index 000000000000..6b92a852e07a --- /dev/null +++ b/.github/workflows/rename-cherry-pick-pr.yml @@ -0,0 +1,20 @@ +name: rename-auto-cherry-pick-pr +on: pull_request + +permissions: + pull-requests: write + +# This job will remove the AUTO: prefix from the PR title +jobs: + rename-auto-cherry-pick-pr: + runs-on: ubuntu-latest + if: startsWith(github.event.pull_request.title, 'AUTO:') + steps: + - name: Make title semantic + run: | + TITLE="${{github.event.pull_request.title}}" + SEMANTIC_TITLE="${TITLE/AUTO: /}" + echo "renaming pr to: $SEMANTIC_TITLE" + gh pr edit ${{github.event.pull_request.html_url}} --title "$SEMANTIC_TITLE" + env: + GH_TOKEN: ${{secrets.OTTO_THE_BOT_GH_TOKEN}} diff --git a/.github/workflows/sync_translations.yml b/.github/workflows/sync_translations.yml index da40831e2f0f..dc8acb83f611 100644 --- a/.github/workflows/sync_translations.yml +++ b/.github/workflows/sync_translations.yml @@ -37,7 +37,7 @@ jobs: run: yarn translate:merge - name: Download translations - uses: crowdin/github-action@v1.16.0 + uses: crowdin/github-action@v1.16.1 env: GITHUB_TOKEN: ${{secrets.OTTO_THE_BOT_GH_TOKEN}} CROWDIN_PROJECT_ID: 342359 diff --git a/bin/push_docker.js b/bin/push_docker.js index 45b95ea2b547..66720158a696 100644 --- a/bin/push_docker.js +++ b/bin/push_docker.js @@ -37,7 +37,7 @@ require('dotenv').config(); */ /** Version tag of webapp (e.g. "2023-11-09-staging.0", "dev") */ -const versionTag = process.argv[2]; +const versionTag = process.argv[2].replace('/', '-'); const uniqueTagOut = process.argv[3] || ''; /** Commit ID of https://github.com/wireapp/wire-webapp (i.e. "1240cfda9e609470cf1154e18f5bc582ca8907ff") */ const commitSha = process.env.GITHUB_SHA || process.argv[4]; diff --git a/package.json b/package.json index 7597c7e4e8aa..99f41648f991 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,27 @@ { "dependencies": { - "@datadog/browser-logs": "^5.7.0", - "@datadog/browser-rum": "^5.7.0", + "@datadog/browser-logs": "^5.8.0", + "@datadog/browser-rum": "^5.8.0", "@emotion/react": "11.11.3", "@lexical/history": "0.12.5", "@lexical/react": "0.12.5", "@peculiar/x509": "1.9.6", "@wireapp/avs": "9.6.9", "@wireapp/commons": "5.2.4", - "@wireapp/core": "43.5.6", - "@wireapp/react-ui-kit": "9.12.6", + "@wireapp/core": "43.11.2", + "@wireapp/react-ui-kit": "9.12.8", "@wireapp/store-engine-dexie": "2.1.7", "@wireapp/webapp-events": "0.20.1", "amplify": "https://github.com/wireapp/amplify#head=master", "beautiful-react-hooks": "^5.0.1", "classnames": "2.5.1", - "copy-webpack-plugin": "12.0.1", - "core-js": "3.35.0", + "copy-webpack-plugin": "12.0.2", + "core-js": "3.35.1", "countly-sdk-web": "23.12.4", - "date-fns": "3.2.0", + "date-fns": "3.3.1", "dexie-batch": "0.4.3", "dexie-encrypted": "2.0.0", - "emoji-picker-react": "4.6.10", + "emoji-picker-react": "4.7.10", "highlight.js": "11.9.0", "http-status-codes": "2.3.0", "jimp": "0.22.10", @@ -41,10 +41,10 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-error-boundary": "4.0.12", - "react-intl": "6.5.5", + "react-intl": "6.6.2", "react-redux": "8.1.3", - "react-router": "6.21.2", - "react-router-dom": "6.21.2", + "react-router": "6.21.3", + "react-router-dom": "6.21.3", "react-transition-group": "4.4.5", "redux": "4.2.1", "redux-logdown": "1.0.4", @@ -55,18 +55,18 @@ "underscore": "1.13.6", "uuidjs": "4.2.13", "webrtc-adapter": "8.2.3", - "zustand": "4.4.7" + "zustand": "4.5.0" }, "devDependencies": { - "@babel/core": "7.23.7", - "@babel/eslint-parser": "7.23.3", - "@babel/plugin-proposal-decorators": "7.23.7", - "@babel/preset-env": "7.23.8", + "@babel/core": "7.23.9", + "@babel/eslint-parser": "7.23.9", + "@babel/plugin-proposal-decorators": "7.23.9", + "@babel/preset-env": "7.23.9", "@babel/preset-react": "7.23.3", "@babel/preset-typescript": "7.23.3", "@emotion/eslint-plugin": "^11.11.0", - "@faker-js/faker": "8.3.1", - "@formatjs/cli": "6.2.4", + "@faker-js/faker": "8.4.0", + "@formatjs/cli": "6.2.7", "@koush/wrtc": "0.5.3", "@testing-library/react": "14.1.2", "@types/dexie-batch": "0.4.7", @@ -82,10 +82,10 @@ "@types/linkify-it": "3.0.5", "@types/loadable__component": "^5", "@types/markdown-it": "13.0.7", - "@types/node": "^20.11.0", + "@types/node": "^20.11.9", "@types/open-graph": "0.2.5", "@types/platform": "1.3.6", - "@types/react": "18.2.47", + "@types/react": "18.2.48", "@types/react-dom": "18.2.18", "@types/react-redux": "7.1.31", "@types/react-transition-group": "4.4.10", @@ -100,21 +100,21 @@ "@wireapp/prettier-config": "0.6.3", "@wireapp/store-engine": "^5.1.4", "archiver": "^6.0.1", - "autoprefixer": "^10.4.16", + "autoprefixer": "^10.4.17", "babel-loader": "9.1.3", "babel-plugin-transform-import-meta": "^2.2.1", "cross-env": "7.0.3", - "css-loader": "^6.9.0", + "css-loader": "^6.9.1", "cssnano": "6.0.3", "dexie": "3.2.4", - "dotenv": "16.3.1", + "dotenv": "16.4.1", "dpdm": "3.14.0", "eslint": "^8.56.0", "eslint-plugin-prettier": "^5.1.3", "fake-indexeddb": "5.0.2", "generate-changelog": "1.8.0", "html-webpack-plugin": "^5.6.0", - "husky": "8.0.3", + "husky": "9.0.6", "i18next-scanner": "4.4.0", "intersection-observer": "0.12.2", "jest": "29.7.0", @@ -123,7 +123,7 @@ "jest-jasmine2": "29.7.0", "jsdom-worker": "0.3.0", "less": "4.2.0", - "less-loader": "^11.1.4", + "less-loader": "^12.1.0", "lint-staged": "15.2.0", "node-fetch": "2.7.0", "os-browserify": "0.3.0", @@ -131,7 +131,7 @@ "postcss": "8.4.33", "postcss-import": "^16.0.0", "postcss-less": "6.0.0", - "postcss-loader": "^7.3.4", + "postcss-loader": "^8.0.0", "postcss-preset-env": "^9.3.0", "postcss-scss": "4.0.9", "prettier": "^3.2.2", @@ -150,7 +150,7 @@ "ts-node": "10.9.2", "tsc-watch": "6.0.4", "typescript": "5.3.3", - "webpack": "5.89.0", + "webpack": "5.90.0", "webpack-cli": "5.1.4", "webpack-dev-middleware": "7.0.0", "webpack-hot-middleware": "2.26.0", diff --git a/server/Server.ts b/server/Server.ts index ff5e24f637de..472ab5b71c0b 100644 --- a/server/Server.ts +++ b/server/Server.ts @@ -33,7 +33,6 @@ import type {ClientConfig, ServerConfig} from './config'; import {HealthCheckRoute} from './routes/_health/HealthRoute'; import {AppleAssociationRoute} from './routes/appleassociation/AppleAssociationRoute'; import {ConfigRoute} from './routes/config/ConfigRoute'; -import {OIDCProxyRoute, OIDCProxyRoutePath} from './routes/E2EIProxy'; import {InternalErrorRoute, NotFoundRoute} from './routes/error/ErrorRoutes'; import {GoogleWebmasterRoute} from './routes/googlewebmaster/GoogleWebmasterRoute'; import {RedirectRoutes} from './routes/RedirectRoutes'; @@ -74,7 +73,6 @@ class Server { this.app.use(ConfigRoute(this.config, this.clientConfig)); this.app.use(GoogleWebmasterRoute(this.config)); this.app.use(AppleAssociationRoute()); - this.app.use(OIDCProxyRoute()); this.app.use(NotFoundRoute()); this.app.use(InternalErrorRoute()); } @@ -190,8 +188,7 @@ class Server { req.path.startsWith('/join') || req.path.startsWith('/auth') || req.path.startsWith('/google') || - req.path.startsWith('/apple-app-site-association') || - req.path.startsWith(OIDCProxyRoutePath); + req.path.startsWith('/apple-app-site-association'); if (ignoredPath) { return next(); diff --git a/server/package.json b/server/package.json index a9f9647f0ba3..cd3dfcbe2b4f 100644 --- a/server/package.json +++ b/server/package.json @@ -5,7 +5,7 @@ "license": "GPL-3.0", "dependencies": { "@wireapp/commons": "5.2.4", - "dotenv": "16.3.1", + "dotenv": "16.4.1", "dotenv-extended": "2.9.0", "express": "4.18.2", "express-sitemap-xml": "3.0.1", @@ -20,7 +20,7 @@ "maxmind": "4.3.10", "nocache": "4.0.0", "opn": "6.0.0", - "pm2": "5.3.0" + "pm2": "5.3.1" }, "devDependencies": { "@types/express": "4.17.21", diff --git a/server/routes/E2EIProxy/common.ts b/server/routes/E2EIProxy/common.ts deleted file mode 100644 index cec817b1413f..000000000000 --- a/server/routes/E2EIProxy/common.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Wire - * Copyright (C) 2023 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -// The path to the OIDC proxy route -export const OIDCProxyRoutePath = '/oidcProxy'; - -// The query parameter name for the target URL -export const targetURLParam = 'targetUrl'; - -const isValidUrl = (urlString: string) => { - try { - new URL(urlString); - return true; - } catch (e) { - return false; - } -}; - -export const getTargetUrlWithQueryParams = (req: any) => { - const targetUrl = req.query[targetURLParam]; - - // Get all query parameters except the targetURLParam - const queryParams = {...req.query}; - delete queryParams[targetURLParam]; - - // Check if the target URL has the shouldBeRedirectedByProxy query parameter - const redirectParamName = 'shouldBeRedirectedByProxy'; - const shouldBeRedirected = req.query[redirectParamName]; - delete queryParams[redirectParamName]; - - // Append the query parameters to the target URL - const targetUrlWithQueryParams = new URL(targetUrl); - - Object.keys(queryParams).forEach(key => { - targetUrlWithQueryParams.searchParams.append(key, queryParams[key] as string); - }); - - return { - isValidUrl: isValidUrl(targetUrl), - targetUrlWithQueryParams, - shouldBeRedirected: typeof shouldBeRedirected === 'string' && shouldBeRedirected === 'true', - }; -}; diff --git a/server/routes/E2EIProxy/proxy.ts b/server/routes/E2EIProxy/proxy.ts deleted file mode 100644 index 9134f8ea8e85..000000000000 --- a/server/routes/E2EIProxy/proxy.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Wire - * Copyright (C) 2023 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import {createProxyMiddleware} from 'http-proxy-middleware'; - -import {OIDCProxyRoutePath, targetURLParam, getTargetUrlWithQueryParams} from './common'; - -// Configure the dynamic proxy middleware -export const OIDCProxy = createProxyMiddleware({ - changeOrigin: true, - ignorePath: true, - logLevel: 'silent', - selfHandleResponse: true, // Handle response manually - followRedirects: true, - router: req => { - // Dynamic target based on the request - - const {isValidUrl, targetUrlWithQueryParams} = getTargetUrlWithQueryParams(req); - - if (isValidUrl) { - return targetUrlWithQueryParams.href; - } - - return undefined; // or handle this case appropriately - }, - onProxyRes: (proxyRes, req, res) => { - // Exception: Modify the response if the target URL is the OIDC discovery URL - if (req.originalUrl.includes('.well-known/openid-configuration')) { - let body = ''; - - proxyRes.on('data', chunk => { - body += chunk; - }); - - proxyRes.on('end', () => { - try { - // Parse the body as JSON - const json = JSON.parse(body); - - if (!req.headers.referer) { - throw new Error('no referrer URL found'); - } - const refererUrl = new URL(req.headers.referer); - - // Modify URLs in the JSON response - Object.keys(json).forEach(key => { - if (typeof json[key] === 'string' && json[key].startsWith('https://')) { - const originalUrl = new URL(json[key]); - - json[key] = `${refererUrl.origin}${OIDCProxyRoutePath}?${targetURLParam}=${encodeURIComponent( - originalUrl.href, - )}`; - } - }); - // Send the modified response back to the client - res.end(JSON.stringify(json)); - } catch (error) { - console.error('Error processing proxy response:', error); - res.status(500).send('Internal Server Error'); - } - }); - } else { - // Default: Send the response back to the client - proxyRes.pipe(res); - } - }, -}); diff --git a/server/yarn.lock b/server/yarn.lock index f0e2a2c18757..b8f1ac5ddcbb 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -805,16 +805,16 @@ __metadata: languageName: node linkType: hard -"@pm2/js-api@npm:~0.6.7": - version: 0.6.7 - resolution: "@pm2/js-api@npm:0.6.7" +"@pm2/js-api@npm:~0.8.0": + version: 0.8.0 + resolution: "@pm2/js-api@npm:0.8.0" dependencies: async: ^2.6.3 - axios: ^0.21.0 debug: ~4.3.1 eventemitter2: ^6.3.1 + extrareqp2: ^1.0.0 ws: ^7.0.0 - checksum: 43d1e4d06328ad18d8929225a0732fa20701694dea0e3af0ea692239e0adc45ef2f48a794599a8df88bc705d2e428b5b8018deb3709983c91ed0b74a834b2f21 + checksum: c17b01d2a5efe8db370b21a7a0452e144d14066632d35a423cc025b812630563f195440dea842281cce614ae5dc3509fce33e27f68318aa024d815332d28edbd languageName: node linkType: hard @@ -1394,15 +1394,6 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.21.0": - version: 0.21.4 - resolution: "axios@npm:0.21.4" - dependencies: - follow-redirects: ^1.14.0 - checksum: 44245f24ac971e7458f3120c92f9d66d1fc695e8b97019139de5b0cc65d9b8104647db01e5f46917728edfc0cfd88eb30fc4c55e6053eef4ace76768ce95ff3c - languageName: node - linkType: hard - "babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -2066,10 +2057,10 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:16.3.1": - version: 16.3.1 - resolution: "dotenv@npm:16.3.1" - checksum: 15d75e7279018f4bafd0ee9706593dd14455ddb71b3bcba9c52574460b7ccaf67d5cf8b2c08a5af1a9da6db36c956a04a1192b101ee102a3e0cf8817bbcf3dfd +"dotenv@npm:16.4.1": + version: 16.4.1 + resolution: "dotenv@npm:16.4.1" + checksum: a343f0a1d156deef8c60034f797969867af4dbccfacedd4ac15fad04547e7ffe0553b58fc3b27a5837950f0d977e38e9234943fbcec4aeced4e3d044309a76ab languageName: node linkType: hard @@ -2391,6 +2382,15 @@ __metadata: languageName: node linkType: hard +"extrareqp2@npm:^1.0.0": + version: 1.0.0 + resolution: "extrareqp2@npm:1.0.0" + dependencies: + follow-redirects: ^1.14.0 + checksum: 1c64c2669715a8dbb07c88ba81a3aa1dd1fe29a794b27db5bece17994de32d3f21ca686af265f56174a748203b57eebdf8ae22afda05f361fc29420059ed14ae + languageName: node + linkType: hard + "fast-json-patch@npm:^3.0.0-1": version: 3.1.1 resolution: "fast-json-patch@npm:3.1.1" @@ -4619,13 +4619,13 @@ __metadata: languageName: node linkType: hard -"pm2@npm:5.3.0": - version: 5.3.0 - resolution: "pm2@npm:5.3.0" +"pm2@npm:5.3.1": + version: 5.3.1 + resolution: "pm2@npm:5.3.1" dependencies: "@pm2/agent": ~2.0.0 "@pm2/io": ~5.0.0 - "@pm2/js-api": ~0.6.7 + "@pm2/js-api": ~0.8.0 "@pm2/pm2-version-check": latest async: ~3.2.0 blessed: 0.1.81 @@ -4661,7 +4661,7 @@ __metadata: pm2-dev: bin/pm2-dev pm2-docker: bin/pm2-docker pm2-runtime: bin/pm2-runtime - checksum: ca1a655ab11b8aa8f7c10098578e7f0ed508fb19fae02694c5478f4167a75cb150eb2c305d734b7420696b70193bb765ffbbca498d2ce427f85ae9d25ef19842 + checksum: 7d82fd70393432abb34218fb82a2ae31e499db13259da6746a371fbf242758c3859a309fd93c836a4cb318721315a95e69126cc16a1843a2f5df931581c47d0e languageName: node linkType: hard @@ -5624,7 +5624,7 @@ __metadata: "@types/jest": ^29.5.11 "@types/node": 18.11.18 "@wireapp/commons": 5.2.4 - dotenv: 16.3.1 + dotenv: 16.4.1 dotenv-extended: 2.9.0 express: 4.18.2 express-sitemap-xml: 3.0.1 @@ -5640,7 +5640,7 @@ __metadata: maxmind: 4.3.10 nocache: 4.0.0 opn: 6.0.0 - pm2: 5.3.0 + pm2: 5.3.1 rimraf: 4.4.1 typescript: 5.3.3 languageName: unknown diff --git a/src/__mocks__/@wireapp/core.ts b/src/__mocks__/@wireapp/core.ts index e6f595e43548..8a35812e90c0 100644 --- a/src/__mocks__/@wireapp/core.ts +++ b/src/__mocks__/@wireapp/core.ts @@ -40,6 +40,11 @@ export class Account extends EventEmitter { getUsersIdentities: jest.fn(() => new Map()), getDeviceIdentities: jest.fn(), getConversationState: jest.fn(), + registerServerCertificates: jest.fn(), + on: jest.fn(), + emit: jest.fn(), + off: jest.fn(), + initialize: jest.fn(), }, mls: { schedulePeriodicKeyMaterialRenewals: jest.fn(), diff --git a/src/i18n/ar-SA.json b/src/i18n/ar-SA.json index 0b4ff13a30e4..1ff7f0450d21 100644 --- a/src/i18n/ar-SA.json +++ b/src/i18n/ar-SA.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "إضافة", "addParticipantsHeader": "أضف أشخاصًا", "addParticipantsHeaderWithCounter": "أضف أشخاصًا ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " اتصل", "conversationVoiceChannelDeactivateYou": " اتصل", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "أمس", "conversationYouAccusative": "أنت", "conversationYouDative": "أنت", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/bn-BD.json b/src/i18n/bn-BD.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/bn-BD.json +++ b/src/i18n/bn-BD.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/ca-ES.json b/src/i18n/ca-ES.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/ca-ES.json +++ b/src/i18n/ca-ES.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/cs-CZ.json b/src/i18n/cs-CZ.json index 6264915187fa..86abd4056e14 100644 --- a/src/i18n/cs-CZ.json +++ b/src/i18n/cs-CZ.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Přidat", "addParticipantsHeader": "Přidat účastníky", "addParticipantsHeaderWithCounter": "Přidat účastníky ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " volal(a)", "conversationVoiceChannelDeactivateYou": " volal(a)", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Včera", "conversationYouAccusative": "jste", "conversationYouDative": "jste", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/da-DK.json b/src/i18n/da-DK.json index b53e24709be4..6dc96a081e16 100644 --- a/src/i18n/da-DK.json +++ b/src/i18n/da-DK.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Tilføj", "addParticipantsHeader": "Tilføj personer", "addParticipantsHeaderWithCounter": "Tilføj personer ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " ringede", "conversationVoiceChannelDeactivateYou": " ringede", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "I går", "conversationYouAccusative": "dig", "conversationYouDative": "dig", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/de-DE.json b/src/i18n/de-DE.json index 9a4041445ec6..b3f62d9dabd7 100644 --- a/src/i18n/de-DE.json +++ b/src/i18n/de-DE.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Fenster 'Es ist ein Fehler aufgetreten' schließen", "acme.error.button.primary": "Wiederholen", "acme.error.button.secondary": "Abbrechen", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Ein Fehler ist aufgetreten", - "acme.error.paragraph": "Das Zertifikat konnte nicht ausgestellt werden. [br] Sie können jetzt erneut versuchen, das Zertifikat zu erhalten, oder Sie bekommen später eine Erinnerung.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Fenster 'Zertifikat erhalten' schließen", "acme.inProgress.headline": "Zertifikat wird abgerufen...", "acme.inProgress.paragraph.alt": "Herunterladen…", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Fenster 'Ende-zu-Ende-Identitätszertifikat aktualisieren' schließen", "acme.renewCertificate.button.primary": "Zertifikat aktualisieren", "acme.renewCertificate.button.secondary": "Später erinnern", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Ende-zu-Ende-Identitätszertifikat aktualisieren", "acme.renewCertificate.paragraph": "Das Ende-zu-Ende-Identitätszertifikat für dieses Gerät läuft bald ab. Um Ihre Kommunikation auf dem höchsten Sicherheitsniveau zu halten, aktualisieren Sie Ihr Zertifikat jetzt.

Geben Sie im nächsten Schritt die Anmeldedaten Ihres Identity-Providers ein, um das Zertifikat automatisch zu aktualisieren.

Erfahren Sie mehr über Ende-zu-Ende-Identität ", "acme.renewal.done.headline": "Zertifikat aktualisiert", "acme.renewal.done.paragraph": "Das Zertifikat wurde aktualisiert und Ihr Gerät überprüft. Weitere Details zum Zertifikat finden Sie in Ihren [bold]Wire Einstellungen[/bold] unter [bold]Geräte.[/bold]

Erfahren Sie mehr über Ende-zu-Ende-Identität ", "acme.renewal.inProgress.headline": "Zertifikat wird aktualisiert...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Fenster 'Ende-zu-Ende-Identitätszertifikat' schließen", "acme.settingsChanged.button.primary": "Zertifikat erhalten", "acme.settingsChanged.button.secondary": "Später erinnern", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "Ende-zu-Ende-Identitätszertifikat", "acme.settingsChanged.headline.main": "Team-Einstellungen geändert", - "acme.settingsChanged.paragraph": "Ihr Team verwendet von heute an Ende-zu-Ende-Identität, um die Nutzung von Wire sicherer und praktikabler zu machen. Die Geräteüberprüfung erfolgt automatisch mit einem Zertifikat und ersetzt den vorherigen manuellen Prozess. Auf diese Weise kommunizieren Sie mit dem höchsten Sicherheitsstandard.

Geben Sie im nächsten Schritt die Anmeldedaten Ihres Identity-Providers ein, um automatisch ein Zertifikat für dieses Gerät zu erhalten.

Erfahren Sie mehr über Ende-zu-Ende-Identität", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Hinzufügen", "addParticipantsHeader": "Teilnehmer hinzufügen", "addParticipantsHeaderWithCounter": "Teilnehmer hinzufügen ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Unterhaltungen", "conversationVoiceChannelDeactivate": " hat angerufen", "conversationVoiceChannelDeactivateYou": " haben angerufen", + "conversationWithBlockedUserMessage": "Der Link zu dieser Gruppenunterhaltung ist nicht mehr gültig oder führt zu einer Unterhaltung mit jemandem, den Sie blockiert haben.", + "conversationWithBlockedUserTitle": "Unterhaltung nicht erreichbar", "conversationYesterday": "Gestern", "conversationYouAccusative": "Sie", "conversationYouDative": "Ihnen", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Erstellen von Gäste-Links ist nun für alle Gruppen-Admins deaktiviert.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Erstellen von Gäste-Links ist nun für alle Gruppen-Admins aktiviert.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team-Einstellungen geändert", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "Es gab eine Änderung bei {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Das Teilen und Empfangen von Dateien jeder Art ist jetzt deaktiviert", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Das Teilen und Empfangen von Dateien jeder Art ist jetzt aktiviert", "featureConfigChangeModalFileSharingHeadline": "Es gab eine Änderung bei {{brandName}}", diff --git a/src/i18n/el-GR.json b/src/i18n/el-GR.json index 2fa36e0f5670..86dd762370c0 100644 --- a/src/i18n/el-GR.json +++ b/src/i18n/el-GR.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Προσθήκη", "addParticipantsHeader": "Προσθήκη ατόμων", "addParticipantsHeaderWithCounter": "Προσθήκη ατόμων ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " κάλεσε", "conversationVoiceChannelDeactivateYou": " κάλεσε", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Χθές", "conversationYouAccusative": "εσύ", "conversationYouDative": "εσύ", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/en-US.json b/src/i18n/en-US.json index a388094f3a7e..af74b25f463d 100644 --- a/src/i18n/en-US.json +++ b/src/i18n/en-US.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -503,8 +510,6 @@ "conversationNewConversation": "Communication in Wire is always end-to-end encrypted. Everything you send and receive in this conversation is only accessible to you and your contact.", "conversationNotClassified": "Security level: Unclassified", "conversationNotFoundMessage": "You may not have permission with this account or it no longer exists.", - "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", - "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationNotFoundTitle": "{{brandName}} can’t open this conversation.", "conversationParticipantsSearchPlaceholder": "Search by name", "conversationParticipantsTitle": "People", @@ -544,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -644,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/es-ES.json b/src/i18n/es-ES.json index 832570f80a86..656c12f991e7 100644 --- a/src/i18n/es-ES.json +++ b/src/i18n/es-ES.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Agregar", "addParticipantsHeader": "Agregar participantes", "addParticipantsHeaderWithCounter": "Añadir participantes ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " llamó", "conversationVoiceChannelDeactivateYou": " llamó", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Ayer", "conversationYouAccusative": "tú", "conversationYouDative": "tú", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/et-EE.json b/src/i18n/et-EE.json index a1c63eafc6b0..92970fc183fb 100644 --- a/src/i18n/et-EE.json +++ b/src/i18n/et-EE.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Lisa", "addParticipantsHeader": "Lisa osalejaid", "addParticipantsHeaderWithCounter": "Lisa osalejaid ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " helistas", "conversationVoiceChannelDeactivateYou": " helistasid", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Eile", "conversationYouAccusative": "sina", "conversationYouDative": "sina", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/fa-IR.json b/src/i18n/fa-IR.json index a2ee969d0908..3674056eadb9 100644 --- a/src/i18n/fa-IR.json +++ b/src/i18n/fa-IR.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "اضافه کردن", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " زنگ زد", "conversationVoiceChannelDeactivateYou": " زنگ زد", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "دیروز", "conversationYouAccusative": "شما", "conversationYouDative": "شما", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/fi-FI.json b/src/i18n/fi-FI.json index 1d6f66a90469..8cac7d7e9d30 100644 --- a/src/i18n/fi-FI.json +++ b/src/i18n/fi-FI.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Lisää", "addParticipantsHeader": "Lisää osallistujia", "addParticipantsHeaderWithCounter": "Lisää osallistujia ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " soitti", "conversationVoiceChannelDeactivateYou": " soitti", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Eilen", "conversationYouAccusative": "sinä", "conversationYouDative": "sinä", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/fr-FR.json b/src/i18n/fr-FR.json index 34e46875ff65..2fb0684f1a2e 100644 --- a/src/i18n/fr-FR.json +++ b/src/i18n/fr-FR.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Ajouter", "addParticipantsHeader": "Ajouter des participants", "addParticipantsHeaderWithCounter": "Ajouter des participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " a essayé d’appeler", "conversationVoiceChannelDeactivateYou": " avez essayé d’appeler", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Hier", "conversationYouAccusative": "vous", "conversationYouDative": "vous", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/ga-IE.json b/src/i18n/ga-IE.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/ga-IE.json +++ b/src/i18n/ga-IE.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/he-IL.json b/src/i18n/he-IL.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/he-IL.json +++ b/src/i18n/he-IL.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/hi-IN.json b/src/i18n/hi-IN.json index e0ee55b4e2c1..acb897e5cffd 100644 --- a/src/i18n/hi-IN.json +++ b/src/i18n/hi-IN.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "आप", "conversationYouDative": "आप", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/hr-HR.json b/src/i18n/hr-HR.json index 936033ddd4c8..4a5cc287160f 100644 --- a/src/i18n/hr-HR.json +++ b/src/i18n/hr-HR.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Dodaj", "addParticipantsHeader": "Dodaj sudionike", "addParticipantsHeaderWithCounter": "Dodaj ({{number}}) sudionika", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " zvao", "conversationVoiceChannelDeactivateYou": " zvao", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Jučer", "conversationYouAccusative": "ti", "conversationYouDative": "ti", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/hu-HU.json b/src/i18n/hu-HU.json index a12e32084c95..75168ae4eb84 100644 --- a/src/i18n/hu-HU.json +++ b/src/i18n/hu-HU.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Hozzáadás", "addParticipantsHeader": "Partnerek hozzáadása", "addParticipantsHeaderWithCounter": "Partnerek hozzáadása ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Beszélgetések", "conversationVoiceChannelDeactivate": " hívást kezdeményezett", "conversationVoiceChannelDeactivateYou": " hívást kezdeményezett", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Tegnap", "conversationYouAccusative": "te", "conversationYouDative": "te", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/id-ID.json b/src/i18n/id-ID.json index 6dcc1a05e5b5..7e96524f3b22 100644 --- a/src/i18n/id-ID.json +++ b/src/i18n/id-ID.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Tambahkan", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " dipanggil", "conversationVoiceChannelDeactivateYou": " dipanggil", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Kemarin", "conversationYouAccusative": "Anda", "conversationYouDative": "Anda", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/is-IS.json b/src/i18n/is-IS.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/is-IS.json +++ b/src/i18n/is-IS.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/it-IT.json b/src/i18n/it-IT.json index 3796e3b3499e..2373e3bd3ec5 100644 --- a/src/i18n/it-IT.json +++ b/src/i18n/it-IT.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Aggiungi", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " ha chiamato", "conversationVoiceChannelDeactivateYou": " ha chiamato", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Ieri", "conversationYouAccusative": "tu", "conversationYouDative": "tu", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/ja-JP.json b/src/i18n/ja-JP.json index 98aed618b0fd..42e9679767d8 100644 --- a/src/i18n/ja-JP.json +++ b/src/i18n/ja-JP.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "追加する", "addParticipantsHeader": "人を追加します", "addParticipantsHeaderWithCounter": "({{number}}) を追加します。", @@ -542,6 +549,8 @@ "conversationViewTooltip": "会話", "conversationVoiceChannelDeactivate": " 呼び出し", "conversationVoiceChannelDeactivateYou": " 呼び出し", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "昨日", "conversationYouAccusative": "あなた", "conversationYouDative": "あなた", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/lt-LT.json b/src/i18n/lt-LT.json index 39fb5f1725b9..6267a48a3861 100644 --- a/src/i18n/lt-LT.json +++ b/src/i18n/lt-LT.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Pridėti", "addParticipantsHeader": "Pridėti žmonių", "addParticipantsHeaderWithCounter": "Pridėti žmonių ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Pokalbiai", "conversationVoiceChannelDeactivate": " skambino", "conversationVoiceChannelDeactivateYou": " skambino", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Vakar", "conversationYouAccusative": "jūs", "conversationYouDative": "jūs", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/lv-LV.json b/src/i18n/lv-LV.json index 417bbc747c3e..4dd24a79b708 100644 --- a/src/i18n/lv-LV.json +++ b/src/i18n/lv-LV.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Pievienot", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " zvanīja", "conversationVoiceChannelDeactivateYou": " zvanīja", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Vakar", "conversationYouAccusative": "tu", "conversationYouDative": "tu", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/ms-MY.json b/src/i18n/ms-MY.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/ms-MY.json +++ b/src/i18n/ms-MY.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/nl-NL.json b/src/i18n/nl-NL.json index 34f5fa444ffb..a357dc3dd92d 100644 --- a/src/i18n/nl-NL.json +++ b/src/i18n/nl-NL.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Toevoegen", "addParticipantsHeader": "Personen toevoegen", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " belde", "conversationVoiceChannelDeactivateYou": " belde", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Gisteren", "conversationYouAccusative": "jij", "conversationYouDative": "jij", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/no-NO.json b/src/i18n/no-NO.json index a5e9e2c157a8..505dd123c8db 100644 --- a/src/i18n/no-NO.json +++ b/src/i18n/no-NO.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Legg til", "addParticipantsHeader": "Legg til deltakere", "addParticipantsHeaderWithCounter": "Legg til deltakere ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " ringte", "conversationVoiceChannelDeactivateYou": " ringte", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "I går", "conversationYouAccusative": "du", "conversationYouDative": "du", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/pl-PL.json b/src/i18n/pl-PL.json index 64dd8724d310..d49e348a9127 100644 --- a/src/i18n/pl-PL.json +++ b/src/i18n/pl-PL.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Dodaj", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " połączono", "conversationVoiceChannelDeactivateYou": " połączono", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Wczoraj", "conversationYouAccusative": "ty", "conversationYouDative": "ty", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/pt-BR.json b/src/i18n/pt-BR.json index bd3b44d7ff5e..b08ca5670cde 100644 --- a/src/i18n/pt-BR.json +++ b/src/i18n/pt-BR.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Adicionar", "addParticipantsHeader": "Adicionar participantes", "addParticipantsHeaderWithCounter": "Adicionar participantes ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversas", "conversationVoiceChannelDeactivate": " chamou", "conversationVoiceChannelDeactivateYou": " chamou", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Ontem", "conversationYouAccusative": "você", "conversationYouDative": "você", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "A geração de links de convidados agora está desabilitada para todos os administradores do grupo.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "A geração de links de convidados agora está habilitada para todos os administradores do grupo.", "featureConfigChangeModalConversationGuestLinksHeadline": "As configurações da equipe foram alteradas", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Compartilhar e receber arquivos de qualquer tipo agora está desativado", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Compartilhar e receber arquivos de qualquer tipo agora está ativado", "featureConfigChangeModalFileSharingHeadline": "Houve uma mudança em {{brandName}}", diff --git a/src/i18n/pt-PT.json b/src/i18n/pt-PT.json index 05bcd4c8e9a2..3c66325601df 100644 --- a/src/i18n/pt-PT.json +++ b/src/i18n/pt-PT.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Adicionar", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " ligou", "conversationVoiceChannelDeactivateYou": " ligou", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Ontem", "conversationYouAccusative": "você", "conversationYouDative": "você", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/ro-RO.json b/src/i18n/ro-RO.json index 4c9e3cf18493..d1df6a2e780e 100644 --- a/src/i18n/ro-RO.json +++ b/src/i18n/ro-RO.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Adaugă", "addParticipantsHeader": "Adaugă persoane", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " sunat", "conversationVoiceChannelDeactivateYou": " sunat", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "ieri", "conversationYouAccusative": "tu", "conversationYouDative": "tu", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/ru-RU.json b/src/i18n/ru-RU.json index ff57960b2229..c72976f759a0 100644 --- a/src/i18n/ru-RU.json +++ b/src/i18n/ru-RU.json @@ -66,7 +66,7 @@ "E2EI.notAvailable": "Недоступно", "E2EI.not_activated": "Не активирован", "E2EI.not_downloaded": "Не скачан", - "E2EI.revoked": "Revoked", + "E2EI.revoked": "Отозван", "E2EI.serialNumber": "Серийный номер: ", "E2EI.showCertificateDetails": "Показать сведения о сертификате", "E2EI.status": "Статус:", @@ -161,31 +161,38 @@ "accountForm.termsAndPrivacyPolicy": "Я принимаю политику конфиденциальности и условия и положения", "acme.done.button": "OK", "acme.done.button.close": "Закрыть окно 'Сертификат загружен'", - "acme.done.button.secondary": "Certificate details", - "acme.done.headline": "Certificate issued", - "acme.done.paragraph": "The certificate is active now and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", + "acme.done.button.secondary": "Сведения о сертификате", + "acme.done.headline": "Сертификат выпущен", + "acme.done.paragraph": "Теперь сертификат активен и ваше устройство верифицировано. Более подробную информацию об этом сертификате можно найти в настройках вашего [bold]Wire[/bold] под [bold]Устройствами.[/bold]

Узнайте больше о сквозной идентификации ", "acme.error.button.close": "Закрыть окно 'Что-то пошло не так'", "acme.error.button.primary": "Повторить", "acme.error.button.secondary": "Отмена", + "acme.error.gracePeriod.paragraph": "Сертификат выпустить не удалось. [br] Пожалуйста, попробуйте еще раз или обратитесь к администратору вашей команды.", "acme.error.headline": "Что-то пошло не так", "acme.error.paragraph": "Сертификат выпустить не удалось. [br] Вы можете повторить попытку получения сертификата сейчас или получить напоминание позже.", "acme.inProgress.button.close": "Закрыть окно 'Получение сертификата'", - "acme.inProgress.headline": "Getting Certificate...", + "acme.inProgress.headline": "Получение сертификата...", "acme.inProgress.paragraph.alt": "Загрузка...", "acme.inProgress.paragraph.main": "Пожалуйста, перейдите в браузер и войдите в сервис сертификации. [br] Если сайт не открывается, вы также можете перейти на него вручную по следующей ссылке: [br] [link] {{url}} [/link]", - "acme.remindLater.button.primary": "Ok", - "acme.remindLater.paragraph": "You can get the certificate in your [bold]Wire settings[/bold] during the next {{delayTime}}. Open [bold]Devices[/bold] and select [bold]Get Certificate[/bold] for your current device.

To continue using Wire without interruption, retrieve it in time – it doesn’t take long.

Learn more about end-to-end identity ", + "acme.remindLater.button.primary": "OK", + "acme.remindLater.paragraph": "Вы можете получить сертификат в настройках вашего [bold]Wire[/bold] в течение {{delayTime}}. Откройте [bold]Устройства[/bold] и выберите [bold]Получить сертификат[/bold] для вашего текущего устройства.

Чтобы продолжать пользоваться Wire без перерыва, своевременно получите его - это не займет много времени.

Узнайте больше о сквозной идентификации ", "acme.renewCertificate.button.close": "Закрыть окно 'Обновление сертификата сквозной идентификации'", "acme.renewCertificate.button.primary": "Обновить сертификат", "acme.renewCertificate.button.secondary": "Напомнить позже", + "acme.renewCertificate.gracePeriodOver.paragraph": "Срок действия сертификата сквозной идентификации для этого устройства истек. Чтобы обеспечить максимальный уровень безопасности связи Wire, обновите сертификат.

На следующем шаге введите учетные данные поставщика идентификационных данных, чтобы автоматически обновить сертификат.

Подробнее о сквозной идентификации ", "acme.renewCertificate.headline.alt": "Обновление сертификата сквозной идентификации", - "acme.renewCertificate.paragraph": "Срок действия сертификата сквозной идентификации для этого устройства истекает в ближайшее время. Чтобы поддерживать связь на самом высоком уровне безопасности, обновите сертификат прямо сейчас.

На следующем шаге введите учетные данные поставщика идентификационных данных, чтобы автоматически обновить сертификат.

Узнать больше о сквозной идентификации ", - "acme.renewal.done.headline": "Certificate updated", - "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", - "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.renewCertificate.paragraph": "Срок действия сертификата сквозной идентификации для этого устройства истекает в ближайшее время. Чтобы обеспечить максимальный уровень безопасности ваших коммуникаций, обновите сертификат прямо сейчас.

На следующем шаге введите учетные данные поставщика идентификационных данных, чтобы автоматически обновить сертификат.

Подробнее о сквозной идентификации ", + "acme.renewal.done.headline": "Сертификат обновлен", + "acme.renewal.done.paragraph": "Теперь сертификат обновлен и ваше устройство верифицировано. Более подробную информацию об этом сертификате можно найти в настройках вашего [bold]Wire[/bold] под [bold]Устройствами.[/bold]

Узнайте больше о сквозной идентификации ", + "acme.renewal.inProgress.headline": "Обновление сертификата...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Закрыть окно 'Сертификат сквозной идентификации'", "acme.settingsChanged.button.primary": "Получить сертификат", "acme.settingsChanged.button.secondary": "Напомнить позже", + "acme.settingsChanged.gracePeriodOver.paragraph": "Теперь ваша команда использует сквозную идентификацию, чтобы обеспечить максимальную безопасность использования Wire. Проверка устройства происходит автоматически с помощью сертификата.

Введите учетные данные поставщика идентификационных данных на следующем шаге, чтобы автоматически получить сертификат верификации для этого устройства.

Подробнее о сквозной идентификации", "acme.settingsChanged.headline.alt": "Сертификат сквозной идентификации", "acme.settingsChanged.headline.main": "Настройки команды изменены", "acme.settingsChanged.paragraph": "Уже сегодня ваша команда использует сквозную идентификацию, чтобы сделать использование Wire более безопасным и практичным. Верификация устройства происходит автоматически с помощью сертификата и заменяет прежний ручной процесс. Благодаря этому коммуникация осуществляется по самым высоким стандартам безопасности.

Введите учетные данные провайдера идентификации на следующем шаге, чтобы автоматически получить сертификат верификации для этого устройства.

Подробнее о сквозной идентификации", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Беседы", "conversationVoiceChannelDeactivate": " звонил(-а)", "conversationVoiceChannelDeactivateYou": " звонили", + "conversationWithBlockedUserMessage": "Ссылка на эту групповую беседу больше не действует или ведет на беседу с кем-то, кого вы заблокировали.", + "conversationWithBlockedUserTitle": "Беседа недоступна", "conversationYesterday": "Вчера", "conversationYouAccusative": "вы", "conversationYouDative": "вы", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Генерация гостевых ссылок теперь отключена для всех администраторов групп.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Генерация гостевых ссылок теперь включена для всех администраторов групп.", "featureConfigChangeModalConversationGuestLinksHeadline": "Настройки команды изменены", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Путь загрузки отключен. Если вы сохраните путь загрузки вам придется перезапустить приложение.", + "featureConfigChangeModalDownloadPathEnabled": "Путь загрузки включен. Приложение будет перезапущено, чтобы новые настройки вступили в силу.", + "featureConfigChangeModalDownloadPathHeadline": "В {{brandName}} произошли изменения", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Обмен и получение файлов любого типа теперь отключены", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Обмен и получение файлов любого типа теперь включены", "featureConfigChangeModalFileSharingHeadline": "В {{brandName}} произошли изменения", diff --git a/src/i18n/si-LK.json b/src/i18n/si-LK.json index 83ab70b23ccd..c4cc31e6bbd6 100644 --- a/src/i18n/si-LK.json +++ b/src/i18n/si-LK.json @@ -66,7 +66,7 @@ "E2EI.notAvailable": "නොතිබේ", "E2EI.not_activated": "සක්‍රිය කර නැත", "E2EI.not_downloaded": "බාගත වී ඇත", - "E2EI.revoked": "Revoked", + "E2EI.revoked": "අහෝසි කෙරිණි", "E2EI.serialNumber": "අනුක්‍රමික අංකය: ", "E2EI.showCertificateDetails": "සහතිකයේ විස්තර පෙන්වන්න", "E2EI.status": "තත්‍වය:", @@ -161,31 +161,38 @@ "accountForm.termsAndPrivacyPolicy": "මම රහස්‍යතා ප්‍රතිපත්තිය, නියම සහ කොන්දේසි පිළිගනිමි", "acme.done.button": "හරි", "acme.done.button.close": "'සහතිකය බාගැනිණි' කවුළුව වසන්න", - "acme.done.button.secondary": "Certificate details", - "acme.done.headline": "Certificate issued", - "acme.done.paragraph": "The certificate is active now and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", + "acme.done.button.secondary": "සහතිකයේ විස්තර", + "acme.done.headline": "සහතිකය නිකුත් කෙරිණි", + "acme.done.paragraph": "සහතිකය දැන් සක්‍රිය අතර ඔබගේ උපාංගය සත්‍යාපිතයි. ඔබගේ [bold]වයර් අභිප්‍රේත[/bold] යටතේ [bold]උපාංගවල[/bold] මෙම සහතිකය පිළිබඳ වැඩි විස්තර හමු වනු ඇත.

අන්ත අනන්‍යතාවය ගැන තව දැනගන්න ", "acme.error.button.close": "'යමක් වැරදී ඇත' කවුළුව වසන්න", "acme.error.button.primary": "නැවත", "acme.error.button.secondary": "අවලංගු", + "acme.error.gracePeriod.paragraph": "සහතිකය නිකුත් කිරීමට නොහැකි විය. [br] කරුණාකර නැවත උත්සාහ කරන්න හෝ ඔබගේ කණ්ඩායමේ පරිපාලකයා අමතන්න.", "acme.error.headline": "යමක් වැරදී ඇත", - "acme.error.paragraph": "සහතිකය නිකුත් කිරීමට නොහැකි විය. [br] ඔබට සහතිකය ගැනීමට දැන් නැවත තැත් කිරීමට හැකිය හෝ පසුව සිහිකැඳවීමක් ලැබෙනු ඇත.", + "acme.error.paragraph": "සහතිකය නිකුත් කිරීමට නොහැකි විය. [br] ඔබට සහතිකය ගැනීමට නැවත උත්සාහ කිරීමට හැකිය හෝ පසුව සිහිකැඳවීමක් ලැබෙනු ඇත.", "acme.inProgress.button.close": "'සහතිකය ගැනෙමින්' කවුළුව වසන්න", - "acme.inProgress.headline": "Getting Certificate...", + "acme.inProgress.headline": "සහතිකය ගැනෙමින්...", "acme.inProgress.paragraph.alt": "බාගැනෙමින්…", "acme.inProgress.paragraph.main": "කරුණාකර ඔබගේ අතිරික්සුවට ගොස් සහතික සේවාවට පිවිසෙන්න. [br] අඩවිය විවෘත නොවේ නම්, ඔබට මෙම ඒ.ස.නි. අනුගමනය කිරීමට හැකිය: [br] [/link]", - "acme.remindLater.button.primary": "Ok", - "acme.remindLater.paragraph": "You can get the certificate in your [bold]Wire settings[/bold] during the next {{delayTime}}. Open [bold]Devices[/bold] and select [bold]Get Certificate[/bold] for your current device.

To continue using Wire without interruption, retrieve it in time – it doesn’t take long.

Learn more about end-to-end identity ", + "acme.remindLater.button.primary": "හරි", + "acme.remindLater.paragraph": "ඊළඟ {{delayTime}} අතරතුර ඔබගේ [bold]වයර් සැකසුම්[/bold] තුළ සහතිකය ලබා ගැනීමට හැකිය. [bold]උපාංග[/bold] විවෘත කර ඔබගේ වත්මන් උපාංගය සඳහා [bold]සහතිකයක් ගන්න[/bold] තෝරන්න.

බාධාවකින් තොරව දිගටම වයර් භාවිතා කිරීමට එය නියමිත වේලාවට ලබා ගන්න – එතරම් කාලයක් ගත නොවේ.

අන්ත අනන්‍යතාවය ගැන තව දැනගන්න ", "acme.renewCertificate.button.close": "'අන්ත අනන්‍යතා සහතිකය යාවත්කාල' කවුළුව වසන්න", "acme.renewCertificate.button.primary": "සහතිකය යාවත්කාලය", "acme.renewCertificate.button.secondary": "පසුව මතක් කරන්න", + "acme.renewCertificate.gracePeriodOver.paragraph": "මෙම උපාංගයේ අන්ත අනන්‍යතා සහතිකය කල් ඉකුත් වී ඇත. ඔබගේ වයර් සන්නිවේදනය ඉහළම ආරක්‍ෂණ මට්ටමින් පවත්වා ගැනීමට කරුණාකර සහතිකය යාවත්කාල කරන්න.

සහතිකය ස්වයංක්‍රීයව යාවත්කාල කිරීමට ඊළඟ පියවරේ දී ඔබගේ අනන්‍යතා ප්‍රතිපාදකයාගේ අක්තපත්‍ර ඇතුල් කරන්න.

අන්ත අනන්‍යතාවය පිළිබඳව තව දැනගන්න", "acme.renewCertificate.headline.alt": "අන්ත අනන්‍යතා සහතිකය යාවත්කාලය", "acme.renewCertificate.paragraph": "මෙම උපාංගයේ අන්ත අනන්‍යතා සහතිකය ළඟදීම කල් ඉකුත් වනු ඇත. ආරක්‍ෂිතව සන්නිවේදනයට, දැන්ම ඔබගේ සහතිකය යාවත්කාල කරන්න.

සහතිකය ස්වයංක්‍රීයව යාවත්කාල කිරීමට ඊළඟ පියවරේ දී ඔබගේ අනන්‍යතා ප්‍රතිපාදකයාගේ අක්තපත්‍ර ඇතුල් කරන්න.

අන්ත අනන්‍යතාවය පිළිබඳව තව දැනගන්න", - "acme.renewal.done.headline": "Certificate updated", - "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", - "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.renewal.done.headline": "සහතිකය යාවත්කාල විය", + "acme.renewal.done.paragraph": "සහතිකය යාවත්කාලීන අතර ඔබගේ උපාංගය සත්‍යාපිතයි. ඔබගේ [bold]වයර් අභිප්‍රේත[/bold] යටතේ [bold]උපාංගවල[/bold] මෙම සහතිකය පිළිබඳ වැඩි විස්තර හමු වනු ඇත.

අන්ත අනන්‍යතාවය ගැන තව දැනගන්න", + "acme.renewal.inProgress.headline": "සහතිකය යාවත්කාල වෙමින්...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "'අන්ත අනන්‍යතා සහතිකය' කවුළුව වසන්න", "acme.settingsChanged.button.primary": "සහතිකය ගන්න", "acme.settingsChanged.button.secondary": "පසුව මතක් කරන්න", + "acme.settingsChanged.gracePeriodOver.paragraph": "ඔබගේ කණ්ඩායමට අන්ත අනන්‍යතාවය යොදා ගෙන දැන් වයර් භාවිතය වඩාත් සුරක්‍ෂිත කර ඇත. සහතිකයක් භාවිතයෙන් උපාංග සත්‍යාපනය ස්වයංක්‍රීයව සිදු වේ.

මෙම උපාංගයට ස්වයංක්‍රීයව සත්‍යාපන සහතිකයක් ලබා ගැනීමට ඊළඟ පියවරේ දී ඔබගේ අනන්‍යතා ප්‍රතිපාදකයාගේ අක්තපත්‍ර ඇතුල් කරන්න.

අන්ත අනන්‍යතාවය පිළිබඳව තව දැනගන්න", "acme.settingsChanged.headline.alt": "අන්ත අනන්‍යතා සහතිකය", "acme.settingsChanged.headline.main": "කණ්ඩායමේ සැකසුම් සංශෝධිතයි", "acme.settingsChanged.paragraph": "ඔබගේ කණ්ඩායමට අන්ත අනන්‍යතාවය යොදා ගෙන අද වන විට වයර් භාවිතය වඩාත් සුරක්‍ෂිත සහ ප්‍රායෝගික කර ඇත. කලින් අතින් කළ යුතු ක්‍රියාවලිය වෙනුවට උපාංග සත්‍යාපන සහතිකයක් භාවිතයෙන් ස්වයංක්‍රීයව සිදු වේ. මෙමගින්, ඔබ දැනට තිබෙන උසස්ම ආරක්‍ෂණ ප්‍රමිතිය යටතේ සන්නිවේදනය කරයි.

මෙම උපාංගයට ස්වයංක්‍රීයව සත්‍යාපන සහතිකයක් ලබා ගැනීමට ඊළඟ පියවරේ දී ඔබගේ අනන්‍යතා ප්‍රතිපාදකයාගේ අක්තපත්‍ර ඇතුල් කරන්න.

අන්ත අනන්‍යතාවය පිළිබඳව තව දැනගන්න", @@ -542,6 +549,8 @@ "conversationViewTooltip": "සංවාද", "conversationVoiceChannelDeactivate": " අමතා ඇත", "conversationVoiceChannelDeactivateYou": " අමතා ඇත", + "conversationWithBlockedUserMessage": "මෙම සමූහ සංවාදයේ සබැඳිය තවදුරටත් වලංගු නොවේ හෝ ඔබ අවහිර කළ පුද්ගලයෙක් සමඟ සංවාදයකට යොමු වේ.", + "conversationWithBlockedUserTitle": "සංවාදයට ළඟා වීමට නොහැකිය", "conversationYesterday": "ඊයේ", "conversationYouAccusative": "ඔබ", "conversationYouDative": "ඔබ", @@ -642,13 +651,17 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "සමූහයේ සියළුම පරිපාලකයින් සඳහා ආගන්තුක සබැඳි උත්පාදනය අබල කර ඇත.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "සමූහයේ සියළුම පරිපාලකයින් සඳහා ආගන්තුක සබැඳි උත්පාදනය සබල කර ඇත.", "featureConfigChangeModalConversationGuestLinksHeadline": "කණ්ඩායමේ සැකසුම් සංශෝධිතයි", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "බලාත්මක බාගැනීම් මාර්ගය අබල කර ඇත. ඔබට බාගැනීම් නව ස්ථානයක සුරැකීමට වුවමනා නම් යෙදුම නැවත ආරම්භ කළ යුතුය.", + "featureConfigChangeModalDownloadPathEnabled": "බලාත්මක බාගැනීම් මාර්ගය සබල කර ඇත. නව සැකසුම් යෙදීමට යෙදුම නැවත ආරම්භ වනු ඇත.", + "featureConfigChangeModalDownloadPathHeadline": "{{brandName}} හි වෙනසක් සිදු වී ඇත", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "ඕනෑම වර්ගයක ගොනු බෙදාගැනීම සහ ලැබීම අබල කර ඇත", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "ඕනෑම වර්ගයක ගොනු බෙදාගැනීම සහ ලැබීම සබල කර ඇත", - "featureConfigChangeModalFileSharingHeadline": "{{brandName}} හි වෙනසක් සිදුවී ඇත", + "featureConfigChangeModalFileSharingHeadline": "{{brandName}} හි වෙනසක් සිදු වී ඇත", "featureConfigChangeModalSelfDeletingMessagesDescriptionItemDisabled": "පණිවිඩ ඉබේ මැකීම අබලයි", "featureConfigChangeModalSelfDeletingMessagesDescriptionItemEnabled": "ඉබේ මැකෙන පණිවිඩ සබලයි. පණිවිඩයක් ලිවීමට පෙර කාලය සැකසීමට හැකිය.", "featureConfigChangeModalSelfDeletingMessagesDescriptionItemEnforced": "ඉබේ මැකෙන පණිවිඩ දැන් අනිවාර්යයි. නව පණිවිඩ {{timeout}} කට පසු ඉබේ මැකෙනු ඇත.", - "featureConfigChangeModalSelfDeletingMessagesHeadline": "{{brandName}} හි වෙනසක් සිදුවී ඇත", + "featureConfigChangeModalSelfDeletingMessagesHeadline": "{{brandName}} හි වෙනසක් සිදු වී ඇත", "federationConnectionRemove": "[bold]{{backendUrlOne}}[/bold] සහ [bold]{{backendUrlTwo}}[/bold] සේවාදායක තවදුරටත් එකාබද්ධ නොවේ.", "federationDelete": "[bold]{{backendUrl}}[/bold] සමඟ තවදුරටත් [bold]ඔබගේ සේවාදායකය[/bold] ඒකාබද්ධ නොවේ.", "fileTypeRestrictedIncoming": " [bold]{{name}}[/bold]  වෙතින් ගොනුව ඇරීමට නොහැකිය", diff --git a/src/i18n/sk-SK.json b/src/i18n/sk-SK.json index 4ab5db85b379..a89c6f42a952 100644 --- a/src/i18n/sk-SK.json +++ b/src/i18n/sk-SK.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Pridať", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " volaný", "conversationVoiceChannelDeactivateYou": " volaný", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Včera", "conversationYouAccusative": "Vy", "conversationYouDative": "Vy", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/sl-SI.json b/src/i18n/sl-SI.json index 4fea9809b362..d0662ac29a1d 100644 --- a/src/i18n/sl-SI.json +++ b/src/i18n/sl-SI.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Dodaj", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " je klical(-a)", "conversationVoiceChannelDeactivateYou": " je klical(-a)", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Včeraj", "conversationYouAccusative": "ti", "conversationYouDative": "ti", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/sr-SP.json b/src/i18n/sr-SP.json index 14f017a7609a..cc2e4d878887 100644 --- a/src/i18n/sr-SP.json +++ b/src/i18n/sr-SP.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Додај", "addParticipantsHeader": "Додајте учеснике", "addParticipantsHeaderWithCounter": "Додајте учеснике ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Разговори", "conversationVoiceChannelDeactivate": " позва", "conversationVoiceChannelDeactivateYou": " позва", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "јуче", "conversationYouAccusative": "ја", "conversationYouDative": "ја", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/sv-SE.json b/src/i18n/sv-SE.json index 4cce4496cbb8..d01404dd14c5 100644 --- a/src/i18n/sv-SE.json +++ b/src/i18n/sv-SE.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Lägg till", "addParticipantsHeader": "Lägg till människor", "addParticipantsHeaderWithCounter": "Lägg till ({{number}}) människor", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " ringde", "conversationVoiceChannelDeactivateYou": " ringde", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Igår", "conversationYouAccusative": "du", "conversationYouDative": "du", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/th-TH.json b/src/i18n/th-TH.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/th-TH.json +++ b/src/i18n/th-TH.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/tr-TR.json b/src/i18n/tr-TR.json index df5488089798..4eea2ff40823 100644 --- a/src/i18n/tr-TR.json +++ b/src/i18n/tr-TR.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Ekle", "addParticipantsHeader": "Katılımcıları ekle", "addParticipantsHeaderWithCounter": "({{number}}) Katılımcı ekle", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " aradı", "conversationVoiceChannelDeactivateYou": " aradı", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Dün", "conversationYouAccusative": "sen", "conversationYouDative": "sen", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/uk-UA.json b/src/i18n/uk-UA.json index 5fdc26ac0ed2..61373cce656f 100644 --- a/src/i18n/uk-UA.json +++ b/src/i18n/uk-UA.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Додати", "addParticipantsHeader": "Додати учасників", "addParticipantsHeaderWithCounter": "Додати учасників ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Розмови", "conversationVoiceChannelDeactivate": " дзвонив(-ла)", "conversationVoiceChannelDeactivateYou": " дзвонив(-ла)", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Вчора", "conversationYouAccusative": "ви", "conversationYouDative": "ви", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/uz-UZ.json b/src/i18n/uz-UZ.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/uz-UZ.json +++ b/src/i18n/uz-UZ.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/vi-VN.json b/src/i18n/vi-VN.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/vi-VN.json +++ b/src/i18n/vi-VN.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/zh-CN.json b/src/i18n/zh-CN.json index 7abf6a23271f..2173b4dc60c9 100644 --- a/src/i18n/zh-CN.json +++ b/src/i18n/zh-CN.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "新增", "addParticipantsHeader": "新增好友", "addParticipantsHeaderWithCounter": "添加人员({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "对话", "conversationVoiceChannelDeactivate": " 已呼叫", "conversationVoiceChannelDeactivateYou": " 已呼叫", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "昨天", "conversationYouAccusative": "你", "conversationYouDative": "你", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/zh-HK.json b/src/i18n/zh-HK.json index af5104d4f689..af74b25f463d 100644 --- a/src/i18n/zh-HK.json +++ b/src/i18n/zh-HK.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "Add", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " called", "conversationVoiceChannelDeactivateYou": " called", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "Yesterday", "conversationYouAccusative": "you", "conversationYouDative": "you", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/i18n/zh-TW.json b/src/i18n/zh-TW.json index 8c9a6961bbe0..56c65c52871e 100644 --- a/src/i18n/zh-TW.json +++ b/src/i18n/zh-TW.json @@ -167,8 +167,9 @@ "acme.error.button.close": "Close window 'Something went wrong'", "acme.error.button.primary": "Retry", "acme.error.button.secondary": "Cancel", + "acme.error.gracePeriod.paragraph": "The certificate couldn't be issued. [br] Please try again, or reach out to your team admin.", "acme.error.headline": "Something went wrong", - "acme.error.paragraph": "The certificate couldn’t be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", + "acme.error.paragraph": "The certificate couldn't be issued. [br] You can retry to get the certificate now, or you will get a reminder later.", "acme.inProgress.button.close": "Close window 'Getting Certificate'", "acme.inProgress.headline": "Getting Certificate...", "acme.inProgress.paragraph.alt": "Downloading...", @@ -178,17 +179,23 @@ "acme.renewCertificate.button.close": "Close window 'Update End-to-end identify certificate'", "acme.renewCertificate.button.primary": "Update Certificate", "acme.renewCertificate.button.secondary": "Remind Me Later", + "acme.renewCertificate.gracePeriodOver.paragraph": "The end-to-end identity certificate for this device has expired. To keep your Wire communication at the highest security level, please update the certificate.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewCertificate.headline.alt": "Update end-to-end identity certificate", "acme.renewCertificate.paragraph": "The end-to-end identity certificate for this device expires soon. To keep your communication at the highest security level, update your certificate now.

Enter your identity provider’s credentials in the next step to update the certificate automatically.

Learn more about end-to-end identity ", "acme.renewal.done.headline": "Certificate updated", "acme.renewal.done.paragraph": "The certificate is updated and your device is verified. You can find more details about this certificate in your [bold]Wire Preferences[/bold] under [bold]Devices.[/bold]

Learn more about end-to-end identity ", "acme.renewal.inProgress.headline": "Updating Certificate...", + "acme.selfCertificateRevoked.button.cancel": "Continue using this device", + "acme.selfCertificateRevoked.button.primary": "Log out", + "acme.selfCertificateRevoked.text": "Your team admin revoked the certificate for this device.
Log out to reduce security risks. Then log in again, get a new certificate, and reset your password.

If you keep using this device, your conversations are no longer verified.", + "acme.selfCertificateRevoked.title": "End-to-end identity certificate revoked", "acme.settingsChanged.button.close": "Close window 'End-to-end identity certificate'", "acme.settingsChanged.button.primary": "Get Certificate", "acme.settingsChanged.button.secondary": "Remind Me Later", + "acme.settingsChanged.gracePeriodOver.paragraph": "Your team now uses end-to-end identity to make Wire's usage more secure. The device verification takes place automatically using a certificate.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "acme.settingsChanged.headline.alt": "End-to-end identity certificate", "acme.settingsChanged.headline.main": "Team settings changed", - "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider’s credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", + "acme.settingsChanged.paragraph": "As of today, your team uses end-to-end identity to make Wire's usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.

Enter your identity provider's credentials in the next step to automatically get a verification certificate for this device.

Learn more about end-to-end identity", "addParticipantsConfirmLabel": "加入", "addParticipantsHeader": "Add participants", "addParticipantsHeaderWithCounter": "Add participants ({{number}})", @@ -542,6 +549,8 @@ "conversationViewTooltip": "Conversations", "conversationVoiceChannelDeactivate": " 有來電", "conversationVoiceChannelDeactivateYou": " 有來電", + "conversationWithBlockedUserMessage": "The link to this group conversation is no longer valid or leads to a conversation with someone you blocked.", + "conversationWithBlockedUserTitle": "Conversation not reachable", "conversationYesterday": "昨天", "conversationYouAccusative": "您", "conversationYouDative": "您", @@ -642,6 +651,10 @@ "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksDisabled": "Generating guest links is now disabled for all group admins.", "featureConfigChangeModalConversationGuestLinksDescriptionItemConversationGuestLinksEnabled": "Generating guest links is now enabled for all group admins.", "featureConfigChangeModalConversationGuestLinksHeadline": "Team settings changed", + "featureConfigChangeModalDownloadPathChanged": "Enforced Download Path location is changed. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathDisabled": "Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.", + "featureConfigChangeModalDownloadPathEnabled": "Enforced Download Path is enabled. The App will restart for the new settings to take effect.", + "featureConfigChangeModalDownloadPathHeadline": "There has been a change in {{brandName}}", "featureConfigChangeModalFileSharingDescriptionItemFileSharingDisabled": "Sharing and receiving files of any type is now disabled", "featureConfigChangeModalFileSharingDescriptionItemFileSharingEnabled": "Sharing and receiving files of any type is now enabled", "featureConfigChangeModalFileSharingHeadline": "There has been a change in {{brandName}}", diff --git a/src/script/E2EIdentity/E2EIdentityEnrollment.test.ts b/src/script/E2EIdentity/E2EIdentityEnrollment.test.ts index a3ef57eabb94..00ad95b2f20a 100644 --- a/src/script/E2EIdentity/E2EIdentityEnrollment.test.ts +++ b/src/script/E2EIdentity/E2EIdentityEnrollment.test.ts @@ -85,7 +85,7 @@ function wait(ms: number) { describe('E2EIHandler', () => { const params = {discoveryUrl: 'http://example.com', gracePeriodInSeconds: 30}; - const user = {name: () => 'John Doe', username: () => 'johndoe'}; + const user = {name: () => 'John Doe', username: () => 'johndoe', teamId: 'team'}; beforeEach(() => { jest.spyOn(util, 'supportsMLS').mockReturnValue(true); @@ -100,40 +100,35 @@ describe('E2EIHandler', () => { jest.spyOn(PrimaryModal, 'show'); - jest - .spyOn(container.resolve(UserState), 'self') - .mockReturnValue({name: () => 'John Doe', username: () => 'johndoe'}); - jest.spyOn(container.resolve(Core), 'enrollE2EI').mockResolvedValue(true); + jest.spyOn(container.resolve(UserState), 'self').mockReturnValue(user); + jest.spyOn(container.resolve(Core), 'enrollE2EI').mockResolvedValue({status: 'successful'}); container.resolve(Core).key = new Uint8Array(); }); it('should create instance with valid params', async () => { - const instance = E2EIHandler.getInstance().initialize(params); + const instance = await E2EIHandler.getInstance().initialize(params); expect(instance).toBeInstanceOf(E2EIHandler); }); it('should always return the same instance', async () => { - const instance1 = E2EIHandler.getInstance().initialize(params); - const instance2 = E2EIHandler.getInstance().initialize(params); + const instance1 = await E2EIHandler.getInstance().initialize(params); + const instance2 = await E2EIHandler.getInstance().initialize(params); expect(instance1).toBe(instance2); }); it('should set currentStep to INITIALIZE after initialize is called', async () => { const instance = E2EIHandler.getInstance(); - instance.initialize(params); + await instance.initialize(params); void instance.attemptEnrollment(); await wait(1); + expect(container.resolve(Core).service?.e2eIdentity?.registerServerCertificates).toHaveBeenCalled(); expect(instance['currentStep']).toBe(E2EIHandlerStep.INITIALIZED); }); it('should set currentStep to SUCCESS when enrollE2EI is called and enrollment succeeds', async () => { - jest - .spyOn(container.resolve(UserState), 'self') - .mockReturnValue({name: () => 'John Doe', username: () => 'johndoe'}); + jest.spyOn(container.resolve(Core), 'enrollE2EI').mockResolvedValueOnce({status: 'successful'}); - jest.spyOn(container.resolve(Core), 'enrollE2EI').mockResolvedValueOnce(true); - - const instance = E2EIHandler.getInstance().initialize(params); + const instance = await E2EIHandler.getInstance().initialize(params); void instance['enroll'](); await wait(1); expect(instance['currentStep']).toBe(E2EIHandlerStep.SUCCESS); @@ -142,16 +137,15 @@ describe('E2EIHandler', () => { it('should set currentStep to ERROR when enrolE2EI is called and enrolment fails', async () => { // Mock the Core service to return an error jest.spyOn(container.resolve(Core), 'enrollE2EI').mockImplementationOnce(jest.fn(() => Promise.reject())); - jest.spyOn(container.resolve(UserState), 'self').mockImplementationOnce(() => user); - const instance = E2EIHandler.getInstance().initialize(params); + const instance = await E2EIHandler.getInstance().initialize(params); void instance['enroll'](); await wait(1); expect(instance['currentStep']).toBe(E2EIHandlerStep.ERROR); }); it('should display user info message when initialized', async () => { - const instance = E2EIHandler.getInstance().initialize(params); + const instance = await E2EIHandler.getInstance().initialize(params); void instance.attemptEnrollment(); await wait(1); expect(getModalOptions).toHaveBeenCalledWith( @@ -168,7 +162,7 @@ describe('E2EIHandler', () => { }); it('should display loading message when enroled', async () => { - const handler = E2EIHandler.getInstance().initialize(params); + const handler = await E2EIHandler.getInstance().initialize(params); void handler['enroll'](); await wait(1); expect(getModalOptions).toHaveBeenCalledWith( @@ -179,9 +173,9 @@ describe('E2EIHandler', () => { }); it('should display success message when enrollment is done', async () => { - jest.spyOn(container.resolve(Core), 'enrollE2EI').mockResolvedValueOnce(true); + jest.spyOn(container.resolve(Core), 'enrollE2EI').mockResolvedValueOnce({status: 'successful'}); - const handler = E2EIHandler.getInstance().initialize(params); + const handler = await E2EIHandler.getInstance().initialize(params); handler['showLoadingMessage'] = jest.fn(); void handler['enroll'](); await wait(1); @@ -195,7 +189,7 @@ describe('E2EIHandler', () => { it('should display error message when enrollment fails', async () => { jest.spyOn(container.resolve(Core), 'enrollE2EI').mockRejectedValueOnce(false); - const handler = E2EIHandler.getInstance().initialize(params); + const handler = await E2EIHandler.getInstance().initialize(params); handler['showLoadingMessage'] = jest.fn(); void handler['enroll'](); await wait(1); @@ -218,7 +212,7 @@ describe('E2EIHandler', () => { const renewCertificateSpy = jest.spyOn(handler as any, 'renewCertificate'); // Initialize E2EI - handler.initialize(params); + await handler.initialize(params); void handler.attemptRenewal(); await wait(1); @@ -238,7 +232,7 @@ describe('E2EIHandler', () => { const enrollSpy = jest.spyOn(handler, 'enroll'); // Initialize E2EI - handler.initialize(params); + await handler.initialize(params); void handler.attemptRenewal(); await wait(1); @@ -270,7 +264,7 @@ describe('E2EIHandler', () => { const renewCertificateSpy = jest.spyOn(handler as any, 'renewCertificate'); // Initialize E2EI - handler.initialize(params); + await handler.initialize(params); void handler.attemptRenewal(); await wait(1); @@ -288,7 +282,7 @@ describe('E2EIHandler', () => { const startEnrollmentSpy = jest.spyOn(handler as any, 'startEnrollment'); // Initialize E2EI - handler.initialize(params); + await handler.initialize(params); void handler.attemptEnrollment(); await wait(1); @@ -316,7 +310,7 @@ describe('E2EIHandler', () => { jest.spyOn(handler as any, 'shouldRefresh').mockReturnValue(false); // Initialize E2EI - handler.initialize(params); + await handler.initialize(params); void handler.attemptRenewal(); await wait(1); diff --git a/src/script/E2EIdentity/E2EIdentityEnrollment.ts b/src/script/E2EIdentity/E2EIdentityEnrollment.ts index c0469af0c2f1..5b4f2d6367a6 100644 --- a/src/script/E2EIdentity/E2EIdentityEnrollment.ts +++ b/src/script/E2EIdentity/E2EIdentityEnrollment.ts @@ -32,23 +32,14 @@ import {getCertificateDetails} from 'Util/certificateDetails'; import {getLogger} from 'Util/Logger'; import {formatDelayTime, TIME_IN_MILLIS} from 'Util/TimeUtil'; import {removeUrlParameters} from 'Util/UrlUtil'; -import {supportsMLS} from 'Util/util'; - -import { - hasActiveCertificate, - isE2EIEnabled, - getActiveWireIdentity, - MLSStatuses, - WireIdentity, -} from './E2EIdentityVerification'; + +import {hasActiveCertificate, getActiveWireIdentity, MLSStatuses, WireIdentity} from './E2EIdentityVerification'; import {getModalOptions, ModalType} from './Modals'; import {OIDCService} from './OIDCService'; import {OIDCServiceStore} from './OIDCService/OIDCServiceStorage'; import {getSnoozeTime, shouldEnableSoftLock} from './SnoozableTimer/delay'; import {SnoozableTimer} from './SnoozableTimer/SnoozableTimer'; -import {Config} from '../Config'; - export enum E2EIHandlerStep { UNINITIALIZED = 'uninitialized', INITIALIZED = 'initialized', @@ -120,23 +111,46 @@ export class E2EIHandler extends TypedEventEmitter { E2EIHandler.instance = null; } - public initialize({discoveryUrl, gracePeriodInSeconds}: E2EIHandlerParams) { - if (isE2EIEnabled()) { - const gracePeriodInMs = gracePeriodInSeconds * TIME_IN_MILLIS.SECOND; - this.config = { - discoveryUrl, - gracePeriodInMs, - timer: new SnoozableTimer({ - gracePeriodInMS: gracePeriodInMs, - onGracePeriodExpired: () => this.startEnrollment(ModalType.ENROLL), - onSnoozeExpired: () => this.startEnrollment(ModalType.ENROLL), - }), - }; - this.currentStep = E2EIHandlerStep.INITIALIZED; + /** + * Returns true if the current instance has been configured with team settings params + * @returns + */ + public isE2EIEnabled() { + return this.currentStep !== E2EIHandlerStep.UNINITIALIZED; + } + + public async initialize({discoveryUrl, gracePeriodInSeconds}: E2EIHandlerParams) { + const gracePeriodInMs = gracePeriodInSeconds * TIME_IN_MILLIS.SECOND; + this.config = { + discoveryUrl, + gracePeriodInMs, + timer: new SnoozableTimer({ + gracePeriodInMS: gracePeriodInMs, + onGracePeriodExpired: () => this.processEnrollmentUponExpiry(), + onSnoozeExpired: () => this.processEnrollmentUponExpiry(), + }), + }; + + await this.coreE2EIService.initialize(discoveryUrl); + await this.coreE2EIService.registerServerCertificates(); + + try { + //FIXME: this doesn't work on curernt core-crypto version + await this.coreE2EIService.validateSelfCrl(); + } catch (error) { + console.error('Error validating self CRL', error); } + + this.currentStep = E2EIHandlerStep.INITIALIZED; return this; } + private async processEnrollmentUponExpiry() { + const hasCertificate = await hasActiveCertificate(); + const enrollmentType = hasCertificate ? ModalType.CERTIFICATE_RENEWAL : ModalType.ENROLL; + await this.startEnrollment(enrollmentType); + } + public async attemptEnrollment(): Promise { const hasCertificate = await hasActiveCertificate(); if (hasCertificate) { @@ -189,8 +203,8 @@ export class E2EIHandler extends TypedEventEmitter { * Renew the certificate without user action */ private async renewCertificate(): Promise { - this.oidcService = this.createOIDCService(); try { + this.oidcService = this.createOIDCService(); // Use the oidc service to get the user data via silent authentication (refresh token) const userData = await this.oidcService.handleSilentAuthentication(); @@ -229,17 +243,6 @@ export class E2EIHandler extends TypedEventEmitter { return renewalDate; } - get isE2EIEnabled(): boolean { - return supportsMLS() && Config.getConfig().FEATURE.ENABLE_E2EI; - } - - private async storeRedirectTargetAndRedirect(targetURL: string): Promise { - // store the target url in the persistent oidc service store, since the oidc service will be destroyed after the redirect - OIDCServiceStore.store.targetURL(targetURL); - this.oidcService = this.createOIDCService(); - await this.oidcService.authenticate(); - } - /** * Used to clean the state/storage after a failed run */ @@ -278,24 +281,26 @@ export class E2EIHandler extends TypedEventEmitter { const displayName = this.userState.self()?.name(); const handle = this.userState.self()?.username(); + const teamId = this.userState.self()?.teamId; // If the user has no username or handle, we cannot enroll - if (!displayName || !handle) { - throw new Error('Username or handle not found'); + if (!displayName || !handle || !teamId) { + throw new Error('Username, handle or teamId not found'); } - const data = await this.core.enrollE2EI({ + const enrollmentState = await this.core.enrollE2EI({ discoveryUrl: this.config.discoveryUrl, displayName, handle, + teamId, oAuthIdToken, }); // If the data is false or we dont get the ACMEChallenge, enrolment failed - if (!data) { - throw new Error('E2EI enrolment failed'); - } - // Check if the data is a boolean, if not, we need to handle the oauth redirect - if (typeof data !== 'boolean') { - await this.storeRedirectTargetAndRedirect(data.target); + if (enrollmentState.status === 'authentication') { + // If the data is authentication flow data, we need to kick off the oauth flow to get an oauth token + const {challenge, keyAuth} = enrollmentState.authenticationChallenge; + OIDCServiceStore.store.targetURL(challenge.target); + this.oidcService = this.createOIDCService(); + await this.oidcService.authenticate(keyAuth, challenge.url); } // Notify user about E2EI enrolment success @@ -365,13 +370,13 @@ export class E2EIHandler extends TypedEventEmitter { // Clear the e2e identity progress this.coreE2EIService.clearAllProgress(); - const isSoftLockEnabled = await shouldEnableSoftLock(this.config!); + const disableSnooze = await shouldEnableSoftLock(this.config!); return new Promise(resolve => { const {modalOptions, modalType} = getModalOptions({ type: ModalType.ERROR, hideClose: true, - hideSecondary: isSoftLockEnabled, + hideSecondary: disableSnooze, primaryActionFn: async () => { this.currentStep = E2EIHandlerStep.INITIALIZED; await this.enroll(); @@ -381,6 +386,9 @@ export class E2EIHandler extends TypedEventEmitter { await this.startEnrollment(ModalType.ENROLL); resolve(); }, + extraParams: { + isGracePeriodOver: disableSnooze, + }, }); PrimaryModal.show(modalType, modalOptions); @@ -406,6 +414,9 @@ export class E2EIHandler extends TypedEventEmitter { this.showSnoozeConfirmationModal(); resolve(); }, + extraParams: { + isGracePeriodOver: disableSnooze, + }, type: modalType, hideClose: true, }); diff --git a/src/script/E2EIdentity/E2EIdentityVerification.ts b/src/script/E2EIdentity/E2EIdentityVerification.ts index d960834c7349..0ae7ced8b828 100644 --- a/src/script/E2EIdentity/E2EIdentityVerification.ts +++ b/src/script/E2EIdentity/E2EIdentityVerification.ts @@ -22,11 +22,10 @@ import {DeviceIdentity} from '@wireapp/core/lib/messagingProtocols/mls'; import {container} from 'tsyringe'; import {Core} from 'src/script/service/CoreSingleton'; -import {base64ToArray, supportsMLS} from 'Util/util'; +import {base64ToArray} from 'Util/util'; import {mapMLSStatus} from './certificateDetails'; -import {Config} from '../Config'; import {ConversationState} from '../conversation/ConversationState'; export enum MLSStatuses { @@ -49,10 +48,6 @@ export function getE2EIdentityService() { return e2eIdentityService; } -export function isE2EIEnabled(): boolean { - return supportsMLS() && Config.getConfig().FEATURE.ENABLE_E2EI; -} - export async function getUsersIdentities(groupId: string, userIds: QualifiedId[]) { const userVerifications = await getE2EIdentityService().getUsersIdentities(groupId, userIds); diff --git a/src/script/E2EIdentity/Modals/Modals.ts b/src/script/E2EIdentity/Modals/Modals.ts index 1872b752f12b..38ade1f224a8 100644 --- a/src/script/E2EIdentity/Modals/Modals.ts +++ b/src/script/E2EIdentity/Modals/Modals.ts @@ -30,6 +30,7 @@ export enum ModalType { SUCCESS = 'success', LOADING = 'loading', CERTIFICATE_RENEWAL = 'certificate_renewal', + SELF_CERTIFICATE_REVOKED = 'self_certificate_revoked', SNOOZE_REMINDER = 'snooze_reminder', } @@ -40,7 +41,16 @@ interface GetModalOptions { hideSecondary?: boolean; hidePrimary?: boolean; hideClose?: boolean; - extraParams?: {delayTime?: string; isRenewal?: boolean}; + extraParams?: { + /** time left to remind the user again (only for enroll and renewal modal types). */ + delayTime?: string; + + /** Flag indicating if this is a renewal action */ + isRenewal?: boolean; + + /** Flag indicating if the grace period is over (only for enroll, renew or error modals) */ + isGracePeriodOver?: boolean; + }; } export const getModalOptions = ({ type, @@ -69,7 +79,9 @@ export const getModalOptions = ({ options = { text: { closeBtnLabel: t('acme.settingsChanged.button.close'), - htmlMessage: t('acme.settingsChanged.paragraph', {}, {br: '
', ...replaceLearnMore}), + htmlMessage: extraParams?.isGracePeriodOver + ? t('acme.settingsChanged.gracePeriodOver.paragraph', {}, {br: '
', ...replaceLearnMore}) + : t('acme.settingsChanged.paragraph', {}, {br: '
', ...replaceLearnMore}), title: t('acme.settingsChanged.headline.alt'), }, primaryAction: { @@ -90,7 +102,9 @@ export const getModalOptions = ({ options = { text: { closeBtnLabel: t('acme.renewCertificate.button.close'), - htmlMessage: t('acme.renewCertificate.paragraph'), + htmlMessage: extraParams?.isGracePeriodOver + ? t('acme.renewCertificate.gracePeriodOver.paragraph') + : t('acme.renewCertificate.paragraph'), title: t('acme.renewCertificate.headline.alt'), }, primaryAction: { @@ -107,6 +121,21 @@ export const getModalOptions = ({ hideSecondary || secondaryActionFn === undefined ? PrimaryModal.type.ACKNOWLEDGE : PrimaryModal.type.CONFIRM; break; + case ModalType.SELF_CERTIFICATE_REVOKED: + options = { + text: { + closeBtnLabel: t('acme.selfCertificateRevoked.button.cancel'), + htmlMessage: t('acme.selfCertificateRevoked.text'), + title: t('acme.selfCertificateRevoked.title'), + }, + primaryAction: { + action: primaryActionFn, + text: t('acme.selfCertificateRevoked.button.primary'), + }, + }; + modalType = PrimaryModal.type.CONFIRM; + break; + case ModalType.SNOOZE_REMINDER: options = { text: { @@ -128,7 +157,9 @@ export const getModalOptions = ({ options = { text: { closeBtnLabel: t('acme.error.button.close'), - htmlMessage: t('acme.error.paragraph', {}, {br: '
'}), + htmlMessage: extraParams?.isGracePeriodOver + ? t('acme.error.gracePeriod.paragraph', {}, {br: '
'}) + : t('acme.error.paragraph', {}, {br: '
'}), title: t('acme.error.headline'), }, primaryAction: { diff --git a/src/script/E2EIdentity/OIDCService/OIDCService.ts b/src/script/E2EIdentity/OIDCService/OIDCService.ts index 526bb0d395de..2303f967d3da 100644 --- a/src/script/E2EIdentity/OIDCService/OIDCService.ts +++ b/src/script/E2EIdentity/OIDCService/OIDCService.ts @@ -17,6 +17,7 @@ * */ +import {KeyAuth} from '@wireapp/core/lib/messagingProtocols/mls'; import {UserManager, User, UserManagerSettings, WebStorageStateStore} from 'oidc-client-ts'; import {clearKeysStartingWith} from 'Util/localStorage'; @@ -41,32 +42,28 @@ export class OIDCService { // Extract the clientId from the targetURL const idpUrl = new URL(targetURL); - // This clientId will be used to create the OIDCService, it is mocked for now - const idpClientId = 'wireapp'; - //const idpClientId = idpUrl.searchParams.get('clientId'); + // This clientId will be used to create the OIDCService. It needs to be attached to the targetURL + const idpClientId = idpUrl.searchParams.get('client_id'); if (!idpClientId) { throw new Error('No clientId provided by the targetUrl'); } - // This secret is only used for testing and needs to be removed in the future - const idpClientSecret = 'dUpVSGx2dVdFdGQ0dmsxWGhDalQ0SldU'; // Build the proxy url and redirect uri const currentOrigin = location.origin; const authorityUrl = idpUrl.origin + idpUrl.pathname; - const proxyUrl = `${currentOrigin}/oidcProxy?targetUrl=${authorityUrl}`; const redirectUri = `${currentOrigin}/oidc`; const dexioConfig: UserManagerSettings = { - authority: proxyUrl, + authority: authorityUrl, client_id: idpClientId, redirect_uri: redirectUri, response_type: 'code', scope: 'openid profile email offline_access', - client_secret: idpClientSecret, extraQueryParams: { access_type: 'offline', prompt: 'consent', }, + automaticSilentRenew: false, stateStore: new WebStorageStateStore({store: window.sessionStorage}), userStore: new WebStorageStateStore({ store: new EncryptedStorage(secretKey), @@ -77,8 +74,18 @@ export class OIDCService { this.logger = getLogger('OIDC Service'); } - public async authenticate(): Promise { - await this.userManager.signinRedirect({extraQueryParams: {shouldBeRedirectedByProxy: true}}); + public async authenticate(keyAuth: KeyAuth, challengeUrl: string): Promise { + // New claims value for keycloak + const claims = { + id_token: { + keyauth: {essential: true, value: keyAuth}, + acme_aud: {essential: true, value: challengeUrl}, + }, + }; + + await this.userManager.signinRedirect({ + extraQueryParams: {shouldBeRedirectedByProxy: true, claims: JSON.stringify(claims)}, + }); } public async handleAuthentication(): Promise { diff --git a/src/script/E2EIdentity/certificateDetails.ts b/src/script/E2EIdentity/certificateDetails.ts index 91496ea9be40..1ffc8b907d62 100644 --- a/src/script/E2EIdentity/certificateDetails.ts +++ b/src/script/E2EIdentity/certificateDetails.ts @@ -27,7 +27,7 @@ export const mapMLSStatus = (status?: CoreStatus) => { const statusMap: Record = { Valid: MLSStatuses.VALID, Expired: MLSStatuses.EXPIRED, - Revoked: MLSStatuses.EXPIRED, + Revoked: MLSStatuses.REVOKED, }; if (!status) { diff --git a/src/script/backup/BackupRepository.test.ts b/src/script/backup/BackupRepository.test.ts index c682d9aa80b5..f809c94130d9 100644 --- a/src/script/backup/BackupRepository.test.ts +++ b/src/script/backup/BackupRepository.test.ts @@ -17,9 +17,12 @@ * */ +import {CONVERSATION_TYPE} from '@wireapp/api-client/lib/conversation'; import {container} from 'tsyringe'; import {omit} from 'underscore'; +import {generateConversation} from 'test/helper/ConversationGenerator'; +import {TestFactory} from 'test/helper/TestFactory'; import {generateAPIUser} from 'test/helper/UserGenerator'; import {noop} from 'Util/util'; import {createUuid} from 'Util/uuid'; @@ -31,7 +34,6 @@ import {BackupService} from './BackupService'; import {CancelError, DifferentAccountError, IncompatiblePlatformError} from './Error'; import {handleZipEvent} from './zipWorker'; -import {ConversationRepository} from '../conversation/ConversationRepository'; import {User} from '../entity/User'; import {ClientEvent} from '../event/Client'; import {DatabaseTypes, createStorageEngine} from '../service/StoreEngineProvider'; @@ -39,22 +41,14 @@ import {StorageService} from '../storage'; import {StorageSchemata} from '../storage/StorageSchemata'; const conversationId = '35a9a89d-70dc-4d9e-88a2-4d8758458a6a'; -const conversation = { - accessModes: ['private'], - accessRole: 'private', - archived_state: false, - archived_timestamp: 0, - creator: '1ccd93e0-0f4b-4a73-b33f-05c464b88439', - id: conversationId, - last_event_timestamp: 2, - last_server_timestamp: 2, - muted_state: false, - muted_timestamp: 0, - name: 'Tom @ Staging', - others: ['a7122859-3f16-4870-b7f2-5cbca5572ab2'], - status: 0, - type: 2, -}; + +const conversation = generateConversation({ + id: {id: conversationId, domain: 'test.wire.link'}, + overwites: { + status: 0, + type: 2, + }, +}).serialize(); const messages = [ { @@ -81,14 +75,16 @@ async function buildBackupRepository() { storageService.init(engine); const backupService = new BackupService(storageService); - const conversationRepository = { - initAllLocal1To1Conversations: jest.fn(), - getAllLocalConversations: jest.fn(), - checkForDeletedConversations: jest.fn(), - mapConnections: jest.fn().mockImplementation(() => []), - updateConversationStates: jest.fn().mockImplementation(conversations => conversations), - updateConversations: jest.fn().mockImplementation(async () => {}), - } as unknown as ConversationRepository; + + const testFactory = new TestFactory(); + const conversationRepository = await testFactory.exposeConversationActors(); + + jest + .spyOn(conversationRepository, 'mapConversations') + .mockImplementation(conversations => conversations.map(c => generateConversation({type: c.type, overwites: c}))); + jest.spyOn(conversationRepository, 'updateConversationStates'); + jest.spyOn(conversationRepository, 'updateConversations'); + jest.spyOn(conversationRepository, 'syncDeletedConversations').mockResolvedValue(undefined); return [ new BackupRepository(backupService, conversationRepository), {backupService, conversationRepository, storageService}, @@ -137,8 +133,8 @@ describe('BackupRepository', () => { }; const importSpy = jest.spyOn(backupService, 'importEntities'); - await storageService.save(StorageSchemata.OBJECT_STORE.EVENTS, undefined, verificationEvent); - await storageService.save(StorageSchemata.OBJECT_STORE.EVENTS, undefined, textEvent); + await storageService.save(StorageSchemata.OBJECT_STORE.EVENTS, '', verificationEvent); + await storageService.save(StorageSchemata.OBJECT_STORE.EVENTS, '', textEvent); const blob = await backupRepository.generateHistory(user, 'client1', noop, password); await backupRepository.importHistory(new User('user1'), blob, noop, noop); @@ -153,7 +149,7 @@ describe('BackupRepository', () => { const [backupRepository, {storageService}] = await buildBackupRepository(); const password = ''; await Promise.all([ - ...messages.map(message => storageService.save(eventStoreName, undefined, message)), + ...messages.map(message => storageService.save(eventStoreName, '', message)), storageService.save('conversations', conversationId, conversation), ]); @@ -201,9 +197,19 @@ describe('BackupRepository', () => { const metadata = {...backupRepository.createMetaData(user, 'client1'), version: mockedDBVersion}; + const conversation = generateConversation({ + id: {id: 'conversation1', domain: 'staging2'}, + type: CONVERSATION_TYPE.ONE_TO_ONE, + }).serialize(); + + const selfConversation = generateConversation({ + id: {id: 'conversation2', domain: 'staging2'}, + type: CONVERSATION_TYPE.SELF, + }).serialize(); + const files = { [Filename.METADATA]: JSON.stringify(metadata), - [Filename.CONVERSATIONS]: JSON.stringify([conversation]), + [Filename.CONVERSATIONS]: JSON.stringify([conversation, selfConversation]), [Filename.EVENTS]: JSON.stringify(messages), [Filename.USERS]: JSON.stringify(users), }; @@ -212,7 +218,17 @@ describe('BackupRepository', () => { await backupRepository.importHistory(user, zip, noop, noop); - expect(conversationRepository.updateConversationStates).toHaveBeenCalledWith([conversation]); + expect(conversationRepository.updateConversationStates).toHaveBeenCalledWith( + expect.arrayContaining([expect.objectContaining({id: conversation.id})]), + ); + + expect(conversationRepository.updateConversations).toHaveBeenCalledWith( + expect.arrayContaining([expect.objectContaining({id: conversation.id})]), + ); + expect(conversationRepository.updateConversations).not.toHaveBeenCalledWith( + expect.arrayContaining([expect.objectContaining({id: selfConversation.id})]), + ); + expect(importSpy).toHaveBeenCalledWith( StorageSchemata.OBJECT_STORE.EVENTS, messages.map(message => omit(message, 'primary_key')), @@ -264,7 +280,7 @@ describe('BackupRepository', () => { expect(mockGenerateChaCha20Key).toHaveBeenCalledWith(decodedHeader); }); - test('compressHistoryFiles does not call the encryption function if no password is provided', async () => { + it('compressHistoryFiles does not call the encryption function if no password is provided', async () => { // Mocked values const password = ''; const clientId = 'ClientId'; @@ -283,7 +299,8 @@ describe('BackupRepository', () => { expect(mockEncodeHeader).not.toHaveBeenCalled(); expect(mockGenerateChaCha20Key).not.toHaveBeenCalled(); }); - test('compressHistoryFiles returns a Blob object with the correct type', async () => { + + it('compressHistoryFiles returns a Blob object with the correct type', async () => { // Mocked values... const password = 'Password'; const clientId = 'ClientId'; diff --git a/src/script/backup/BackupRepository.ts b/src/script/backup/BackupRepository.ts index 8c5fb03f5d20..6f312b95c6a7 100644 --- a/src/script/backup/BackupRepository.ts +++ b/src/script/backup/BackupRepository.ts @@ -41,6 +41,7 @@ import { import {preprocessConversations, preprocessEvents, preprocessUsers} from './recordPreprocessors'; import type {ConversationRepository} from '../conversation/ConversationRepository'; +import {isReadableConversation} from '../conversation/ConversationSelectors'; import type {Conversation} from '../entity/Conversation'; import {User} from '../entity/User'; import {EventRecord, UserRecord} from '../storage'; @@ -381,10 +382,12 @@ export class BackupRepository { // Run all the database migrations on the imported data await this.backupService.runDbSchemaUpdates(archiveVersion); - await this.conversationRepository.updateConversations(importedConversations); + const readableConversations = importedConversations.filter(isReadableConversation); + + await this.conversationRepository.updateConversations(readableConversations); await this.conversationRepository.initAllLocal1To1Conversations(); // doesn't need to be awaited - void this.conversationRepository.checkForDeletedConversations(); + void this.conversationRepository.syncDeletedConversations(); } private async importConversations( diff --git a/src/script/components/AppContainer/AppContainer.tsx b/src/script/components/AppContainer/AppContainer.tsx index 011795b365fe..cee360895501 100644 --- a/src/script/components/AppContainer/AppContainer.tsx +++ b/src/script/components/AppContainer/AppContainer.tsx @@ -64,7 +64,10 @@ export const AppContainer: FC = ({config, clientType}) => { return; } const killInstance = registerInstance(); - window.addEventListener('beforeunload', killInstance); + /* We need to wait the very last moment to de-register the instance. + * If we do it too early (like beforeunload event) then the app could detect it's no longer the single instance running and redirect to the login page + */ + window.addEventListener('pagehide', killInstance); }, []); useEffect(() => { diff --git a/src/script/components/InputBar/InputBar.tsx b/src/script/components/InputBar/InputBar.tsx index 02d3d29bfc33..3d3ff194f570 100644 --- a/src/script/components/InputBar/InputBar.tsx +++ b/src/script/components/InputBar/InputBar.tsx @@ -58,7 +58,6 @@ import {loadDraftState, saveDraftState} from './util/DraftStateUtil'; import {Config} from '../../Config'; import {ConversationVerificationState} from '../../conversation/ConversationVerificationState'; import {MessageRepository, OutgoingQuote} from '../../conversation/MessageRepository'; -import {isE2EIEnabled} from '../../E2EIdentity'; import {Conversation} from '../../entity/Conversation'; import {ContentMessage} from '../../entity/message/ContentMessage'; import {User} from '../../entity/User'; @@ -353,7 +352,7 @@ export const InputBar = ({ const handleSendMessage = () => { const isE2EIDegraded = conversation.mlsVerificationState() === ConversationVerificationState.DEGRADED; - if (isE2EIEnabled() && isE2EIDegraded) { + if (isE2EIDegraded) { PrimaryModal.show(PrimaryModal.type.CONFIRM, { primaryAction: { action: () => { @@ -612,7 +611,11 @@ export const InputBar = ({ ) : ( <> -
    +
    diff --git a/src/script/components/MessagesList/Message/ContentMessage/ContentMessage.tsx b/src/script/components/MessagesList/Message/ContentMessage/ContentMessage.tsx index ff04635b302b..27701c02fff9 100644 --- a/src/script/components/MessagesList/Message/ContentMessage/ContentMessage.tsx +++ b/src/script/components/MessagesList/Message/ContentMessage/ContentMessage.tsx @@ -29,6 +29,7 @@ import {useRelativeTimestamp} from 'src/script/hooks/useRelativeTimestamp'; import {StatusType} from 'src/script/message/StatusType'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {getMessageAriaLabel} from 'Util/conversationMessages'; +import {TIME_IN_MILLIS} from 'Util/TimeUtil'; import {ContentAsset} from './asset'; import {MessageActionsMenu} from './MessageActions/MessageActions'; @@ -43,7 +44,6 @@ import {EphemeralStatusType} from '../../../../message/EphemeralStatusType'; import {ContextMenuEntry} from '../../../../ui/ContextMenu'; import {EphemeralTimer} from '../EphemeralTimer'; import {MessageTime} from '../MessageTime'; -import {ReadReceiptStatus} from '../ReadReceiptStatus'; import {useMessageFocusedTabIndex} from '../util'; export interface ContentMessageProps extends Omit { @@ -117,7 +117,7 @@ export const ContentMessageComponent: React.FC = ({ 'quote', ]); - const shouldShowAvatar = (): boolean => { + const shouldShowMessageHeader = (): boolean => { if (!previousMessage || hasMarker) { return true; } @@ -126,9 +126,21 @@ export const ContentMessageComponent: React.FC = ({ return true; } + // Interval in seconds, within which messages are grouped together + const GROUPED_MESSAGE_INTERVAL = 30 * TIME_IN_MILLIS.SECOND; + + const currentMessageDate = message.timestamp(); + const previousMessageDate = previousMessage.timestamp(); + + if (currentMessageDate - previousMessageDate >= GROUPED_MESSAGE_INTERVAL) { + return true; + } + return !previousMessage.isContent() || previousMessage.user().id !== user.id; }; + const timeAgo = useRelativeTimestamp(message.timestamp()); + const [messageAriaLabel] = getMessageAriaLabel({ assets, displayTimestampShort: message.displayTimestampShort(), @@ -168,25 +180,20 @@ export const ContentMessageComponent: React.FC = ({ } }} > - {shouldShowAvatar() && ( + {shouldShowMessageHeader() && ( {was_edited && ( )} + - + {timeAgo} - - )} +
    {ephemeral_status === EphemeralStatusType.ACTIVE && ( @@ -194,6 +201,7 @@ export const ContentMessageComponent: React.FC = ({
    )} + {quote && ( = ({ isMessageFocused={msgFocusState} /> )} + {assets.map(asset => ( = ({ onClickImage={onClickImage} onClickMessage={onClickMessage} isMessageFocused={msgFocusState} + is1to1Conversation={conversation.is1to1()} + isLastDeliveredMessage={isLastDeliveredMessage} + onClickDetails={() => onClickDetails(message)} /> ))} + {failedToSend && ( = ({ /> )}
    + {!isConversationReadonly && isActionMenuVisible && ( { }; export const messageWithHeaderTop: CSSObject = { - top: '-53px', + top: '-63px', }; diff --git a/src/script/components/MessagesList/Message/ContentMessage/MessageActions/MessageReactions/MessageReactions.styles.ts b/src/script/components/MessagesList/Message/ContentMessage/MessageActions/MessageReactions/MessageReactions.styles.ts index 3e71e865fd03..f2dce61d028e 100644 --- a/src/script/components/MessagesList/Message/ContentMessage/MessageActions/MessageReactions/MessageReactions.styles.ts +++ b/src/script/components/MessagesList/Message/ContentMessage/MessageActions/MessageReactions/MessageReactions.styles.ts @@ -41,10 +41,9 @@ import {CSSObject} from '@emotion/react'; export const messageReactionWrapper: CSSObject = { display: 'flex', gap: '0.5rem', - paddingLeft: 'var(--conversation-message-sender-width)', + paddingInline: 'var(--conversation-message-sender-width)', flexWrap: 'wrap', maxWidth: '100%', - marginRight: 'var(--conversation-message-timestamp-width)', '.tooltip-content': { backgroundColor: 'var(--white) !important', marginBottom: '0 !important', diff --git a/src/script/components/MessagesList/Message/ContentMessage/asset/ImageAsset.tsx b/src/script/components/MessagesList/Message/ContentMessage/asset/ImageAsset.tsx index a06793f10ee1..74bc261947ac 100644 --- a/src/script/components/MessagesList/Message/ContentMessage/asset/ImageAsset.tsx +++ b/src/script/components/MessagesList/Message/ContentMessage/asset/ImageAsset.tsx @@ -102,7 +102,7 @@ export const ImageAsset: React.FC = ({ const imageContainerStyle: CSSObject = { aspectRatio: isFileSharingReceivingEnabled ? `${asset.ratio}` : undefined, - maxWidth: '100%', + maxWidth: 'var(--conversation-message-asset-width)', width: asset.width, maxHeight: '80vh', }; diff --git a/src/script/components/MessagesList/Message/ContentMessage/asset/index.tsx b/src/script/components/MessagesList/Message/ContentMessage/asset/index.tsx index a7db6095c6ac..e7c1454bc1a1 100644 --- a/src/script/components/MessagesList/Message/ContentMessage/asset/index.tsx +++ b/src/script/components/MessagesList/Message/ContentMessage/asset/index.tsx @@ -43,6 +43,20 @@ import {AssetType} from '../../../../../assets/AssetType'; import {Button} from '../../../../../entity/message/Button'; import {CompositeMessage} from '../../../../../entity/message/CompositeMessage'; import {ContentMessage} from '../../../../../entity/message/ContentMessage'; +import {ReadIndicator} from '../../ReadIndicator'; + +interface ContentAssetProps { + asset: Asset; + message: ContentMessage; + onClickButton: (message: CompositeMessage, buttonId: string) => void; + onClickImage: MessageActions['onClickImage']; + onClickMessage: MessageActions['onClickMessage']; + selfId: QualifiedId; + isMessageFocused: boolean; + is1to1Conversation: boolean; + isLastDeliveredMessage: boolean; + onClickDetails: () => void; +} const ContentAsset = ({ asset, @@ -52,25 +66,23 @@ const ContentAsset = ({ onClickMessage, onClickButton, isMessageFocused, -}: { - asset: Asset; - message: ContentMessage; - onClickButton: (message: CompositeMessage, buttonId: string) => void; - onClickImage: MessageActions['onClickImage']; - onClickMessage: MessageActions['onClickMessage']; - selfId: QualifiedId; - isMessageFocused: boolean; -}) => { + is1to1Conversation, + isLastDeliveredMessage, + onClickDetails, +}: ContentAssetProps) => { const {isObfuscated, status} = useKoSubscribableChildren(message, ['isObfuscated', 'status']); switch (asset.type) { case AssetType.TEXT: + const shouldRenderText = (asset as Text).should_render_text(); + const renderText = (asset as Text).render(selfId, message.accent_color()); + return ( <> - {(asset as Text).should_render_text() && ( + {shouldRenderText && ( )} + + {shouldRenderText && ( + + )} + {(asset as Text).previews().map(preview => (
    + + {!shouldRenderText && ( + + )}
    ))} @@ -93,6 +124,13 @@ const ContentAsset = ({ return (
    + +
    ); } @@ -101,6 +139,13 @@ const ContentAsset = ({ return (
    + +
    ); } @@ -109,17 +154,33 @@ const ContentAsset = ({ return (
    + +
    ); } case AssetType.IMAGE: return ( - +
    + + + +
    ); case AssetType.LOCATION: return ; diff --git a/src/script/components/MessagesList/Message/E2EIVerificationMessage/E2EIVerificationMessage.tsx b/src/script/components/MessagesList/Message/E2EIVerificationMessage/E2EIVerificationMessage.tsx index 4c65073876f5..867083aeb8c1 100644 --- a/src/script/components/MessagesList/Message/E2EIVerificationMessage/E2EIVerificationMessage.tsx +++ b/src/script/components/MessagesList/Message/E2EIVerificationMessage/E2EIVerificationMessage.tsx @@ -87,12 +87,17 @@ export const E2EIVerificationMessage = ({message, conversation}: E2EIVerificatio try { await E2EIHandler.getInstance().enroll(); } catch (error) { - logger.error('Cannot get E2EI instance: ', error); + logger.error('Failed to enroll user certificate: ', error); } }; - // TODO: Add update certificate method while this functionality will be finished - const updateCertificate = () => {}; + const updateCertificate = async () => { + try { + await E2EIHandler.getInstance().attemptRenewal(); + } catch (error) { + logger.error('Failed to renew user certificate: ', error); + } + }; return (
    diff --git a/src/script/components/MessagesList/Message/ReadIndicator/ReadIndicator.styles.ts b/src/script/components/MessagesList/Message/ReadIndicator/ReadIndicator.styles.ts new file mode 100644 index 000000000000..19870b89fd8b --- /dev/null +++ b/src/script/components/MessagesList/Message/ReadIndicator/ReadIndicator.styles.ts @@ -0,0 +1,57 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {CSSObject} from '@emotion/react'; + +export const ReadReceiptText: CSSObject = { + display: 'inline-flex', + alignItems: 'center', + verticalAlign: 'text-bottom', +}; + +export const ReadIndicatorStyles = (showIconOnly = false): CSSObject => ({ + color: 'var(--content-message-timestamp)', + fontSize: 'var(--font-size-small)', + fontWeight: 'var(--font-weight-regular)', + lineHeight: 'var(--line-height-sm)', + + svg: { + width: '10px', + minHeight: '10px', + marginRight: '4px', + fill: 'currentColor', + }, + + ...(showIconOnly && { + display: 'flex', + alignItems: 'center', + marginLeft: '8px', + }), + + '.message-asset &': { + marginLeft: '12px', + }, + + ...(!showIconOnly && { + opacity: 0, + '.message:hover &': { + opacity: '1', + }, + }), +}); diff --git a/src/script/components/MessagesList/Message/ReadIndicator/ReadIndicator.tsx b/src/script/components/MessagesList/Message/ReadIndicator/ReadIndicator.tsx new file mode 100644 index 000000000000..929ff76d5b66 --- /dev/null +++ b/src/script/components/MessagesList/Message/ReadIndicator/ReadIndicator.tsx @@ -0,0 +1,97 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {Icon} from 'Components/Icon'; +import {useKoSubscribableChildren} from 'Util/ComponentUtil'; +import {t} from 'Util/LocalizerUtil'; +import {formatTimeShort} from 'Util/TimeUtil'; + +import {ReadIndicatorStyles, ReadReceiptText} from './ReadIndicator.styles'; + +import {Message} from '../../../../entity/message/Message'; + +interface ReadIndicatorProps { + message: Message; + is1to1Conversation?: boolean; + isLastDeliveredMessage?: boolean; + showIconOnly?: boolean; + onClick?: (message: Message) => void; +} + +export const ReadIndicator = ({ + message, + is1to1Conversation = false, + isLastDeliveredMessage = false, + showIconOnly = false, + onClick, +}: ReadIndicatorProps) => { + const {readReceipts} = useKoSubscribableChildren(message, ['readReceipts']); + + if (!message.expectsReadConfirmation) { + return null; + } + + if (is1to1Conversation) { + const readReceiptText = readReceipts.length ? formatTimeShort(readReceipts[0].time) : ''; + const showDeliveredMessage = isLastDeliveredMessage && readReceiptText === ''; + + return ( + + {showDeliveredMessage && ( + {t('conversationMessageDelivered')} + )} + + {showIconOnly && readReceiptText && } + + {!showIconOnly && !!readReceiptText && ( +
    + {readReceiptText} +
    + )} +
    + ); + } + + const readReceiptCount = readReceipts.length; + + if (readReceiptCount === 0) { + return null; + } + + if (showIconOnly) { + return ( + + + + ); + } + + return ( + + ); +}; diff --git a/server/routes/E2EIProxy/index.ts b/src/script/components/MessagesList/Message/ReadIndicator/index.ts similarity index 86% rename from server/routes/E2EIProxy/index.ts rename to src/script/components/MessagesList/Message/ReadIndicator/index.ts index f7e61abc4a55..c74885f8cc1e 100644 --- a/server/routes/E2EIProxy/index.ts +++ b/src/script/components/MessagesList/Message/ReadIndicator/index.ts @@ -1,6 +1,6 @@ /* * Wire - * Copyright (C) 2023 Wire Swiss GmbH + * Copyright (C) 2024 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,5 +17,4 @@ * */ -export {OIDCProxyRoutePath} from './common'; -export * from './route'; +export * from './ReadIndicator'; diff --git a/src/script/components/MessagesList/Message/SystemMessage/SystemMessage.tsx b/src/script/components/MessagesList/Message/SystemMessage/SystemMessage.tsx index 565f25ba473d..a2b3699e3ad5 100644 --- a/src/script/components/MessagesList/Message/SystemMessage/SystemMessage.tsx +++ b/src/script/components/MessagesList/Message/SystemMessage/SystemMessage.tsx @@ -27,6 +27,7 @@ import {JoinedAfterMLSMigrationFinalisationMessage} from 'src/script/entity/mess import {MessageTimerUpdateMessage} from 'src/script/entity/message/MessageTimerUpdateMessage'; import {MLSConversationRecoveredMessage} from 'src/script/entity/message/MLSConversationRecoveredMessage'; import {MLSMigrationFinalisationOngoingCallMessage} from 'src/script/entity/message/MLSMigrationFinalisationOngoingCallMessage'; +import {OneToOneMigratedToMlsMessage} from 'src/script/entity/message/OneToOneMigratedToMlsMessage'; import {ProtocolUpdateMessage} from 'src/script/entity/message/ProtocolUpdateMessage'; import {ReceiptModeUpdateMessage} from 'src/script/entity/message/ReceiptModeUpdateMessage'; import {RenameMessage} from 'src/script/entity/message/RenameMessage'; @@ -74,6 +75,10 @@ export const SystemMessage: React.FC = ({message}) => { return } />; } + if (message instanceof OneToOneMigratedToMlsMessage) { + return } />; + } + if (message instanceof MLSMigrationFinalisationOngoingCallMessage) { return } />; } diff --git a/src/script/components/UserSearchableList.tsx b/src/script/components/UserSearchableList.tsx index 100d9ef7209e..c3a30b0c9a95 100644 --- a/src/script/components/UserSearchableList.tsx +++ b/src/script/components/UserSearchableList.tsx @@ -82,7 +82,7 @@ export const UserSearchableList: React.FC = ({ */ const fetchMembersFromBackend = useCallback( debounce(async (query: string, ignoreMembers: User[]) => { - const resultUsers = await searchRepository.searchByName(query); + const resultUsers = await searchRepository.searchByName(query, selfUser.teamId); const selfTeamId = selfUser.teamId; const foundMembers = resultUsers.filter(user => user.teamId === selfTeamId); const ignoreIds = ignoreMembers.map(member => member.id); diff --git a/src/script/components/VerificationBadge/VerificationBadges.tsx b/src/script/components/VerificationBadge/VerificationBadges.tsx index c635d0fd0aa8..0f073c4dcc2f 100644 --- a/src/script/components/VerificationBadge/VerificationBadges.tsx +++ b/src/script/components/VerificationBadge/VerificationBadges.tsx @@ -146,6 +146,12 @@ const MLSVerificationBadge = ({context, MLSStatus}: {MLSStatus?: MLSStatuses; co ); + case MLSStatuses.REVOKED: + return ( + + + + ); case MLSStatuses.EXPIRES_SOON: return ( diff --git a/src/script/conversation/ConversationRepository.test.ts b/src/script/conversation/ConversationRepository.test.ts index a62ffb4a69bb..397456bc8bd6 100644 --- a/src/script/conversation/ConversationRepository.test.ts +++ b/src/script/conversation/ConversationRepository.test.ts @@ -538,6 +538,7 @@ describe('ConversationRepository', () => { .mockReturnValueOnce(proteus1to1Conversation); jest.spyOn(conversationRepository['conversationService'], 'deleteConversationFromDb'); jest.spyOn(conversationRepository['conversationService'], 'blacklistConversation'); + jest.spyOn(conversationRepository['eventRepository'], 'injectEvent').mockResolvedValueOnce(undefined); const conversationEntity = await conversationRepository.getInitialised1To1Conversation(otherUser); @@ -560,6 +561,7 @@ describe('ConversationRepository', () => { proteus1to1Conversation.qualifiedId, ); expect(container.resolve(Core).service!.conversation.establishMLS1to1Conversation).toHaveBeenCalled(); + expect(conversationRepository['eventRepository'].injectEvent).toHaveBeenCalled(); expect(conversationRepository['conversationState'].conversations()).not.toEqual( expect.arrayContaining([proteus1to1Conversation]), ); @@ -1945,22 +1947,16 @@ describe('ConversationRepository', () => { describe('checkForDeletedConversations', () => { it('removes conversations that have been deleted on the backend', async () => { - const existingGroup = _generateConversation(); const deletedGroup = _generateConversation(); const conversationRepository = testFactory.conversation_repository!; - spyOn(testFactory.conversation_service, 'getConversationById').and.callFake(({id}) => { - if (id === deletedGroup.id) { - // eslint-disable-next-line prefer-promise-reject-errors - return Promise.reject({code: HTTP_STATUS.NOT_FOUND}); - } - return Promise.resolve(); + jest.spyOn(testFactory.conversation_service!, 'getConversationByIds').mockResolvedValue({ + not_found: [deletedGroup], }); - await conversationRepository['saveConversation'](existingGroup); await conversationRepository['saveConversation'](deletedGroup); const currentNbConversations = conversationRepository['conversationState'].conversations().length; - await testFactory.conversation_repository.checkForDeletedConversations(); + await testFactory.conversation_repository!.syncDeletedConversations(); expect(conversationRepository['conversationState'].conversations()).toHaveLength(currentNbConversations - 1); }); diff --git a/src/script/conversation/ConversationRepository.ts b/src/script/conversation/ConversationRepository.ts index 01fda1a97f50..d829b8a4d599 100644 --- a/src/script/conversation/ConversationRepository.ts +++ b/src/script/conversation/ConversationRepository.ts @@ -89,6 +89,7 @@ import { MLSConversation, isProteus1to1ConversationWithUser, ProteusConversation, + isConnectionRequestConversation, } from './ConversationSelectors'; import {ConversationService} from './ConversationService'; import {ConversationState} from './ConversationState'; @@ -1407,13 +1408,21 @@ export class ConversationRepository { * @param mlsConversation - mls 1:1 conversation * @returns {shouldOpenMLS1to1Conversation, wasProteus1to1Replaced} - whether proteus 1:1 was replaced with mls and whether it was an active conversation and mls 1:1 conversation should be opened in the UI */ - private readonly replaceProteus1to1WithMLS = async ( + private readonly migrateProteus1to1MLS = async ( otherUserId: QualifiedId, mlsConversation: MLSConversation, ): Promise<{shouldOpenMLS1to1Conversation: boolean; wasProteus1to1Replaced: boolean}> => { const proteusConversations = this.conversationState.findProteus1to1Conversations(otherUserId); if (!proteusConversations || proteusConversations.length < 1) { + // Even if we don't have proteus 1:1 conversation, we still want to blacklist the proteus 1:1 conversation + // which is by default assigned to connection entity by backend (so it's not being fetched anymore). + const otherUser = this.userRepository.findUserById(otherUserId); + const conversationId = otherUser?.connection()?.conversationId; + + if (conversationId) { + await this.blacklistConversation(conversationId); + } return {shouldOpenMLS1to1Conversation: false, wasProteus1to1Replaced: false}; } @@ -1464,6 +1473,12 @@ export class ConversationRepository { ConversationMapper.updateProperties(mlsConversation, updates); + const wasProteus1to1ActiveConversation = proteusConversations.some(conversation => + this.conversationState.isActiveConversation(conversation), + ); + + const wasProteusConnectionIncomingRequest = proteusConversations.some(isConnectionRequestConversation); + await Promise.allSettled( proteusConversations.map(async proteusConversation => { this.logger.info(`Deleting proteus 1:1 conversation ${proteusConversation.id}`); @@ -1472,9 +1487,11 @@ export class ConversationRepository { }), ); - const wasProteus1to1ActiveConversation = - !!proteusConversations && - proteusConversations.some(conversation => this.conversationState.isActiveConversation(conversation)); + // Because of the current architecture and the fact that we present a connection request as a conversation of connect type, + // we don't want to inject conversation migrated event if the only proteus 1:1 conversation we had was a connection request. + if (!wasProteusConnectionIncomingRequest) { + await this.inject1to1MigratedToMLS(mlsConversation); + } const isMLS1to1ActiveConversation = this.conversationState.isActiveConversation(mlsConversation); @@ -1595,7 +1612,7 @@ export class ConversationRepository { } // If proteus 1:1 conversation with the same user is known, we have to make sure it is replaced with mls 1:1 conversation. - const {shouldOpenMLS1to1Conversation, wasProteus1to1Replaced} = await this.replaceProteus1to1WithMLS( + const {shouldOpenMLS1to1Conversation, wasProteus1to1Replaced} = await this.migrateProteus1to1MLS( otherUserId, mlsConversation, ); @@ -1677,6 +1694,12 @@ export class ConversationRepository { throw new Error('initProteus1to1Conversation provided with conversation id of conversation that is not proteus'); } + const connection = proteusConversation.connection(); + + if (connection && connection.isConnected()) { + proteusConversation.type(CONVERSATION_TYPE.ONE_TO_ONE); + } + // If proteus is not supported by the other user we have to mark conversation as readonly if (!doesOtherUserSupportProteus) { await this.blacklistConversation(proteusConversationId); @@ -1852,10 +1875,6 @@ export class ConversationRepository { conversation.connection(connectionEntity); - if (connectionEntity.isConnected()) { - conversation.type(CONVERSATION_TYPE.ONE_TO_ONE); - } - const updatedConversation = await this.updateParticipatingUserEntities(conversation); this.conversationState.conversations.notifySubscribers(); @@ -1873,20 +1892,12 @@ export class ConversationRepository { }; /** - * @returns resolves when deleted conversations are locally deleted, too. + * will locally delete conversations that no longer exist on backend side */ - checkForDeletedConversations() { - return Promise.all( - this.conversationState.conversations().map(async conversation => { - try { - await this.conversationService.getConversationById(conversation); - } catch ({code}) { - if (code === HTTP_STATUS.NOT_FOUND) { - this.deleteConversationLocally(conversation, true); - } - } - }), - ); + async syncDeletedConversations() { + const conversationIds = this.conversationState.conversations().map(conversation => conversation.qualifiedId); + const {not_found = []} = await this.conversationService.getConversationByIds(conversationIds); + not_found.forEach(deletedConversationId => this.deleteConversationLocally(deletedConversationId, true)); } private readonly onUserSupportedProtocolsUpdated = async ({user}: {user: User}) => { @@ -2385,6 +2396,11 @@ export class ConversationRepository { return undefined; } + private readonly inject1to1MigratedToMLS = async (conversation: Conversation) => { + const protocolUpdateEvent = EventBuilder.build1to1MigratedToMLS(conversation); + await this.eventRepository.injectEvent(protocolUpdateEvent); + }; + /** * Update conversation protocol * This will update the protocol of the conversation and refetch the conversation to get all new fields (groupId, ciphersuite, epoch and new protocol) @@ -2810,11 +2826,9 @@ export class ConversationRepository { const isExpectedType = typesInSelfConversation.includes(type); if (!isExpectedType) { - return Promise.reject( - new ConversationError( - ConversationError.TYPE.WRONG_CONVERSATION, - ConversationError.MESSAGE.WRONG_CONVERSATION, - ), + throw new ConversationError( + ConversationError.TYPE.WRONG_CONVERSATION, + ConversationError.MESSAGE.WRONG_CONVERSATION, ); } } @@ -3073,6 +3087,7 @@ export class ConversationRepository { case ClientEvent.CONVERSATION.JOINED_AFTER_MLS_MIGRATION: case ClientEvent.CONVERSATION.MLS_MIGRATION_ONGOING_CALL: case ClientEvent.CONVERSATION.MLS_CONVERSATION_RECOVERED: + case ClientEvent.CONVERSATION.ONE2ONE_MIGRATED_TO_MLS: case ClientEvent.CONVERSATION.UNABLE_TO_DECRYPT: case ClientEvent.CONVERSATION.VERIFICATION: case ClientEvent.CONVERSATION.E2EI_VERIFICATION: diff --git a/src/script/conversation/ConversationSelectors.ts b/src/script/conversation/ConversationSelectors.ts index 1dcac39bf0c5..73659f9c7fad 100644 --- a/src/script/conversation/ConversationSelectors.ts +++ b/src/script/conversation/ConversationSelectors.ts @@ -17,6 +17,7 @@ * */ +import {ConnectionStatus} from '@wireapp/api-client/lib/connection/'; import {CONVERSATION_TYPE, ConversationProtocol} from '@wireapp/api-client/lib/conversation/'; import {QualifiedId} from '@wireapp/api-client/lib/user/'; @@ -57,6 +58,10 @@ export function isTeamConversation(conversation: Conversation): boolean { return conversation.type() === CONVERSATION_TYPE.GLOBAL_TEAM; } +export function isConnectionRequestConversation(conversation: Conversation): boolean { + return conversation.type() === CONVERSATION_TYPE.CONNECT; +} + interface ProtocolToConversationType { [ConversationProtocol.PROTEUS]: ProteusConversation; [ConversationProtocol.MLS]: MLSConversation; @@ -78,7 +83,7 @@ const is1to1ConversationWithUser = } const isProteusConnectType = - protocol === ConversationProtocol.PROTEUS && conversation.type() === CONVERSATION_TYPE.CONNECT; + protocol === ConversationProtocol.PROTEUS && isConnectionRequestConversation(conversation); if (!conversation.is1to1() && !isProteusConnectType) { return false; @@ -96,3 +101,16 @@ export const isProteus1to1ConversationWithUser = (userId: QualifiedId) => export const isMLS1to1ConversationWithUser = (userId: QualifiedId) => is1to1ConversationWithUser(userId, ConversationProtocol.MLS); + +export const isReadableConversation = (conversation: Conversation): boolean => { + const states_to_filter = [ + ConnectionStatus.MISSING_LEGAL_HOLD_CONSENT, + ConnectionStatus.BLOCKED, + ConnectionStatus.CANCELLED, + ConnectionStatus.PENDING, + ]; + + const connection = conversation.connection(); + + return !(isSelfConversation(conversation) || (connection && states_to_filter.includes(connection.status()))); +}; diff --git a/src/script/conversation/ConversationState.ts b/src/script/conversation/ConversationState.ts index 7b22dfaf1151..c8cb1197785f 100644 --- a/src/script/conversation/ConversationState.ts +++ b/src/script/conversation/ConversationState.ts @@ -17,7 +17,6 @@ * */ -import {ConnectionStatus} from '@wireapp/api-client/lib/connection/'; import {QualifiedId} from '@wireapp/api-client/lib/user'; import ko from 'knockout'; import {container, singleton} from 'tsyringe'; @@ -32,6 +31,7 @@ import { isMLSConversation, isProteus1to1ConversationWithUser, isSelfConversation, + isReadableConversation, } from './ConversationSelectors'; import {Conversation} from '../entity/Conversation'; @@ -103,21 +103,7 @@ export class ConversationState { }); this.filteredConversations = ko.pureComputed(() => { - return this.conversations().filter(conversationEntity => { - const states_to_filter = [ - ConnectionStatus.MISSING_LEGAL_HOLD_CONSENT, - ConnectionStatus.BLOCKED, - ConnectionStatus.CANCELLED, - ConnectionStatus.PENDING, - ]; - - const connection = conversationEntity.connection(); - - return !( - isSelfConversation(conversationEntity) || - (connection && states_to_filter.includes(connection.status())) - ); - }); + return this.conversations().filter(isReadableConversation); }); this.connectedUsers = ko.pureComputed(() => { diff --git a/src/script/conversation/ConversationVerificationStateHandler/MLS/MLSStateHandler.test.ts b/src/script/conversation/ConversationVerificationStateHandler/MLS/MLSStateHandler.test.ts index cc13b3bee75a..ce0e8395e2d1 100644 --- a/src/script/conversation/ConversationVerificationStateHandler/MLS/MLSStateHandler.test.ts +++ b/src/script/conversation/ConversationVerificationStateHandler/MLS/MLSStateHandler.test.ts @@ -47,7 +47,7 @@ describe('MLSConversationVerificationStateHandler', () => { it('should do nothing if MLS service is not available', () => { core.service!.mls = undefined; - const t = () => registerMLSConversationVerificationStateHandler(undefined, conversationState, core); + const t = () => registerMLSConversationVerificationStateHandler(undefined, undefined, conversationState, core); expect(t).not.toThrow(); }); @@ -55,7 +55,7 @@ describe('MLSConversationVerificationStateHandler', () => { it('should do nothing if e2eIdentity service is not available', () => { core.service!.e2eIdentity = undefined; - registerMLSConversationVerificationStateHandler(undefined, conversationState, core); + registerMLSConversationVerificationStateHandler(undefined, undefined, conversationState, core); expect(core.service?.mls?.on).not.toHaveBeenCalled(); }); @@ -69,7 +69,7 @@ describe('MLSConversationVerificationStateHandler', () => { .spyOn(core.service!.mls!, 'on') .mockImplementation((_event, listener) => (triggerEpochChange = listener) as any); - registerMLSConversationVerificationStateHandler(undefined, conversationState, core); + registerMLSConversationVerificationStateHandler(undefined, undefined, conversationState, core); triggerEpochChange({groupId}); await new Promise(resolve => setTimeout(resolve, 0)); @@ -84,7 +84,7 @@ describe('MLSConversationVerificationStateHandler', () => { .spyOn(core.service!.mls!, 'on') .mockImplementation((_event, listener) => (triggerEpochChange = listener) as any); - registerMLSConversationVerificationStateHandler(undefined, conversationState, core); + registerMLSConversationVerificationStateHandler(undefined, undefined, conversationState, core); triggerEpochChange({groupId}); await new Promise(resolve => setTimeout(resolve, 0)); @@ -99,7 +99,7 @@ describe('MLSConversationVerificationStateHandler', () => { .spyOn(core.service!.mls!, 'on') .mockImplementation((_event, listener) => (triggerEpochChange = listener) as any); - registerMLSConversationVerificationStateHandler(undefined, conversationState, core); + registerMLSConversationVerificationStateHandler(undefined, undefined, conversationState, core); triggerEpochChange({groupId}); await new Promise(resolve => setTimeout(resolve, 0)); @@ -116,7 +116,7 @@ describe('MLSConversationVerificationStateHandler', () => { .spyOn(core.service!.mls!, 'on') .mockImplementation((_event, listener) => (triggerEpochChange = listener) as any); - registerMLSConversationVerificationStateHandler(undefined, conversationState, core); + registerMLSConversationVerificationStateHandler(undefined, undefined, conversationState, core); triggerEpochChange({groupId: newConversation.groupId}); setTimeout(() => { diff --git a/src/script/conversation/ConversationVerificationStateHandler/MLS/MLSStateHandler.ts b/src/script/conversation/ConversationVerificationStateHandler/MLS/MLSStateHandler.ts index 342756d86416..abc780b830c6 100644 --- a/src/script/conversation/ConversationVerificationStateHandler/MLS/MLSStateHandler.ts +++ b/src/script/conversation/ConversationVerificationStateHandler/MLS/MLSStateHandler.ts @@ -17,11 +17,18 @@ * */ +import {CONVERSATION_TYPE} from '@wireapp/api-client/lib/conversation'; import {QualifiedId} from '@wireapp/api-client/lib/user'; import {E2eiConversationState} from '@wireapp/core/lib/messagingProtocols/mls'; import {container} from 'tsyringe'; -import {getConversationVerificationState, getUsersIdentities, MLSStatuses} from 'src/script/E2EIdentity'; +import { + getActiveWireIdentity, + getConversationVerificationState, + getUsersIdentities, + MLSStatuses, +} from 'src/script/E2EIdentity'; +import {Conversation} from 'src/script/entity/Conversation'; import {E2EIVerificationMessageType} from 'src/script/message/E2EIVerificationMessageType'; import {Core} from 'src/script/service/CoreSingleton'; import {Logger, getLogger} from 'Util/Logger'; @@ -37,6 +44,7 @@ class MLSConversationVerificationStateHandler { public constructor( private readonly onConversationVerificationStateChange: OnConversationE2EIVerificationStateChange, + private readonly onSelfClientCertificateRevoked: () => Promise, private readonly conversationState: ConversationState, private readonly core: Core, ) { @@ -47,7 +55,9 @@ class MLSConversationVerificationStateHandler { } // We hook into the newEpoch event of the MLS service to check if the conversation needs to be verified or degraded - this.core.service.mls.on('newEpoch', this.checkConversationVerificationState); + this.core.service.mls.on('newEpoch', this.onEpochChanged); + this.core.service.e2eIdentity.on('remoteCrlChanged', this.checkAllConversationsVerificationState); + this.core.service.e2eIdentity.on('selfCrlChanged', this.checkSelfCertificateRevocation); } /** @@ -88,7 +98,34 @@ class MLSConversationVerificationStateHandler { }); } - private checkConversationVerificationState = async ({groupId}: {groupId: string}): Promise => { + /** + * This function checks if self client certificate is revoked + */ + private checkSelfCertificateRevocation = async (): Promise => { + const activeIdentity = await getActiveWireIdentity(); + + if (!activeIdentity) { + return; + } + + const isRevoked = activeIdentity.status === MLSStatuses.REVOKED; + + if (isRevoked) { + await this.onSelfClientCertificateRevoked(); + } + + await this.checkAllConversationsVerificationState(); + }; + + /** + * This function checks all conversations if they are verified or degraded and updates them accordingly + */ + private checkAllConversationsVerificationState = async (): Promise => { + const conversations = this.conversationState.conversations(); + await Promise.all(conversations.map(conversation => this.checkConversationVerificationState(conversation))); + }; + + private onEpochChanged = async ({groupId}: {groupId: string}): Promise => { // There could be a race condition where we would receive an epoch update for a conversation that is not yet known by the webapp. // We just wait for it to be available and then check the verification state const conversation = await waitFor(() => @@ -99,11 +136,16 @@ class MLSConversationVerificationStateHandler { return this.logger.warn(`Epoch changed but conversation could not be found after waiting for 5 seconds`); } - if (!isMLSConversation(conversation)) { + return this.checkConversationVerificationState(conversation); + }; + + private checkConversationVerificationState = async (conversation: Conversation): Promise => { + const isSelfConversation = conversation.type() === CONVERSATION_TYPE.SELF; + if (!isMLSConversation(conversation) || isSelfConversation) { return; } - const verificationState = await getConversationVerificationState(groupId); + const verificationState = await getConversationVerificationState(conversation.groupId); if ( verificationState === E2eiConversationState.NotVerified && @@ -121,8 +163,14 @@ class MLSConversationVerificationStateHandler { export const registerMLSConversationVerificationStateHandler = ( onConversationVerificationStateChange: OnConversationE2EIVerificationStateChange = () => {}, + onSelfClientCertificateRevoked: () => Promise = async () => {}, conversationState: ConversationState = container.resolve(ConversationState), core: Core = container.resolve(Core), ): void => { - new MLSConversationVerificationStateHandler(onConversationVerificationStateChange, conversationState, core); + new MLSConversationVerificationStateHandler( + onConversationVerificationStateChange, + onSelfClientCertificateRevoked, + conversationState, + core, + ); }; diff --git a/src/script/conversation/EventBuilder.ts b/src/script/conversation/EventBuilder.ts index b6d80ede2c80..902acd68a1a2 100644 --- a/src/script/conversation/EventBuilder.ts +++ b/src/script/conversation/EventBuilder.ts @@ -78,6 +78,7 @@ export type VoiceChannelDeactivateEvent = ConversationEvent< export type AllVerifiedEventData = {type: VerificationMessageType.VERIFIED}; export type AllVerifiedEvent = ConversationEvent; +export type OneToOneMigratedToMlsEvent = ConversationEvent; export type AssetAddEvent = ConversationEvent< CONVERSATION.ASSET_ADD, { @@ -252,6 +253,7 @@ export type ClientConversationEvent = | MemberLeaveEvent | MemberJoinEvent | OneToOneCreationEvent + | OneToOneMigratedToMlsEvent | VoiceChannelDeactivateEvent | FileTypeRestrictedEvent | CallingTimeoutEvent @@ -290,6 +292,17 @@ export const EventBuilder = { }; }, + build1to1MigratedToMLS(conversationEntity: Conversation): OneToOneMigratedToMlsEvent { + return { + ...buildQualifiedId(conversationEntity), + time: new Date(conversationEntity.getNextTimestamp()).toISOString(), + type: ClientEvent.CONVERSATION.ONE2ONE_MIGRATED_TO_MLS, + from: conversationEntity.selfUser().id, + data: undefined, + id: createUuid(), + }; + }, + buildAllVerified(conversationEntity: Conversation): AllVerifiedEvent { return { ...buildQualifiedId(conversationEntity), diff --git a/src/script/conversation/EventMapper.ts b/src/script/conversation/EventMapper.ts index e68d41bd45b7..d9d8bf9f2aef 100644 --- a/src/script/conversation/EventMapper.ts +++ b/src/script/conversation/EventMapper.ts @@ -67,6 +67,7 @@ import {MessageTimerUpdateMessage} from '../entity/message/MessageTimerUpdateMes import {MissedMessage} from '../entity/message/MissedMessage'; import {MLSConversationRecoveredMessage} from '../entity/message/MLSConversationRecoveredMessage'; import {MLSMigrationFinalisationOngoingCallMessage} from '../entity/message/MLSMigrationFinalisationOngoingCallMessage'; +import {OneToOneMigratedToMlsMessage} from '../entity/message/OneToOneMigratedToMlsMessage'; import {PingMessage} from '../entity/message/PingMessage'; import {ProtocolUpdateMessage} from '../entity/message/ProtocolUpdateMessage'; import {ReceiptModeUpdateMessage} from '../entity/message/ReceiptModeUpdateMessage'; @@ -356,6 +357,11 @@ export class EventMapper { break; } + case ClientEvent.CONVERSATION.ONE2ONE_MIGRATED_TO_MLS: { + messageEntity = this._mapEventOneToOneMigratedToMls(); + break; + } + case ClientEvent.CONVERSATION.TEAM_MEMBER_LEAVE: { messageEntity = this._mapEventTeamMemberLeave(event); break; @@ -678,10 +684,17 @@ export class EventMapper { /** * Maps JSON data of local MLS conversation recovered event to message entity. */ - private _mapEventMLSConversationRecovered(): MissedMessage { + private _mapEventMLSConversationRecovered(): MLSConversationRecoveredMessage { return new MLSConversationRecoveredMessage(); } + /** + * Maps 1:1 conversation migrated to mls event to message entity. + */ + private _mapEventOneToOneMigratedToMls(): OneToOneMigratedToMlsMessage { + return new OneToOneMigratedToMlsMessage(); + } + /** * Maps JSON data of `conversation.knock` message into message entity. */ diff --git a/server/routes/E2EIProxy/route.ts b/src/script/entity/message/OneToOneMigratedToMlsMessage.ts similarity index 51% rename from server/routes/E2EIProxy/route.ts rename to src/script/entity/message/OneToOneMigratedToMlsMessage.ts index 0f50792e24d8..173b94cb20f8 100644 --- a/server/routes/E2EIProxy/route.ts +++ b/src/script/entity/message/OneToOneMigratedToMlsMessage.ts @@ -17,25 +17,20 @@ * */ -import {Router} from 'express'; +import {Config} from 'src/script/Config'; +import {SystemMessageType} from 'src/script/message/SystemMessageType'; +import {replaceLink, t} from 'Util/LocalizerUtil'; -import {OIDCProxyRoutePath, getTargetUrlWithQueryParams} from './common'; -import {OIDCProxy} from './proxy'; +import {SystemMessage} from './SystemMessage'; -export const OIDCProxyRoute = () => { - return Router().use(OIDCProxyRoutePath, (req, res, next) => { - // Redirect to the target URL if the shouldBeRedirected query parameter is set - try { - const {shouldBeRedirected, targetUrlWithQueryParams} = getTargetUrlWithQueryParams(req); - - if (shouldBeRedirected) { - return res.redirect(targetUrlWithQueryParams.href); - } - - // Apply the proxy middleware - OIDCProxy(req, res, next); - } catch (e) { - res.status(500).send(e.message); - } - }); -}; +export class OneToOneMigratedToMlsMessage extends SystemMessage { + constructor() { + super(); + this.system_message_type = SystemMessageType.ONE2ONE_MIGRATED_TO_MLS; + this.caption = t( + 'conversationProtocolUpdatedToMLS', + {}, + replaceLink(Config.getConfig().URL.SUPPORT.MLS_LEARN_MORE), + ); + } +} diff --git a/src/script/error/BaseError.ts b/src/script/error/BaseError.ts index 46c031db0dfa..b8dd37f5f323 100644 --- a/src/script/error/BaseError.ts +++ b/src/script/error/BaseError.ts @@ -27,11 +27,9 @@ export class BaseError extends Error { type: BASE_ERROR_TYPE | string; constructor(type: BASE_ERROR_TYPE | string, message: string) { - super(); + super(message); this.type = type; - this.message = message; - this.stack = new Error().stack; this.name = this.constructor.name; } diff --git a/src/script/event/Client.ts b/src/script/event/Client.ts index f83c2b3a96fb..c6268e724f37 100644 --- a/src/script/event/Client.ts +++ b/src/script/event/Client.ts @@ -51,6 +51,7 @@ export enum CONVERSATION { VOICE_CHANNEL_ACTIVATE = 'conversation.voice-channel-activate', VOICE_CHANNEL_DEACTIVATE = 'conversation.voice-channel-deactivate', E2EI_VERIFICATION = 'conversation.e2ei-verification', + ONE2ONE_MIGRATED_TO_MLS = 'conversation.one2one-migrated-to-mls', } export enum USER { diff --git a/src/script/event/EventTypeHandling.ts b/src/script/event/EventTypeHandling.ts index b801a5c9b477..b8c1c6663ee5 100644 --- a/src/script/event/EventTypeHandling.ts +++ b/src/script/event/EventTypeHandling.ts @@ -59,6 +59,7 @@ export const EventTypeHandling = { ClientEvent.CONVERSATION.JOINED_AFTER_MLS_MIGRATION, ClientEvent.CONVERSATION.MLS_MIGRATION_ONGOING_CALL, ClientEvent.CONVERSATION.MLS_CONVERSATION_RECOVERED, + ClientEvent.CONVERSATION.ONE2ONE_MIGRATED_TO_MLS, ClientEvent.CONVERSATION.ONE2ONE_CREATION, ClientEvent.CONVERSATION.TEAM_MEMBER_LEAVE, ClientEvent.CONVERSATION.UNABLE_TO_DECRYPT, diff --git a/src/script/hooks/useAppSoftLock.test.ts b/src/script/hooks/useAppSoftLock.test.ts index 48d34982e9de..ee18a61f2651 100644 --- a/src/script/hooks/useAppSoftLock.test.ts +++ b/src/script/hooks/useAppSoftLock.test.ts @@ -22,12 +22,11 @@ import {renderHook, waitFor} from '@testing-library/react'; import {useAppSoftLock} from './useAppSoftLock'; import {CallingRepository} from '../calling/CallingRepository'; -import {E2EIHandler, isE2EIEnabled} from '../E2EIdentity'; +import {E2EIHandler} from '../E2EIdentity'; import {isFreshMLSSelfClient} from '../E2EIdentity/E2EIdentityVerification'; import {NotificationRepository} from '../notification/NotificationRepository'; const isFreshMLSSelfClientMock = isFreshMLSSelfClient as jest.MockedFn; -const isE2EIEnabledMock = isE2EIEnabled as jest.MockedFn; const E2EIHandlerMock = E2EIHandler as jest.Mocked; jest.mock('../E2EIdentity/E2EIdentityVerification', () => ({ @@ -35,7 +34,6 @@ jest.mock('../E2EIdentity/E2EIdentityVerification', () => ({ })); jest.mock('../E2EIdentity', () => ({ - isE2EIEnabled: jest.fn(), E2EIHandler: { getInstance: jest.fn(), }, @@ -50,6 +48,9 @@ describe('useAppSoftLock', () => { }); it('should not do anything if e2ei is not enabled', () => { + E2EIHandlerMock.getInstance.mockReturnValue({ + isE2EIEnabled: jest.fn(() => false), + } as any); const {result} = renderHook(() => useAppSoftLock(callingRepository, notificationRepository)); expect(result.current).toEqual({softLockEnabled: false}); expect(callingRepository.setSoftLock).not.toHaveBeenCalledWith(true); @@ -57,8 +58,8 @@ describe('useAppSoftLock', () => { }); it('should set soft lock to true if the user has used up the entire grace period', async () => { - isE2EIEnabledMock.mockReturnValue(true); E2EIHandlerMock.getInstance.mockReturnValue({ + isE2EIEnabled: jest.fn(() => true), on: jest.fn((eventName, callback) => callback({enrollmentConfig: {timer: {isSnoozeTimeAvailable: () => false}}})), off: jest.fn(), } as any); @@ -73,9 +74,9 @@ describe('useAppSoftLock', () => { }); it('should set softLock if the device is a fresh new device', async () => { - isE2EIEnabledMock.mockReturnValue(true); isFreshMLSSelfClientMock.mockResolvedValue(true); E2EIHandlerMock.getInstance.mockReturnValue({ + isE2EIEnabled: jest.fn(() => true), on: jest.fn((eventName, callback) => callback({enrollmentConfig: {timer: {isSnoozeTimeAvailable: () => true}}})), off: jest.fn(), } as any); @@ -90,8 +91,8 @@ describe('useAppSoftLock', () => { }); it('should not set softLock if the device is an old device and the grace period is not expireds', async () => { - isE2EIEnabledMock.mockReturnValue(true); E2EIHandlerMock.getInstance.mockReturnValue({ + isE2EIEnabled: jest.fn(() => true), on: jest.fn((eventName, callback) => callback({enrollmentConfig: {timer: {isSnoozeTimeAvailable: () => true}, isFreshMLSSelfClient: false}}), ), diff --git a/src/script/hooks/useAppSoftLock.ts b/src/script/hooks/useAppSoftLock.ts index 89e9bfcd95a4..8a4019c106d4 100644 --- a/src/script/hooks/useAppSoftLock.ts +++ b/src/script/hooks/useAppSoftLock.ts @@ -20,13 +20,11 @@ import {useCallback, useEffect, useState} from 'react'; import {CallingRepository} from '../calling/CallingRepository'; -import {E2EIHandler, EnrollmentConfig, isE2EIEnabled, WireIdentity} from '../E2EIdentity'; +import {E2EIHandler, EnrollmentConfig, WireIdentity} from '../E2EIdentity'; import {shouldEnableSoftLock} from '../E2EIdentity/SnoozableTimer/delay'; import {NotificationRepository} from '../notification/NotificationRepository'; export function useAppSoftLock(callingRepository: CallingRepository, notificationRepository: NotificationRepository) { - const e2eiEnabled = isE2EIEnabled(); - const [softLockEnabled, setSoftLockEnabled] = useState(false); const handleSoftLockActivation = useCallback( @@ -41,16 +39,16 @@ export function useAppSoftLock(callingRepository: CallingRepository, notificatio ); useEffect(() => { - if (!e2eiEnabled) { + const e2eiHandler = E2EIHandler.getInstance(); + if (!e2eiHandler.isE2EIEnabled()) { return () => {}; } - const e2eiHandler = E2EIHandler.getInstance(); e2eiHandler.on('identityUpdated', handleSoftLockActivation); return () => { e2eiHandler.off('identityUpdated', handleSoftLockActivation); }; - }, [e2eiEnabled, handleSoftLockActivation]); + }, [handleSoftLockActivation]); return {softLockEnabled}; } diff --git a/src/script/hooks/useDeviceIdentities.ts b/src/script/hooks/useDeviceIdentities.ts index 2b0459acdb38..006ca06f0604 100644 --- a/src/script/hooks/useDeviceIdentities.ts +++ b/src/script/hooks/useDeviceIdentities.ts @@ -21,13 +21,13 @@ import {useCallback, useEffect, useState} from 'react'; import {QualifiedId} from '@wireapp/api-client/lib/user'; -import {E2EIHandler, getUsersIdentities, isE2EIEnabled, MLSStatuses, WireIdentity} from '../E2EIdentity'; +import {E2EIHandler, getUsersIdentities, MLSStatuses, WireIdentity} from '../E2EIdentity'; export const useUserIdentity = (userId: QualifiedId, groupId?: string, updateAfterEnrollment?: boolean) => { const [deviceIdentities, setDeviceIdentities] = useState(); const refreshDeviceIdentities = useCallback(async () => { - if (!isE2EIEnabled() || !groupId) { + if (!E2EIHandler.getInstance().isE2EIEnabled() || !groupId) { return; } const userIdentities = await getUsersIdentities(groupId, [userId]); diff --git a/src/script/hooks/useRelativeTimestamp.tsx b/src/script/hooks/useRelativeTimestamp.tsx index d664d12df25d..d348545666c2 100644 --- a/src/script/hooks/useRelativeTimestamp.tsx +++ b/src/script/hooks/useRelativeTimestamp.tsx @@ -23,7 +23,6 @@ import {t} from 'Util/LocalizerUtil'; import { TIME_IN_MILLIS, fromUnixTime, - isYoungerThan2Minutes, isYoungerThan1Hour, isToday, isYesterday, @@ -33,12 +32,13 @@ import { formatLocale, formatDayMonth, isThisYear, + isYoungerThanMinute, } from 'Util/TimeUtil'; export function useRelativeTimestamp(timestamp: number, asDay = false) { const calculateTimestamp = (ts: number, isDay: boolean) => { const date = fromUnixTime(ts / TIME_IN_MILLIS.SECOND); - if (isYoungerThan2Minutes(date)) { + if (isYoungerThanMinute(date)) { return t('conversationJustNow'); } diff --git a/src/script/main/app.ts b/src/script/main/app.ts index 340ab4d8c8c9..b356b53967d6 100644 --- a/src/script/main/app.ts +++ b/src/script/main/app.ts @@ -31,6 +31,7 @@ import {container} from 'tsyringe'; import {Runtime} from '@wireapp/commons'; import {WebAppEvents} from '@wireapp/webapp-events'; +import {PrimaryModal} from 'Components/Modals/PrimaryModal'; import {initializeDataDog} from 'Util/DataDog'; import {DebugUtil} from 'Util/DebugUtil'; import {Environment} from 'Util/Environment'; @@ -63,6 +64,7 @@ import {OnConversationE2EIVerificationStateChange} from '../conversation/Convers import {EventBuilder} from '../conversation/EventBuilder'; import {MessageRepository} from '../conversation/MessageRepository'; import {CryptographyRepository} from '../cryptography/CryptographyRepository'; +import {getModalOptions, ModalType} from '../E2EIdentity/Modals'; import {User} from '../entity/User'; import {AccessTokenError} from '../error/AccessTokenError'; import {AuthError} from '../error/AuthError'; @@ -386,6 +388,16 @@ export class App { const selfUser = await this.initiateSelfUser(); + const {features: teamFeatures, team} = await teamRepository.initTeam(selfUser.teamId); + const e2eiHandler = await configureE2EI(this.logger, teamFeatures); + if (e2eiHandler) { + /* We first try to do the initial enrollment (if the user has not yet enrolled) + * We need to enroll before anything else (in particular joining MLS conversations) + * Until the user is enrolled, we need to pause loading the app + */ + await e2eiHandler.attemptEnrollment(); + } + this.core.configureCoreCallbacks({ groupIdFromConversationId: async conversationId => { const conversation = await conversationRepository.getConversationById(conversationId); @@ -424,29 +436,32 @@ export class App { onProgress(10); telemetry.timeStep(AppInitTimingsStep.INITIALIZED_CRYPTOGRAPHY); - const {members: teamMembers, features: teamFeatures} = await teamRepository.initTeam(selfUser.teamId); - const e2eiHandler = configureE2EI(this.logger, teamFeatures); - if (e2eiHandler) { - /* We first try to do the initial enrollment (if the user has not yet enrolled) - * We need to enroll before anything else (in particular joining MLS conversations) - * Until the user is enrolled, we need to pause loading the app - */ - await e2eiHandler.attemptEnrollment(); - } + const connections = await connectionRepository.getConnections(); telemetry.timeStep(AppInitTimingsStep.RECEIVED_USER_DATA); - const connections = await connectionRepository.getConnections(); telemetry.addStatistic(AppInitStatisticsValue.CONNECTIONS, connections.length, 50); const conversations = await conversationRepository.loadConversations(); - await userRepository.loadUsers(selfUser, connections, conversations, teamMembers); + // We load all the users the self user is connected with + const contacts = await userRepository.loadUsers(selfUser, connections, conversations); + + if (team) { + // If we are in the context of team, we load the team members metadata (user roles) + await teamRepository.updateTeamMembersByIds( + team, + contacts.filter(user => user.teamId === team.id).map(({id}) => id), + ); + } if (supportsMLS()) { //if mls is supported, we need to initialize the callbacks (they are used when decrypting messages) conversationRepository.initMLSConversationRecoveredListener(); - registerMLSConversationVerificationStateHandler(this.updateConversationE2EIVerificationState); + registerMLSConversationVerificationStateHandler( + this.updateConversationE2EIVerificationState, + this.showClientCertificateRevokedWarning, + ); } onProgress(25, t('initReceivedUserData')); @@ -492,10 +507,10 @@ export class App { telemetry.timeStep(AppInitTimingsStep.UPDATED_FROM_NOTIFICATIONS); telemetry.addStatistic(AppInitStatisticsValue.NOTIFICATIONS, totalNotifications, 100); - eventTrackerRepository.init(propertiesRepository.properties.settings.privacy.telemetry_sharing); onProgress(97.5, t('initUpdatedFromNotifications', this.config.BRAND_NAME)); const clientEntities = await clientRepository.updateClientsForSelf(); + await eventTrackerRepository.init(propertiesRepository.properties.settings.privacy.telemetry_sharing); onProgress(99); @@ -526,7 +541,11 @@ export class App { if (e2eiHandler) { // At the end of the process (once conversations are loaded and joined), we can check if we need to renew the user's certificate - await e2eiHandler.attemptRenewal(); + try { + await e2eiHandler.attemptRenewal(); + } catch (error) { + this.logger.error('Failed to renew user certificate: ', error); + } } return selfUser; } catch (error) { @@ -851,4 +870,13 @@ export class App { break; } }; + + private showClientCertificateRevokedWarning = async () => { + const {modalOptions, modalType} = getModalOptions({ + type: ModalType.SELF_CERTIFICATE_REVOKED, + primaryActionFn: () => this.logout(SIGN_OUT_REASON.APP_INIT, false), + }); + + PrimaryModal.show(modalType, modalOptions); + }; } diff --git a/src/script/message/SystemMessageType.ts b/src/script/message/SystemMessageType.ts index c6308b93e474..2f9650e42c37 100644 --- a/src/script/message/SystemMessageType.ts +++ b/src/script/message/SystemMessageType.ts @@ -37,5 +37,6 @@ export enum SystemMessageType { MEMBER_LEAVE = 'leave', NORMAL = 'normal', MLS_CONVERSATION_RECOVERED = 'mls-conversation-recovered', + ONE2ONE_MIGRATED_TO_MLS = 'one2one-migrated-to-mls', E2EI_VERIFIED = 'e2ei-verified', } diff --git a/src/script/mls/MLSConversations.ts b/src/script/mls/MLSConversations.ts index a7e8f3246f25..4ea7d001c52f 100644 --- a/src/script/mls/MLSConversations.ts +++ b/src/script/mls/MLSConversations.ts @@ -75,10 +75,7 @@ export async function initMLSGroupConversations( //otherwise we should try joining via external commit await conversationService.joinByExternalCommit(qualifiedId); - - if (onSuccessfulJoin) { - return onSuccessfulJoin(mlsConversation); - } + onSuccessfulJoin?.(mlsConversation); } catch (error) { onError?.(mlsConversation, error); } diff --git a/src/script/page/AppMain.tsx b/src/script/page/AppMain.tsx index 9e7ad5ed13ae..5193a093ddcc 100644 --- a/src/script/page/AppMain.tsx +++ b/src/script/page/AppMain.tsx @@ -35,7 +35,7 @@ import {showUserModal, UserModal} from 'Components/Modals/UserModal'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {AppLock} from './AppLock'; -import {FeatureConfigChangeHandler} from './components/FeatureConfigChange/FeatureConfigChangeHandler/FeatureConfigChangeHandler'; +import {useE2EIFeatureConfigUpdate} from './components/FeatureConfigChange/FeatureConfigChangeHandler/Features/useE2EIFeatureConfigUpdate'; import {FeatureConfigChangeNotifier} from './components/FeatureConfigChange/FeatureConfigChangeNotifier'; import {WindowTitleUpdater} from './components/WindowTitleUpdater'; import {LeftSidebar} from './LeftSidebar'; @@ -216,6 +216,8 @@ export const AppMain: FC = ({ } }, [locked]); + useE2EIFeatureConfigUpdate(repositories.team); + return ( = ({ {!locked && ( <> - id); const onlyRemoteUsers = userEntities.filter(user => !localUserIds.includes(user.id)); const results = inTeam diff --git a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/FeatureConfigChangeHandler.tsx b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/FeatureConfigChangeHandler.tsx deleted file mode 100644 index b8088cebe1cb..000000000000 --- a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/FeatureConfigChangeHandler.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Wire - * Copyright (C) 2023 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import {useEffect} from 'react'; - -import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {getLogger} from 'Util/Logger'; - -import {configureE2EI} from './Features/E2EIdentity'; - -import {TeamState} from '../../../../team/TeamState'; - -const logger = getLogger('FeatureConfigChangeHandler'); - -type Props = { - teamState: TeamState; -}; - -export function FeatureConfigChangeHandler({teamState}: Props): null { - const {teamFeatures: config} = useKoSubscribableChildren(teamState, ['teamFeatures']); - - useEffect(() => { - if (config) { - // initialize feature handlers - configureE2EI(logger, config)?.attemptEnrollment(); - } - }, [config]); - - return null; -} diff --git a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/E2EIdentity.ts b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/E2EIdentity.ts index 2fbcc30d90bb..e50ab8529797 100644 --- a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/E2EIdentity.ts +++ b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/E2EIdentity.ts @@ -19,12 +19,14 @@ import {FeatureStatus, FEATURE_KEY, FeatureList} from '@wireapp/api-client/lib/team'; +import {Config} from 'src/script/Config'; import {E2EIHandler} from 'src/script/E2EIdentity'; import {Logger} from 'Util/Logger'; +import {supportsMLS} from 'Util/util'; import {hasE2EIVerificationExpiration, hasMLSDefaultProtocol} from '../../../../../guards/Protocol'; -export const configureE2EI = (logger: Logger, config: FeatureList): undefined | E2EIHandler => { +export const configureE2EI = (logger: Logger, config: FeatureList): undefined | Promise => { const e2eiConfig = config[FEATURE_KEY.MLSE2EID]; const mlsConfig = config[FEATURE_KEY.MLS]; // Check if MLS or MLS E2EIdentity feature is existent @@ -32,6 +34,10 @@ export const configureE2EI = (logger: Logger, config: FeatureList): undefined | return undefined; } + if (!supportsMLS() && Config.getConfig().FEATURE.ENABLE_E2EI) { + return undefined; + } + // Check if E2EIdentity feature is enabled if (e2eiConfig?.status === FeatureStatus.ENABLED) { // Check if MLS feature is enabled diff --git a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/useE2EIFeatureConfigUpdate.ts b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/useE2EIFeatureConfigUpdate.ts new file mode 100644 index 000000000000..ff680a4baa79 --- /dev/null +++ b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeHandler/Features/useE2EIFeatureConfigUpdate.ts @@ -0,0 +1,55 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {useEffect} from 'react'; + +import {FEATURE_KEY, FeatureList} from '@wireapp/api-client/lib/team'; + +import { + FeatureUpdateType, + detectTeamFeatureUpdate, +} from 'src/script/team/TeamFeatureConfigChangeDetector/TeamFeatureConfigChangeDetector'; +import {TeamRepository} from 'src/script/team/TeamRepository'; +import {getLogger} from 'Util/Logger'; + +import {configureE2EI} from './E2EIdentity'; + +const logger = getLogger('useE2EIFeatureConfigUpdate'); + +const onConfigUpdate = async (configUpdate: { + prevFeatureList?: FeatureList | undefined; + newFeatureList: FeatureList; +}) => { + const {type} = detectTeamFeatureUpdate(configUpdate, FEATURE_KEY.MLSE2EID); + + if (type !== FeatureUpdateType.UNCHANGED) { + const client = await configureE2EI(logger, configUpdate.newFeatureList); + return client?.attemptEnrollment(); + } +}; + +export const useE2EIFeatureConfigUpdate = (teamRepository: TeamRepository) => { + useEffect(() => { + teamRepository.on('featureConfigUpdated', onConfigUpdate); + + return () => { + teamRepository.off('featureConfigUpdated', onConfigUpdate); + }; + }, [teamRepository]); +}; diff --git a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeNotifier/FeatureConfigChangeNotifier.test.tsx b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeNotifier/FeatureConfigChangeNotifier.test.tsx index 0cc5ba32cf6e..ff8250e35c2b 100644 --- a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeNotifier/FeatureConfigChangeNotifier.test.tsx +++ b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeNotifier/FeatureConfigChangeNotifier.test.tsx @@ -18,7 +18,8 @@ */ import {act, render, waitFor} from '@testing-library/react'; -import {FeatureStatus, FEATURE_KEY} from '@wireapp/api-client/lib/team/feature'; +import {FeatureStatus, FEATURE_KEY, FeatureList} from '@wireapp/api-client/lib/team/feature'; +import {Runtime} from '@wireapp/commons/lib/util/Runtime'; import {PrimaryModal} from 'Components/Modals/PrimaryModal'; import en from 'I18n/en-US.json'; @@ -36,9 +37,11 @@ describe('FeatureConfigChangeNotifier', () => { beforeEach(() => { showModalSpy.mockClear(); localStorage.clear(); + jest.spyOn(Runtime, 'isDesktopApp').mockReturnValue(true); + jest.spyOn(Runtime, 'isWindows').mockReturnValue(true); }); - const baseConfig = { + const baseConfig: FeatureList = { [FEATURE_KEY.FILE_SHARING]: { status: FeatureStatus.DISABLED, }, @@ -55,6 +58,10 @@ describe('FeatureConfigChangeNotifier', () => { [FEATURE_KEY.CONVERSATION_GUEST_LINKS]: { status: FeatureStatus.DISABLED, }, + [FEATURE_KEY.ENFORCE_DOWNLOAD_PATH]: { + status: FeatureStatus.DISABLED, + config: {enforcedDownloadLocation: ''}, + }, }; it.each([ @@ -74,6 +81,11 @@ describe('FeatureConfigChangeNotifier', () => { 'Generating guest links is now enabled for all group admins.', 'Generating guest links is now disabled for all group admins.', ], + [ + FEATURE_KEY.ENFORCE_DOWNLOAD_PATH, + 'Enforced Download Path is enabled. The App will restart for the new settings to take effect.', + 'Enforced Download Path is disabled. You will need to restart the app if you want to save downloads in a new location.', + ], ] as const)('shows a modal when feature %s is turned on and off', async (feature, enabledString, disabledString) => { const teamState = new TeamState(); render(); @@ -86,17 +98,21 @@ describe('FeatureConfigChangeNotifier', () => { ...baseConfig, [feature]: { status: FeatureStatus.ENABLED, + ...(feature === FEATURE_KEY.ENFORCE_DOWNLOAD_PATH && {config: {enforcedDownloadLocation: 'dlpath'}}), }, }); }); await waitFor(() => { expect(showModalSpy).toHaveBeenCalledTimes(1); - expect(showModalSpy).toHaveBeenCalledWith(PrimaryModal.type.ACKNOWLEDGE, { - text: expect.objectContaining({ - htmlMessage: enabledString, + expect(showModalSpy).toHaveBeenCalledWith( + PrimaryModal.type.ACKNOWLEDGE, + expect.objectContaining({ + text: expect.objectContaining({ + htmlMessage: enabledString, + }), }), - }); + ); }); act(() => { @@ -104,6 +120,7 @@ describe('FeatureConfigChangeNotifier', () => { ...baseConfig, [feature]: { status: FeatureStatus.DISABLED, + ...(feature === FEATURE_KEY.ENFORCE_DOWNLOAD_PATH && {config: {enforcedDownloadLocation: ''}}), }, }); }); @@ -113,11 +130,14 @@ describe('FeatureConfigChangeNotifier', () => { } else { await waitFor(() => { expect(showModalSpy).toHaveBeenCalledTimes(2); - expect(showModalSpy).toHaveBeenCalledWith(PrimaryModal.type.ACKNOWLEDGE, { - text: expect.objectContaining({ - htmlMessage: disabledString, + expect(showModalSpy).toHaveBeenCalledWith( + PrimaryModal.type.ACKNOWLEDGE, + expect.objectContaining({ + text: expect.objectContaining({ + htmlMessage: disabledString, + }), }), - }); + ); }); } }); @@ -179,6 +199,9 @@ describe('FeatureConfigChangeNotifier', () => { await waitFor(() => { expect(showModalSpy).toHaveBeenCalledTimes(1); expect(showModalSpy).toHaveBeenCalledWith(PrimaryModal.type.ACKNOWLEDGE, { + hideCloseBtn: false, + primaryAction: undefined, + preventClose: false, text: expect.objectContaining({ htmlMessage: expectedText, }), diff --git a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeNotifier/FeatureConfigChangeNotifier.ts b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeNotifier/FeatureConfigChangeNotifier.ts index 3a3930b674c1..caa84b270c0b 100644 --- a/src/script/page/components/FeatureConfigChange/FeatureConfigChangeNotifier/FeatureConfigChangeNotifier.ts +++ b/src/script/page/components/FeatureConfigChange/FeatureConfigChangeNotifier/FeatureConfigChangeNotifier.ts @@ -27,8 +27,13 @@ import { FeatureStatus, SelfDeletingTimeout, } from '@wireapp/api-client/lib/team/feature/'; +import {amplify} from 'amplify'; + +import {Runtime} from '@wireapp/commons'; +import {WebAppEvents} from '@wireapp/webapp-events'; import {PrimaryModal} from 'Components/Modals/PrimaryModal'; +import {Action} from 'Components/Modals/PrimaryModal/PrimaryModalTypes'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {StringIdentifer, replaceLink, t} from 'Util/LocalizerUtil'; import {getLogger} from 'Util/Logger'; @@ -44,8 +49,8 @@ const featureNotifications: Partial< FEATURE_KEY, ( oldConfig?: Feature | FeatureWithoutConfig, - newConfig?: Feature | FeatureWithoutConfig, - ) => undefined | {htmlMessage: string; title: StringIdentifer} + newConfig?: FeatureWithoutConfig | Feature | undefined, + ) => undefined | {htmlMessage: string; title: StringIdentifer; primaryAction?: Action} > > = { [FEATURE_KEY.FILE_SHARING]: (oldConfig, newConfig) => { @@ -74,6 +79,43 @@ const featureNotifications: Partial< title: 'featureConfigChangeModalAudioVideoHeadline', }; }, + [FEATURE_KEY.ENFORCE_DOWNLOAD_PATH]: (oldConfig, newConfig) => { + if ( + newConfig && + 'config' in newConfig && + oldConfig && + 'config' in oldConfig && + Runtime.isDesktopApp() && + Runtime.isWindows() + ) { + const status = wasTurnedOnOrOff(oldConfig, newConfig); + const configStatus = newConfig?.config?.enforcedDownloadLocation !== oldConfig?.config?.enforcedDownloadLocation; + if (!status && !configStatus) { + return undefined; + } + amplify.publish( + WebAppEvents.TEAM.DOWNLOAD_PATH_UPDATE, + newConfig.status === FeatureStatus.ENABLED ? newConfig.config.enforcedDownloadLocation : undefined, + ); + return { + htmlMessage: + status === FeatureStatus.ENABLED + ? t('featureConfigChangeModalDownloadPathEnabled') + : status === FeatureStatus.DISABLED + ? t('featureConfigChangeModalDownloadPathDisabled') + : t('featureConfigChangeModalDownloadPathChanged'), + title: 'featureConfigChangeModalDownloadPathHeadline', + primaryAction: { + action: () => { + if (Runtime.isDesktopApp() && status !== FeatureStatus.DISABLED) { + amplify.publish(WebAppEvents.LIFECYCLE.RESTART); + } + }, + }, + }; + } + return undefined; + }, [FEATURE_KEY.SELF_DELETING_MESSAGES]: (oldConfig, newConfig) => { if (!oldConfig || !('config' in oldConfig) || !newConfig || !('config' in newConfig)) { return undefined; @@ -166,6 +208,8 @@ export function FeatureConfigChangeNotifier({teamState, selfUserId}: Props): nul Object.entries(featureNotifications).forEach(([feature, getMessage]) => { const featureKey = feature as FEATURE_KEY; const message = getMessage(previous?.[featureKey], config[featureKey]); + const isEnforceDownloadPath = featureKey === FEATURE_KEY.ENFORCE_DOWNLOAD_PATH; + if (!message) { return; } @@ -181,6 +225,9 @@ export function FeatureConfigChangeNotifier({teamState, selfUserId}: Props): nul brandName: Config.getConfig().BRAND_NAME, }), }, + primaryAction: message.primaryAction, + hideCloseBtn: isEnforceDownloadPath, + preventClose: isEnforceDownloadPath, }); }); } diff --git a/src/script/search/SearchRepository.test.ts b/src/script/search/SearchRepository.test.ts index b3cc35fae6e7..5c215db18a93 100644 --- a/src/script/search/SearchRepository.test.ts +++ b/src/script/search/SearchRepository.test.ts @@ -19,6 +19,7 @@ import {User} from 'src/script/entity/User'; import {generateUser} from 'test/helper/UserGenerator'; +import {createUuid} from 'Util/uuid'; import {SearchRepository} from './SearchRepository'; @@ -233,6 +234,27 @@ describe('SearchRepository', () => { expect(suggestions.length).toEqual(localUsers.length - 1); }); + + it('returns team users first', async () => { + const [searchRepository, {apiClient, userRepository}] = buildSearchRepository(); + const teamId = createUuid(); + const teamUsers = [generateUser(undefined, {team: teamId}), generateUser(undefined, {team: teamId})]; + const otherTeamUsers = [generateUser(undefined, {team: createUuid()})]; + const localUsers = [generateUser(), generateUser(), generateUser()]; + const allUsers = [...localUsers, ...otherTeamUsers, ...teamUsers]; + userRepository.getUsersById.mockResolvedValue(allUsers); + + const searchResults = allUsers.map(({qualifiedId}) => qualifiedId); + jest + .spyOn(apiClient.api.user, 'getSearchContacts') + .mockResolvedValue({response: {documents: searchResults}} as any); + + const suggestions = await searchRepository.searchByName('term', teamId); + + expect(suggestions.length).toEqual(allUsers.length); + expect(suggestions[0].teamId).toEqual(teamId); + expect(suggestions[1].teamId).toEqual(teamId); + }); }); }); diff --git a/src/script/search/SearchRepository.ts b/src/script/search/SearchRepository.ts index 21778d894453..89424cffeb8a 100644 --- a/src/script/search/SearchRepository.ts +++ b/src/script/search/SearchRepository.ts @@ -178,11 +178,11 @@ export class SearchRepository { * @note We skip a few results as connection changes need a while to reflect on the backend. * * @param query Search query - * @param isHandle Is query a user handle + * @param teamId Current team ID the selfUser is in (will help prioritize results) * @param maxResults Maximum number of results * @returns Resolves with the search results */ - async searchByName(term: string, maxResults = CONFIG.MAX_SEARCH_RESULTS): Promise { + async searchByName(term: string, teamId = '', maxResults = CONFIG.MAX_SEARCH_RESULTS): Promise { const {query, isHandleQuery} = this.normalizeQuery(term); const [rawName, rawDomain] = this.core.backendFeatures.isFederated ? query.split('@') : [query]; const [name, domain] = validateHandle(rawName, rawDomain) ? [rawName, rawDomain] : [query]; @@ -199,6 +199,10 @@ export class SearchRepository { .filter(user => !user.isMe) .filter(user => !isHandleQuery || startsWith(user.username(), query)) .sort((userA, userB) => { + if (userA.teamId === teamId && userB.teamId !== teamId) { + // put team members first + return -1; + } return isHandleQuery ? sortByPriority(userA.username(), userB.username(), query) : sortByPriority(userA.name(), userB.name(), query); diff --git a/src/script/self/SelfRepository.test.ts b/src/script/self/SelfRepository.test.ts index 2bba1e36a803..d996e01a8fec 100644 --- a/src/script/self/SelfRepository.test.ts +++ b/src/script/self/SelfRepository.test.ts @@ -18,7 +18,6 @@ */ import {ConversationProtocol} from '@wireapp/api-client/lib/conversation'; -import {TeamFeatureConfigurationUpdateEvent, TEAM_EVENT} from '@wireapp/api-client/lib/event'; import {FeatureList, FeatureStatus} from '@wireapp/api-client/lib/team'; import {FEATURE_KEY} from '@wireapp/api-client/lib/team/feature'; import {act} from 'react-dom/test-utils'; @@ -206,47 +205,23 @@ describe('SelfRepository', () => { }, }; - const mockedMLSFeatureUpdateEvent: TeamFeatureConfigurationUpdateEvent = { - name: FEATURE_KEY.MLS, - team: '', - time: '', - data: { - status: FeatureStatus.ENABLED, + const mockedNewFeatureList: FeatureList = { + [FEATURE_KEY.MLS]: { config: generateMLSFeatureConfig(newSupportedProtocols), + status: FeatureStatus.ENABLED, }, - - type: TEAM_EVENT.FEATURE_CONFIG_UPDATE, }; jest.spyOn(selfRepository, 'refreshSelfSupportedProtocols').mockImplementationOnce(jest.fn()); - selfRepository['teamRepository'].emit('featureUpdated', { - event: mockedMLSFeatureUpdateEvent, + selfRepository['teamRepository'].emit('featureConfigUpdated', { prevFeatureList: mockedFeatureList, + newFeatureList: mockedNewFeatureList, }); expect(selfRepository.refreshSelfSupportedProtocols).toHaveBeenCalled(); }); - it('refreshes self supported protocols on team refresh', async () => { - const selfRepository = await testFactory.exposeSelfActors(); - - const selfUser = selfRepository['userState'].self()!; - - const initialProtocols = [ConversationProtocol.PROTEUS]; - selfUser.supportedProtocols(initialProtocols); - - const evaluatedProtocols = [ConversationProtocol.PROTEUS, ConversationProtocol.MLS]; - - jest.spyOn(SelfSupportedProtocols, 'evaluateSelfSupportedProtocols').mockResolvedValueOnce(evaluatedProtocols); - jest.spyOn(selfRepository['selfService'], 'putSupportedProtocols'); - - await act(async () => selfRepository['teamRepository'].emit('teamRefreshed')); - - expect(selfUser.supportedProtocols()).toEqual(evaluatedProtocols); - expect(selfRepository['selfService'].putSupportedProtocols).toHaveBeenCalledWith(evaluatedProtocols); - }); - it('refreshes self supported protocols after mls feature is enabled', async () => { const selfRepository = await testFactory.exposeSelfActors(); @@ -263,25 +238,22 @@ describe('SelfRepository', () => { }, }; - const mockedMLSFeatureUpdateEvent: TeamFeatureConfigurationUpdateEvent = { - name: FEATURE_KEY.MLS, - team: '', - time: '', - data: { - status: newFeatureStatus, + const mockedNewFeatureList: FeatureList = { + [FEATURE_KEY.MLS]: { config: generateMLSFeatureConfig(newSupportedProtocols), + status: newFeatureStatus, }, - - type: TEAM_EVENT.FEATURE_CONFIG_UPDATE, }; jest.spyOn(selfRepository, 'refreshSelfSupportedProtocols').mockImplementationOnce(jest.fn()); - selfRepository['teamRepository'].emit('featureUpdated', { - event: mockedMLSFeatureUpdateEvent, + selfRepository['teamRepository'].emit('featureConfigUpdated', { prevFeatureList: mockedFeatureList, + newFeatureList: mockedNewFeatureList, }); + // Await for async work caused by event emitter to finish + await Promise.resolve(); expect(selfRepository.refreshSelfSupportedProtocols).toHaveBeenCalled(); }); @@ -298,50 +270,49 @@ describe('SelfRepository', () => { }, }; - const mockedMLSFeatureUpdateEvent: TeamFeatureConfigurationUpdateEvent = { - name: FEATURE_KEY.MLS, - team: '', - time: '', - data: { - status: FeatureStatus.ENABLED, + const mockedNewFeatureList: FeatureList = { + [FEATURE_KEY.MLS]: { config: generateMLSFeatureConfig(newSupportedProtocols), + status: FeatureStatus.ENABLED, }, - - type: TEAM_EVENT.FEATURE_CONFIG_UPDATE, }; jest.spyOn(selfRepository, 'refreshSelfSupportedProtocols').mockImplementationOnce(jest.fn()); - selfRepository['teamRepository'].emit('featureUpdated', { - event: mockedMLSFeatureUpdateEvent, + selfRepository['teamRepository'].emit('featureConfigUpdated', { prevFeatureList: mockedFeatureList, + newFeatureList: mockedNewFeatureList, }); + await Promise.resolve(); expect(selfRepository.refreshSelfSupportedProtocols).not.toHaveBeenCalled(); }); it('refreshes self supported protocols on mls migration feature config update', async () => { const selfRepository = await testFactory.exposeSelfActors(); - const mockedMLSMigrationFeatureUpdateEvent: TeamFeatureConfigurationUpdateEvent = { - name: FEATURE_KEY.MLS_MIGRATION, - team: '', - time: '', - data: { - status: FeatureStatus.ENABLED, - config: {finaliseRegardlessAfter: '', startTime: ''}, + const mockedFeatureList: FeatureList = { + [FEATURE_KEY.MLS_MIGRATION]: { + config: {}, + status: FeatureStatus.DISABLED, }, + }; - type: TEAM_EVENT.FEATURE_CONFIG_UPDATE, + const mockedNewFeatureList: FeatureList = { + [FEATURE_KEY.MLS_MIGRATION]: { + config: {}, + status: FeatureStatus.ENABLED, + }, }; jest.spyOn(selfRepository, 'refreshSelfSupportedProtocols').mockImplementationOnce(jest.fn()); - selfRepository['teamRepository'].emit('featureUpdated', { - event: mockedMLSMigrationFeatureUpdateEvent, - prevFeatureList: {}, + selfRepository['teamRepository'].emit('featureConfigUpdated', { + prevFeatureList: mockedFeatureList, + newFeatureList: mockedNewFeatureList, }); + await Promise.resolve(); expect(selfRepository.refreshSelfSupportedProtocols).toHaveBeenCalled(); }); }); diff --git a/src/script/self/SelfRepository.ts b/src/script/self/SelfRepository.ts index f9e3b704d3e1..a0ce30748815 100644 --- a/src/script/self/SelfRepository.ts +++ b/src/script/self/SelfRepository.ts @@ -18,7 +18,7 @@ */ import {ConversationProtocol} from '@wireapp/api-client/lib/conversation'; -import {FEATURE_KEY, FeatureMLS} from '@wireapp/api-client/lib/team/feature/'; +import {FEATURE_KEY, FeatureStatus, FeatureList} from '@wireapp/api-client/lib/team/feature/'; import {amplify} from 'amplify'; import {container} from 'tsyringe'; @@ -33,6 +33,10 @@ import {evaluateSelfSupportedProtocols} from './SelfSupportedProtocols/SelfSuppo import {ClientEntity, ClientRepository} from '../client'; import {Core} from '../service/CoreSingleton'; +import { + FeatureUpdateType, + detectTeamFeatureUpdate, +} from '../team/TeamFeatureConfigChangeDetector/TeamFeatureConfigChangeDetector'; import {TeamRepository} from '../team/TeamRepository'; import {UserRepository} from '../user/UserRepository'; import {UserState} from '../user/UserState'; @@ -58,18 +62,10 @@ export class SelfRepository extends TypedEventEmitter { // It's possible that they have removed proteus client, and now all their clients are mls-capable. amplify.subscribe(WebAppEvents.CLIENT.REMOVE, this.refreshSelfSupportedProtocols); - teamRepository.on('teamRefreshed', this.refreshSelfSupportedProtocols); - teamRepository.on('featureUpdated', ({event, prevFeatureList}) => { - if (event.name === FEATURE_KEY.MLS) { - void this.handleMLSFeatureUpdate(event.data, prevFeatureList?.[FEATURE_KEY.MLS]); - } - - // MLS Migration feature config is also considered when evaluating self supported protocols - // We still allow proteus to be used if migration is enabled (but startTime has not been reached yet), - // or when migration is enabled, started and not finalised yet (finaliseRegardlessAfter has not arrived yet) - if (event.name === FEATURE_KEY.MLS_MIGRATION) { - void this.refreshSelfSupportedProtocols(); - } + teamRepository.on('featureConfigUpdated', async configUpdate => { + await this.handleMLSFeatureUpdate(configUpdate); + await this.handleMLSMigrationFeatureUpdate(configUpdate); + await this.handleDownloadPathFeatureUpdate(configUpdate); }); } @@ -81,22 +77,76 @@ export class SelfRepository extends TypedEventEmitter { return selfUser; } - private handleMLSFeatureUpdate = async (newMLSFeature: FeatureMLS, prevMLSFeature?: FeatureMLS) => { - const prevSupportedProtocols = prevMLSFeature?.config.supportedProtocols ?? []; - const newSupportedProtocols = newMLSFeature.config.supportedProtocols ?? []; + private handleMLSFeatureUpdate = async ({ + prevFeatureList, + newFeatureList, + }: { + prevFeatureList?: FeatureList; + newFeatureList?: FeatureList; + }) => { + const mlsFeatureUpdate = detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS); + + // Nothing to do if MLS feature was not changed + if (mlsFeatureUpdate.type === FeatureUpdateType.UNCHANGED) { + return; + } - const hasFeatureStatusChanged = prevMLSFeature?.status !== newMLSFeature.status; + // If MLS feature was enabled or disabled, we need to re-evaluate self supported protocols + if (mlsFeatureUpdate.type === FeatureUpdateType.DISABLED || mlsFeatureUpdate.type === FeatureUpdateType.ENABLED) { + await this.refreshSelfSupportedProtocols(); + return; + } - const hasTeamSupportedProtocolsChanged = !( - prevSupportedProtocols.length === newSupportedProtocols.length && - [...prevSupportedProtocols].every(protocol => newSupportedProtocols.includes(protocol)) - ); + if (mlsFeatureUpdate.type === FeatureUpdateType.CONFIG_CHANGED) { + const {prev, next} = mlsFeatureUpdate; + + const prevSupportedProtocols = prev?.config.supportedProtocols ?? []; + const newSupportedProtocols = next.config.supportedProtocols ?? []; + + const hasTeamSupportedProtocolsChanged = !( + prevSupportedProtocols.length === newSupportedProtocols.length && + [...prevSupportedProtocols].every(protocol => newSupportedProtocols.includes(protocol)) + ); + + if (hasTeamSupportedProtocolsChanged) { + await this.refreshSelfSupportedProtocols(); + } + } + }; + + private handleMLSMigrationFeatureUpdate = async (featureUpdate: { + prevFeatureList?: FeatureList; + newFeatureList?: FeatureList; + }) => { + // MLS Migration feature config is also considered when evaluating self supported protocols + // We still allow proteus to be used if migration is enabled (but startTime has not been reached yet), + // or when migration is enabled, started and not finalised yet (finaliseRegardlessAfter has not arrived yet) + const {type} = detectTeamFeatureUpdate(featureUpdate, FEATURE_KEY.MLS_MIGRATION); - if (hasFeatureStatusChanged || hasTeamSupportedProtocolsChanged) { + if (type !== FeatureUpdateType.UNCHANGED) { await this.refreshSelfSupportedProtocols(); } }; + private handleDownloadPathFeatureUpdate = async (featureUpdate: { + prevFeatureList?: FeatureList; + newFeatureList?: FeatureList; + }) => { + const {type, next} = detectTeamFeatureUpdate(featureUpdate, FEATURE_KEY.ENFORCE_DOWNLOAD_PATH); + + if (type === FeatureUpdateType.UNCHANGED) { + return; + } + + this.handleDownloadPathUpdate( + next?.status === FeatureStatus.ENABLED ? next.config.enforcedDownloadLocation : undefined, + ); + }; + + private handleDownloadPathUpdate = (dlPath?: string) => { + amplify.publish(WebAppEvents.TEAM.DOWNLOAD_PATH_UPDATE, dlPath); + }; + /** * Update self user's list of supported protocols. * It will send a request to the backend to change the supported protocols and then update the user in the local state. diff --git a/src/script/service/CoreSingleton.ts b/src/script/service/CoreSingleton.ts index 06c44ea32a5c..56d5f4e6f474 100644 --- a/src/script/service/CoreSingleton.ts +++ b/src/script/service/CoreSingleton.ts @@ -28,7 +28,6 @@ import {createStorageEngine, DatabaseTypes} from './StoreEngineProvider'; import {SystemCrypto, wrapSystemCrypto} from './utils/systemCryptoWrapper'; import {Config} from '../Config'; -import {isE2EIEnabled} from '../E2EIdentity'; declare global { interface Window { @@ -63,7 +62,7 @@ export class Core extends Account { ? { keyingMaterialUpdateThreshold: Config.getConfig().FEATURE.MLS_CONFIG_KEYING_MATERIAL_UPDATE_THRESHOLD, cipherSuite: Config.getConfig().FEATURE.MLS_CONFIG_DEFAULT_CIPHERSUITE, - useE2EI: isE2EIEnabled(), + useE2EI: Config.getConfig().FEATURE.ENABLE_E2EI, } : undefined, } diff --git a/src/script/team/TeamFeatureConfigChangeDetector/TeamFeatureConfigChangeDetector.test.ts b/src/script/team/TeamFeatureConfigChangeDetector/TeamFeatureConfigChangeDetector.test.ts new file mode 100644 index 000000000000..888ec0d5426f --- /dev/null +++ b/src/script/team/TeamFeatureConfigChangeDetector/TeamFeatureConfigChangeDetector.test.ts @@ -0,0 +1,201 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {ConversationProtocol} from '@wireapp/api-client/lib/conversation'; +import {FEATURE_KEY, FeatureStatus, FeatureMLS, FeatureMLSE2EId, FeatureList} from '@wireapp/api-client/lib/team'; + +import {FeatureUpdateType, detectTeamFeatureUpdate} from './TeamFeatureConfigChangeDetector'; + +describe('TeamFeatureUtil', () => { + describe('hasTeamFeatureChanged', () => { + it(`returns "unchanged" if feature list didn't exist before and it was added with feature disabled`, () => { + const prevFeatureList: FeatureList | undefined = undefined; + const newFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.DISABLED} as unknown as FeatureMLS, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.UNCHANGED, + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + + it(`returns "unchanged" if feature list didn't exist before and it was added without the feature`, () => { + const prevFeatureList: FeatureList | undefined = undefined; + const newFeatureList = { + [FEATURE_KEY.MLSE2EID]: {status: FeatureStatus.DISABLED} as unknown as FeatureMLSE2EId, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.UNCHANGED, + }); + }); + + it(`returns "unchanged" if feature list didn't exist before and it was added without a feature`, () => { + const prevFeatureList: FeatureList | undefined = undefined; + const newFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.DISABLED} as unknown as FeatureMLS, + [FEATURE_KEY.MLSE2EID]: {status: FeatureStatus.DISABLED} as unknown as FeatureMLSE2EId, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.UNCHANGED, + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + + it(`returns "unchanged" if the feature was not in the list before and it was added with disabled status`, () => { + const prevFeatureList = { + [FEATURE_KEY.MLSE2EID]: {status: FeatureStatus.ENABLED} as unknown as FeatureMLSE2EId, + }; + const newFeatureList = { + [FEATURE_KEY.MLSE2EID]: {status: FeatureStatus.ENABLED} as unknown as FeatureMLSE2EId, + [FEATURE_KEY.MLS]: {status: FeatureStatus.DISABLED} as unknown as FeatureMLS, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.UNCHANGED, + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + + it('should return "unchanged" if the feature list was not defined previously but feature is not included in the new list', () => { + const prevFeatureList: FeatureList | undefined = undefined; + const newFeatureList = {}; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.UNCHANGED, + }); + }); + + it("should return 'unchanged' if the feature config has changed but it's still disabled", () => { + const prevFeatureList = { + [FEATURE_KEY.MLS]: { + status: FeatureStatus.DISABLED, + config: {defaultProtocol: ConversationProtocol.PROTEUS}, + } as unknown as FeatureMLS, + }; + const newFeatureList = { + [FEATURE_KEY.MLS]: { + status: FeatureStatus.DISABLED, + config: {defaultProtocol: ConversationProtocol.MLS}, + } as unknown as FeatureMLS, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.UNCHANGED, + prev: prevFeatureList[FEATURE_KEY.MLS], + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + + it(`returns "enabled" if the feature list didn't exist before and it was added with feature enabled`, () => { + const prevFeatureList: FeatureList | undefined = undefined; + const newFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.ENABLED} as unknown as FeatureMLS, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.ENABLED, + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + + it(`returns "enabled" if feature didn't exist before and it was added with feature enabled`, () => { + const prevFeatureList = {}; + const newFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.ENABLED} as unknown as FeatureMLS, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.ENABLED, + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + + it(`returns "enabled" if feature's status has changed from disabled to enabled`, () => { + const prevFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.DISABLED} as unknown as FeatureMLS, + }; + const newFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.ENABLED} as unknown as FeatureMLS, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.ENABLED, + prev: prevFeatureList[FEATURE_KEY.MLS], + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + + it(`returns "disabled" if feature config was removed from the feature list`, () => { + const prevFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.DISABLED} as unknown as FeatureMLS, + }; + const newFeatureList = {}; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.DISABLED, + prev: prevFeatureList[FEATURE_KEY.MLS], + }); + }); + + it(`returns "disabled" after feature status was changed from enabled to disabled`, () => { + const prevFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.ENABLED} as unknown as FeatureMLS, + }; + const newFeatureList = { + [FEATURE_KEY.MLS]: {status: FeatureStatus.DISABLED} as unknown as FeatureMLS, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.DISABLED, + prev: prevFeatureList[FEATURE_KEY.MLS], + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + + it('should return "config changed" when feature config has changed and feature is still enabled', () => { + const prevFeatureList = { + [FEATURE_KEY.MLS]: { + status: FeatureStatus.ENABLED, + config: { + defaultProtocol: ConversationProtocol.PROTEUS, + }, + } as unknown as FeatureMLS, + }; + + const newFeatureList = { + [FEATURE_KEY.MLS]: { + status: FeatureStatus.ENABLED, + config: { + defaultProtocol: ConversationProtocol.MLS, + }, + } as unknown as FeatureMLS, + [FEATURE_KEY.MLSE2EID]: {} as unknown as FeatureMLSE2EId, + }; + + expect(detectTeamFeatureUpdate({prevFeatureList, newFeatureList}, FEATURE_KEY.MLS)).toEqual({ + type: FeatureUpdateType.CONFIG_CHANGED, + prev: prevFeatureList[FEATURE_KEY.MLS], + next: newFeatureList[FEATURE_KEY.MLS], + }); + }); + }); +}); diff --git a/src/script/team/TeamFeatureConfigChangeDetector/TeamFeatureConfigChangeDetector.ts b/src/script/team/TeamFeatureConfigChangeDetector/TeamFeatureConfigChangeDetector.ts new file mode 100644 index 000000000000..ea596ce28c31 --- /dev/null +++ b/src/script/team/TeamFeatureConfigChangeDetector/TeamFeatureConfigChangeDetector.ts @@ -0,0 +1,126 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {FeatureList, FEATURE_KEY, FeatureStatus} from '@wireapp/api-client/lib/team'; + +export enum FeatureUpdateType { + ENABLED = 'ENABLED', // Feature was enabled or didn't exist before and now it was added and is enabled + DISABLED = 'DISABLED', // Feature was previously enabled and now it was removed or disabled + CONFIG_CHANGED = 'CONFIG_CHANGED', // Feature was enabled and now it's config has changed + UNCHANGED = 'UNCHANGED', // Feature is enabled or disabled or doesn't exist and it's config hasn't changed +} + +type FeatureUpdateEnabled = { + type: FeatureUpdateType.ENABLED; + prev?: FeatureList[Key]; + next: FeatureList[Key]; +}; + +type FeatureUpdateDisabled = { + type: FeatureUpdateType.DISABLED; + prev: FeatureList[Key]; + next?: FeatureList[Key]; +}; + +type FeatureUpdateConfigChanged = { + type: FeatureUpdateType.CONFIG_CHANGED; + prev: FeatureList[Key]; + next: NonNullable; +}; + +type FeatureUpdateUnchanged = { + type: FeatureUpdateType.UNCHANGED; + prev?: FeatureList[Key]; + next?: FeatureList[Key]; +}; + +type FeatureUpdate = + | FeatureUpdateEnabled + | FeatureUpdateDisabled + | FeatureUpdateConfigChanged + | FeatureUpdateUnchanged; + +export const detectTeamFeatureUpdate = ( + {prevFeatureList, newFeatureList}: {prevFeatureList?: FeatureList; newFeatureList?: FeatureList}, + key: Key, +): FeatureUpdate => { + const newFeature = newFeatureList?.[key]; + + if (!prevFeatureList) { + // Feature was added and is enabled + if (newFeature && newFeature.status === FeatureStatus.ENABLED) { + return {type: FeatureUpdateType.ENABLED, next: newFeature}; + } + + // Feature was not added or it was added but disabled + return {type: FeatureUpdateType.UNCHANGED, next: newFeature}; + } + + const prevFeature = prevFeatureList[key]; + + const wasFeatureAdded = !prevFeature && newFeature; + + if (wasFeatureAdded) { + // Feature was added and is enabled + if (newFeature.status === FeatureStatus.ENABLED) { + return {type: FeatureUpdateType.ENABLED, next: newFeature}; + } + + // Feature config was added but it is disabled + return {type: FeatureUpdateType.UNCHANGED, next: newFeature}; + } + + const wasFeatureRemoved = prevFeature && !newFeature; + + if (wasFeatureRemoved) { + // Feature was removed + return {type: FeatureUpdateType.DISABLED, prev: prevFeature}; + } + + // This feature was never there; + if (!prevFeature && !newFeature) { + return {type: FeatureUpdateType.UNCHANGED}; + } + + if (!prevFeature || !newFeature) { + throw new Error('This should never happen'); + } + + const hasFeatureStatusChanged = prevFeature.status !== newFeature.status; + + if (hasFeatureStatusChanged) { + if (newFeature.status === FeatureStatus.ENABLED) { + return {type: FeatureUpdateType.ENABLED, prev: prevFeature, next: newFeature}; + } + + return {type: FeatureUpdateType.DISABLED, prev: prevFeature, next: newFeature}; + } + + const hasFeatureConfigChanged = + newFeature.status === FeatureStatus.ENABLED && + 'config' in prevFeature && + 'config' in newFeature && + JSON.stringify(prevFeature.config) !== JSON.stringify(newFeature.config); + + if (hasFeatureConfigChanged) { + return {type: FeatureUpdateType.CONFIG_CHANGED, prev: prevFeature, next: newFeature}; + } + + return {type: FeatureUpdateType.UNCHANGED, prev: prevFeature, next: newFeature}; +}; diff --git a/src/script/team/TeamRepository.test.ts b/src/script/team/TeamRepository.test.ts index 1854e042ca4d..d0c83633333d 100644 --- a/src/script/team/TeamRepository.test.ts +++ b/src/script/team/TeamRepository.test.ts @@ -19,7 +19,6 @@ import {ConversationProtocol} from '@wireapp/api-client/lib/conversation'; import {FeatureList, FeatureStatus} from '@wireapp/api-client/lib/team/feature/'; -import {Permissions} from '@wireapp/api-client/lib/team/member'; import {randomUUID} from 'crypto'; @@ -71,12 +70,6 @@ describe('TeamRepository', () => { has_more: false, }; const team_metadata = teams_data.teams[0]; - const team_members = { - members: [ - {user: randomUUID(), permissions: {copy: Permissions.DEFAULT, self: Permissions.DEFAULT}}, - {user: randomUUID(), permissions: {copy: Permissions.DEFAULT, self: Permissions.DEFAULT}}, - ], - }; describe('getTeam()', () => { it('returns the team entity', async () => { @@ -93,17 +86,6 @@ describe('TeamRepository', () => { }); }); - describe('getAllTeamMembers()', () => { - it('returns team member entities', async () => { - const [teamRepo, {teamService}] = buildConnectionRepository(); - jest.spyOn(teamService, 'getAllTeamMembers').mockResolvedValue({hasMore: false, members: team_members.members}); - const entities = await teamRepo['getAllTeamMembers'](team_metadata.id); - expect(entities.length).toEqual(team_members.members.length); - expect(entities[0].userId).toEqual(team_members.members[0].user); - expect(entities[0].permissions).toEqual(team_members.members[0].permissions); - }); - }); - describe('sendAccountInfo', () => { it('does not crash when there is no team logo', async () => { const [teamRepo] = buildConnectionRepository(); diff --git a/src/script/team/TeamRepository.ts b/src/script/team/TeamRepository.ts index 8790cf95d4d4..ad87d929bc5d 100644 --- a/src/script/team/TeamRepository.ts +++ b/src/script/team/TeamRepository.ts @@ -22,14 +22,12 @@ import type { TeamConversationDeleteEvent, TeamDeleteEvent, TeamEvent, - TeamFeatureConfigurationUpdateEvent, TeamMemberLeaveEvent, } from '@wireapp/api-client/lib/event'; import {TEAM_EVENT} from '@wireapp/api-client/lib/event/TeamEvent'; import {FeatureStatus, FeatureList} from '@wireapp/api-client/lib/team/feature/'; import type {PermissionsData} from '@wireapp/api-client/lib/team/member/PermissionsData'; import type {TeamData} from '@wireapp/api-client/lib/team/team/TeamData'; -import {QualifiedId} from '@wireapp/api-client/lib/user'; import {amplify} from 'amplify'; import {container} from 'tsyringe'; @@ -72,11 +70,10 @@ export interface AccountInfo { } type Events = { - featureUpdated: { + featureConfigUpdated: { prevFeatureList?: FeatureList; - event: TeamFeatureConfigurationUpdateEvent; + newFeatureList: FeatureList; }; - teamRefreshed: void; }; export class TeamRepository extends TypedEventEmitter { @@ -117,15 +114,21 @@ export class TeamRepository extends TypedEventEmitter { ); } - async initTeam(teamId?: string): Promise<{members: QualifiedId[]; features: FeatureList}> { + /** + * Will init the team configuration and all the team members from the contact list. + * @param teamId the Id of the team to init + * @param contacts all the contacts the self user has, team members will be deduced from it. + */ + async initTeam(teamId?: string): Promise<{team: TeamEntity | undefined; features: FeatureList}> { + // async initTeam(teamId?: string): Promise<{members: QualifiedId[]; features: FeatureList}> { const team = await this.getTeam(); // get the fresh feature config from backend const {newFeatureList} = await this.updateFeatureConfig(); if (!teamId) { - return {members: [], features: {}}; + return {team: undefined, features: {}}; } + // Subscribe to team members change and update the user role and guest status this.teamState.teamMembers.subscribe(members => { - // Subscribe to team members change and update the user role and guest status this.userRepository.mapGuestStatus(members); const roles = this.teamState.memberRoles(); members.forEach(user => { @@ -134,14 +137,17 @@ export class TeamRepository extends TypedEventEmitter { } }); }); - const members = await this.loadTeamMembers(team); + this.scheduleTeamRefresh(); - return {members, features: newFeatureList}; + return {team, features: newFeatureList}; } private async updateFeatureConfig(): Promise<{newFeatureList: FeatureList; prevFeatureList?: FeatureList}> { const prevFeatureList = this.teamState.teamFeatures(); const newFeatureList = await this.teamService.getAllTeamFeatures(); + + this.emit('featureConfigUpdated', {prevFeatureList, newFeatureList}); + this.teamState.teamFeatures(newFeatureList); return { @@ -155,11 +161,10 @@ export class TeamRepository extends TypedEventEmitter { try { await this.getTeam(); await this.updateFeatureConfig(); - this.emit('teamRefreshed'); } catch (error) { this.logger.error(error); } - }, TIME_IN_MILLIS.DAY); + }, TIME_IN_MILLIS.SECOND * 30); }; async getTeam(): Promise { @@ -187,14 +192,6 @@ export class TeamRepository extends TypedEventEmitter { return memberEntity; } - private async getAllTeamMembers(teamId: string): Promise { - const {members, hasMore} = await this.teamService.getAllTeamMembers(teamId); - if (!hasMore && members.length) { - return this.teamMapper.mapMembers(members); - } - return []; - } - async conversationHasGuestLinkEnabled(conversationId: string): Promise { return this.teamService.conversationHasGuestLink(conversationId); } @@ -255,10 +252,6 @@ export class TeamRepository extends TypedEventEmitter { this.onMemberLeave(eventJson); break; } - case TEAM_EVENT.FEATURE_CONFIG_UPDATE: { - await this.onFeatureConfigUpdate(eventJson, source); - break; - } case TEAM_EVENT.CONVERSATION_CREATE: default: { this.onUnhandled(eventJson); @@ -327,17 +320,6 @@ export class TeamRepository extends TypedEventEmitter { this.updateMemberRoles(mappedMembers); } - private async loadTeamMembers(teamEntity: TeamEntity): Promise { - const teamMembers = await this.getAllTeamMembers(teamEntity.id); - this.teamState.memberRoles({}); - this.teamState.memberInviters({}); - - this.updateMemberRoles(teamMembers); - return teamMembers - .filter(({userId}) => userId !== this.userState.self().id) - .map(memberEntity => ({domain: this.teamState.teamDomain() ?? '', id: memberEntity.userId})); - } - private getTeamById(teamId: string): Promise { return this.teamService.getTeamById(teamId); } @@ -367,20 +349,6 @@ export class TeamRepository extends TypedEventEmitter { } }; - private readonly onFeatureConfigUpdate = async ( - event: TeamFeatureConfigurationUpdateEvent, - source: EventSource, - ): Promise => { - if (source !== EventSource.WEBSOCKET) { - // Ignore notification stream events - return; - } - - // When we receive a `feature-config.update` event, we will refetch the entire feature config - const {prevFeatureList} = await this.updateFeatureConfig(); - this.emit('featureUpdated', {event, prevFeatureList}); - }; - private onMemberLeave(eventJson: TeamMemberLeaveEvent): void { const { data: {user: userId}, diff --git a/src/script/team/TeamState.ts b/src/script/team/TeamState.ts index 12c451c89aa0..f22935021649 100644 --- a/src/script/team/TeamState.ts +++ b/src/script/team/TeamState.ts @@ -90,8 +90,8 @@ export class TeamState { }); this.classifiedDomains = ko.pureComputed(() => { - return this.teamFeatures()?.classifiedDomains.status === FeatureStatus.ENABLED - ? this.teamFeatures().classifiedDomains.config.domains + return this.teamFeatures()?.classifiedDomains?.status === FeatureStatus.ENABLED + ? this.teamFeatures()?.classifiedDomains?.config.domains : undefined; }); diff --git a/src/script/user/UserRepository.test.ts b/src/script/user/UserRepository.test.ts index f29add7450c9..de88c7d35cdc 100644 --- a/src/script/user/UserRepository.test.ts +++ b/src/script/user/UserRepository.test.ts @@ -265,7 +265,7 @@ describe('UserRepository', () => { const connections = createConnections(users); const fetchUserSpy = jest.spyOn(userService, 'getUsers').mockResolvedValue({found: users}); - await userRepository.loadUsers(new User('self'), connections, [], []); + await userRepository.loadUsers(new User('self'), connections, []); expect(userState.users()).toHaveLength(users.length + 1); expect(fetchUserSpy).toHaveBeenCalledWith(users.map(user => user.qualified_id!)); @@ -277,7 +277,7 @@ describe('UserRepository', () => { const connections = createConnections(users); jest.spyOn(userService, 'getUsers').mockResolvedValue({found: users}); - await userRepository.loadUsers(new User('self'), connections, [], []); + await userRepository.loadUsers(new User('self'), connections, []); expect(userState.users()).toHaveLength(users.length + 1); users.forEach(user => { @@ -297,7 +297,7 @@ describe('UserRepository', () => { jest.spyOn(userRepository['userService'], 'loadUserFromDb').mockResolvedValue(partialUsers as any); const fetchUserSpy = jest.spyOn(userService, 'getUsers').mockResolvedValue({found: localUsers}); - await userRepository.loadUsers(new User('self'), connections, [], []); + await userRepository.loadUsers(new User('self'), connections, []); expect(userState.users()).toHaveLength(localUsers.length + 1); expect(fetchUserSpy).toHaveBeenCalledWith(userIds); @@ -312,7 +312,7 @@ describe('UserRepository', () => { const removeUserSpy = jest.spyOn(userService, 'removeUserFromDb').mockResolvedValue(); jest.spyOn(userService, 'getUsers').mockResolvedValue({found: newUsers}); - await userRepository.loadUsers(new User(), connections, [], []); + await userRepository.loadUsers(new User(), connections, []); expect(userState.users()).toHaveLength(newUsers.length + 1); expect(removeUserSpy).toHaveBeenCalledTimes(localUsers.length); diff --git a/src/script/user/UserRepository.ts b/src/script/user/UserRepository.ts index b31420948bc2..9c2e493a5647 100644 --- a/src/script/user/UserRepository.ts +++ b/src/script/user/UserRepository.ts @@ -196,19 +196,10 @@ export class UserRepository extends TypedEventEmitter { * @param selfUser the user currently logged in (will be excluded from fetch) * @param connections the connection to other users * @param conversations the conversation the user is part of (used to compute extra users that are part of those conversations but not directly connected to the user) - * @param extraUsers other users that would need to be loaded (team users usually that are not direct connections) */ - async loadUsers( - selfUser: User, - connections: ConnectionEntity[], - conversations: Conversation[], - extraUsers: QualifiedId[], - ): Promise { + async loadUsers(selfUser: User, connections: ConnectionEntity[], conversations: Conversation[]): Promise { const conversationMembers = flatten(conversations.map(conversation => conversation.participating_user_ids())); - const allUserIds = connections - .map(connectionEntity => connectionEntity.userId) - .concat(conversationMembers) - .concat(extraUsers); + const allUserIds = connections.map(connectionEntity => connectionEntity.userId).concat(conversationMembers); const users = uniq(allUserIds, false, (userId: QualifiedId) => userId.id); // Remove all users that have non-qualified Ids in DB (there could be duplicated entries one qualified and one non-qualified) @@ -724,16 +715,51 @@ export class UserRepository extends TypedEventEmitter { } } + /** + * Will refetch supported protocols for the given user and (if they changed) update the local user entity. + * @param user - the user to fetch the supported protocols for + */ + private async refreshUserSupportedProtocols(user: User): Promise { + try { + const localSupportedProtocols = user.supportedProtocols(); + const supportedProtocols = await this.userService.getUserSupportedProtocols(user.qualifiedId); + + const haveSupportedProtocolsChanged = + !localSupportedProtocols || + !( + localSupportedProtocols.length === supportedProtocols.length && + [...localSupportedProtocols].every(protocol => supportedProtocols.includes(protocol)) + ); + + if (!haveSupportedProtocolsChanged) { + return; + } + + await this.updateUserSupportedProtocols(user.qualifiedId, supportedProtocols); + this.emit('supportedProtocolsUpdated', {user, supportedProtocols}); + } catch (error) { + this.logger.warn(`Failed to refresh supported protocols for user ${user.qualifiedId.id}`, error); + } + } + /** * Check for supported protocols on user entity locally, otherwise fetch them from the backend. * @param userId - the user to fetch the supported protocols for * @param forceRefetch - if true, the supported protocols will be fetched from the backend even if they are already stored locally */ + public async getUserSupportedProtocols( + userId: QualifiedId, + shouldRefreshUser = false, + ): Promise { + const localUser = this.findUserById(userId); + const localSupportedProtocols = localUser?.supportedProtocols(); + + if (shouldRefreshUser && localUser) { + // Trigger a refresh of the supported protocols in the background. No need to await for this one. + void this.refreshUserSupportedProtocols(localUser); + } - public async getUserSupportedProtocols(userId: QualifiedId, forceRefetch = false): Promise { - const localSupportedProtocols = this.findUserById(userId)?.supportedProtocols(); - - if (!forceRefetch && localSupportedProtocols) { + if (localSupportedProtocols) { return localSupportedProtocols; } diff --git a/src/script/util/TimeUtil.ts b/src/script/util/TimeUtil.ts index 0236354a05c4..6859fc4647e9 100644 --- a/src/script/util/TimeUtil.ts +++ b/src/script/util/TimeUtil.ts @@ -285,7 +285,7 @@ export const formatTimestamp = (timestamp: number | string, longFormat: boolean export const getCurrentDate = () => new Date().toISOString().substring(0, 10); export const getUnixTimestamp = () => Math.floor(Date.now() / TIME_IN_MILLIS.SECOND); export const isBeforeToday = (date: FnDate): boolean => isBefore(date, startOfToday()); -export const isYoungerThan2Minutes = (date: FnDate): boolean => differenceInMinutes(new Date(), date) < 2; +export const isYoungerThanMinute = (date: FnDate): boolean => differenceInMinutes(new Date(), date) < 1; export const isYoungerThan1Hour = (date: FnDate) => differenceInHours(new Date(), date) < 1; export const isYoungerThan7Days = (date: FnDate) => differenceInDays(new Date(), date) < 7; diff --git a/src/script/view_model/CallingViewModel.ts b/src/script/view_model/CallingViewModel.ts index 829a5997945c..8e0037fdb027 100644 --- a/src/script/view_model/CallingViewModel.ts +++ b/src/script/view_model/CallingViewModel.ts @@ -42,7 +42,6 @@ import {PrimaryModal} from '../components/Modals/PrimaryModal'; import {Config} from '../Config'; import {ConversationState} from '../conversation/ConversationState'; import {ConversationVerificationState} from '../conversation/ConversationVerificationState'; -import {isE2EIEnabled} from '../E2EIdentity'; import type {Conversation} from '../entity/Conversation'; import type {User} from '../entity/User'; import type {ElectronDesktopCapturerSource, MediaDevicesHandler} from '../media/MediaDevicesHandler'; @@ -257,7 +256,7 @@ export class CallingViewModel { const memberCount = conversationEntity.participating_user_ets().length; const isE2EIDegraded = conversationEntity.mlsVerificationState() === ConversationVerificationState.DEGRADED; - if (isE2EIEnabled() && isE2EIDegraded) { + if (isE2EIDegraded) { showE2EICallModal(conversationEntity, callType); } else if (memberCount > MAX_USERS_TO_CALL_WITHOUT_CONFIRM) { showMaxUsersToCallModalWithoutConfirm(conversationEntity, callType); diff --git a/src/style/common/variables.less b/src/style/common/variables.less index 1a0dc2d45580..c697e48a0459 100644 --- a/src/style/common/variables.less +++ b/src/style/common/variables.less @@ -233,18 +233,14 @@ body { // ---------------------------------------------------------------------------- // Conversation // ---------------------------------------------------------------------------- -@conversation-max-width: 800px; +@conversation-max-width: 100%; @conversation-message-max-width: 640px; @conversation-message-sender-width: 64px; body { --conversation-message-sender-width: @conversation-message-sender-width; - - --conversation-message-timestamp-width: 140px; - @media (max-width: @screen-md-min) { - --conversation-message-timestamp-width: 60px; - } + --conversation-message-asset-width: 800px; } // ---------------------------------------------------------------------------- diff --git a/src/style/components/asset/common/common.less b/src/style/components/asset/common/common.less index 1b209887c78f..0a57a5e08b94 100644 --- a/src/style/components/asset/common/common.less +++ b/src/style/components/asset/common/common.less @@ -24,6 +24,8 @@ position: relative; display: flex; overflow: hidden; + width: 100%; + max-width: var(--conversation-message-asset-width); min-height: 64px; border-radius: 12px; diff --git a/src/style/components/asset/link-preview-asset.less b/src/style/components/asset/link-preview-asset.less index bfef1522521a..2bdedc3c9106 100644 --- a/src/style/components/asset/link-preview-asset.less +++ b/src/style/components/asset/link-preview-asset.less @@ -20,13 +20,8 @@ // variables @link-preview-height: 88px; -link-preview-asset, .link-preview-asset { .asset-container-style; - width: 100%; -} - -.link-preview-asset { display: flex; width: 100%; cursor: pointer; diff --git a/src/style/components/asset/video-asset.less b/src/style/components/asset/video-asset.less index 9f56914f02a5..c0ee9287a86d 100644 --- a/src/style/components/asset/video-asset.less +++ b/src/style/components/asset/video-asset.less @@ -27,8 +27,10 @@ // Video asset component .video-asset { + .asset-container-style; position: relative; display: block; + flex: 1 1 auto; &__container { .asset-container-style; diff --git a/src/style/content/conversation.less b/src/style/content/conversation.less index 6cd07de508c3..9dee189a82d2 100644 --- a/src/style/content/conversation.less +++ b/src/style/content/conversation.less @@ -61,7 +61,6 @@ } .readonly-message-container { - max-width: calc(800 - var(--conversation-message-timestamp-width)); margin-bottom: 16px; } diff --git a/src/style/content/conversation/input-bar.less b/src/style/content/conversation/input-bar.less index 2bfef2eb8e2a..0bff4136d682 100644 --- a/src/style/content/conversation/input-bar.less +++ b/src/style/content/conversation/input-bar.less @@ -52,9 +52,7 @@ .reset-textarea; width: 100%; - max-width: calc( - @conversation-max-width - @conversation-message-sender-width - var(--conversation-message-timestamp-width) - ); + max-width: @conversation-max-width; height: auto; min-height: @conversation-input-line-height; max-height: @conversation-input-max-height; @@ -108,11 +106,14 @@ .list-unstyled; display: flex; - min-width: var(--conversation-message-timestamp-width); align-items: center; justify-content: flex-end; margin: 0; + &.controls-right-shrinked { + min-width: auto; + } + .conversation-button { padding: 0; } diff --git a/src/style/content/conversation/message-list.less b/src/style/content/conversation/message-list.less index 59f335931990..661be3b52765 100644 --- a/src/style/content/conversation/message-list.less +++ b/src/style/content/conversation/message-list.less @@ -37,7 +37,6 @@ // MESSAGE .message { position: relative; - margin-bottom: 16px; & * { .accent-selection; @@ -158,7 +157,6 @@ .message-header-label { display: flex; min-width: 0; // fixes ellipsis not working with flexbox (FF) - flex: 1; align-items: center; font-size: @font-size-small; font-weight: @font-weight-regular; @@ -309,22 +307,26 @@ display: flex; max-width: @conversation-max-width; justify-content: space-between; + padding-top: 6px; padding-left: @conversation-message-sender-width; &-content { - width: calc(100% - var(--conversation-message-timestamp-width)); - max-width: calc( - @conversation-max-width - @conversation-message-sender-width - var(--conversation-message-timestamp-width) - ); + width: 100%; + max-width: calc(@conversation-max-width - var(--conversation-message-sender-width)); + height: fit-content; + + .text:has(> .iframe-container) { + margin-right: 0; + } } .text { .text-selection; .accent-selection; - display: inline-block; - width: 100%; + display: inline; min-width: 0; + margin-right: 12px; line-height: @line-height-lg; white-space: pre-wrap; word-wrap: break-word; @@ -343,23 +345,14 @@ line-height: 2.5rem; } - .iframe-container { + embed, + iframe, + object { + max-width: var(--conversation-message-asset-width); margin-top: 16px; - margin-bottom: 24px; + aspect-ratio: 16 / 9; } - .iframe-container-video { - position: relative; - padding-bottom: 75%; - - embed, - iframe, - object { - position: absolute; - left: 0; - max-width: 100%; - } - } .message-ephemeral-timer { position: absolute; top: 2px; @@ -389,7 +382,7 @@ .image-asset { position: relative; display: flex; - margin: 8px 0 24px; + max-width: var(--conversation-message-asset-width); cursor: pointer; &--no-image { @@ -422,72 +415,9 @@ } } -// MESSAGE FOOTER -.message-footer { - display: flex; - flex-wrap: wrap; - line-height: @avatar-diameter-xs; -} - -.message-footer-text { - color: var(--gray-70); - font-size: @font-size-xsmall; - - body.theme-dark & { - color: var(--gray-60); - } -} - -.message-footer-icon { - .flex-center; - - width: @conversation-message-sender-width; -} - -.message-footer-label { - display: flex; - overflow: hidden; - flex: 1; - align-items: center; - font-size: @font-size-xs; - - & > span { - overflow: hidden; - text-overflow: ellipsis; - white-space: pre; - } - - > * + * { - margin-left: 8px; - } -} - -.message-footer-bottom { - display: flex; - width: 100%; - flex-wrap: wrap; - margin-top: 4px; - margin-right: var(--conversation-message-timestamp-width); - margin-left: @conversation-message-sender-width; - - > *:not(:last-child) { - margin-right: 8px; - margin-bottom: 8px; - } -} - -.message-footer-close-button { - .square(@avatar-diameter-xs); - .flex-center; - - cursor: pointer; - font-size: @font-size-xs; -} - // MESSAGE - ACTIONS .message-body-actions { display: flex; - min-width: var(--conversation-message-timestamp-width); align-items: flex-start; justify-content: flex-start; padding: 5px; @@ -790,8 +720,9 @@ // MESSAGE SPACING .message-asset { - flex: 1; - margin-top: 8px; + display: flex; + align-items: flex-start; + margin-bottom: 6px; } .message-call, diff --git a/src/style/content/conversation/message-quote.less b/src/style/content/conversation/message-quote.less index 458bd72bedb3..72bbc33def7c 100644 --- a/src/style/content/conversation/message-quote.less +++ b/src/style/content/conversation/message-quote.less @@ -1,9 +1,6 @@ .message-quote { position: relative; - max-width: calc( - @conversation-max-width - var(--conversation-message-timestamp-width) - @conversation-message-sender-width - 16px - ); - padding-right: var(--conversation-message-timestamp-width); + max-width: calc(@conversation-max-width - @conversation-message-sender-width - 16px); padding-left: 16px; margin-bottom: 10px; font-size: @font-size-medium; diff --git a/test/helper/UserGenerator.ts b/test/helper/UserGenerator.ts index 996617d4817a..71b04123ffa1 100644 --- a/test/helper/UserGenerator.ts +++ b/test/helper/UserGenerator.ts @@ -19,7 +19,7 @@ import {faker} from '@faker-js/faker'; import {QualifiedId, UserAssetType} from '@wireapp/api-client/lib/user'; -import type {User as APIClientUser} from '@wireapp/api-client/lib/user/'; +import type {User as APIClientUser} from '@wireapp/api-client/lib/user'; import {createUuid} from 'Util/uuid'; @@ -61,7 +61,7 @@ export function generateAPIUser( }; } -export function generateUser(id?: QualifiedId): User { - const apiUser = generateAPIUser(id); +export function generateUser(id?: QualifiedId, overwites?: Partial): User { + const apiUser = generateAPIUser(id, overwites); return new UserMapper(serverTimeHandler).mapUserFromJson(apiUser, ''); } diff --git a/yarn.lock b/yarn.lock index 097c02ea2aca..97c1c621e934 100644 --- a/yarn.lock +++ b/yarn.lock @@ -52,7 +52,30 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:7.23.7, @babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": +"@babel/core@npm:7.23.9": + version: 7.23.9 + resolution: "@babel/core@npm:7.23.9" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.23.5 + "@babel/generator": ^7.23.6 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-module-transforms": ^7.23.3 + "@babel/helpers": ^7.23.9 + "@babel/parser": ^7.23.9 + "@babel/template": ^7.23.9 + "@babel/traverse": ^7.23.9 + "@babel/types": ^7.23.9 + convert-source-map: ^2.0.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.3 + semver: ^6.3.1 + checksum: 634a511f74db52a5f5a283c1121f25e2227b006c095b84a02a40a9213842489cd82dc7d61cdc74e10b5bcd9bb0a4e28bab47635b54c7e2256d47ab57356e2a76 + languageName: node + linkType: hard + +"@babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": version: 7.23.7 resolution: "@babel/core@npm:7.23.7" dependencies: @@ -75,9 +98,9 @@ __metadata: languageName: node linkType: hard -"@babel/eslint-parser@npm:7.23.3": - version: 7.23.3 - resolution: "@babel/eslint-parser@npm:7.23.3" +"@babel/eslint-parser@npm:7.23.9": + version: 7.23.9 + resolution: "@babel/eslint-parser@npm:7.23.9" dependencies: "@nicolo-ribaudo/eslint-scope-5-internals": 5.1.1-v1 eslint-visitor-keys: ^2.1.0 @@ -85,7 +108,7 @@ __metadata: peerDependencies: "@babel/core": ^7.11.0 eslint: ^7.5.0 || ^8.0.0 - checksum: 9573daebe21af5123c302c307be80cacf1c2bf236a9497068a14726d3944ef55e1282519d0ccf51882dfc369359a3442299c98cb22a419e209924db39d4030fd + checksum: cfb87bc48d005f181807ae8f8357ba9eeb3ece38480084fb5d997bac03ebb4cf709ee197d697f506de8faa7f665fa07579b9b9c2045d86d6c17174b6c1b0c5c9 languageName: node linkType: hard @@ -132,7 +155,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.23.7": +"@babel/helper-create-class-features-plugin@npm:^7.22.15": version: 7.23.7 resolution: "@babel/helper-create-class-features-plugin@npm:7.23.7" dependencies: @@ -151,6 +174,25 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-class-features-plugin@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/helper-create-class-features-plugin@npm:7.23.9" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-member-expression-to-functions": ^7.23.0 + "@babel/helper-optimise-call-expression": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.20 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 0f0c8592ec8833c0fd1d131655de929af07942fd626049d1e8fae5d85c1fe33fad97f7e9457a14b10258bc926a0cb39debc54a553abe8b4f7575c446d1c16d80 + languageName: node + linkType: hard + "@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.15, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": version: 7.22.15 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" @@ -179,6 +221,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-define-polyfill-provider@npm:^0.5.0": + version: 0.5.0 + resolution: "@babel/helper-define-polyfill-provider@npm:0.5.0" + dependencies: + "@babel/helper-compilation-targets": ^7.22.6 + "@babel/helper-plugin-utils": ^7.22.5 + debug: ^4.1.1 + lodash.debounce: ^4.0.8 + resolve: ^1.14.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: d24626b819d3875cb65189d761004e9230f2b3fb60542525c4785616f4b2366741369235a864b744f54beb26d625ae4b0af0c9bb3306b61bf4fccb61e0620020 + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-environment-visitor@npm:7.22.20" @@ -350,6 +407,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/helpers@npm:7.23.9" + dependencies: + "@babel/template": ^7.23.9 + "@babel/traverse": ^7.23.9 + "@babel/types": ^7.23.9 + checksum: 2678231192c0471dbc2fc403fb19456cc46b1afefcfebf6bc0f48b2e938fdb0fef2e0fe90c8c8ae1f021dae5012b700372e4b5d15867f1d7764616532e4a6324 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.23.4": version: 7.23.4 resolution: "@babel/highlight@npm:7.23.4" @@ -370,6 +438,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/parser@npm:7.23.9" + bin: + parser: ./bin/babel-parser.js + checksum: e7cd4960ac8671774e13803349da88d512f9292d7baa952173260d3e8f15620a28a3701f14f709d769209022f9e7b79965256b8be204fc550cfe783cdcabe7c7 + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.23.3" @@ -406,16 +483,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-decorators@npm:7.23.7": - version: 7.23.7 - resolution: "@babel/plugin-proposal-decorators@npm:7.23.7" +"@babel/plugin-proposal-decorators@npm:7.23.9": + version: 7.23.9 + resolution: "@babel/plugin-proposal-decorators@npm:7.23.9" dependencies: - "@babel/helper-create-class-features-plugin": ^7.23.7 + "@babel/helper-create-class-features-plugin": ^7.23.9 "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-decorators": ^7.23.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 53c3d3af451ea75fa48cb26811dce8a9cdcc51ff4bd48fa037482a6527e0c3eec1737541ab0f7e7d5c210cbe81badda15cf043b21049e036ef376deabf176c06 + checksum: 1fac4d8a8ac23c6a3621d43dd2c5cab28006f989a51ea49d8af77c43a6933458a1bedf2cdd259e935bc56bb07c8429ca1c122aaa99e068efd31f65a602aafbec languageName: node linkType: hard @@ -696,6 +773,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-async-generator-functions@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.9" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-remap-async-to-generator": ^7.22.20 + "@babel/plugin-syntax-async-generators": ^7.8.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d402494087a6b803803eb5ab46b837aab100a04c4c5148e38bfa943ea1bbfc1ecfb340f1ced68972564312d3580f550c125f452372e77607a558fbbaf98c31c0 + languageName: node + linkType: hard + "@babel/plugin-transform-async-to-generator@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-async-to-generator@npm:7.23.3" @@ -966,6 +1057,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-systemjs@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.9" + dependencies: + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-module-transforms": ^7.23.3 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cec6abeae6be66fd1a5940c482fe9ff94b689c71fcf4147e179119e4accd09d17d476e36528bc9cb4ab0ec6728fedf48b1c49d0551ea707fb192575d8eac9167 + languageName: node + linkType: hard + "@babel/plugin-transform-modules-umd@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-modules-umd@npm:7.23.3" @@ -1314,7 +1419,97 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:7.23.8, @babel/preset-env@npm:^7.11.0": +"@babel/preset-env@npm:7.23.9": + version: 7.23.9 + resolution: "@babel/preset-env@npm:7.23.9" + dependencies: + "@babel/compat-data": ^7.23.5 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.23.5 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.23.3 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.23.3 + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.23.7 + "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 + "@babel/plugin-syntax-async-generators": ^7.8.4 + "@babel/plugin-syntax-class-properties": ^7.12.13 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + "@babel/plugin-syntax-import-assertions": ^7.23.3 + "@babel/plugin-syntax-import-attributes": ^7.23.3 + "@babel/plugin-syntax-import-meta": ^7.10.4 + "@babel/plugin-syntax-json-strings": ^7.8.3 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + "@babel/plugin-syntax-top-level-await": ^7.14.5 + "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 + "@babel/plugin-transform-arrow-functions": ^7.23.3 + "@babel/plugin-transform-async-generator-functions": ^7.23.9 + "@babel/plugin-transform-async-to-generator": ^7.23.3 + "@babel/plugin-transform-block-scoped-functions": ^7.23.3 + "@babel/plugin-transform-block-scoping": ^7.23.4 + "@babel/plugin-transform-class-properties": ^7.23.3 + "@babel/plugin-transform-class-static-block": ^7.23.4 + "@babel/plugin-transform-classes": ^7.23.8 + "@babel/plugin-transform-computed-properties": ^7.23.3 + "@babel/plugin-transform-destructuring": ^7.23.3 + "@babel/plugin-transform-dotall-regex": ^7.23.3 + "@babel/plugin-transform-duplicate-keys": ^7.23.3 + "@babel/plugin-transform-dynamic-import": ^7.23.4 + "@babel/plugin-transform-exponentiation-operator": ^7.23.3 + "@babel/plugin-transform-export-namespace-from": ^7.23.4 + "@babel/plugin-transform-for-of": ^7.23.6 + "@babel/plugin-transform-function-name": ^7.23.3 + "@babel/plugin-transform-json-strings": ^7.23.4 + "@babel/plugin-transform-literals": ^7.23.3 + "@babel/plugin-transform-logical-assignment-operators": ^7.23.4 + "@babel/plugin-transform-member-expression-literals": ^7.23.3 + "@babel/plugin-transform-modules-amd": ^7.23.3 + "@babel/plugin-transform-modules-commonjs": ^7.23.3 + "@babel/plugin-transform-modules-systemjs": ^7.23.9 + "@babel/plugin-transform-modules-umd": ^7.23.3 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5 + "@babel/plugin-transform-new-target": ^7.23.3 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.23.4 + "@babel/plugin-transform-numeric-separator": ^7.23.4 + "@babel/plugin-transform-object-rest-spread": ^7.23.4 + "@babel/plugin-transform-object-super": ^7.23.3 + "@babel/plugin-transform-optional-catch-binding": ^7.23.4 + "@babel/plugin-transform-optional-chaining": ^7.23.4 + "@babel/plugin-transform-parameters": ^7.23.3 + "@babel/plugin-transform-private-methods": ^7.23.3 + "@babel/plugin-transform-private-property-in-object": ^7.23.4 + "@babel/plugin-transform-property-literals": ^7.23.3 + "@babel/plugin-transform-regenerator": ^7.23.3 + "@babel/plugin-transform-reserved-words": ^7.23.3 + "@babel/plugin-transform-shorthand-properties": ^7.23.3 + "@babel/plugin-transform-spread": ^7.23.3 + "@babel/plugin-transform-sticky-regex": ^7.23.3 + "@babel/plugin-transform-template-literals": ^7.23.3 + "@babel/plugin-transform-typeof-symbol": ^7.23.3 + "@babel/plugin-transform-unicode-escapes": ^7.23.3 + "@babel/plugin-transform-unicode-property-regex": ^7.23.3 + "@babel/plugin-transform-unicode-regex": ^7.23.3 + "@babel/plugin-transform-unicode-sets-regex": ^7.23.3 + "@babel/preset-modules": 0.1.6-no-external-plugins + babel-plugin-polyfill-corejs2: ^0.4.8 + babel-plugin-polyfill-corejs3: ^0.9.0 + babel-plugin-polyfill-regenerator: ^0.5.5 + core-js-compat: ^3.31.0 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 23a48468ba820c68ba34ea2c1dbc62fd2ff9cf858cfb69e159cabb0c85c72dc4c2266ce20ca84318d8742de050cb061e7c66902fbfddbcb09246afd248847933 + languageName: node + linkType: hard + +"@babel/preset-env@npm:^7.11.0": version: 7.23.8 resolution: "@babel/preset-env@npm:7.23.8" dependencies: @@ -1475,6 +1670,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/template@npm:7.23.9" + dependencies: + "@babel/code-frame": ^7.23.5 + "@babel/parser": ^7.23.9 + "@babel/types": ^7.23.9 + checksum: 6e67414c0f7125d7ecaf20c11fab88085fa98a96c3ef10da0a61e962e04fdf3a18a496a66047005ddd1bb682a7cc7842d556d1db2f3f3f6ccfca97d5e445d342 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.23.7": version: 7.23.7 resolution: "@babel/traverse@npm:7.23.7" @@ -1493,6 +1699,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/traverse@npm:7.23.9" + dependencies: + "@babel/code-frame": ^7.23.5 + "@babel/generator": ^7.23.6 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/parser": ^7.23.9 + "@babel/types": ^7.23.9 + debug: ^4.3.1 + globals: ^11.1.0 + checksum: a932f7aa850e158c00c97aad22f639d48c72805c687290f6a73e30c5c4957c07f5d28310c9bf59648e2980fe6c9d16adeb2ff92a9ca0f97fa75739c1328fc6c3 + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.23.6 resolution: "@babel/types@npm:7.23.6" @@ -1504,6 +1728,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/types@npm:7.23.9" + dependencies: + "@babel/helper-string-parser": ^7.23.4 + "@babel/helper-validator-identifier": ^7.22.20 + to-fast-properties: ^2.0.0 + checksum: 0a9b008e9bfc89beb8c185e620fa0f8ed6c771f1e1b2e01e1596870969096fec7793898a1d64a035176abf1dd13e2668ee30bf699f2d92c210a8128f4b151e65 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -1927,48 +2162,48 @@ __metadata: languageName: node linkType: hard -"@datadog/browser-core@npm:5.7.0": - version: 5.7.0 - resolution: "@datadog/browser-core@npm:5.7.0" - checksum: fee15bfcfbc6b9da1adc59573889cd7d58946730bab1b01bae733da6736df421c02040eb8e4c776b1002918feffdccc5a51e1d5a167155a775633ec3bfa3925e +"@datadog/browser-core@npm:5.8.0": + version: 5.8.0 + resolution: "@datadog/browser-core@npm:5.8.0" + checksum: 3282c104976b7e151a3db5d67100b2b98714d092f3c8395cf8dbafd6db470a83ef54a61ffb1e2a171e147145a95a0a0af50918baa5a14251996b8c68788a5c0b languageName: node linkType: hard -"@datadog/browser-logs@npm:^5.7.0": - version: 5.7.0 - resolution: "@datadog/browser-logs@npm:5.7.0" +"@datadog/browser-logs@npm:^5.8.0": + version: 5.8.0 + resolution: "@datadog/browser-logs@npm:5.8.0" dependencies: - "@datadog/browser-core": 5.7.0 + "@datadog/browser-core": 5.8.0 peerDependencies: - "@datadog/browser-rum": 5.7.0 + "@datadog/browser-rum": 5.8.0 peerDependenciesMeta: "@datadog/browser-rum": optional: true - checksum: ae07d8302fe7be7fee1b4a20c0617b77090bb7dcb9227716dadbf617f733bb4bef74b5fd1ee19199904bc19f7a5257a14973269c2ebaf332c0c620f1e861f3b6 + checksum: ceb4daae67bc9fc720284881d2ce27b417bf004f123989be8c747771587373083ce2f370311eb42823bef80dd4ee0b8023a492a87a14e0ff8ca2127f36d455e7 languageName: node linkType: hard -"@datadog/browser-rum-core@npm:5.7.0": - version: 5.7.0 - resolution: "@datadog/browser-rum-core@npm:5.7.0" +"@datadog/browser-rum-core@npm:5.8.0": + version: 5.8.0 + resolution: "@datadog/browser-rum-core@npm:5.8.0" dependencies: - "@datadog/browser-core": 5.7.0 - checksum: 348b98944615d41cbfe81ba6b51fc851c1fee969c5a9a4a0716d5daff161878b23fff47d4ae83c537e160a0f8bd8d04e8be861e159c5027157257e98fd07ea5e + "@datadog/browser-core": 5.8.0 + checksum: b99d5dbe5dc2b9976362a5028cf97cd8f274b65729e92f3d8086e24c540ad987ae558e8f246a6b10ff41bf27c3679b8d43736b462411a3ad06cd9b9d9d72de80 languageName: node linkType: hard -"@datadog/browser-rum@npm:^5.7.0": - version: 5.7.0 - resolution: "@datadog/browser-rum@npm:5.7.0" +"@datadog/browser-rum@npm:^5.8.0": + version: 5.8.0 + resolution: "@datadog/browser-rum@npm:5.8.0" dependencies: - "@datadog/browser-core": 5.7.0 - "@datadog/browser-rum-core": 5.7.0 + "@datadog/browser-core": 5.8.0 + "@datadog/browser-rum-core": 5.8.0 peerDependencies: - "@datadog/browser-logs": 5.7.0 + "@datadog/browser-logs": 5.8.0 peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: be5e252a12e9868ff96ecb9d6caf80974887b3495ce88b90edd88bb97551b1448017f665236af0ec7c97a26d473dbcafc61c15a8e5f566809209c87ec7a0a45a + checksum: ca564c4a23c3b2d2343c048c74ca03774a90c32bac8aea29050ed286a3698d4a071fa00ea7a629543df6bcbc88595f9b78dd8fa032be623819100110dfbd996b languageName: node linkType: hard @@ -2158,10 +2393,10 @@ __metadata: languageName: node linkType: hard -"@faker-js/faker@npm:8.3.1": - version: 8.3.1 - resolution: "@faker-js/faker@npm:8.3.1" - checksum: 33efe912411fe61f43b313784a9ce041dfbfb54bc3b2f7b923a547f97beb6b3763534f9c37af25ab330982e6b36e6f7b040dfb35c115deb8c789d8ada413bd94 +"@faker-js/faker@npm:8.4.0": + version: 8.4.0 + resolution: "@faker-js/faker@npm:8.4.0" + checksum: 682581f0b009b7e8b81bc0736a3f1df2fb5179706786b87ef5bed5e2e28e22dfeba10e5122942371f12d68e833be3b3726850f96940baf080500cef35a77403b languageName: node linkType: hard @@ -2191,9 +2426,9 @@ __metadata: languageName: node linkType: hard -"@formatjs/cli@npm:6.2.4": - version: 6.2.4 - resolution: "@formatjs/cli@npm:6.2.4" +"@formatjs/cli@npm:6.2.7": + version: 6.2.7 + resolution: "@formatjs/cli@npm:6.2.7" peerDependencies: vue: ^3.3.4 peerDependenciesMeta: @@ -2201,17 +2436,17 @@ __metadata: optional: true bin: formatjs: bin/formatjs - checksum: 6ff9e07ae7ab23cd83be3ad7dca0dcd6529f3852a7e8d2b56121ac8410e1a072fdb3b40dd0c2d6ab4ac3158efc4047615d0f77629aec3259ba4884f4cd45073a + checksum: 7c98bca31605f8695ec032eefc82c9312f396ac11276f17be860340bdcf96cf0ab01cc00d6ed8f4f0b90e2d0b504e31b93a96010000065d4ac1f97b49b89121c languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.18.0": - version: 1.18.0 - resolution: "@formatjs/ecma402-abstract@npm:1.18.0" +"@formatjs/ecma402-abstract@npm:1.18.2": + version: 1.18.2 + resolution: "@formatjs/ecma402-abstract@npm:1.18.2" dependencies: - "@formatjs/intl-localematcher": 0.5.2 + "@formatjs/intl-localematcher": 0.5.4 tslib: ^2.4.0 - checksum: 22be7f02397d565de621bba5d57135bf7a360b4f3f04e7d75194854f47c22fa8cc2e43ede2c6d1dea885d3cb5df6f58e82ea7ba457a7b3e208403372cd6b90f3 + checksum: c664056ccab4e3407feabd5802276075eae2b614acb8c5979045ff5a70bfec4c04488188c30b311b6db0e0eb0b5c1ca328868d76472a14243c944bc0639e8a4d languageName: node linkType: hard @@ -2224,75 +2459,75 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-messageformat-parser@npm:2.7.3": - version: 2.7.3 - resolution: "@formatjs/icu-messageformat-parser@npm:2.7.3" +"@formatjs/icu-messageformat-parser@npm:2.7.6": + version: 2.7.6 + resolution: "@formatjs/icu-messageformat-parser@npm:2.7.6" dependencies: - "@formatjs/ecma402-abstract": 1.18.0 - "@formatjs/icu-skeleton-parser": 1.7.0 + "@formatjs/ecma402-abstract": 1.18.2 + "@formatjs/icu-skeleton-parser": 1.8.0 tslib: ^2.4.0 - checksum: 3efd07e26dfd768cfb4ebee72787f150eb7c65849610d0b08b09ffd26f127ce2a7027dc901a3a2ee536597a26bce289bff3f3d9de8247c274e364c0666f685d6 + checksum: d537253cbfe0515c0b72495b1133528a6643f23f978f6d9576defe5150dbb4b9b4e4b7028e2ff1bfaa4d104b05aa1119688d3fb7a4cf9b1b78ba8019a6adfeb1 languageName: node linkType: hard -"@formatjs/icu-skeleton-parser@npm:1.7.0": - version: 1.7.0 - resolution: "@formatjs/icu-skeleton-parser@npm:1.7.0" +"@formatjs/icu-skeleton-parser@npm:1.8.0": + version: 1.8.0 + resolution: "@formatjs/icu-skeleton-parser@npm:1.8.0" dependencies: - "@formatjs/ecma402-abstract": 1.18.0 + "@formatjs/ecma402-abstract": 1.18.2 tslib: ^2.4.0 - checksum: a461d95b0a39a52d2acb776cb60818188f32ca5d8be7d97440b892bb30564e852410c3fffe96c4c5e6793934f3f694958da8297bd7e3b0cbe114f11223a57013 + checksum: 85ca45148a8535c61f2667d24d3e59ab97cd2b4accee8383594872a319e875effae7d54e070fd0d3926fc1407b04f5685f94336c1d0d587fcb1064bb498e5319 languageName: node linkType: hard -"@formatjs/intl-displaynames@npm:6.6.4": - version: 6.6.4 - resolution: "@formatjs/intl-displaynames@npm:6.6.4" +"@formatjs/intl-displaynames@npm:6.6.6": + version: 6.6.6 + resolution: "@formatjs/intl-displaynames@npm:6.6.6" dependencies: - "@formatjs/ecma402-abstract": 1.18.0 - "@formatjs/intl-localematcher": 0.5.2 + "@formatjs/ecma402-abstract": 1.18.2 + "@formatjs/intl-localematcher": 0.5.4 tslib: ^2.4.0 - checksum: f1300ac7e7cc05041464a7f5a19ced83361fb7846d4c2727ede3c3bae836f0995565e44128b9de8182f07c13e8594d4c84c73c375824c9ad991031c96b1cd141 + checksum: 4f4f2c690dff61570872eb397ed8e7e8e31d67acf94813c165ac96db8d83f9321c19b9410275f592cdeea980cd9391b14f823a142d5b52e85aab499cd3a00d39 languageName: node linkType: hard -"@formatjs/intl-listformat@npm:7.5.3": - version: 7.5.3 - resolution: "@formatjs/intl-listformat@npm:7.5.3" +"@formatjs/intl-listformat@npm:7.5.5": + version: 7.5.5 + resolution: "@formatjs/intl-listformat@npm:7.5.5" dependencies: - "@formatjs/ecma402-abstract": 1.18.0 - "@formatjs/intl-localematcher": 0.5.2 + "@formatjs/ecma402-abstract": 1.18.2 + "@formatjs/intl-localematcher": 0.5.4 tslib: ^2.4.0 - checksum: c3f9ba6b6bf400e3f86da652b303db093516cae85c4dafed7ae675e905bbbcd595db402e42601f50ea1feba9229848a63602ab39ac85553df622b7645f111969 + checksum: ed49f0820e45e600ea4cbd72be894b741a45446959e9d8e007416e50236e663aa18ba46cf0040b35190765e3e67b11c673d4930f0f9a733f4f9cf7ab15d8a08c languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.5.2": - version: 0.5.2 - resolution: "@formatjs/intl-localematcher@npm:0.5.2" +"@formatjs/intl-localematcher@npm:0.5.4": + version: 0.5.4 + resolution: "@formatjs/intl-localematcher@npm:0.5.4" dependencies: tslib: ^2.4.0 - checksum: a741d69e9d3b71bee19726484de4a296711d96dc27f588d995b9e2079d3bc5d06370b6e84136003197d558d45f9faf507321627a78d8cd986705b78ec701c016 + checksum: a0af57874fcd163add5f7a0cb1c008e9b09feb1d24cbce1263379ae0393cddd6681197a7f2f512f351a97666fc8675ed52cc17d1834266ee8fc65e9edf3435f6 languageName: node linkType: hard -"@formatjs/intl@npm:2.9.9": - version: 2.9.9 - resolution: "@formatjs/intl@npm:2.9.9" +"@formatjs/intl@npm:2.10.0": + version: 2.10.0 + resolution: "@formatjs/intl@npm:2.10.0" dependencies: - "@formatjs/ecma402-abstract": 1.18.0 + "@formatjs/ecma402-abstract": 1.18.2 "@formatjs/fast-memoize": 2.2.0 - "@formatjs/icu-messageformat-parser": 2.7.3 - "@formatjs/intl-displaynames": 6.6.4 - "@formatjs/intl-listformat": 7.5.3 - intl-messageformat: 10.5.8 + "@formatjs/icu-messageformat-parser": 2.7.6 + "@formatjs/intl-displaynames": 6.6.6 + "@formatjs/intl-listformat": 7.5.5 + intl-messageformat: 10.5.11 tslib: ^2.4.0 peerDependencies: - typescript: 5 + typescript: ^4.7 || 5 peerDependenciesMeta: typescript: optional: true - checksum: a235f5366834c751313763071036a321a24f429435de48a8f30289111ef96c4109ee65507e0aee82365629673744aaf9a017c38c2998d8e2df18514fd79811e4 + checksum: 45ed03c7c4a378606b273477a1fd0323804caf2eee1d0ace17b8dfe15a9c71b4083ffc4592c02a1261bcbc2edfd09e81d3144b5b7599dcd51f3cae48c5c93d9a languageName: node linkType: hard @@ -3969,7 +4204,7 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0": +"@types/estree@npm:*": version: 1.0.2 resolution: "@types/estree@npm:1.0.2" checksum: aeedb1b2fe20cbe06f44b99b562bf9703e360bfcdf5bb3d61d248182ee1dd63500f2474e12f098ffe1f5ac3202b43b3e18ec99902d9328d5374f5512fa077e45 @@ -3983,6 +4218,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:^1.0.5": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: dd8b5bed28e6213b7acd0fb665a84e693554d850b0df423ac8076cc3ad5823a6bc26b0251d080bdc545af83179ede51dd3f6fa78cad2c46ed1f29624ddf3e41a + languageName: node + linkType: hard + "@types/fs-extra@npm:11.0.4": version: 11.0.4 resolution: "@types/fs-extra@npm:11.0.4" @@ -4197,12 +4439,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=13.7.0, @types/node@npm:^20.11.0": - version: 20.11.0 - resolution: "@types/node@npm:20.11.0" +"@types/node@npm:*, @types/node@npm:>=13.7.0": + version: 20.11.5 + resolution: "@types/node@npm:20.11.5" dependencies: undici-types: ~5.26.4 - checksum: 1bd6890db7e0404d11c33d28f46f19f73256f0ba35d19f0ef2a0faba09f366f188915fb9338eebebcc472075c1c4941e17c7002786aa69afa44980737846b200 + checksum: a542727de1334ae20a3ca034b0ecf4b464a57ca01efc4f9cf43bd9ab93896125ab3c2de060ecd8f6ae23b86c6bf3463f681b643e69c032c6a662d376c98a6092 languageName: node linkType: hard @@ -4213,6 +4455,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^20.11.9": + version: 20.11.9 + resolution: "@types/node@npm:20.11.9" + dependencies: + undici-types: ~5.26.4 + checksum: 14a11ac2e0fc97b4d35c20fee65393fcd5a9adc55bf8317a5000d35d94fa5410469e8f99c3b765643b1a5e49288c8a18422493eb177a156e7bdb4b2c95e40183 + languageName: node + linkType: hard + "@types/node@npm:~14": version: 14.18.63 resolution: "@types/node@npm:14.18.63" @@ -4289,14 +4540,14 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:18.2.47": - version: 18.2.47 - resolution: "@types/react@npm:18.2.47" +"@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:18.2.48": + version: 18.2.48 + resolution: "@types/react@npm:18.2.48" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: 49608f07f73374e535b21f99fee28e6cfd5801d887c6ed88c41b4dc701dbcee9f0c4d289d9af7b2b23114f76dbf203ffe2c9191bfb4958cf18dae5a25daedbd0 + checksum: c9ca43ed2995389b7e09492c24e6f911a8439bb8276dd17cc66a2fbebbf0b42daf7b2ad177043256533607c2ca644d7d928fdfce37a67af1f8646d2bac988900 languageName: node linkType: hard @@ -4803,9 +5054,9 @@ __metadata: languageName: node linkType: hard -"@wireapp/api-client@npm:^26.10.0": - version: 26.10.0 - resolution: "@wireapp/api-client@npm:26.10.0" +"@wireapp/api-client@npm:^26.10.1": + version: 26.10.1 + resolution: "@wireapp/api-client@npm:26.10.1" dependencies: "@wireapp/commons": ^5.2.4 "@wireapp/priority-queue": ^2.1.4 @@ -4821,7 +5072,7 @@ __metadata: tough-cookie: 4.1.3 ws: 8.16.0 zod: 3.22.4 - checksum: 9023270f8688887a1adef7188e8889e243a3fd3171576a988c79cbb3a2fdbb50541fd32be3b6dee91b4126f299df81cbd2773c410dde378fa96c74e1b06ce42e + checksum: 896affd13be653b7dfe1bf67b028c32f91b03ce446da0e5019e50a8524532cb31c8c6d06b46927bea379a0ddf6b5f12f68f7d29e5ecda6445bfcd8f435472802 languageName: node linkType: hard @@ -4867,20 +5118,20 @@ __metadata: languageName: node linkType: hard -"@wireapp/core-crypto@npm:1.0.0-rc.29": - version: 1.0.0-rc.29 - resolution: "@wireapp/core-crypto@npm:1.0.0-rc.29" - checksum: 6805c9401ef20745d7385549e81cb50ded70369bbf40c8f1b1d6bc376ef0d9360373c8edcafe3c808dcb20086714759f5b05311e81275f56c09a5e368817c6fa +"@wireapp/core-crypto@npm:1.0.0-rc.33": + version: 1.0.0-rc.33 + resolution: "@wireapp/core-crypto@npm:1.0.0-rc.33" + checksum: 44b88f4b7a1ec2ce9c13ce48329c53193c91833f13345abf28e3bfcf51f41ab510187d1192dcf76293c23b9fa4167e67ee1bd084a9739f2dc598ca7987258d27 languageName: node linkType: hard -"@wireapp/core@npm:43.5.6": - version: 43.5.6 - resolution: "@wireapp/core@npm:43.5.6" +"@wireapp/core@npm:43.11.2": + version: 43.11.2 + resolution: "@wireapp/core@npm:43.11.2" dependencies: - "@wireapp/api-client": ^26.10.0 + "@wireapp/api-client": ^26.10.1 "@wireapp/commons": ^5.2.4 - "@wireapp/core-crypto": 1.0.0-rc.29 + "@wireapp/core-crypto": 1.0.0-rc.33 "@wireapp/cryptobox": 12.8.0 "@wireapp/promise-queue": ^2.2.9 "@wireapp/protocol-messaging": 1.44.0 @@ -4896,7 +5147,7 @@ __metadata: long: ^5.2.0 uuidjs: 4.2.13 zod: 3.22.4 - checksum: 79d26ebb9e9d47298f5a971de6293804ac12e3f04c0cfc36003a887776060d95fce2a856101902e49da9979686815ffa8889881e5f2f1bc46fab58d089f450f0 + checksum: 685d047c9dd296e528ae8500e6b82c1ad6aa07762fd6ae549672028e8f9741cc88c3dbab15959b68d3b0fc47870daab7ba30d3b2127c15d256409551165df002 languageName: node linkType: hard @@ -5010,9 +5261,9 @@ __metadata: languageName: node linkType: hard -"@wireapp/react-ui-kit@npm:9.12.6": - version: 9.12.6 - resolution: "@wireapp/react-ui-kit@npm:9.12.6" +"@wireapp/react-ui-kit@npm:9.12.8": + version: 9.12.8 + resolution: "@wireapp/react-ui-kit@npm:9.12.8" dependencies: "@types/color": 3.0.6 color: 4.2.3 @@ -5027,7 +5278,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 57e91477c6784ec0d64227fd360e8a830e76606551046ebc2e6accce1125b23b86cb4ccdbeba055ed00aca679bc6f4149291b31e0c97f49ed127d7d69c3e78ce + checksum: eaab4ee5abbc36b1b5a50511b7b7824c9f7f717b2b852a35fac148ecb505f1f2a3ad910ecfd3b54c16de04b0fd7284ef60442a957e78da7a25f20a466c6b7fa5 languageName: node linkType: hard @@ -5682,13 +5933,13 @@ __metadata: languageName: node linkType: hard -"autoprefixer@npm:^10.4.16": - version: 10.4.16 - resolution: "autoprefixer@npm:10.4.16" +"autoprefixer@npm:^10.4.16, autoprefixer@npm:^10.4.17": + version: 10.4.17 + resolution: "autoprefixer@npm:10.4.17" dependencies: - browserslist: ^4.21.10 - caniuse-lite: ^1.0.30001538 - fraction.js: ^4.3.6 + browserslist: ^4.22.2 + caniuse-lite: ^1.0.30001578 + fraction.js: ^4.3.7 normalize-range: ^0.1.2 picocolors: ^1.0.0 postcss-value-parser: ^4.2.0 @@ -5696,7 +5947,7 @@ __metadata: postcss: ^8.1.0 bin: autoprefixer: bin/autoprefixer - checksum: 45fad7086495048dacb14bb7b00313e70e135b5d8e8751dcc60548889400763705ab16fc2d99ea628b44c3472698fb0e39598f595ba28409c965ab159035afde + checksum: 1b4cf4097507f9dc48cef3194f18a05901311c881380cc634b308fce54a6554cf2dcd20aec8384b44e994d4665ab12c63dc89492523f8d74ff5d4d5eb1469f8c languageName: node linkType: hard @@ -5831,6 +6082,19 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs2@npm:^0.4.8": + version: 0.4.8 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.8" + dependencies: + "@babel/compat-data": ^7.22.6 + "@babel/helper-define-polyfill-provider": ^0.5.0 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 22857b87268b354e095452199464accba5fd8f690558a2f24b0954807ca2494b96da8d5c13507955802427582015160bce26a66893acf6da5dafbed8b336cf79 + languageName: node + linkType: hard + "babel-plugin-polyfill-corejs3@npm:^0.8.7": version: 0.8.7 resolution: "babel-plugin-polyfill-corejs3@npm:0.8.7" @@ -5843,6 +6107,18 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs3@npm:^0.9.0": + version: 0.9.0 + resolution: "babel-plugin-polyfill-corejs3@npm:0.9.0" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.5.0 + core-js-compat: ^3.34.0 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 65bbf59fc0145c7a264822777403632008dce00015b4b5c7ec359125ef4faf9e8f494ae5123d2992104feb6f19a3cff85631992862e48b6d7bd64eb7e755ee1f + languageName: node + linkType: hard + "babel-plugin-polyfill-regenerator@npm:^0.5.4": version: 0.5.4 resolution: "babel-plugin-polyfill-regenerator@npm:0.5.4" @@ -5854,6 +6130,17 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-regenerator@npm:^0.5.5": + version: 0.5.5 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.5" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.5.0 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 3a9b4828673b23cd648dcfb571eadcd9d3fadfca0361d0a7c6feeb5a30474e92faaa49f067a6e1c05e49b6a09812879992028ff3ef3446229ff132d6e1de7eb6 + languageName: node + linkType: hard + "babel-plugin-transform-import-meta@npm:^2.2.1": version: 2.2.1 resolution: "babel-plugin-transform-import-meta@npm:2.2.1" @@ -6053,7 +6340,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.21.10, browserslist@npm:^4.22.1, browserslist@npm:^4.22.2": +"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.22.1, browserslist@npm:^4.22.2": version: 4.22.2 resolution: "browserslist@npm:4.22.2" dependencies: @@ -6213,10 +6500,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565": - version: 1.0.30001570 - resolution: "caniuse-lite@npm:1.0.30001570" - checksum: 460be2c7a9b1c8a83b6aae4226661c276d9dada6c84209dee547699cf4b28030b9d1fc29ddd7626acee77412b6401993878ea0ef3eadbf3a63ded9034896ae20 +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001565, caniuse-lite@npm:^1.0.30001578": + version: 1.0.30001579 + resolution: "caniuse-lite@npm:1.0.30001579" + checksum: 7539dcff74d2243a30c428393dc690c87fa34d7da36434731853e9bcfe783757763b2971f5cc878e25242a93e184e53f167d11bd74955af956579f7af71cc764 languageName: node linkType: hard @@ -6628,9 +6915,9 @@ __metadata: languageName: node linkType: hard -"copy-webpack-plugin@npm:12.0.1": - version: 12.0.1 - resolution: "copy-webpack-plugin@npm:12.0.1" +"copy-webpack-plugin@npm:12.0.2": + version: 12.0.2 + resolution: "copy-webpack-plugin@npm:12.0.2" dependencies: fast-glob: ^3.3.2 glob-parent: ^6.0.1 @@ -6640,7 +6927,7 @@ __metadata: serialize-javascript: ^6.0.2 peerDependencies: webpack: ^5.1.0 - checksum: f43948ef04e7b2ec3b860bf61735163962de0b5f78f9a70365d504463751aa288006e63106ada4e626e4079e3c08c0ff872afcfad68bafdd2c799ded9ace2fe5 + checksum: 98127735336c6db5924688486d3a1854a41835963d0c0b81695b2e3d58c6675164be7d23dee7090b84a56d3c9923175d3d0863ac1942bcc3317d2efc1962b927 languageName: node linkType: hard @@ -6678,10 +6965,19 @@ __metadata: languageName: node linkType: hard -"core-js@npm:3.35.0": - version: 3.35.0 - resolution: "core-js@npm:3.35.0" - checksum: 25c224aca3df012b98f08f13ccbd8171ef5852acd33fd5e58e106d27f5f0c97de2fdbc520f0b4364d26253caf2deb3e5d265310f57d2a66ae6cc922850e649f0 +"core-js-compat@npm:^3.34.0": + version: 3.35.1 + resolution: "core-js-compat@npm:3.35.1" + dependencies: + browserslist: ^4.22.2 + checksum: 4c1a7076d31fa489eec5c46eb11c7127703f9756b5fed1eab9bf27b7f0f151247886d3fa488911078bd2801a5dfa12a9ea2ecb7a4e61dfa460b2c291805f503b + languageName: node + linkType: hard + +"core-js@npm:3.35.1": + version: 3.35.1 + resolution: "core-js@npm:3.35.1" + checksum: e246af6b634be3763ffe3ce6ac4601b4dc5b928006fb6c95e5d08ecd82a2413bf36f00ffe178b89c9a8e94000288933a78a9881b2c9498e6cf312b031013b952 languageName: node linkType: hard @@ -6692,7 +6988,7 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:8.3.6, cosmiconfig@npm:^8.3.5": +"cosmiconfig@npm:8.3.6": version: 8.3.6 resolution: "cosmiconfig@npm:8.3.6" dependencies: @@ -6866,21 +7162,21 @@ __metadata: languageName: node linkType: hard -"css-loader@npm:^6.9.0": - version: 6.9.0 - resolution: "css-loader@npm:6.9.0" +"css-loader@npm:^6.9.1": + version: 6.9.1 + resolution: "css-loader@npm:6.9.1" dependencies: icss-utils: ^5.1.0 - postcss: ^8.4.31 + postcss: ^8.4.33 postcss-modules-extract-imports: ^3.0.0 - postcss-modules-local-by-default: ^4.0.3 - postcss-modules-scope: ^3.1.0 + postcss-modules-local-by-default: ^4.0.4 + postcss-modules-scope: ^3.1.1 postcss-modules-values: ^4.0.0 postcss-value-parser: ^4.2.0 semver: ^7.5.4 peerDependencies: webpack: ^5.0.0 - checksum: 71f20ee5eb5a4a9373ab41a5c17df411cb4f6f2de037297a2b0c2150681578f4979f319f4307a61e23c231dd6546e657ae95cba5a0698ad13ca43f91d4d2a0bc + checksum: b0c1776f9c46474219eb471eeb8f4c8986a7735dc8356e578a63303cf292a7c8cb868fa74bf94a1a174e948fcb6523c63fca081cac6bbf246be8275b3cc384f0 languageName: node linkType: hard @@ -7086,10 +7382,10 @@ __metadata: languageName: node linkType: hard -"date-fns@npm:3.2.0": - version: 3.2.0 - resolution: "date-fns@npm:3.2.0" - checksum: ff5dab139f40170c4ba5472bab9bc887dd3940f7661bd8322f074faadbd422513c7195296541b5237fc450a0333a4b1c5659f887c7c14b1bfa2902998ac7582e +"date-fns@npm:3.3.1": + version: 3.3.1 + resolution: "date-fns@npm:3.3.1" + checksum: 6245e93a47de28ac96dffd4d62877f86e6b64854860ae1e00a4f83174d80bc8e59bd1259cf265223fb2ddce5c8e586dc9cc210f0d052faba2f7660e265877283 languageName: node linkType: hard @@ -7513,10 +7809,10 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:16.3.1": - version: 16.3.1 - resolution: "dotenv@npm:16.3.1" - checksum: 15d75e7279018f4bafd0ee9706593dd14455ddb71b3bcba9c52574460b7ccaf67d5cf8b2c08a5af1a9da6db36c956a04a1192b101ee102a3e0cf8817bbcf3dfd +"dotenv@npm:16.4.1": + version: 16.4.1 + resolution: "dotenv@npm:16.4.1" + checksum: a343f0a1d156deef8c60034f797969867af4dbccfacedd4ac15fad04547e7ffe0553b58fc3b27a5837950f0d977e38e9234943fbcec4aeced4e3d044309a76ab languageName: node linkType: hard @@ -7576,14 +7872,14 @@ __metadata: languageName: node linkType: hard -"emoji-picker-react@npm:4.6.10": - version: 4.6.10 - resolution: "emoji-picker-react@npm:4.6.10" +"emoji-picker-react@npm:4.7.10": + version: 4.7.10 + resolution: "emoji-picker-react@npm:4.7.10" dependencies: - flairup: 0.0.31 + flairup: 0.0.35 peerDependencies: react: ">=16" - checksum: bbbae2379b94f56315eb635e28d409beca515c4c696749e4d3313317a1f440202c69db36f1021e733030201364c430c1159b11a8128eba12df66f0e0e4216b07 + checksum: a7c55ef8860d76fa642ef189840ca9d320064b1da4d96b8440c4c0f349d41e35d2f5b6ba36edf80ae970db87bdb0e5f13a2a4dd3a02041bf48587bb895b8eba7 languageName: node linkType: hard @@ -8736,10 +9032,10 @@ __metadata: languageName: node linkType: hard -"flairup@npm:0.0.31": - version: 0.0.31 - resolution: "flairup@npm:0.0.31" - checksum: e25c35626f24cc7bef3fdefa611827af779ee907ea3f66c95b867dbd2780678d27954abf6574096be12aa3e83e5df08515217647897bb99fdb604c2d68035333 +"flairup@npm:0.0.35": + version: 0.0.35 + resolution: "flairup@npm:0.0.35" + checksum: ad67c3b9c8e53e28b5ea8f4729592e23d277224c87f168302735ac6232351e44e8f5d48a049cba1fb9d8b0f072597c0d2c9b4bf490b65ead9a36335933afe9d6 languageName: node linkType: hard @@ -8810,7 +9106,7 @@ __metadata: languageName: node linkType: hard -"fraction.js@npm:^4.3.6": +"fraction.js@npm:^4.3.7": version: 4.3.7 resolution: "fraction.js@npm:4.3.7" checksum: e1553ae3f08e3ba0e8c06e43a3ab20b319966dfb7ddb96fd9b5d0ee11a66571af7f993229c88ebbb0d4a816eb813a24ed48207b140d442a8f76f33763b8d1f3f @@ -9604,12 +9900,12 @@ __metadata: languageName: node linkType: hard -"husky@npm:8.0.3": - version: 8.0.3 - resolution: "husky@npm:8.0.3" +"husky@npm:9.0.6": + version: 9.0.6 + resolution: "husky@npm:9.0.6" bin: - husky: lib/bin.js - checksum: 837bc7e4413e58c1f2946d38fb050f5d7324c6f16b0fd66411ffce5703b294bd21429e8ba58711cd331951ee86ed529c5be4f76805959ff668a337dbfa82a1b0 + husky: bin.js + checksum: e198c90a59d460cf860c33e0a4c3927ecfb645d4fd4c2de3fbcd5fb56b858a923af452508d549f6ed020bb48de08290912cd77c006dd2a83e551c24c17340d5b languageName: node linkType: hard @@ -9814,15 +10110,15 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.5.8": - version: 10.5.8 - resolution: "intl-messageformat@npm:10.5.8" +"intl-messageformat@npm:10.5.11": + version: 10.5.11 + resolution: "intl-messageformat@npm:10.5.11" dependencies: - "@formatjs/ecma402-abstract": 1.18.0 + "@formatjs/ecma402-abstract": 1.18.2 "@formatjs/fast-memoize": 2.2.0 - "@formatjs/icu-messageformat-parser": 2.7.3 + "@formatjs/icu-messageformat-parser": 2.7.6 tslib: ^2.4.0 - checksum: f0fc0c4ce4f711ac46227e1b41e1494bfadfd047e4581299ef4fbf79dcbd85fcc9851e7051432a02239fab9673c212a50f03060b5f83a930c286d4ba6c2261de + checksum: b5574447a0d938170049042ec807344d57c72e9aabb2e72be0d5197baabeb763e05680b19b7607df93fadeec0e13c9bfcb450e9ba2fe7464b4f06600b612bf5e languageName: node linkType: hard @@ -11520,13 +11816,13 @@ __metadata: languageName: node linkType: hard -"less-loader@npm:^11.1.4": - version: 11.1.4 - resolution: "less-loader@npm:11.1.4" +"less-loader@npm:^12.1.0": + version: 12.1.0 + resolution: "less-loader@npm:12.1.0" peerDependencies: less: ^3.5.0 || ^4.0.0 webpack: ^5.0.0 - checksum: 29b2055a05283e16e99d0333802c185b6e1a5408212336e25b07f53d56acd8683dcd643b3e3c0c32abba0d9d5fda5ccf73cb8da00ae634ec6b929307861955c8 + checksum: e950ef8d8cf10a2a53dccc8daf1118604e10ed817ca32e4a292a026c3ab985bf8f00d6b8c74ca9007bd33d6c98315139a7be26f4c59423a68a83a6755a1a285f languageName: node linkType: hard @@ -13664,17 +13960,17 @@ __metadata: languageName: node linkType: hard -"postcss-loader@npm:^7.3.4": - version: 7.3.4 - resolution: "postcss-loader@npm:7.3.4" +"postcss-loader@npm:^8.0.0": + version: 8.0.0 + resolution: "postcss-loader@npm:8.0.0" dependencies: - cosmiconfig: ^8.3.5 + cosmiconfig: ^9.0.0 jiti: ^1.20.0 semver: ^7.5.4 peerDependencies: postcss: ^7.0.0 || ^8.0.1 webpack: ^5.0.0 - checksum: f109eb266580eb296441a1ae057f93629b9b79ad962bdd3fc134417180431606a5419b6f5848c31e6d92c818e71fe96e4335a85cc5332c2f7b14e2869951e5b3 + checksum: 10a79c1ceabf32f323a068c1369fe0e5b7fcf694af47e1e59b4c5a679bcc80969e77a1d21f1f156d49aa2979d0929a59cf2774c6ea4ee728d11b7e6c636c5e20 languageName: node linkType: hard @@ -13772,27 +14068,27 @@ __metadata: languageName: node linkType: hard -"postcss-modules-local-by-default@npm:^4.0.3": - version: 4.0.3 - resolution: "postcss-modules-local-by-default@npm:4.0.3" +"postcss-modules-local-by-default@npm:^4.0.4": + version: 4.0.4 + resolution: "postcss-modules-local-by-default@npm:4.0.4" dependencies: icss-utils: ^5.0.0 postcss-selector-parser: ^6.0.2 postcss-value-parser: ^4.1.0 peerDependencies: postcss: ^8.1.0 - checksum: 2f8083687f3d6067885f8863dd32dbbb4f779cfcc7e52c17abede9311d84faf6d3ed8760e7c54c6380281732ae1f78e5e56a28baf3c271b33f450a11c9e30485 + checksum: 578b955b0773147890caa88c30b10dfc849c5b1412a47ad51751890dba16fca9528c3ab00a19b186a8c2c150c2d08e2ce64d3d907800afee1f37c6d38252e365 languageName: node linkType: hard -"postcss-modules-scope@npm:^3.1.0": - version: 3.1.0 - resolution: "postcss-modules-scope@npm:3.1.0" +"postcss-modules-scope@npm:^3.1.1": + version: 3.1.1 + resolution: "postcss-modules-scope@npm:3.1.1" dependencies: postcss-selector-parser: ^6.0.4 peerDependencies: postcss: ^8.1.0 - checksum: 919d02e2e31956fa3dae2036d4f3259c9b8c5361bd58ee55867edededbee03507df88e98f418b5e553e47f3888daba9ea9ef0b18a82c41cf96cdb74df15322c7 + checksum: 9e9d23abb0babc7fa243be65704d72a5a9ceb2bded4dbaef96a88210d468b03c8c3158c197f4e22300c851f08c6fdddd6ebe65f44e4c34448b45b8a2e063a16d languageName: node linkType: hard @@ -14167,7 +14463,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:8.4.33, postcss@npm:^8.4.31, postcss@npm:^8.4.32": +"postcss@npm:8.4.33, postcss@npm:^8.4.32, postcss@npm:^8.4.33": version: 8.4.33 resolution: "postcss@npm:8.4.33" dependencies: @@ -14211,16 +14507,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:*, prettier@npm:^3": - version: 3.1.1 - resolution: "prettier@npm:3.1.1" - bin: - prettier: bin/prettier.cjs - checksum: e386855e3a1af86a748e16953f168be555ce66d6233f4ba54eb6449b88eb0c6b2ca79441b11eae6d28a7f9a5c96440ce50864b9d5f6356d331d39d6bb66c648e - languageName: node - linkType: hard - -"prettier@npm:^3.2.2": +"prettier@npm:*, prettier@npm:^3, prettier@npm:^3.2.2": version: 3.2.2 resolution: "prettier@npm:3.2.2" bin: @@ -14512,27 +14799,27 @@ __metadata: languageName: node linkType: hard -"react-intl@npm:6.5.5": - version: 6.5.5 - resolution: "react-intl@npm:6.5.5" +"react-intl@npm:6.6.2": + version: 6.6.2 + resolution: "react-intl@npm:6.6.2" dependencies: - "@formatjs/ecma402-abstract": 1.18.0 - "@formatjs/icu-messageformat-parser": 2.7.3 - "@formatjs/intl": 2.9.9 - "@formatjs/intl-displaynames": 6.6.4 - "@formatjs/intl-listformat": 7.5.3 + "@formatjs/ecma402-abstract": 1.18.2 + "@formatjs/icu-messageformat-parser": 2.7.6 + "@formatjs/intl": 2.10.0 + "@formatjs/intl-displaynames": 6.6.6 + "@formatjs/intl-listformat": 7.5.5 "@types/hoist-non-react-statics": ^3.3.1 "@types/react": 16 || 17 || 18 hoist-non-react-statics: ^3.3.2 - intl-messageformat: 10.5.8 + intl-messageformat: 10.5.11 tslib: ^2.4.0 peerDependencies: react: ^16.6.0 || 17 || 18 - typescript: 5 + typescript: ^4.7 || 5 peerDependenciesMeta: typescript: optional: true - checksum: 3413dc812f5a8723a9019905251eafae78fd3c2675291d97dd2ae0d105a52602c4be07b45e2ddeca7d42c5eb2b7b8bfe6b59719a9bdb0679fa497568b4e9d3e9 + checksum: a7a7cffa68089053f4d6e87bba8c84e23b2ed27200764bc115edd2455fa2b538c5890fd2f112056e66fceed2ab77e6abdf7c63d6e357ead5549f5eabbd666840 languageName: node linkType: hard @@ -14589,27 +14876,27 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:6.21.2": - version: 6.21.2 - resolution: "react-router-dom@npm:6.21.2" +"react-router-dom@npm:6.21.3": + version: 6.21.3 + resolution: "react-router-dom@npm:6.21.3" dependencies: "@remix-run/router": 1.14.2 - react-router: 6.21.2 + react-router: 6.21.3 peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: 3fc17fd6693ba8fd710937a5d694172eac4b14dddfe3df61f5339718fa36caaa894135807e0d704bddd5f277db6950117bb312d76da90921dd014e225b2cf575 + checksum: bcf668aa1428ca3048d7675f1ae3fe983c8792357a0ed59a1414cb1d682227727aad7c44c4222c6774b8d01bf352478845f7f3f668ebfcaa177208ef64e10bdc languageName: node linkType: hard -"react-router@npm:6.21.2": - version: 6.21.2 - resolution: "react-router@npm:6.21.2" +"react-router@npm:6.21.3": + version: 6.21.3 + resolution: "react-router@npm:6.21.3" dependencies: "@remix-run/router": 1.14.2 peerDependencies: react: ">=16.8" - checksum: 8c38a4914892d5b8052bc5c244af95109affd8b74bffa16f9ea7856dc0e992dd8539b19d2618721cd7ef091a585f394fac9d05ab7a98cf3ca6aeb7519b7bce0e + checksum: 7e6297d5b67ae07d2e8564e036dbb15ebd706b41c22238940f47eee9b21ffb76d41336803c3b33435f1ebe210226577e32df3838bcbf2cd7c813fa357c0a4fac languageName: node linkType: hard @@ -15330,16 +15617,7 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^6.0.1": - version: 6.0.1 - resolution: "serialize-javascript@npm:6.0.1" - dependencies: - randombytes: ^2.1.0 - checksum: 3c4f4cb61d0893b988415bdb67243637333f3f574e9e9cc9a006a2ced0b390b0b3b44aef8d51c951272a9002ec50885eefdc0298891bc27eb2fe7510ea87dc4f - languageName: node - linkType: hard - -"serialize-javascript@npm:^6.0.2": +"serialize-javascript@npm:^6.0.1, serialize-javascript@npm:^6.0.2": version: 6.0.2 resolution: "serialize-javascript@npm:6.0.2" dependencies: @@ -16287,7 +16565,7 @@ __metadata: languageName: node linkType: hard -"terser-webpack-plugin@npm:5.3.10, terser-webpack-plugin@npm:^5.3.7": +"terser-webpack-plugin@npm:5.3.10, terser-webpack-plugin@npm:^5.3.10": version: 5.3.10 resolution: "terser-webpack-plugin@npm:5.3.10" dependencies: @@ -17304,18 +17582,18 @@ __metadata: languageName: node linkType: hard -"webpack@npm:5.89.0": - version: 5.89.0 - resolution: "webpack@npm:5.89.0" +"webpack@npm:5.90.0": + version: 5.90.0 + resolution: "webpack@npm:5.90.0" dependencies: "@types/eslint-scope": ^3.7.3 - "@types/estree": ^1.0.0 + "@types/estree": ^1.0.5 "@webassemblyjs/ast": ^1.11.5 "@webassemblyjs/wasm-edit": ^1.11.5 "@webassemblyjs/wasm-parser": ^1.11.5 acorn: ^8.7.1 acorn-import-assertions: ^1.9.0 - browserslist: ^4.14.5 + browserslist: ^4.21.10 chrome-trace-event: ^1.0.2 enhanced-resolve: ^5.15.0 es-module-lexer: ^1.2.1 @@ -17329,7 +17607,7 @@ __metadata: neo-async: ^2.6.2 schema-utils: ^3.2.0 tapable: ^2.1.1 - terser-webpack-plugin: ^5.3.7 + terser-webpack-plugin: ^5.3.10 watchpack: ^2.4.0 webpack-sources: ^3.2.3 peerDependenciesMeta: @@ -17337,7 +17615,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 43fe0dbc30e168a685ef5a86759d5016a705f6563b39a240aa00826a80637d4a3deeb8062e709d6a4b05c63e796278244c84b04174704dc4a37bedb0f565c5ed + checksum: 178a0e7e9e5b26264a19dd5fe554a3508a8afafc9cce972bfd4452b5128d0db1b37832f5e615be1cff1934f24da0de967929f199be2b3fe283ca1951f98ea3fe languageName: node linkType: hard @@ -17522,18 +17800,18 @@ __metadata: version: 0.0.0-use.local resolution: "wire-webapp@workspace:." dependencies: - "@babel/core": 7.23.7 - "@babel/eslint-parser": 7.23.3 - "@babel/plugin-proposal-decorators": 7.23.7 - "@babel/preset-env": 7.23.8 + "@babel/core": 7.23.9 + "@babel/eslint-parser": 7.23.9 + "@babel/plugin-proposal-decorators": 7.23.9 + "@babel/preset-env": 7.23.9 "@babel/preset-react": 7.23.3 "@babel/preset-typescript": 7.23.3 - "@datadog/browser-logs": ^5.7.0 - "@datadog/browser-rum": ^5.7.0 + "@datadog/browser-logs": ^5.8.0 + "@datadog/browser-rum": ^5.8.0 "@emotion/eslint-plugin": ^11.11.0 "@emotion/react": 11.11.3 - "@faker-js/faker": 8.3.1 - "@formatjs/cli": 6.2.4 + "@faker-js/faker": 8.4.0 + "@formatjs/cli": 6.2.7 "@koush/wrtc": 0.5.3 "@lexical/history": 0.12.5 "@lexical/react": 0.12.5 @@ -17552,10 +17830,10 @@ __metadata: "@types/linkify-it": 3.0.5 "@types/loadable__component": ^5 "@types/markdown-it": 13.0.7 - "@types/node": ^20.11.0 + "@types/node": ^20.11.9 "@types/open-graph": 0.2.5 "@types/platform": 1.3.6 - "@types/react": 18.2.47 + "@types/react": 18.2.48 "@types/react-dom": 18.2.18 "@types/react-redux": 7.1.31 "@types/react-transition-group": 4.4.10 @@ -17568,33 +17846,33 @@ __metadata: "@wireapp/avs": 9.6.9 "@wireapp/commons": 5.2.4 "@wireapp/copy-config": 2.1.14 - "@wireapp/core": 43.5.6 + "@wireapp/core": 43.11.2 "@wireapp/eslint-config": 3.0.5 "@wireapp/prettier-config": 0.6.3 - "@wireapp/react-ui-kit": 9.12.6 + "@wireapp/react-ui-kit": 9.12.8 "@wireapp/store-engine": ^5.1.4 "@wireapp/store-engine-dexie": 2.1.7 "@wireapp/webapp-events": 0.20.1 amplify: "https://github.com/wireapp/amplify#head=master" archiver: ^6.0.1 - autoprefixer: ^10.4.16 + autoprefixer: ^10.4.17 babel-loader: 9.1.3 babel-plugin-transform-import-meta: ^2.2.1 beautiful-react-hooks: ^5.0.1 classnames: 2.5.1 - copy-webpack-plugin: 12.0.1 - core-js: 3.35.0 + copy-webpack-plugin: 12.0.2 + core-js: 3.35.1 countly-sdk-web: 23.12.4 cross-env: 7.0.3 - css-loader: ^6.9.0 + css-loader: ^6.9.1 cssnano: 6.0.3 - date-fns: 3.2.0 + date-fns: 3.3.1 dexie: 3.2.4 dexie-batch: 0.4.3 dexie-encrypted: 2.0.0 - dotenv: 16.3.1 + dotenv: 16.4.1 dpdm: 3.14.0 - emoji-picker-react: 4.6.10 + emoji-picker-react: 4.7.10 eslint: ^8.56.0 eslint-plugin-prettier: ^5.1.3 fake-indexeddb: 5.0.2 @@ -17602,7 +17880,7 @@ __metadata: highlight.js: 11.9.0 html-webpack-plugin: ^5.6.0 http-status-codes: 2.3.0 - husky: 8.0.3 + husky: 9.0.6 i18next-scanner: 4.4.0 intersection-observer: 0.12.2 jest: 29.7.0 @@ -17617,7 +17895,7 @@ __metadata: keyboardjs: 2.7.0 knockout: 3.5.1 less: 4.2.0 - less-loader: ^11.1.4 + less-loader: ^12.1.0 lexical: 0.12.5 libsodium-wrappers: 0.7.13 linkify-it: 5.0.0 @@ -17633,7 +17911,7 @@ __metadata: postcss: 8.4.33 postcss-import: ^16.0.0 postcss-less: 6.0.0 - postcss-loader: ^7.3.4 + postcss-loader: ^8.0.0 postcss-preset-env: ^9.3.0 postcss-scss: 4.0.9 prettier: ^3.2.2 @@ -17641,10 +17919,10 @@ __metadata: react: 18.2.0 react-dom: 18.2.0 react-error-boundary: 4.0.12 - react-intl: 6.5.5 + react-intl: 6.6.2 react-redux: 8.1.3 - react-router: 6.21.2 - react-router-dom: 6.21.2 + react-router: 6.21.3 + react-router-dom: 6.21.3 react-transition-group: 4.4.5 redux: 4.2.1 redux-devtools-extension: 2.13.9 @@ -17668,13 +17946,13 @@ __metadata: typescript: 5.3.3 underscore: 1.13.6 uuidjs: 4.2.13 - webpack: 5.89.0 + webpack: 5.90.0 webpack-cli: 5.1.4 webpack-dev-middleware: 7.0.0 webpack-hot-middleware: 2.26.0 webrtc-adapter: 8.2.3 workbox-webpack-plugin: 7.0.0 - zustand: 4.4.7 + zustand: 4.5.0 languageName: unknown linkType: soft @@ -18173,14 +18451,14 @@ __metadata: languageName: node linkType: hard -"zustand@npm:4.4.7": - version: 4.4.7 - resolution: "zustand@npm:4.4.7" +"zustand@npm:4.5.0": + version: 4.5.0 + resolution: "zustand@npm:4.5.0" dependencies: use-sync-external-store: 1.2.0 peerDependencies: "@types/react": ">=16.8" - immer: ">=9.0" + immer: ">=9.0.6" react: ">=16.8" peerDependenciesMeta: "@types/react": @@ -18189,6 +18467,6 @@ __metadata: optional: true react: optional: true - checksum: 9aeb6cc86162296c1dac504b8906ff952252c129fb3f05cc8926a7f5c9d7fbe098571d5161b3efe3347c0ee1d80197f787b768c7522721864f7323c28766717e + checksum: 91685492ab33bb656b98e07d8fff2be1794d8e68ac5dc546ec457f4ae3d709f0c19de9e93045b9ee5d6b704f64503d9e085ffe1f600f6ade0459e572d1cf5c0d languageName: node linkType: hard