Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 00f63db80f | |||
| 9bcb83a20a | |||
| dd8d8e5410 | |||
| 32b8ff8116 | |||
| 3ceadd512d | |||
| 8182180550 | |||
| aed74c5a72 | |||
| 8c259c53a6 | |||
| 4d59291538 | |||
| 80009a1b31 | |||
| 93e6c95953 | |||
| 27a5507cef | |||
| be06f6655e | |||
| 71152f33bf | |||
| bc8f67089c | |||
| acc9aa8939 | |||
| e76f627fe3 | |||
| 45b1e73842 | |||
| f3eefd2f32 | |||
| f7c053216b | |||
| 9c7739f14f | |||
| 897afe153a | |||
| a929391dcd | |||
| 45c5ee9f65 | |||
| e56aaa16c7 | |||
| da0d3d791e | |||
| ed5eb670a1 | |||
| b7fcb6e4c1 | |||
| bd775f6b61 | |||
| c2f9ad28fc | |||
| 7f33e3462e | |||
| d99363d288 | |||
| 3642b99212 | |||
| 6ec0987286 | |||
| 219eb617dc | |||
| 5d0e2efaf3 | |||
| c7cd5570d3 | |||
| c2f6dd2ce0 | |||
| 393732aaae | |||
| d373fd8540 | |||
| 44a8a9a47a |
@@ -22,7 +22,7 @@ runs:
|
||||
|
||||
- name: Upload tarball signature
|
||||
if: ${{ inputs.upload-url }}
|
||||
uses: shogo82148/actions-upload-release-asset@8f6863c6c894ba46f9e676ef5cccec4752723c1e # v1
|
||||
uses: shogo82148/actions-upload-release-asset@96bc1f0cb850b65efd58a6b5eaa0a69f88d38077 # v1
|
||||
with:
|
||||
upload_url: ${{ inputs.upload-url }}
|
||||
asset_path: ${{ env.VERSION }}.tar.gz.asc
|
||||
|
||||
@@ -29,13 +29,13 @@ runs:
|
||||
|
||||
- name: Upload asset signatures
|
||||
if: inputs.gpg-fingerprint
|
||||
uses: shogo82148/actions-upload-release-asset@8f6863c6c894ba46f9e676ef5cccec4752723c1e # v1
|
||||
uses: shogo82148/actions-upload-release-asset@96bc1f0cb850b65efd58a6b5eaa0a69f88d38077 # v1
|
||||
with:
|
||||
upload_url: ${{ inputs.upload-url }}
|
||||
asset_path: ${{ inputs.asset-path }}.asc
|
||||
|
||||
- name: Upload assets
|
||||
uses: shogo82148/actions-upload-release-asset@8f6863c6c894ba46f9e676ef5cccec4752723c1e # v1
|
||||
uses: shogo82148/actions-upload-release-asset@96bc1f0cb850b65efd58a6b5eaa0a69f88d38077 # v1
|
||||
with:
|
||||
upload_url: ${{ inputs.upload-url }}
|
||||
asset_path: ${{ inputs.asset-path }}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
name: Backport
|
||||
on:
|
||||
pull_request_target:
|
||||
# Privilege escalation necessary to enable backporting PRs from forks
|
||||
# 🚨 We must not execute any checked out code here.
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers]
|
||||
types:
|
||||
- closed
|
||||
- labeled
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
name: Deploy documentation PR preview
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
# Privilege escalation necessary to publish to Netlify
|
||||
# 🚨 We must not execute any checked out code here.
|
||||
workflow_run: # zizmor: ignore[dangerous-triggers]
|
||||
workflows: ["Static Analysis"]
|
||||
types:
|
||||
- completed
|
||||
@@ -15,7 +17,7 @@ jobs:
|
||||
deployments: write
|
||||
steps:
|
||||
- name: 📥 Download artifact
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
|
||||
@@ -21,7 +21,7 @@ concurrency:
|
||||
jobs:
|
||||
playwright:
|
||||
name: Playwright
|
||||
uses: element-hq/element-web/.github/workflows/end-to-end-tests.yaml@develop
|
||||
uses: element-hq/element-web/.github/workflows/end-to-end-tests.yaml@develop # zizmor: ignore[unpinned-uses]
|
||||
permissions:
|
||||
actions: read
|
||||
issues: read
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
name: Pull Request
|
||||
on:
|
||||
pull_request_target:
|
||||
# Privilege escalation necessary access members of the review teams
|
||||
# 🚨 We must not execute any checked out code here, and be careful around use of user-controlled inputs.
|
||||
# FIXME: only `community-prs` job needs this privilege, so it should be in its own workflow file.
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers]
|
||||
types: [opened, edited, labeled, unlabeled, synchronize]
|
||||
merge_group:
|
||||
types: [checks_requested]
|
||||
@@ -15,7 +18,7 @@ jobs:
|
||||
name: Preview Changelog
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: mheap/github-action-required-labels@8afbe8ae6ab7647d0c9f0cfa7c2f939650d22509 # v5
|
||||
- uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5
|
||||
if: github.event_name != 'merge_group'
|
||||
with:
|
||||
labels: |
|
||||
|
||||
@@ -20,9 +20,10 @@ jobs:
|
||||
with:
|
||||
ref: staging
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
node-version-file: package.json
|
||||
cache: "pnpm"
|
||||
|
||||
@@ -13,4 +13,4 @@ jobs:
|
||||
draft:
|
||||
permissions:
|
||||
contents: write
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/release-drafter-workflow.yml@develop
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/release-drafter-workflow.yml@develop # zizmor: ignore[unpinned-uses]
|
||||
|
||||
@@ -27,6 +27,7 @@ jobs:
|
||||
# We will be pushing to this branch and want the CI to run after we do so we cannot use the GITHUB_TOKEN
|
||||
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: true
|
||||
|
||||
- name: Get actions scripts
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
@@ -37,8 +38,8 @@ jobs:
|
||||
sparse-checkout: |
|
||||
scripts/release
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: package.json
|
||||
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
permissions:
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/release-checks.yml@develop
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/release-checks.yml@develop # zizmor: ignore[unpinned-uses]
|
||||
|
||||
release:
|
||||
name: Release
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
- name: Load GPG key
|
||||
id: gpg
|
||||
if: inputs.gpg-fingerprint
|
||||
uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6
|
||||
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
|
||||
- name: Get draft release
|
||||
id: draft-release
|
||||
uses: cardinalby/git-get-release-action@5172c3a026600b1d459b117738c605fabc9e4e44 # v1
|
||||
uses: cardinalby/git-get-release-action@5172c3a026600b1d459b117738c605fabc9e4e44 # 1.2.5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
@@ -82,6 +82,7 @@ jobs:
|
||||
# We will be pushing to this branch and want the CI to run after we do so we cannot use the GITHUB_TOKEN
|
||||
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: true
|
||||
|
||||
- name: Get actions scripts
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
@@ -129,8 +130,8 @@ jobs:
|
||||
git config --global user.email "releases@riot.im"
|
||||
git config --global user.name "RiotRobot"
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: ${{ inputs.dir }}/package.json
|
||||
@@ -286,7 +287,7 @@ jobs:
|
||||
name: Publish to npm
|
||||
needs: release
|
||||
if: inputs.npm
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/release-npm.yml@develop
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/release-npm.yml@develop # zizmor: ignore[unpinned-uses]
|
||||
with:
|
||||
dir: ${{ inputs.dir }}
|
||||
permissions:
|
||||
|
||||
@@ -25,10 +25,11 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: staging
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- name: 🔧 pnpm cache
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
@@ -24,7 +24,7 @@ concurrency: ${{ github.workflow }}
|
||||
permissions: {} # No permissions required
|
||||
jobs:
|
||||
release:
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop # zizmor: ignore[unpinned-uses,secrets-inherit]
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
@@ -50,9 +50,10 @@ jobs:
|
||||
repository: ${{ matrix.repo }}
|
||||
ref: staging
|
||||
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
persist-credentials: true
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version: "lts/*"
|
||||
@@ -77,10 +78,12 @@ jobs:
|
||||
steps:
|
||||
- name: 🧮 Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- name: 🔧 pnpm cache
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: package.json
|
||||
@@ -110,4 +113,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
|
||||
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5
|
||||
|
||||
@@ -13,6 +13,10 @@ on:
|
||||
type: boolean
|
||||
required: false
|
||||
description: "Whether to combine multiple LCOV and sonar-report files in coverage artifact"
|
||||
version-pkg-json-dir:
|
||||
type: string
|
||||
default: "."
|
||||
description: "Relative path of the directory containing package.json with the `version` to use."
|
||||
permissions: {}
|
||||
jobs:
|
||||
sonarqube:
|
||||
@@ -41,9 +45,10 @@ jobs:
|
||||
repository: ${{ github.event.workflow_run.head_repository.full_name }}
|
||||
ref: ${{ github.event.workflow_run.head_branch }} # checkout commit that triggered this workflow
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
persist-credentials: false
|
||||
|
||||
- name: 📥 Download artifact
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
if: ${{ !inputs.sharded }}
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -51,7 +56,7 @@ jobs:
|
||||
name: coverage
|
||||
path: coverage
|
||||
- name: 📥 Download sharded artifacts
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
if: inputs.sharded
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -83,7 +88,7 @@ jobs:
|
||||
repository: ${{ github.event.workflow_run.head_repository.full_name }}
|
||||
is_pr: ${{ github.event.workflow_run.event == 'pull_request' }}
|
||||
skip_coverage_label: Z-Skip-Coverage
|
||||
version_cmd: "cat package.json | jq -r .version"
|
||||
version_cmd: "cat ${{ inputs.version-pkg-json-dir }}/package.json | jq -r .version"
|
||||
branch: ${{ github.event.workflow_run.head_branch }}
|
||||
revision: ${{ github.event.workflow_run.head_sha }}
|
||||
token: ${{ secrets.SONAR_TOKEN }}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
name: SonarQube
|
||||
on:
|
||||
workflow_run:
|
||||
# Privilege escalation necessary to call upon SonarCloud
|
||||
# 🚨 We must not execute any checked out code here.
|
||||
workflow_run: # zizmor: ignore[dangerous-triggers]
|
||||
workflows: ["Tests"]
|
||||
types:
|
||||
- completed
|
||||
@@ -16,7 +18,7 @@ jobs:
|
||||
actions: read
|
||||
statuses: write
|
||||
id-token: write # sonar
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/sonarcloud.yml@develop
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/sonarcloud.yml@develop # zizmor: ignore[unpinned-uses]
|
||||
secrets:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
@@ -15,9 +15,11 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: package.json
|
||||
@@ -33,9 +35,11 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: package.json
|
||||
@@ -51,9 +55,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: package.json
|
||||
@@ -79,11 +85,15 @@ jobs:
|
||||
workflow_lint:
|
||||
name: "Workflow Lint"
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: package.json
|
||||
@@ -94,14 +104,19 @@ jobs:
|
||||
- name: Run Linter
|
||||
run: "pnpm lint:workflows"
|
||||
|
||||
- name: Run zizmor
|
||||
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
|
||||
|
||||
docs:
|
||||
name: "JSDoc Checker"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: package.json
|
||||
@@ -113,7 +128,7 @@ jobs:
|
||||
run: "pnpm run gendoc --treatWarningsAsErrors --suppressCommentWarningsInDeclarationFiles"
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||
with:
|
||||
name: docs
|
||||
path: _docs
|
||||
@@ -125,9 +140,11 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version-file: package.json
|
||||
@@ -146,9 +163,10 @@ jobs:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
repository: element-hq/element-web
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version: "lts/*"
|
||||
@@ -163,13 +181,19 @@ jobs:
|
||||
working-directory: apps/web
|
||||
run: "pnpm run lint:types"
|
||||
|
||||
# Hook for branch protection to skip downstream typechecking outside of merge queues
|
||||
downstream:
|
||||
name: Downstream Typescript Syntax Check
|
||||
# Workflow consolidation job
|
||||
done:
|
||||
needs:
|
||||
- ts_lint
|
||||
- js_lint
|
||||
- node_example_lint
|
||||
- workflow_lint
|
||||
- docs
|
||||
- analyse_dead_code
|
||||
- element-web
|
||||
name: Static Analysis
|
||||
runs-on: ubuntu-24.04
|
||||
if: always()
|
||||
needs:
|
||||
- element-web
|
||||
steps:
|
||||
- if: needs.element-web.result != 'skipped' && needs.element-web.result != 'success'
|
||||
- if: contains(needs.*.result , 'failure') || contains(needs.*.result, 'cancelled')
|
||||
run: exit 1
|
||||
|
||||
@@ -11,7 +11,7 @@ on:
|
||||
permissions: {} # We use ELEMENT_BOT_TOKEN instead
|
||||
jobs:
|
||||
sync-labels:
|
||||
uses: element-hq/element-meta/.github/workflows/sync-labels.yml@develop
|
||||
uses: element-hq/element-meta/.github/workflows/sync-labels.yml@7f2f93fb9b52ece7a0998f60e64862aa203c1746
|
||||
with:
|
||||
LABELS: |
|
||||
element-hq/element-meta
|
||||
|
||||
+15
-10
@@ -23,11 +23,13 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
|
||||
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
|
||||
- name: Setup Node
|
||||
id: setupNode
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
||||
with:
|
||||
cache: "pnpm"
|
||||
node-version: ${{ matrix.node }}
|
||||
@@ -42,19 +44,22 @@ jobs:
|
||||
- name: Run tests
|
||||
run: |
|
||||
pnpm test \
|
||||
--coverage=${{ env.ENABLE_COVERAGE }} \
|
||||
--maxWorkers ${{ steps.cpu-cores.outputs.count }} \
|
||||
--coverage=${ENABLE_COVERAGE} \
|
||||
--maxWorkers ${NUM_WORKERS} \
|
||||
./spec/${{ matrix.specs }}
|
||||
env:
|
||||
SHARD: ${{ matrix.specs }}
|
||||
NUM_WORKERS: ${{ steps.cpu-cores.outputs.count }}
|
||||
|
||||
- name: Move coverage files into place
|
||||
if: env.ENABLE_COVERAGE == 'true'
|
||||
run: mv coverage/lcov.info coverage/${{ steps.setupNode.outputs.node-version }}-${{ matrix.specs }}.lcov.info
|
||||
run: mv coverage/lcov.info coverage/${NODE_VERSION}-${{ matrix.specs }}.lcov.info
|
||||
env:
|
||||
NODE_VERSION: ${{ steps.setupNode.outputs.node-version }}
|
||||
|
||||
- name: Upload Artifact
|
||||
if: env.ENABLE_COVERAGE == 'true'
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||
with:
|
||||
name: coverage-${{ matrix.specs }}-${{ matrix.node == 'lts/*' && 'lts' || matrix.node }}
|
||||
path: |
|
||||
@@ -74,7 +79,7 @@ jobs:
|
||||
element-web:
|
||||
name: Downstream test element-web
|
||||
if: github.event_name == 'merge_group'
|
||||
uses: element-hq/element-web/.github/workflows/tests.yml@develop
|
||||
uses: element-hq/element-web/.github/workflows/tests.yml@develop # zizmor: ignore[unpinned-uses]
|
||||
permissions:
|
||||
statuses: write
|
||||
with:
|
||||
@@ -83,9 +88,9 @@ jobs:
|
||||
|
||||
complement-crypto:
|
||||
name: "Run Complement Crypto tests"
|
||||
if: github.event_name == 'merge_group'
|
||||
permissions: read-all
|
||||
uses: matrix-org/complement-crypto/.github/workflows/single_sdk_tests.yml@main
|
||||
if: false # disabled due to flakiness
|
||||
permissions: read-all # zizmor: ignore[excessive-permissions]
|
||||
uses: matrix-org/complement-crypto/.github/workflows/single_sdk_tests.yml@main # zizmor: ignore[unpinned-uses]
|
||||
with:
|
||||
use_js_sdk: "."
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
automate-project-columns-next:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
- uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
|
||||
with:
|
||||
project-url: https://github.com/orgs/element-hq/projects/120
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
@@ -6,6 +6,6 @@ on:
|
||||
permissions: {} # We use ELEMENT_BOT_TOKEN instead
|
||||
jobs:
|
||||
call-triage-labelled:
|
||||
uses: element-hq/element-web/.github/workflows/triage-labelled.yml@develop
|
||||
uses: element-hq/element-web/.github/workflows/triage-labelled.yml@6339bcda15c71d209303b18a06a9b1c021220bf9
|
||||
secrets:
|
||||
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
Changes in [41.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v41.2.0) (2026-03-24)
|
||||
==================================================================================================
|
||||
## ✨ Features
|
||||
|
||||
* Only share history if room history visibility is shared ([#5216](https://github.com/matrix-org/matrix-js-sdk/pull/5216)). Contributed by @kaylendog.
|
||||
* History sharing: resume key-bundle import on restart ([#5214](https://github.com/matrix-org/matrix-js-sdk/pull/5214)). Contributed by @richvdh.
|
||||
* Move `CryptoApi.shareRoomHistoryWithUser` to `CryptoBackend` ([#5218](https://github.com/matrix-org/matrix-js-sdk/pull/5218)). Contributed by @richvdh.
|
||||
|
||||
|
||||
Changes in [41.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v41.1.0) (2026-03-10)
|
||||
==================================================================================================
|
||||
## ✨ Features
|
||||
|
||||
+6
-6
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "matrix-js-sdk",
|
||||
"version": "41.1.0",
|
||||
"version": "41.3.0-rc.0",
|
||||
"description": "Matrix Client-Server SDK for Javascript",
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
@@ -48,7 +48,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@matrix-org/matrix-sdk-crypto-wasm": "^17.1.0",
|
||||
"@matrix-org/matrix-sdk-crypto-wasm": "^18.0.0",
|
||||
"another-json": "^0.2.0",
|
||||
"bs58": "^6.0.0",
|
||||
"content-type": "^1.0.4",
|
||||
@@ -106,7 +106,7 @@
|
||||
"fetch-mock": "^12.6.0",
|
||||
"happy-dom": "^20.1.0",
|
||||
"husky": "^9.0.0",
|
||||
"knip": "^5.0.0",
|
||||
"knip": "^6.0.0",
|
||||
"lint-staged": "^16.0.0",
|
||||
"matrix-mock-request": "^2.5.0",
|
||||
"prettier": "3.8.1",
|
||||
@@ -114,12 +114,12 @@
|
||||
"typedoc-plugin-coverage": "^4.0.0",
|
||||
"typedoc-plugin-mdn-links": "^5.0.0",
|
||||
"typedoc-plugin-missing-exports": "^4.0.0",
|
||||
"typescript": "^5.4.2",
|
||||
"typescript": "^6.0.0",
|
||||
"vitest": "^4.0.17",
|
||||
"vitest-sonar-reporter": "^3.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"expect": "30.2.0"
|
||||
"expect": "30.3.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
@@ -131,5 +131,5 @@
|
||||
"eslint": "8"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@10.29.3+sha512.498e1fb4cca5aa06c1dcf2611e6fafc50972ffe7189998c409e90de74566444298ffe43e6cd2acdc775ba1aa7cc5e092a8b7054c811ba8c5770f84693d33d2dc"
|
||||
"packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be"
|
||||
}
|
||||
|
||||
Generated
+945
-609
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { QrCodeData, QrCodeMode } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { QrCodeData, QrCodeIntent } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import fetchMock from "@fetch-mock/vitest";
|
||||
|
||||
import {
|
||||
@@ -146,7 +146,7 @@ describe("MSC4108SignInWithQR", () => {
|
||||
|
||||
const ourChannel = new MSC4108SecureChannel(ourMockSession);
|
||||
const qrCodeData = QrCodeData.fromBytes(
|
||||
await ourChannel.generateCode(QrCodeMode.Reciprocate, client.getDomain()!),
|
||||
await ourChannel.generateCode(QrCodeIntent.Reciprocate, client.getDomain()!),
|
||||
);
|
||||
const opponentChannel = new MSC4108SecureChannel(opponentMockSession, qrCodeData.publicKey);
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ describe("oidc authorization", () => {
|
||||
describe("completeAuthorizationCodeGrant", () => {
|
||||
const homeserverUrl = "https://server.org/";
|
||||
const identityServerUrl = "https://id.org/";
|
||||
const nonce = "test-nonce";
|
||||
const nonce = "hRpB6pkE06";
|
||||
const redirectUri = baseUrl;
|
||||
const code = "auth_code_xyz";
|
||||
const validBearerTokenResponse = {
|
||||
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { type EstablishedEcies, QrCodeData, QrCodeMode, Ecies } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { type EstablishedEcies, QrCodeData, QrCodeIntent, Ecies } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
|
||||
import { MSC4108RendezvousSession, MSC4108SecureChannel, PayloadType } from "../../../../src/rendezvous";
|
||||
|
||||
@@ -28,7 +28,7 @@ describe("MSC4108SecureChannel", () => {
|
||||
});
|
||||
const channel = new MSC4108SecureChannel(session);
|
||||
|
||||
const code = await channel.generateCode(QrCodeMode.Login);
|
||||
const code = await channel.generateCode(QrCodeIntent.Login);
|
||||
expect(code).toHaveLength(71);
|
||||
const text = new TextDecoder().decode(code);
|
||||
expect(text.startsWith("MATRIX")).toBeTruthy();
|
||||
@@ -43,7 +43,7 @@ describe("MSC4108SecureChannel", () => {
|
||||
} as unknown as MSC4108RendezvousSession;
|
||||
const channel = new MSC4108SecureChannel(mockSession);
|
||||
|
||||
const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeMode.Reciprocate, baseUrl));
|
||||
const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeIntent.Reciprocate, baseUrl));
|
||||
const { initial_message: ciphertext } = new Ecies().establish_outbound_channel(
|
||||
qrCodeData.publicKey,
|
||||
"MATRIX_QR_CODE_LOGIN_INITIATE",
|
||||
@@ -64,7 +64,7 @@ describe("MSC4108SecureChannel", () => {
|
||||
vi.mocked(mockSession.receive).mockResolvedValue("");
|
||||
await expect(channel.connect()).rejects.toThrow("No response from other device");
|
||||
|
||||
const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeMode.Reciprocate, baseUrl));
|
||||
const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeIntent.Reciprocate, baseUrl));
|
||||
const { initial_message: ciphertext } = new Ecies().establish_outbound_channel(
|
||||
qrCodeData.publicKey,
|
||||
"NOT_REAL_MATRIX_QR_CODE_LOGIN_INITIATE",
|
||||
@@ -87,7 +87,7 @@ describe("MSC4108SecureChannel", () => {
|
||||
} as unknown as MSC4108RendezvousSession;
|
||||
channel = new MSC4108SecureChannel(mockSession);
|
||||
|
||||
const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeMode.Reciprocate, baseUrl));
|
||||
const qrCodeData = QrCodeData.fromBytes(await channel.generateCode(QrCodeIntent.Reciprocate, baseUrl));
|
||||
const { channel: _opponentChannel, initial_message: ciphertext } = new Ecies().establish_outbound_channel(
|
||||
qrCodeData.publicKey,
|
||||
"MATRIX_QR_CODE_LOGIN_INITIATE",
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
KeysQueryRequest,
|
||||
Migration,
|
||||
OlmMachine,
|
||||
type OtherUserIdentity,
|
||||
type PickledInboundGroupSession,
|
||||
type PickledSession,
|
||||
StoreHandle,
|
||||
@@ -109,6 +110,7 @@ describe("initRustCrypto", () => {
|
||||
getBackupKeys: vi.fn(),
|
||||
getIdentity: vi.fn().mockResolvedValue(null),
|
||||
trackedUsers: vi.fn(),
|
||||
getAllRoomsPendingKeyBundles: vi.fn().mockResolvedValue([]),
|
||||
} as unknown as Mocked<OlmMachine>;
|
||||
}
|
||||
|
||||
@@ -1535,7 +1537,7 @@ describe("RustCrypto", () => {
|
||||
free: vi.fn(),
|
||||
isVerified: vi.fn().mockReturnValue(true),
|
||||
wasPreviouslyVerified: vi.fn().mockReturnValue(true),
|
||||
});
|
||||
} as unknown as OtherUserIdentity);
|
||||
|
||||
const userVerificationStatus = await rustCrypto.getUserVerificationStatus(testData.TEST_USER_ID);
|
||||
expect(userVerificationStatus.isVerified()).toBeTruthy();
|
||||
@@ -2388,6 +2390,7 @@ describe("RustCrypto", () => {
|
||||
queryKeysForUsers: vi.fn().mockReturnValue({}),
|
||||
getReceivedRoomKeyBundleData: vi.fn(),
|
||||
receiveRoomKeyBundle: vi.fn(),
|
||||
clearRoomPendingKeyBundle: vi.fn(),
|
||||
} as unknown as Mocked<OlmMachine>;
|
||||
|
||||
const http = new MatrixHttpApi(new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>(), {
|
||||
@@ -2448,6 +2451,10 @@ describe("RustCrypto", () => {
|
||||
expect(mockOlmMachine.receiveRoomKeyBundle).toHaveBeenCalledTimes(1);
|
||||
expect(mockOlmMachine.receiveRoomKeyBundle.mock.calls[0][0]).toBe(bundleData);
|
||||
expect(mockOlmMachine.receiveRoomKeyBundle.mock.calls[0][1]).toEqual(new TextEncoder().encode("asdfghjkl"));
|
||||
|
||||
// It should also flag the room as not waiting for a key bundle
|
||||
expect(mockOlmMachine.clearRoomPendingKeyBundle).toHaveBeenCalledTimes(1);
|
||||
expect(mockOlmMachine.clearRoomPendingKeyBundle.mock.calls[0][0].toString()).toEqual("!room_id");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { type OutgoingRequest } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { type OtherUserIdentity, type OutgoingRequest } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { type Mocked } from "vitest";
|
||||
|
||||
import {
|
||||
@@ -138,7 +138,9 @@ describe("VerificationRequest", () => {
|
||||
await bobOlmMachine.updateTrackedUsers([new RustSdkCryptoJs.UserId(aliceUserId)]);
|
||||
|
||||
// Alice requests verification
|
||||
const bobUserIdentity = await aliceOlmMachine.getIdentity(new RustSdkCryptoJs.UserId(bobUserId));
|
||||
const bobUserIdentity = (await aliceOlmMachine.getIdentity(
|
||||
new RustSdkCryptoJs.UserId(bobUserId),
|
||||
)) as OtherUserIdentity;
|
||||
|
||||
const roomId = new RustSdkCryptoJs.RoomId("!roomId:example.org");
|
||||
const methods = [verificationMethodIdentifierToMethod("m.sas.v1")];
|
||||
@@ -276,7 +278,9 @@ describe("VerificationRequest", () => {
|
||||
await bobOlmMachine.updateTrackedUsers([new RustSdkCryptoJs.UserId(aliceUserId)]);
|
||||
|
||||
// Alice requests verification
|
||||
const bobUserIdentity = await aliceOlmMachine.getIdentity(new RustSdkCryptoJs.UserId(bobUserId));
|
||||
const bobUserIdentity = (await aliceOlmMachine.getIdentity(
|
||||
new RustSdkCryptoJs.UserId(bobUserId),
|
||||
)) as OtherUserIdentity;
|
||||
|
||||
const roomId = new RustSdkCryptoJs.RoomId("!roomId:example.org");
|
||||
const methods = [verificationMethodIdentifierToMethod("m.sas.v1")];
|
||||
@@ -394,7 +398,9 @@ describe("VerificationRequest", () => {
|
||||
await bobOlmMachine.updateTrackedUsers([new RustSdkCryptoJs.UserId(aliceUserId)]);
|
||||
|
||||
// Alice requests verification
|
||||
const bobUserIdentity = await aliceOlmMachine.getIdentity(new RustSdkCryptoJs.UserId(bobUserId));
|
||||
const bobUserIdentity = (await aliceOlmMachine.getIdentity(
|
||||
new RustSdkCryptoJs.UserId(bobUserId),
|
||||
)) as OtherUserIdentity;
|
||||
|
||||
const roomId = new RustSdkCryptoJs.RoomId("!roomId:example.org");
|
||||
const methods = [
|
||||
|
||||
@@ -58,7 +58,9 @@ export interface InviteOpts {
|
||||
/**
|
||||
* Before sending the invite, if the room is encrypted, share the keys for any messages sent while the history
|
||||
* visibility was `shared`, via the experimental
|
||||
* support for [MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268).
|
||||
* support for [MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268). If the room's current
|
||||
* history visibility setting is neither `shared` nor `world_readable`, history sharing will be disabled to prevent
|
||||
* exposing keys for messages sent prior to the visibility restriction.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
|
||||
+12
-7
@@ -101,7 +101,7 @@ import {
|
||||
type RoomNameState,
|
||||
} from "./models/room.ts";
|
||||
import { RoomMemberEvent, type RoomMemberEventHandlerMap } from "./models/room-member.ts";
|
||||
import { type IPowerLevelsContent, type RoomStateEvent, type RoomStateEventHandlerMap } from "./models/room-state.ts";
|
||||
import { RoomStateEvent, type IPowerLevelsContent, type RoomStateEventHandlerMap } from "./models/room-state.ts";
|
||||
import {
|
||||
isSendDelayedEventRequestOpts,
|
||||
UpdateDelayedEventAction,
|
||||
@@ -2027,6 +2027,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
|
||||
// attach the event listeners needed by RustCrypto
|
||||
this.on(RoomMemberEvent.Membership, rustCrypto.onRoomMembership.bind(rustCrypto));
|
||||
this.on(RoomStateEvent.Events, rustCrypto.onRoomStateEvent.bind(rustCrypto));
|
||||
this.on(ClientEvent.Event, (event) => {
|
||||
rustCrypto.onLiveEventFromSync(event);
|
||||
});
|
||||
@@ -2428,12 +2429,10 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
|
||||
const roomId = res.room_id;
|
||||
if (opts.acceptSharedHistory && inviter && this.cryptoBackend) {
|
||||
// Flag upfront that we are waiting for a key bundle, so that if we crash mid-import, we can try again.
|
||||
await this.cryptoBackend.markRoomAsPendingKeyBundle(roomId, inviter);
|
||||
// Try to accept the room key bundle specified in a `m.room_key_bundle` to-device message we (might have) already received.
|
||||
const bundleDownloaded = await this.cryptoBackend.maybeAcceptKeyBundle(roomId, inviter);
|
||||
// If this fails, i.e. we haven't received this message yet, we need to wait until the to-device message arrives.
|
||||
if (!bundleDownloaded) {
|
||||
this.cryptoBackend.markRoomAsPendingKeyBundle(roomId, inviter);
|
||||
}
|
||||
await this.cryptoBackend.maybeAcceptKeyBundle(roomId, inviter);
|
||||
}
|
||||
|
||||
// In case we were originally given an alias, check the room cache again
|
||||
@@ -4088,7 +4087,13 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
}
|
||||
|
||||
if (opts.shareEncryptedHistory) {
|
||||
await this.cryptoBackend?.shareRoomHistoryWithUser(roomId, userId);
|
||||
const historyVisibility = this.getRoom(roomId)?.getHistoryVisibility() ?? HistoryVisibility.Shared;
|
||||
// We should only share room history if the *current* visibility allows it.
|
||||
if ([HistoryVisibility.Invited, HistoryVisibility.Joined].includes(historyVisibility)) {
|
||||
this.logger.debug("Not sharing message history as the room history visibility is currently unshared");
|
||||
} else {
|
||||
await this.cryptoBackend?.shareRoomHistoryWithUser(roomId, userId);
|
||||
}
|
||||
}
|
||||
|
||||
return await this.membershipChange(roomId, userId, KnownMembership.Invite, opts.reason);
|
||||
|
||||
@@ -80,6 +80,18 @@ export interface CryptoBackend extends SyncCryptoCallbacks, CryptoApi {
|
||||
*/
|
||||
importBackedUpRoomKeys(keys: IMegolmSessionData[], backupVersion: string, opts?: ImportRoomKeysOpts): Promise<void>;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Room key history sharing (MSC4268)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Share any shareable E2EE history in the given room with the given recipient,
|
||||
* as per [MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268)
|
||||
*/
|
||||
shareRoomHistoryWithUser(roomId: string, userId: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Having accepted an invite for the given room from the given user, attempt to
|
||||
* find information about a room key bundle and, if found, download the
|
||||
@@ -103,7 +115,7 @@ export interface CryptoBackend extends SyncCryptoCallbacks, CryptoApi {
|
||||
* @param roomId - The room we were invited to, for which we did not receive a key bundle before accepting the invite.
|
||||
* @param inviterId - The user who invited us to the room and is expected to send the room key bundle.
|
||||
*/
|
||||
markRoomAsPendingKeyBundle(roomId: string, inviterId: string): void;
|
||||
markRoomAsPendingKeyBundle(roomId: string, inviterId: string): Promise<void>;
|
||||
}
|
||||
|
||||
/** The methods which crypto implementations should expose to the Sync api
|
||||
|
||||
+6
-14
@@ -720,20 +720,6 @@ export interface CryptoApi {
|
||||
* @param secrets - The secrets bundle received from the other device
|
||||
*/
|
||||
importSecretsBundle?(secrets: Awaited<ReturnType<SecretsBundle["to_json"]>>): Promise<void>;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Room key history sharing (MSC4268)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Share any shareable E2EE history in the given room with the given recipient,
|
||||
* as per [MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268)
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
shareRoomHistoryWithUser(roomId: string, userId: string): Promise<void>;
|
||||
}
|
||||
|
||||
/** A reason code for a failure to decrypt an event. */
|
||||
@@ -808,6 +794,9 @@ export enum DeviceIsolationModeKind {
|
||||
*
|
||||
* Events from all senders are always decrypted (and should be decorated with message shields in case
|
||||
* of authenticity warnings, see {@link EventEncryptionInfo}).
|
||||
*
|
||||
* `AllDevicesIsolationMode` is used in the legacy, non-'exclude insecure devices' mode in Element Web. It is not
|
||||
* recommended (see {@link https://github.com/matrix-org/matrix-spec-proposals/pull/4153 | MSC4153}).
|
||||
*/
|
||||
export class AllDevicesIsolationMode {
|
||||
public readonly kind = DeviceIsolationModeKind.AllDevicesIsolationMode;
|
||||
@@ -834,6 +823,9 @@ export class AllDevicesIsolationMode {
|
||||
*
|
||||
* Events are decrypted only if they come from a cross-signed device. Other events will result in a decryption
|
||||
* failure. (To access the failure reason, see {@link MatrixEvent.decryptionFailureReason}.)
|
||||
*
|
||||
* `OnlySignedDevicesIsolationMode` corresponds to the 'Exclude insecure devices' mode in Element Web, which is
|
||||
* recommended by {@link https://github.com/matrix-org/matrix-spec-proposals/pull/4153 | MSC4153}.
|
||||
*/
|
||||
export class OnlySignedDevicesIsolationMode {
|
||||
public readonly kind = DeviceIsolationModeKind.OnlySignedDevicesIsolationMode;
|
||||
|
||||
@@ -82,6 +82,7 @@ export * from "./models/room-summary.ts";
|
||||
export * from "./models/event-status.ts";
|
||||
export * from "./models/profile-keys.ts";
|
||||
export * from "./models/related-relations.ts";
|
||||
export { type StickyMatrixEvent, RoomStickyEventsEvent } from "./models/room-sticky-events.ts";
|
||||
export type { RoomSummary } from "./client.ts";
|
||||
export * as ContentHelpers from "./content-helpers.ts";
|
||||
export * as SecretStorage from "./secret-storage.ts";
|
||||
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { QrCodeMode } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { QrCodeIntent } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
|
||||
import {
|
||||
ClientRendezvousFailureReason,
|
||||
@@ -108,7 +108,7 @@ interface SecretsPayload extends MSC4108Payload, Awaited<ReturnType<NonNullable<
|
||||
* @experimental Note that this is UNSTABLE and may have breaking changes without notice.
|
||||
*/
|
||||
export class MSC4108SignInWithQR {
|
||||
private readonly ourIntent: QrCodeMode;
|
||||
private readonly ourIntent: QrCodeIntent;
|
||||
private _code?: Uint8Array;
|
||||
private expectingNewDeviceId?: string;
|
||||
|
||||
@@ -131,7 +131,7 @@ export class MSC4108SignInWithQR {
|
||||
private readonly client?: MatrixClient,
|
||||
public onFailure?: RendezvousFailureListener,
|
||||
) {
|
||||
this.ourIntent = client ? QrCodeMode.Reciprocate : QrCodeMode.Login;
|
||||
this.ourIntent = client ? QrCodeIntent.Reciprocate : QrCodeIntent.Login;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,9 +149,9 @@ export class MSC4108SignInWithQR {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ourIntent === QrCodeMode.Reciprocate && this.client) {
|
||||
if (this.ourIntent === QrCodeIntent.Reciprocate && this.client) {
|
||||
this._code = await this.channel.generateCode(this.ourIntent, this.client.getDomain()!);
|
||||
} else if (this.ourIntent === QrCodeMode.Login) {
|
||||
} else if (this.ourIntent === QrCodeIntent.Login) {
|
||||
this._code = await this.channel.generateCode(this.ourIntent);
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ export class MSC4108SignInWithQR {
|
||||
* Returns true if the device is the already logged in device reciprocating a new login on the other side of the channel.
|
||||
*/
|
||||
public get isExistingDevice(): boolean {
|
||||
return this.ourIntent === QrCodeMode.Reciprocate;
|
||||
return this.ourIntent === QrCodeIntent.Reciprocate;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
Ecies,
|
||||
type EstablishedEcies,
|
||||
QrCodeData,
|
||||
QrCodeMode,
|
||||
QrCodeIntent,
|
||||
} from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
|
||||
import {
|
||||
@@ -56,9 +56,9 @@ export class MSC4108SecureChannel {
|
||||
* @param mode the mode to generate the QR code in, either `Login` or `Reciprocate`.
|
||||
* @param serverName the name of the homeserver to connect to, as defined by server discovery in the spec, required for `Reciprocate` mode.
|
||||
*/
|
||||
public async generateCode(mode: QrCodeMode.Login): Promise<Uint8Array>;
|
||||
public async generateCode(mode: QrCodeMode.Reciprocate, serverName: string): Promise<Uint8Array>;
|
||||
public async generateCode(mode: QrCodeMode, serverName?: string): Promise<Uint8Array> {
|
||||
public async generateCode(mode: QrCodeIntent.Login): Promise<Uint8Array>;
|
||||
public async generateCode(mode: QrCodeIntent.Reciprocate, serverName: string): Promise<Uint8Array>;
|
||||
public async generateCode(mode: QrCodeIntent, serverName?: string): Promise<Uint8Array> {
|
||||
const { url } = this.rendezvousSession;
|
||||
|
||||
if (!url) {
|
||||
@@ -68,7 +68,7 @@ export class MSC4108SecureChannel {
|
||||
return new QrCodeData(
|
||||
this.secureChannel.public_key(),
|
||||
url,
|
||||
mode === QrCodeMode.Reciprocate ? serverName : undefined,
|
||||
mode === QrCodeIntent.Reciprocate ? serverName : undefined,
|
||||
).toBytes();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ limitations under the License.
|
||||
import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { StoreHandle } from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
|
||||
import { RustCrypto } from "./rust-crypto.ts";
|
||||
import { MAX_INVITE_ACCEPTANCE_MS_FOR_KEY_BUNDLE, RustCrypto } from "./rust-crypto.ts";
|
||||
import { type IHttpOpts, type MatrixHttpApi } from "../http-api/index.ts";
|
||||
import { type ServerSideSecretStorage } from "../secret-storage.ts";
|
||||
import { type Logger } from "../logger.ts";
|
||||
@@ -247,5 +247,21 @@ async function initOlmMachine(
|
||||
}
|
||||
}
|
||||
|
||||
// If we have any recently-joined rooms, see if we have a pending key bundle for them.
|
||||
for (const pendingDetails of await olmMachine.getAllRoomsPendingKeyBundles()) {
|
||||
const roomId = pendingDetails.roomId.toString();
|
||||
if (Date.now() - pendingDetails.inviteAcceptedAtMillis <= MAX_INVITE_ACCEPTANCE_MS_FOR_KEY_BUNDLE) {
|
||||
logger.info(
|
||||
`Checking for pending key bundle for recently-joined room ${roomId} (joined ${new Date(pendingDetails.inviteAcceptedAtMillis).toISOString()})`,
|
||||
);
|
||||
await rustCrypto.maybeAcceptKeyBundle(roomId, pendingDetails.inviterId.toString());
|
||||
} else {
|
||||
logger.info(
|
||||
`Clearing pending-key-bundle flag for room ${roomId} (too old: joined ${new Date(pendingDetails.inviteAcceptedAtMillis).toISOString()})`,
|
||||
);
|
||||
await olmMachine.clearRoomPendingKeyBundle(new RustSdkCryptoJs.RoomId(roomId));
|
||||
}
|
||||
}
|
||||
|
||||
return rustCrypto;
|
||||
}
|
||||
|
||||
+108
-46
@@ -98,6 +98,7 @@ import { VerificationMethod } from "../types.ts";
|
||||
import { keyFromAuthData } from "../common-crypto/key-passphrase.ts";
|
||||
import { type UIAuthCallback } from "../interactive-auth.ts";
|
||||
import { getHttpUriForMxc } from "../content-repo.ts";
|
||||
import { type RoomState } from "../matrix.ts";
|
||||
|
||||
const ALL_VERIFICATION_METHODS = [
|
||||
VerificationMethod.Sas,
|
||||
@@ -111,6 +112,9 @@ interface ISignableObject {
|
||||
unsigned?: object;
|
||||
}
|
||||
|
||||
/** The maximum time, in milliseconds, since we accepted an invite, that we should accept a key bundle. */
|
||||
export const MAX_INVITE_ACCEPTANCE_MS_FOR_KEY_BUNDLE = 24 * 60 * 60 * 1000; // 24 hours
|
||||
|
||||
/**
|
||||
* An implementation of {@link CryptoBackend} using the Rust matrix-sdk-crypto.
|
||||
*
|
||||
@@ -131,9 +135,6 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
/** mapping of roomId → encryptor class */
|
||||
private roomEncryptors: Record<string, RoomEncryptor> = {};
|
||||
|
||||
/** mapping of room ID -> inviter ID for rooms pending MSC4268 key bundles */
|
||||
private readonly roomsPendingKeyBundles: Map<string, string> = new Map();
|
||||
|
||||
private eventDecryptor: EventDecryptor;
|
||||
private keyClaimManager: KeyClaimManager;
|
||||
private outgoingRequestProcessor: OutgoingRequestProcessor;
|
||||
@@ -370,10 +371,10 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
/* allowRedirects */ true,
|
||||
/* useAuthentication */ true,
|
||||
);
|
||||
let encryptedBundle: Blob;
|
||||
let encryptedBundle: Uint8Array;
|
||||
try {
|
||||
const bundleUrl = new URL(url);
|
||||
encryptedBundle = await this.http.authedRequest<Blob>(
|
||||
const encryptedBundleBlob = await this.http.authedRequest<Blob>(
|
||||
Method.Get,
|
||||
bundleUrl.pathname + bundleUrl.search,
|
||||
{},
|
||||
@@ -383,17 +384,24 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
prefix: "",
|
||||
},
|
||||
);
|
||||
logger.info(`Received blob of length ${encryptedBundleBlob.size}`);
|
||||
encryptedBundle = new Uint8Array(await encryptedBundleBlob.arrayBuffer());
|
||||
} catch (err) {
|
||||
logger.warn(`Error downloading encrypted bundle from ${url}:`, err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
logger.info(`Received blob of length ${encryptedBundle.size}`);
|
||||
try {
|
||||
await this.olmMachine.receiveRoomKeyBundle(bundleData, new Uint8Array(await encryptedBundle.arrayBuffer()));
|
||||
await this.olmMachine.receiveRoomKeyBundle(bundleData, encryptedBundle);
|
||||
} catch (err) {
|
||||
logger.warn(`Error receiving encrypted bundle:`, err);
|
||||
|
||||
throw err;
|
||||
} finally {
|
||||
// Even if we were unable to import the bundle, we still clear the flag that indicates that we
|
||||
// are waiting for the bundle to be received. The only reason this can happen is that the bundle was
|
||||
// malformed somehow, so we don't want to keep retrying it.
|
||||
await this.olmMachine.clearRoomPendingKeyBundle(new RustSdkCryptoJs.RoomId(roomId));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -402,8 +410,11 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
/**
|
||||
* Implementation of {@link CryptoBackend.markRoomAsPendingKeyBundle}.
|
||||
*/
|
||||
public markRoomAsPendingKeyBundle(roomId: string, inviter: string): void {
|
||||
this.roomsPendingKeyBundles.set(roomId, inviter);
|
||||
public async markRoomAsPendingKeyBundle(roomId: string, inviter: string): Promise<void> {
|
||||
await this.olmMachine.storeRoomPendingKeyBundle(
|
||||
new RustSdkCryptoJs.RoomId(roomId),
|
||||
new RustSdkCryptoJs.UserId(inviter),
|
||||
);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -781,9 +792,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
* Implementation of {@link CryptoApi#getCrossSigningKeyId}
|
||||
*/
|
||||
public async getCrossSigningKeyId(type: CrossSigningKey = CrossSigningKey.Master): Promise<string | null> {
|
||||
const userIdentity: RustSdkCryptoJs.OwnUserIdentity | undefined = await this.olmMachine.getIdentity(
|
||||
new RustSdkCryptoJs.UserId(this.userId),
|
||||
);
|
||||
const userIdentity = await this.getOwnIdentity();
|
||||
if (!userIdentity) {
|
||||
// The public keys are not available on this device
|
||||
return null;
|
||||
@@ -1012,9 +1021,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
* Implementation of {@link CryptoApi#getCrossSigningStatus}
|
||||
*/
|
||||
public async getCrossSigningStatus(): Promise<CrossSigningStatus> {
|
||||
const userIdentity: RustSdkCryptoJs.OwnUserIdentity | null = await this.getOlmMachineOrThrow().getIdentity(
|
||||
new RustSdkCryptoJs.UserId(this.userId),
|
||||
);
|
||||
const userIdentity = await this.getOwnIdentity();
|
||||
|
||||
const publicKeysOnDevice =
|
||||
Boolean(userIdentity?.masterKey) &&
|
||||
@@ -1128,9 +1135,9 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
* Implementation of {@link CryptoApi#requestVerificationDM}
|
||||
*/
|
||||
public async requestVerificationDM(userId: string, roomId: string): Promise<VerificationRequest> {
|
||||
const userIdentity: RustSdkCryptoJs.OtherUserIdentity | undefined = await this.olmMachine.getIdentity(
|
||||
new RustSdkCryptoJs.UserId(userId),
|
||||
);
|
||||
const userIdentity = (await this.olmMachine.getIdentity(new RustSdkCryptoJs.UserId(userId))) as
|
||||
| RustSdkCryptoJs.OtherUserIdentity
|
||||
| undefined;
|
||||
|
||||
if (!userIdentity) throw new Error(`unknown userId ${userId}`);
|
||||
|
||||
@@ -1214,9 +1221,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
* @returns a VerificationRequest when the request has been sent to the other party.
|
||||
*/
|
||||
public async requestOwnUserVerification(): Promise<VerificationRequest> {
|
||||
const userIdentity: RustSdkCryptoJs.OwnUserIdentity | undefined = await this.olmMachine.getIdentity(
|
||||
new RustSdkCryptoJs.UserId(this.userId),
|
||||
);
|
||||
const userIdentity = await this.getOwnIdentity();
|
||||
if (userIdentity === undefined) {
|
||||
throw new Error("cannot request verification for this device when there is no existing cross-signing key");
|
||||
}
|
||||
@@ -1726,34 +1731,37 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
},
|
||||
});
|
||||
|
||||
// If we have received a room key bundle message, and have previously marked the room
|
||||
// IDs it references as pending key bundles, tell the Rust SDK to try and accept it,
|
||||
// just in case it was received after invite.
|
||||
// If we have received a room key bundle message, and have recently joined the room in question,
|
||||
// tell the Rust SDK to try and accept the key bundle.
|
||||
//
|
||||
// We don't actually need to validate the contents of the bundle message, or do
|
||||
// anything with its contents at all. We simply want to inform the Rust SDK we have
|
||||
// received a new room key bundle that we might be able to download.
|
||||
if (
|
||||
isRoomKeyBundleMessage(parsedMessage) &&
|
||||
this.roomsPendingKeyBundles.has(parsedMessage.content.room_id)
|
||||
) {
|
||||
// No `await`-ing here, as this is called from inside the `/sync` loop.
|
||||
this.maybeAcceptKeyBundle(
|
||||
parsedMessage.content.room_id,
|
||||
this.roomsPendingKeyBundles.get(parsedMessage.content.room_id)!,
|
||||
).then(
|
||||
(success) => {
|
||||
if (success) {
|
||||
this.roomsPendingKeyBundles.delete(parsedMessage.content.room_id);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
this.logger.error(
|
||||
`Error attempting to download key bundle for room ${parsedMessage.content.room_id}`,
|
||||
);
|
||||
this.logger.error(err);
|
||||
},
|
||||
if (isRoomKeyBundleMessage(parsedMessage)) {
|
||||
const roomId = parsedMessage.content.room_id;
|
||||
const pendingDetails = await this.olmMachine.getPendingKeyBundleDetailsForRoom(
|
||||
new RustSdkCryptoJs.RoomId(roomId),
|
||||
);
|
||||
// Only accept the key bundle if we joined the room less than 24 hours ago.
|
||||
if (!pendingDetails) {
|
||||
this.logger.debug(
|
||||
`Not yet accepting key bundle for room where we are not awaiting a bundle: ${roomId}`,
|
||||
);
|
||||
} else if (
|
||||
Date.now() - pendingDetails.inviteAcceptedAtMillis >
|
||||
MAX_INVITE_ACCEPTANCE_MS_FOR_KEY_BUNDLE
|
||||
) {
|
||||
this.logger.info(
|
||||
`Ignoring key bundle for room we joined too long ago: ${roomId}, joining time: ${new Date(pendingDetails.inviteAcceptedAtMillis).toISOString()}`,
|
||||
);
|
||||
} else {
|
||||
this.logger.info(`Considering key bundle for recently-joined room ${roomId}`);
|
||||
// Don't block for the import to happen, here, as this is called from inside the `/sync` loop.
|
||||
this.maybeAcceptKeyBundle(roomId, pendingDetails.inviterId.toString()).catch((err) => {
|
||||
this.logger.error(`Error attempting to download key bundle for room ${roomId}`);
|
||||
this.logger.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1926,7 +1934,21 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
* @param oldMembership - The previous membership state. Null if it's a new member.
|
||||
*/
|
||||
public onRoomMembership(event: MatrixEvent, member: RoomMember, oldMembership?: string): void {
|
||||
const enc = this.roomEncryptors[event.getRoomId()!];
|
||||
const roomId = event.getRoomId()!;
|
||||
|
||||
// If it's our own membership, and we are no longer joined, clear any indication that we are waiting for a key
|
||||
// bundle.
|
||||
if (
|
||||
oldMembership === KnownMembership.Join &&
|
||||
member.membership !== KnownMembership.Join &&
|
||||
member.userId === this.olmMachine.userId.toString()
|
||||
) {
|
||||
this.olmMachine.clearRoomPendingKeyBundle(new RustSdkCryptoJs.RoomId(roomId)).catch((e) => {
|
||||
this.logger.error(`Error clearing room pending key bundle indicator for ${roomId}: ${e}`);
|
||||
});
|
||||
}
|
||||
|
||||
const enc = this.roomEncryptors[roomId];
|
||||
if (!enc) {
|
||||
// not encrypting in this room
|
||||
return;
|
||||
@@ -1934,6 +1956,43 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
enc.onRoomMembership(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Previously, it was sufficient to check if we need to rotate the room key
|
||||
* prior to sending a message. However, the history sharing feature
|
||||
* (MSC4268) breaks this logic:
|
||||
*
|
||||
* 1. Alice sends a message M1 in room X;
|
||||
* 2. Bob invites Charlie, who joins and immediately leaves the room;
|
||||
* 3. Alice sends another message M2 in room X.
|
||||
*
|
||||
* Under the old logic, Alice would not rotate her key after Charlie
|
||||
* leaves, resulting in M2 being encrypted with the same session as M1.
|
||||
* This would allow Charlie to decrypt M2 if he ever gains access to
|
||||
* the event.
|
||||
*
|
||||
* To counter this, we proactively discard any active outgoing Megolm
|
||||
* session when we see a `leave` event. Note that we have to do this in
|
||||
* `onRoomStateEvent` rather than `onRoomMembership`, because
|
||||
* `onRoomMembership` is only called when we see a *change* in membership.
|
||||
* In the case of a gappy sync, we might miss Charlie's invite and join,
|
||||
* and only see the final `leave` event (sohis membership goes from `leave`
|
||||
* to `leave`).
|
||||
*/
|
||||
public onRoomStateEvent(event: MatrixEvent, state: RoomState, prevEvent: MatrixEvent | null): void {
|
||||
if (event.getType() != EventType.RoomMember) {
|
||||
// Ignore all events that aren't member updates.
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
event.getStateKey()! !== this.olmMachine.userId.toString() &&
|
||||
event.getContent().membership === KnownMembership.Leave
|
||||
) {
|
||||
this.logger.info(`Rotating session for room ${event.getRoomId()} due to member leaving the room`);
|
||||
this.forceDiscardSession(event.getRoomId()!);
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback for OlmMachine.registerRoomKeyUpdatedCallback
|
||||
*
|
||||
* Called by the rust-sdk whenever there is an update to (megolm) room keys. We
|
||||
@@ -2189,7 +2248,10 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
* Used during migration from legacy js-crypto to update local trust if needed.
|
||||
*/
|
||||
public async getOwnIdentity(): Promise<RustSdkCryptoJs.OwnUserIdentity | undefined> {
|
||||
return await this.olmMachine.getIdentity(new RustSdkCryptoJs.UserId(this.userId));
|
||||
const identity = (await this.getOlmMachineOrThrow().getIdentity(new RustSdkCryptoJs.UserId(this.userId))) as
|
||||
| RustSdkCryptoJs.OwnUserIdentity
|
||||
| undefined;
|
||||
return identity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user