Compare commits

..

1 Commits

Author SHA1 Message Date
David Baker
3d1c4e394d Force upgrade lru-cache with a resolution
Due to https://github.com/isaacs/node-lru-cache/issues/352 preventing us from upgrading typescript

Causes more warnings about the version being incompatible with what the deps want, unfortunately.

Attempt #2 with newer yarn, replacing https://github.com/element-hq/element-desktop/pull/1904
2024-10-03 14:26:40 +01:00
119 changed files with 3247 additions and 4792 deletions

22
.eslintrc-hak.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = {
plugins: ["matrix-org"],
extends: [".eslintrc.js"],
parserOptions: {
project: ["hak/tsconfig.json"],
},
overrides: [
{
files: ["hak/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
},
],
};

22
.eslintrc-scripts.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = {
plugins: ["matrix-org"],
extends: [".eslintrc.js"],
parserOptions: {
project: ["scripts/tsconfig.json"],
},
overrides: [
{
files: ["scripts/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
},
],
};

22
.eslintrc-test.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = {
plugins: ["matrix-org"],
extends: [".eslintrc.js"],
parserOptions: {
project: ["playwright/tsconfig.json"],
},
overrides: [
{
files: ["playwright/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
},
],
};

View File

@ -1,88 +0,0 @@
module.exports = {
plugins: ["matrix-org", "n"],
extends: ["plugin:matrix-org/javascript"],
parserOptions: {
ecmaVersion: 2021,
project: ["tsconfig.json"],
},
env: {
es6: true,
node: true,
// we also have some browser code (ie. the preload script)
browser: true,
},
// NOTE: These rules are frozen and new rules should not be added here.
// New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/
rules: {
"quotes": "off",
"indent": "off",
"prefer-promise-reject-errors": "off",
"no-async-promise-executor": "off",
"n/file-extension-in-import": ["error", "always"],
"unicorn/prefer-node-protocol": ["error"],
},
overrides: [
{
files: ["src/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
},
{
files: ["hak/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
parserOptions: {
project: ["hak/tsconfig.json"],
},
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
},
{
files: ["scripts/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
parserOptions: {
project: ["scripts/tsconfig.json"],
},
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
},
{
files: ["playwright/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
parserOptions: {
project: ["playwright/tsconfig.json"],
},
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
},
],
};

37
.eslintrc.js Normal file
View File

@ -0,0 +1,37 @@
module.exports = {
plugins: ["matrix-org"],
extends: ["plugin:matrix-org/javascript"],
parserOptions: {
ecmaVersion: 2021,
project: ["tsconfig.json"],
},
env: {
es6: true,
node: true,
// we also have some browser code (ie. the preload script)
browser: true,
},
// NOTE: These rules are frozen and new rules should not be added here.
// New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/
rules: {
"quotes": "off",
"indent": "off",
"prefer-promise-reject-errors": "off",
"no-async-promise-executor": "off",
},
overrides: [
{
files: ["src/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
},
],
};

View File

@ -1,23 +0,0 @@
on: [push, workflow_dispatch]
jobs:
build-element:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Download Cringe Studios configuration
run: "mkdir cringe && wget -O cringe/config.json https://chat.cringe-studios.com/config.json"
- name: Docker setup
run: "docker build --platform linux/amd64 -t element-desktop-dockerbuild -f dockerbuild/Dockerfile ."
- name: Docker build
run: >
ls -la && PWD=$(pwd) scripts/in-docker.sh bash -c 'ls -la &&
yarn add matrix-seshat &&
yarn &&
yarn run fetch --noverify --cfgdir cringe &&
SQLCIPHER_BUNDLED=1 yarn run docker:build:native &&
yarn run docker:build --linux rpm --linux deb --linux tar.xz --linux AppImage --win squirrel'

View File

@ -1,5 +1 @@
blank_issues_enabled: false
contact_links:
- name: Bug report for the Element flatpak app
url: https://github.com/flathub/im.riot.Riot/issues
about: Please file bugs with the Flatpak application on the respective repository.

View File

@ -2,7 +2,7 @@
## Checklist
- [ ] Ensure your code works with manual testing.
- [ ] New or updated `public`/`exported` symbols have accurate [TSDoc](https://tsdoc.org/) documentation.
- [ ] Linter and other CI checks pass.
- [ ] I have licensed the changes to Element by completing the [Contributor License Agreement (CLA)](https://cla-assistant.io/element-hq/element-desktop)
- [ ] Ensure your code works with manual testing.
- [ ] New or updated `public`/`exported` symbols have accurate [TSDoc](https://tsdoc.org/) documentation.
- [ ] Linter and other CI checks pass.
- [ ] I have licensed the changes to Element by completing the [Contributor License Agreement (CLA)](https://cla-assistant.io/element-hq/element-desktop)

View File

@ -1,35 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIGBzCCA++gAwIBAgIIaI6ivggL++4wDQYJKoZIhvcNAQELBQAwgZAxCzAJBgNV
BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE
CgwPU1NMIENvcnBvcmF0aW9uMUUwQwYDVQQDDDxTU0wuY29tIEVWIFJvb3QgQ2Vy
dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyIC0gRGV2ZWxvcG1lbnQwHhcNMTgw
MTE2MTIxNjM2WhcNNDMwMTE1MTIxNjM2WjCBkDELMAkGA1UEBhMCVVMxDjAMBgNV
BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9y
YXRpb24xRTBDBgNVBAMMPFNTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1
dGhvcml0eSBSU0EgUjIgLSBEZXZlbG9wbWVudDCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAK/qcD65JCkueKp0+KXG2kAw8euDHuraLR3lJoUFz4ilGK1M
t+RjSuY6dHQw8ku7TnW9ejWoSFjCBSDx7tP/fzOwOxmBW6+F1NDuV/IaUtn3G2lk
CZglVk9z3n1HuWDN10xNiLoo5nzeIlvNAoDbXDGhI4Y6Z0qouAIS607JpJMWHOqZ
OUiiOuM11gI5Kz9GtVttXCjRmwlkU8WiJVIUuVedQAQt2FChrzNQewGFFi0uIau/
wFRclx6hd4JRIImC6VMJd9lcitWsqMcM94pD3fX2ozNgWX+MVlmcDYFSN9Sv8tG4
yCj4ONS8HZGzbxeyQXJhEJSi2FnBi0j6MD/d4DNFj0hCg9wz3fgVLDGCO0pNMO0Y
oXdrzfoj1/zEv0Ibgh7zKG2JHkPfapn3ExFI5d6xi66u5tPVI8cvLxqrgybRPs7Z
y1dQA7ew3LyTPAHoGtbTMvewtx1TkTtRxxhRRm0l58owqSVbSYrixFtosNobCERo
uiknaQqoY1ZDsdKsaqFoZDbntNRYhN3Ea4OPWVqDUU5ZPz9MTIRAi3MIq854yyQo
BjX9nv+kYa+Esr19pxUW0z7BWFhbXsMVpt0QMVyhwgzXvEreaZHFwHHaGb9d5x5P
VBDhsigMmtzBk9NlbCsy+uGXWHgZA/DVefueEq0sv38VoU30uYa5Tj0FLm09AgMB
AAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUI9PCucv3G9fRoTDu
ZQ4Hw6g4PkIwHQYDVR0OBBYEFCPTwrnL9xvX0aEw7mUOB8OoOD5CMA4GA1UdDwEB
/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAk43CCrC0Zbvi7YUsSePKi+KzvyQ9
mjKa5NBU/A5/sLeZS3R+wqCX7l5euYVDsUuNgNVD/QL9jNIonuHBrvKaxkmqxE1r
IcDEaUdjy2lQ0uqD7UDoS3ctrjGkPpUahrTdr3gaKcQBtUhn9v4Y2OBm6J1hDVwI
CIKcxIzRv6AUpApOtk+++m5tzDU48t8+GzrVl1hkspSYcumA+zuHllbPDL1ADdo5
kK/bBQtZrGqzPqKzeqaB1A5Wm0Igwf++7nyzdKNdjxtv907D9vg8EB4Swavuv/Ne
5/jbpI32pz0NIzzSl5ARAHuFhILsO/cEAlloDoTHzibHqFDIeU9/59HMUsJYMOtD
Ii0/LmQ6dBE4TeukCCLJwtkFYZ2eBgDjF/LHBB+z/UBs4milRgwx+Pe5UDUEjtGe
G/XMVnTSKZTy9jMaXJD5EmfP+Cfh8EEgFgjg4AmLUbEo9gXzPxyXSLgd8JGSsjg8
EV/Ri4Mmmt4XUwlSVvEOezxxDGd17gwbottCIC+rqPHonHkGmKpLMH80Bk0uOOCs
ui1oVwSifMyIcudgCcOfRLUf/f2j2NW7N7E7Vw/Zqfn+pqp/EG0KCqOM2vfJAc0s
u3rSrOJZGtB6txgtmTjoadxApWf4U/FCi3uArt6gS5MJqZjuiRNXs/K3SlSAqLGl
5UiG52ew+VdBHzE=
-----END CERTIFICATE-----

View File

@ -7,12 +7,10 @@ on:
branches:
- develop
permissions: {} # We use ELEMENT_BOT_TOKEN instead
jobs:
backport:
name: Backport
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
# Only react to merged PRs for security reasons.
# See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
if: >

View File

@ -41,12 +41,9 @@ run-name: Element ${{ inputs.mode != 'release' && github.event_name != 'release'
concurrency: ${{ github.workflow }}
env:
R2_BUCKET: ${{ vars.R2_BUCKET }}
permissions: {} # Uses ELEMENT_BOT_TOKEN
jobs:
prepare:
uses: ./.github/workflows/build_prepare.yaml
permissions:
contents: read
with:
config: element.io/${{ inputs.mode || (github.event_name == 'release' && 'release') || 'nightly' }}
version: ${{ (inputs.mode != 'release' && github.event_name != 'release') && 'develop' || '' }}
@ -62,7 +59,7 @@ jobs:
name: Windows ${{ matrix.arch }}
strategy:
matrix:
arch: [ia32, x64, arm64]
arch: [ia32, x64]
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
@ -92,6 +89,7 @@ jobs:
uses: ./.github/workflows/build_linux.yaml
with:
arch: ${{ matrix.arch }}
config: ${{ needs.prepare.outputs.config }}
sqlcipher: ${{ matrix.sqlcipher }}
version: ${{ needs.prepare.outputs.nightly-version }}
@ -101,7 +99,7 @@ jobs:
- macos
- linux
- windows
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
name: ${{ needs.prepare.outputs.deploy == 'true' && 'Deploy' || 'Deploy (dry-run)' }}
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
environment: ${{ needs.prepare.outputs.deploy == 'true' && 'packages.element.io' || '' }}
@ -111,8 +109,6 @@ jobs:
- name: Prepare artifacts for deployment
run: |
set -x
# Windows
for arch in x64 ia32 arm64
do
@ -146,8 +142,6 @@ jobs:
- name: "[Nightly] Strip version from installer file"
if: needs.prepare.outputs.nightly-version != ''
run: |
set -x
# Windows
for arch in x64 ia32 arm64
do
@ -164,8 +158,6 @@ jobs:
- name: "[Release] Prepare release latest symlink"
if: needs.prepare.outputs.nightly-version == ''
run: |
set -x
# Windows
for arch in x64 ia32 arm64
do
@ -202,18 +194,9 @@ jobs:
name: packages.element.io
path: packages.element.io
# Workaround for https://www.cloudflarestatus.com/incidents/t5nrjmpxc1cj
- uses: unfor19/install-aws-cli-action@e8b481e524a99f37fbd39fdc1dcb3341ab091367 # v1
if: needs.prepare.outputs.deploy == 'true'
with:
version: 2.22.35
verbose: false
arch: amd64
- name: Deploy artifacts
if: needs.prepare.outputs.deploy == 'true'
run: |
set -x
aws s3 cp --recursive packages.element.io/ s3://$R2_BUCKET/$DEPLOYMENT_DIR --endpoint-url $R2_URL --region auto
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
@ -233,8 +216,6 @@ jobs:
id: deb
if: needs.linux.result == 'success'
run: |
set -x
for arch in amd64 arm64
do
echo "$arch=$(ls linux-$arch-sqlcipher-static/*.deb | tail -n1)" >> $GITHUB_OUTPUT
@ -271,7 +252,7 @@ jobs:
deploy-ess:
needs: deploy
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
name: Deploy builds to ESS
if: needs.prepare.outputs.deploy == 'true' && github.event_name == 'release'
env:
@ -294,8 +275,6 @@ jobs:
- name: Copy files to S3
run: |
set -x
PREFIX="${VERSION%.*}"
for file in win-*/*.msi; do
filename=$(basename "$file")

View File

@ -6,12 +6,9 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: {} # No permissions required
jobs:
fetch:
uses: ./.github/workflows/build_prepare.yaml
permissions:
contents: read
with:
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
version: ${{ github.event.pull_request.base.ref == 'develop' && 'develop' || '' }}
@ -22,7 +19,7 @@ jobs:
uses: ./.github/workflows/build_windows.yaml
strategy:
matrix:
arch: [x64, ia32, arm64]
arch: [x64, ia32]
with:
arch: ${{ matrix.arch }}
@ -35,6 +32,7 @@ jobs:
sqlcipher: [system, static]
arch: [amd64, arm64]
with:
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
sqlcipher: ${{ matrix.sqlcipher }}
arch: ${{ matrix.arch }}
@ -52,7 +50,7 @@ jobs:
matrix:
include:
- name: macOS Universal
os: macos-14
os: macos-latest
artifact: macos
executable: "/Users/runner/Applications/Element.app/Contents/MacOS/Element"
# We need to mount the DMG and copy the app to the Applications folder as a mounted DMG is
@ -62,41 +60,54 @@ jobs:
rsync -a /Volumes/Element/Element.app ~/Applications/ &&
hdiutil detach /Volumes/Element
- name: "Linux (amd64) (sqlcipher: system)"
os: ubuntu-22.04
os: ubuntu-latest
artifact: linux-amd64-sqlcipher-system
executable: "/opt/Element/element-desktop"
prepare_cmd: "sudo apt-get -qq update && sudo apt install ./dist/*.deb"
- name: "Linux (amd64) (sqlcipher: static)"
os: ubuntu-22.04
os: ubuntu-latest
artifact: linux-amd64-sqlcipher-static
executable: "/opt/Element/element-desktop"
prepare_cmd: "sudo apt-get -qq update && sudo apt install ./dist/*.deb"
- name: "Linux (arm64) (sqlcipher: system)"
os: ubuntu-22.04-arm
os: dind-l-arm64
artifact: linux-arm64-sqlcipher-system
executable: "/opt/Element/element-desktop"
prepare_cmd: "sudo apt-get -qq update && sudo apt install -y ./dist/*.deb"
- name: "Linux (arm64) (sqlcipher: static)"
os: ubuntu-22.04-arm
os: dind-l-arm64
artifact: linux-arm64-sqlcipher-static
executable: "/opt/Element/element-desktop"
prepare_cmd: "sudo apt-get -qq update && sudo apt install -y ./dist/*.deb"
- name: Windows (x86)
os: windows-2022
os: windows-latest
artifact: win-ia32
executable: "./dist/win-ia32-unpacked/Element.exe"
- name: Windows (x64)
os: windows-2022
os: windows-latest
artifact: win-x64
executable: "./dist/win-unpacked/Element.exe"
name: Test ${{ matrix.name }}
runs-on: ${{ matrix.os }}
steps:
# Workaround for self-hosted runners lacking yarn
- name: Install Yarn
if: runner.environment == 'self-hosted'
run: |
# Sanity check that the arch is arm64 as we expect
[[ $(uname -p) == "aarch64" ]] || exit 1
sudo apt-get -qq update
sudo apt-get install -y curl
curl -fsSL --create-dirs -o $HOME/bin/yarn https://github.com/yarnpkg/yarn/releases/download/v1.22.19/yarn-1.22.19.js
chmod +x $HOME/bin/yarn
echo "$HOME/bin" >> $GITHUB_PATH
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
node-version-file: package.json
cache: "yarn"
- name: Install Deps
@ -120,6 +131,12 @@ jobs:
# We need sudo on Linux as it is installed in /opt/
RUN_AS: ${{ runner.os == 'Linux' && 'sudo' || '' }}
- name: Workaround macOS GHA permission issues
if: matrix.os == 'macos-latest'
run: |
sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"
sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/opt/off/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"
- name: Run tests
uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a
timeout-minutes: 5

View File

@ -8,6 +8,10 @@ on:
type: string
required: true
description: "The architecture to build for, one of 'amd64' | 'arm64'"
config:
type: string
required: true
description: "The config directory to use"
version:
type: string
required: false
@ -18,16 +22,32 @@ on:
description: "How to link sqlcipher, one of 'system' | 'static'"
env:
SQLCIPHER_BUNDLED: ${{ inputs.sqlcipher == 'static' && '1' || '' }}
MAX_GLIBC: 2.31 # bullseye-era glibc, used by glibc-check.sh
permissions: {} # No permissions required
jobs:
build:
# We build on native infrastructure as matrix-seshat fails to cross-compile properly
# https://github.com/matrix-org/seshat/issues/135
runs-on: ${{ inputs.arch == 'arm64' && 'ubuntu-22.04-arm' || 'ubuntu-22.04' }}
# We build the hak files on native infrastructure as matrix-seshat fails to cross-compile properly
# https://github.com/matrix-org/seshat/issues/135
hak:
runs-on: ${{ inputs.arch == 'arm64' && 'dind-l-arm64' || 'ubuntu-latest' }}
env:
HAK_DOCKER_IMAGE: ghcr.io/element-hq/element-desktop-dockerbuild
outputs:
cache-key: ${{ steps.cache-key.outputs.key }}
arch: ${{ steps.config.outputs.arch }}
build-args: ${{ steps.config.outputs.build-args }}
steps:
# Workaround for self-hosted runners lacking tools
- name: Install missing tools
if: runner.environment == 'self-hosted'
run: |
# Sanity check that the arch is arm64 as we expect
[[ $(uname -p) == "aarch64" ]] || exit 1
sudo apt-get -qq update
# curl for yarn download, git for tj-actions/changed-files, zstd for actions/cache
sudo apt-get install -y curl git zstd
curl -fsSL --create-dirs -o $HOME/bin/yarn https://github.com/yarnpkg/yarn/releases/download/v1.22.19/yarn-1.22.19.js
chmod +x $HOME/bin/yarn
echo "$HOME/bin" >> $GITHUB_PATH
- name: Resolve docker image tag for push
if: github.event_name == 'push'
run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:$GITHUB_REF_NAME" >> $GITHUB_ENV
@ -62,39 +82,47 @@ jobs:
with:
name: webapp
- name: Calculate cache key
id: cache-key
run: |
echo "key=$CACHE_KEY" >> $GITHUB_OUTPUT
env:
CACHE_KEY: ${{ runner.os }}-${{ github.ref_name }}-${{ inputs.sqlcipher }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion', 'dockerbuild/*') }}
- name: Cache .hak
id: cache
uses: actions/cache@v4
with:
key: ${{ runner.os }}-${{ github.ref_name }}-${{ inputs.sqlcipher }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion', 'dockerbuild/*') }}
key: ${{ steps.cache-key.outputs.key }}
path: |
./.hak
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
node-version-file: package.json
cache: "yarn"
env:
# Workaround for https://github.com/actions/setup-node/issues/317
FORCE_COLOR: 0
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: "Get modified files"
id: changed_files
if: steps.cache.outputs.cache-hit != 'true' && github.event_name == 'pull_request'
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8 # v45
uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c # v45
with:
files: |
dockerbuild/**
# This allows contributors to test changes to the dockerbuild image within a pull request
- name: Build docker image
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6
if: steps.changed_files.outputs.any_modified == 'true'
with:
file: dockerbuild/Dockerfile
context: dockerbuild
load: true
platforms: linux/${{ inputs.arch }}
tags: ${{ env.HAK_DOCKER_IMAGE }}
@ -108,16 +136,51 @@ jobs:
$HAK_DOCKER_IMAGE \
yarn build:native
- name: Fix permissions on .hak
run: sudo chown -R $USER:$USER .hak
- name: Check native libraries in hak dependencies
- name: Check native libraries
run: |
shopt -s globstar
for filename in ./.hak/hakModules/**/*.node; do
./scripts/glibc-check.sh $filename
done
env:
MAX_VER: 2.28 # buster-era glibc
build:
needs: hak
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: webapp
- name: Load .hak
id: cache
uses: actions/cache/restore@v4
with:
key: ${{ needs.hak.outputs.cache-key }}
fail-on-cache-miss: true
path: |
./.hak
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
env:
# Workaround for https://github.com/actions/setup-node/issues/317
FORCE_COLOR: 0
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: "[Nightly] Resolve version"
if: inputs.version != ''
run: |
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
- name: Generate debian files and arguments
run: |
@ -125,19 +188,8 @@ jobs:
echo "ED_DEBIAN_CHANGELOG=changelog.Debian" >> $GITHUB_ENV
fi
# Workaround for https://github.com/electron-userland/electron-builder/issues/6116
- name: Install fpm
if: inputs.arch == 'arm64'
run: |
sudo apt-get install ruby-dev build-essential
sudo gem install fpm
echo "USE_SYSTEM_FPM=true" >> $GITHUB_ENV
- name: Build App
run: yarn build --publish never -l ${{ steps.config.outputs.build-args }}
env:
# Only set for Nightly builds
ED_NIGHTLY: ${{ inputs.version }}
run: yarn build --publish never -l ${{ needs.hak.outputs.build-args }}
- name: Check native libraries
run: |
@ -165,7 +217,7 @@ jobs:
./scripts/glibc-check.sh dist/linux-*unpacked/element-desktop*
env:
ARCH: ${{ steps.config.outputs.arch }}
ARCH: ${{ needs.hak.outputs.arch }}
# We exclude *-unpacked as it loses permissions and the tarball contains it with correct permissions
- name: Upload Artifacts
@ -176,10 +228,3 @@ jobs:
dist
!dist/*-unpacked/**
retention-days: 1
- name: Assert all required files are present
run: |
test -f ./dist/element-desktop*$ARCH.deb
test -f ./dist/element-desktop*.tar.gz
env:
ARCH: ${{ inputs.arch }}

View File

@ -27,7 +27,6 @@ on:
type: string
required: false
description: "The URL to which the output will be deployed."
permissions: {} # No permissions required
jobs:
build:
runs-on: macos-14 # M1
@ -62,19 +61,24 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
# Python 3.12 drops distutils which keytar relies on
- name: Install setuptools
run: pip3 install setuptools
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: yarn build:native:universal
run: |
# Python 3.12 drops distutils which keytar relies on
pip3 install setuptools
yarn build:native:universal
- name: "[Nightly] Resolve version"
if: inputs.version != ''
run: |
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
# We split these because electron-builder gets upset if we set CSC_LINK even to an empty string
- name: "[Signed] Build App"
@ -82,13 +86,11 @@ jobs:
run: |
yarn build:universal --publish never
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
ED_NOTARYTOOL_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
# Only set for Nightly builds
ED_NIGHTLY: ${{ inputs.version }}
- name: Check app was signed & notarised successfully
if: inputs.sign != ''
@ -140,8 +142,3 @@ jobs:
dist
!dist/mac-universal/**
retention-days: 1
- name: Assert all required files are present
run: |
test -f ./dist/Element*.dmg
test -f ./dist/Element*-mac.zip

View File

@ -34,18 +34,18 @@ on:
packages-dir:
description: "The directory non-deb packages for this run should live in within packages.element.io"
value: ${{ inputs.nightly && 'nightly' || 'desktop' }}
# This is just a simple pass-through of the input to simplify reuse of complex inline conditions
# These are just simple pass-throughs of the input to simplify reuse of complex inline conditions
config:
description: "The relative path to the config file for this run"
value: ${{ inputs.config }}
deploy:
description: "Whether the build should be deployed to production"
description: "The relative path to the config file for this run"
value: ${{ inputs.deploy }}
permissions: {}
jobs:
prepare:
name: Prepare
environment: ${{ inputs.nightly && 'packages.element.io' || '' }}
runs-on: ubuntu-24.04
permissions:
contents: read
runs-on: ubuntu-latest
outputs:
nightly-version: ${{ steps.versions.outputs.nightly }}
steps:
@ -53,7 +53,7 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
node-version-file: package.json
cache: "yarn"
- name: Install Deps
@ -65,8 +65,7 @@ jobs:
# We split this out to save the build_* scripts having to do it to make use of `hashFiles` in the cache action
- name: Generate cache hash files
run: |
# Add --no-sandbox as otherwise it fails because the helper isn't setuid root. It's only getting the version.
yarn run --silent electron --no-sandbox --version > electronVersion
yarn run --silent electron --version > electronVersion
cat package.json | jq -c .hakDependencies | sha1sum > hakHash
find hak -type f -print0 | xargs -0 sha1sum >> hakHash
find scripts/hak -type f -print0 | xargs -0 sha1sum >> hakHash
@ -90,8 +89,6 @@ jobs:
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
# Workaround for https://www.cloudflarestatus.com/incidents/t5nrjmpxc1cj
AWS_REQUEST_CHECKSUM_CALCULATION: when_required
R2_BUCKET: ${{ vars.R2_BUCKET }}
R2_URL: ${{ vars.CF_R2_S3_API }}
@ -129,7 +126,8 @@ jobs:
BUNDLE_HASH=$(npx asar l webapp.asar | grep /bundles/ | head -n 1 | sed 's|.*/||')
WEBAPP_VERSION=$(./scripts/get-version.ts)
WEB_VERSION=${WEBAPP_VERSION:0:12}
JS_VERSION=${WEBAPP_VERSION:16:12}
REACT_VERSION=${WEBAPP_VERSION:19:12}
JS_VERSION=${WEBAPP_VERSION:35:12}
echo "### Nightly build ${{ steps.versions.outputs.nightly }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
@ -137,6 +135,7 @@ jobs:
echo "| ----------- | ------- |" >> $GITHUB_STEP_SUMMARY
echo "| Bundle Hash | $BUNDLE_HASH |" >> $GITHUB_STEP_SUMMARY
echo "| Element Web | [$WEB_VERSION](https://github.com/element-hq/element-web/commit/$WEB_VERSION) |" >> $GITHUB_STEP_SUMMARY
echo "| React SDK | [$REACT_VERSION](https://github.com/matrix-org/matrix-react-sdk/commit/$REACT_VERSION) |" >> $GITHUB_STEP_SUMMARY
echo "| JS SDK | [$JS_VERSION](https://github.com/matrix-org/matrix-js-sdk/commit/$JS_VERSION) |" >> $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v4

View File

@ -2,9 +2,7 @@
# Due to this extra care must be taken to only ever run all build_* scripts against the same branch to ensure
# the correct cache scoping, and additional care must be taken to not run untrusted actions on the develop branch.
# Windows GHA runner by default uses the pwsh shell which breaks codeSigningCert in the workflow
# We always sign using eSignerCKA to ensure it keeps working, but aside from release & nightlies we use demo credentials
# which do not yield trusted signatures.
# window-latest by default uses the pwsh shell which breaks codeSigningCert in the workflow
defaults:
run:
shell: powershell
@ -30,10 +28,9 @@ on:
type: string
required: false
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
permissions: {} # No permissions required
jobs:
build:
runs-on: windows-2022
runs-on: windows-latest
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
env:
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.22000.0/x86/signtool.exe"
@ -56,8 +53,7 @@ jobs:
"ia32": {
"target": "i686-pc-windows-msvc",
"build-args": "--ia32",
"arch": "x86",
"extra_config": "{\"user_notice\": {\"title\": \"Your desktop support ends soon\",\"description\": \"Support for 32-bit Windows installations will end soon, this impacts you. Transition to the web or mobile app for continued access.\"}}"
"arch": "x86"
}
}
@ -75,6 +71,11 @@ jobs:
path: |
./.hak
- name: Set up build tools
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
with:
arch: ${{ steps.config.outputs.arch || inputs.arch }}
# ActiveTCL package on choco is from 2015,
# this one is newer but includes more than we need
- name: Choco install tclsh
@ -100,38 +101,13 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Insert config snippet
if: steps.config.outputs.extra_config != ''
shell: bash
run: |
mkdir config-edit
yarn asar extract webapp.asar config-edit
cd config-edit
mv config.json old-config.json
echo '${{ steps.config.outputs.extra_config }}' | jq -s '.[0] * .[1]' old-config.json - > config.json
rm old-config.json
cd ..
rm webapp.asar
yarn asar pack config-edit/ webapp.asar
- name: Set up sqlcipher macros
if: steps.cache.outputs.cache-hit != 'true' && contains(inputs.arch, 'arm')
shell: pwsh
run: |
echo "NCC=${{ github.workspace }}\scripts\cl.bat" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Set up build tools
if: steps.cache.outputs.cache-hit != 'true'
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
with:
arch: ${{ steps.config.outputs.arch || inputs.arch }}
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: |
@ -139,6 +115,7 @@ jobs:
yarn build:native --target ${{ steps.config.outputs.target }}
- name: Install and configure eSigner CKA
if: inputs.sign
run: |
Set-StrictMode -Version 'Latest'
@ -156,13 +133,8 @@ jobs:
$LogConfig[0] = '<log4net threshold="OFF">'
$LogConfig | Set-Content -Path ${{ env.INSTALL_DIR }}/log4net.config
# Configure - default credentials from https://www.ssl.com/guide/esigner-demo-credentials-and-certificates/
${{ env.INSTALL_DIR }}/eSignerCKATool.exe config `
-mode ${{ vars.ESIGNER_MODE || 'sandbox' }} `
-user "${{ secrets.ESIGNER_USER_NAME || 'esigner_demo' }}" `
-pass "${{ secrets.ESIGNER_USER_PASSWORD || 'esignerDemo#1' }}" `
-totp "${{ secrets.ESIGNER_USER_TOTP || 'RDXYgV9qju+6/7GnMf1vCbKexXVJmUVr+86Wq/8aIGg=' }}" `
-key "${{ env.MASTER_KEY_FILE }}" -r
# Configure
${{ env.INSTALL_DIR }}/eSignerCKATool.exe config -mode product -user "${{ secrets.ESIGNER_USER_NAME }}" -pass "${{ secrets.ESIGNER_USER_PASSWORD }}" -totp "${{ secrets.ESIGNER_USER_TOTP }}" -key "${{ env.MASTER_KEY_FILE }}" -r
${{ env.INSTALL_DIR }}/eSignerCKATool.exe unload
${{ env.INSTALL_DIR }}/eSignerCKATool.exe load
@ -181,25 +153,24 @@ jobs:
INSTALL_DIR: C:\Users\runneradmin\eSignerCKA
MASTER_KEY_FILE: C:\Users\runneradmin\eSignerCKA\master.key
- name: Build App
run: yarn build --publish never -w ${{ steps.config.outputs.build-args }}
env:
# Only set for Nightly builds
ED_NIGHTLY: ${{ inputs.version }}
- name: Trust eSigner sandbox cert
if: inputs.sign == ''
- name: "[Nightly] Resolve version"
if: inputs.version != ''
shell: bash
run: |
Set-StrictMode -Version 'Latest'
Import-Certificate -CertStoreLocation Cert:\LocalMachine\Root -FilePath .github/SSLcom-sandbox.crt
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
# XXX: For whatever reason if we use `yarn build ...` it freezes, but splitting it into parts it is fine
- run: yarn run build:ts
- run: yarn run build:res
- name: Build App
run: |
yarn electron-builder --publish never -w ${{ steps.config.outputs.build-args }}
- name: Check app was signed successfully
if: inputs.sign != ''
run: |
Set-StrictMode -Version 'Latest'
Get-ChildItem `
-Recurse dist `
-Include *.exe, *.msi `
| ForEach-Object -Process {. $env:SIGNTOOL_PATH verify /pa $_.FullName; if(!$?) { throw }}
. "$env:SIGNTOOL_PATH" verify /pa (get-item ./dist/squirrel-windows*/*.exe)
- name: Upload Artifacts
uses: actions/upload-artifact@v4
@ -208,11 +179,3 @@ jobs:
path: |
dist
retention-days: 1
- name: Assert all required files are present
run: |
Test-Path './dist/win-*unpacked/Element*.exe'
Test-Path './dist/squirrel-windows*/Element Setup*.exe'
Test-Path './dist/squirrel-windows*/element-desktop-*-full.nupkg'
Test-Path './dist/squirrel-windows*/RELEASES'
Test-Path './dist/Element*.msi'

View File

@ -5,16 +5,14 @@ on:
branches: [master, staging, develop]
paths:
- "dockerbuild/**"
pull_request:
concurrency: ${{ github.workflow }}-${{ github.ref_name }}
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}-dockerbuild
permissions: {}
jobs:
build:
name: Docker Build
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
@ -22,28 +20,15 @@ jobs:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3
with:
install: true
- name: Build test image
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
with:
file: dockerbuild/Dockerfile
push: false
load: true
tags: element-desktop-dockerbuild
platforms: linux/amd64
- name: Test image
run: docker run -v $PWD:/project element-desktop-dockerbuild yarn install
- name: Log in to the Container registry
uses: docker/login-action@327cd5a69de6c009b9ce71bce8395f28e651bf99
if: github.event_name != 'pull_request'
uses: docker/login-action@3b8fed7e4b60203b2aa0ecc6c6d6d91d12c06760
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@ -51,19 +36,16 @@ jobs:
- name: Extract metadata for Docker
id: meta
if: github.event_name != 'pull_request'
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
- name: Build and push Docker image
if: github.event_name != 'pull_request'
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6
with:
file: dockerbuild/Dockerfile
context: dockerbuild
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -3,8 +3,6 @@ on:
workflow_dispatch: {}
schedule:
- cron: "0 6 * * 1,3,5" # Every Monday, Wednesday and Friday at 6am UTC
permissions:
pull-requests: write # needed to auto-approve PRs
jobs:
download:
uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_download.yaml@main

View File

@ -4,7 +4,6 @@ on:
branches: [develop]
paths:
- "src/i18n/strings/en_EN.json"
permissions: {} # No permissions needed
jobs:
upload:
uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_upload.yaml@main

View File

@ -2,11 +2,8 @@ name: Pull Request
on:
pull_request_target:
types: [opened, edited, labeled, unlabeled, synchronize]
permissions: {}
jobs:
action:
uses: matrix-org/matrix-js-sdk/.github/workflows/pull_request.yaml@develop
permissions:
pull-requests: write
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@ -4,11 +4,8 @@ on:
branches: [staging]
workflow_dispatch: {}
concurrency: ${{ github.workflow }}
permissions: {}
jobs:
draft:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-drafter-workflow.yml@develop
permissions:
contents: write
with:
include-changes: element-hq/element-web~$VERSION

View File

@ -4,7 +4,6 @@ on:
push:
branches: [master]
concurrency: ${{ github.repository }}-${{ github.workflow }}
permissions: {} # Uses ELEMENT_BOT_TOKEN
jobs:
merge:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-gitflow.yml@develop

View File

@ -11,15 +11,9 @@ on:
- rc
- final
concurrency: ${{ github.workflow }}
permissions: {}
jobs:
release:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop
permissions:
contents: write
issues: write
pull-requests: read
id-token: write
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
@ -32,9 +26,7 @@ jobs:
check:
name: Post release checks
needs: release
runs-on: ubuntu-24.04
permissions:
checks: read
runs-on: ubuntu-latest
steps:
- name: Wait for desktop packaging
uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork
@ -42,5 +34,5 @@ jobs:
ref: master
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
check-regexp: Prepare|Linux|macOS|Windows|Deploy|deploy
check-name: Deploy
allowed-conclusions: success

View File

@ -3,11 +3,10 @@ on:
pull_request: {}
push:
branches: [develop, master]
permissions: {} # No permissions needed
jobs:
ts_lint:
name: "Typescript Syntax Check"
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -26,14 +25,12 @@ jobs:
i18n_lint:
name: "i18n Check"
uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main
permissions:
pull-requests: read
with:
hardcoded-words: "Element"
js_lint:
name: "ESLint"
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -51,7 +48,7 @@ jobs:
workflow_lint:
name: "Workflow Lint"
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -69,7 +66,7 @@ jobs:
analyse_dead_code:
name: "Analyse Dead Code"
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

View File

@ -8,7 +8,6 @@ on:
- develop
paths:
- .github/labels.yml
permissions: {} # Uses ELEMENT_BOT_TOKEN
jobs:
sync-labels:
uses: element-hq/element-meta/.github/workflows/sync-labels.yml@develop

View File

@ -4,11 +4,9 @@ on:
issues:
types: [opened]
permissions: {} # Uses ELEMENT_BOT_TOKEN
jobs:
automate-project-columns-next:
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@main
with:

View File

@ -4,8 +4,6 @@ on:
issues:
types: [labeled]
permissions: {} # Uses ELEMENT_BOT_TOKEN
jobs:
call-triage-labelled:
uses: element-hq/element-web/.github/workflows/triage-labelled.yml@develop

View File

@ -1,22 +0,0 @@
name: Close stale PRs
on:
workflow_dispatch: {}
schedule:
- cron: "30 1 * * *"
permissions: {}
jobs:
close:
runs-on: ubuntu-24.04
permissions:
actions: write
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
operations-per-run: 250
days-before-issue-stale: -1
days-before-issue-close: -1
days-before-pr-stale: 180
days-before-pr-close: 0
close-pr-message: "This PR has been automatically closed because it has been stale for 180 days. If you wish to continue working on this PR, please ping a maintainer to reopen it."

1
.gitignore vendored
View File

@ -17,4 +17,3 @@ node_modules/
yarn-error.log
/hak/**/*.js
/scripts/hak/**/*.js
.DS_Store

View File

@ -1,4 +0,0 @@
#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged --concurrent false

View File

@ -1,4 +0,0 @@
{
"*": "prettier --write",
"*.(ts|tsx)": ["eslint --fix"]
}

View File

@ -1 +0,0 @@
v22.14.0

View File

@ -1,321 +1,3 @@
Changes in [1.11.94](https://github.com/element-hq/element-desktop/releases/tag/v1.11.94) (2025-02-27)
======================================================================================================
* No changes
## 🐛 Bug Fixes
* [Backport staging] fix: /tmp/element-web-config may already exist preventing the container from booting up ([#29377](https://github.com/element-hq/element-web/pull/29377)). Contributed by @RiotRobot.
Changes in [1.11.93](https://github.com/element-hq/element-desktop/releases/tag/v1.11.93) (2025-02-25)
======================================================================================================
## ✨ Features
* [backport] Dynamically load Element Web modules in Docker entrypoint ([#29358](https://github.com/element-hq/element-web/pull/29358)). Contributed by @t3chguy.
* ChangeRecoveryKey: error handling ([#29262](https://github.com/element-hq/element-web/pull/29262)). Contributed by @richvdh.
* Dehydration: enable dehydrated device on "Set up recovery" ([#29265](https://github.com/element-hq/element-web/pull/29265)). Contributed by @richvdh.
* Render reason for invite rejection. ([#29257](https://github.com/element-hq/element-web/pull/29257)). Contributed by @Half-Shot.
* New room list: add search section ([#29251](https://github.com/element-hq/element-web/pull/29251)). Contributed by @florianduros.
* New room list: hide favourites and people meta spaces ([#29241](https://github.com/element-hq/element-web/pull/29241)). Contributed by @florianduros.
* New Room List: Create new labs flag ([#29239](https://github.com/element-hq/element-web/pull/29239)). Contributed by @MidhunSureshR.
* Stop URl preview from covering message box ([#29215](https://github.com/element-hq/element-web/pull/29215)). Contributed by @edent.
* Rename "security key" into "recovery key" ([#29217](https://github.com/element-hq/element-web/pull/29217)). Contributed by @florianduros.
* Add new verification section to user profile ([#29200](https://github.com/element-hq/element-web/pull/29200)). Contributed by @MidhunSureshR.
* Initial support for runtime modules ([#29104](https://github.com/element-hq/element-web/pull/29104)). Contributed by @t3chguy.
* Add `Forgot recovery key?` button to encryption tab ([#29202](https://github.com/element-hq/element-web/pull/29202)). Contributed by @florianduros.
* Add KeyIcon to key storage out of sync toast ([#29201](https://github.com/element-hq/element-web/pull/29201)). Contributed by @florianduros.
* Improve rendering of empty topics in the timeline ([#29152](https://github.com/element-hq/element-web/pull/29152)). Contributed by @Half-Shot.
## 🐛 Bug Fixes
* Fix font scaling in member list ([#29285](https://github.com/element-hq/element-web/pull/29285)). Contributed by @florianduros.
* Grow member list search field when resizing the right panel ([#29267](https://github.com/element-hq/element-web/pull/29267)). Contributed by @langleyd.
* Don't reload roomview on offline connectivity check ([#29243](https://github.com/element-hq/element-web/pull/29243)). Contributed by @dbkr.
* Respect user's 12/24 hour preference consistently ([#29237](https://github.com/element-hq/element-web/pull/29237)). Contributed by @t3chguy.
* Restore the accessibility role on call views ([#29225](https://github.com/element-hq/element-web/pull/29225)). Contributed by @robintown.
* Revert `GoToHome` keyboard shortcut to `Ctrl``Shift``H` on macOS ([#28577](https://github.com/element-hq/element-web/pull/28577)). Contributed by @gy-mate.
* Encryption tab: display correct encryption panel when user cancels the reset identity flow ([#29216](https://github.com/element-hq/element-web/pull/29216)). Contributed by @florianduros.
Changes in [1.11.92](https://github.com/element-hq/element-desktop/releases/tag/v1.11.92) (2025-02-11)
======================================================================================================
## ✨ Features
* Enable fuse EnableEmbeddedAsarIntegrityValidation ([#1979](https://github.com/element-hq/element-desktop/pull/1979)). Contributed by @t3chguy.
* Update electron-builder and harden fuse configuration ([#2106](https://github.com/element-hq/element-desktop/pull/2106)). Contributed by @t3chguy.
* [Backport staging] Log when we show, and hide, encryption setup toasts ([#29238](https://github.com/element-hq/element-web/pull/29238)). Contributed by @richvdh.
* Make profile header section match the designs ([#29163](https://github.com/element-hq/element-web/pull/29163)). Contributed by @MidhunSureshR.
* Always show back button in the right panel ([#29128](https://github.com/element-hq/element-web/pull/29128)). Contributed by @MidhunSureshR.
* Schedule dehydration on reload if the dehydration key is already cached locally ([#29021](https://github.com/element-hq/element-web/pull/29021)). Contributed by @uhoreg.
* update to twemoji 15.1.0 ([#29115](https://github.com/element-hq/element-web/pull/29115)). Contributed by @ara4n.
* Update matrix-widget-api ([#29112](https://github.com/element-hq/element-web/pull/29112)). Contributed by @toger5.
* Allow navigating through the memberlist using up/down keys ([#28949](https://github.com/element-hq/element-web/pull/28949)). Contributed by @MidhunSureshR.
* Style room header icons and facepile for toggled state ([#28968](https://github.com/element-hq/element-web/pull/28968)). Contributed by @MidhunSureshR.
* Move threads header below base card header ([#28969](https://github.com/element-hq/element-web/pull/28969)). Contributed by @MidhunSureshR.
* Add `Advanced` section to the user settings encryption tab ([#28804](https://github.com/element-hq/element-web/pull/28804)). Contributed by @florianduros.
* Fix outstanding UX issues with replies/mentions/keyword notifs ([#28270](https://github.com/element-hq/element-web/pull/28270)). Contributed by @taffyko.
* Distinguish room state and timeline events when dealing with widgets ([#28681](https://github.com/element-hq/element-web/pull/28681)). Contributed by @robintown.
* Switch OIDC primarily to new `/auth_metadata` API ([#29019](https://github.com/element-hq/element-web/pull/29019)). Contributed by @t3chguy.
* More memberlist changes ([#29069](https://github.com/element-hq/element-web/pull/29069)). Contributed by @MidhunSureshR.
## 🐛 Bug Fixes
* [Backport staging] Wire up the "Forgot recovery key" button for the "Key storage out of sync" toast ([#29190](https://github.com/element-hq/element-web/pull/29190)). Contributed by @RiotRobot.
* Encryption tab: hide `Advanced` section when the key storage is out of sync ([#29129](https://github.com/element-hq/element-web/pull/29129)). Contributed by @florianduros.
* Fix share button in discovery settings being disabled incorrectly ([#29151](https://github.com/element-hq/element-web/pull/29151)). Contributed by @t3chguy.
* Ensure switching rooms does not wrongly focus timeline search ([#29153](https://github.com/element-hq/element-web/pull/29153)). Contributed by @t3chguy.
* Stop showing a dialog prompting the user to enter an old recovery key ([#29143](https://github.com/element-hq/element-web/pull/29143)). Contributed by @richvdh.
* Make themed widgets reflect the effective theme ([#28342](https://github.com/element-hq/element-web/pull/28342)). Contributed by @robintown.
* support non-VS16 emoji ligatures in TwemojiMozilla ([#29100](https://github.com/element-hq/element-web/pull/29100)). Contributed by @ara4n.
* e2e test: Verify session with the encryption tab instead of the security \& privacy tab ([#29090](https://github.com/element-hq/element-web/pull/29090)). Contributed by @florianduros.
* Work around cloudflare R2 / aws client incompatability ([#29086](https://github.com/element-hq/element-web/pull/29086)). Contributed by @dbkr.
* Fix identity server settings visibility ([#29083](https://github.com/element-hq/element-web/pull/29083)). Contributed by @dbkr.
Changes in [1.11.91](https://github.com/element-hq/element-desktop/releases/tag/v1.11.91) (2025-01-28)
======================================================================================================
## ✨ Features
* Implement changes to memberlist from feedback ([#29029](https://github.com/element-hq/element-web/pull/29029)). Contributed by @MidhunSureshR.
* Add toast for recovery keys being out of sync ([#28946](https://github.com/element-hq/element-web/pull/28946)). Contributed by @dbkr.
* Refactor LegacyCallHandler event emitter to use TypedEventEmitter ([#29008](https://github.com/element-hq/element-web/pull/29008)). Contributed by @t3chguy.
* Add `Recovery` section in the new user settings `Encryption` tab ([#28673](https://github.com/element-hq/element-web/pull/28673)). Contributed by @florianduros.
* Retry loading chunks to make the app more resilient ([#29001](https://github.com/element-hq/element-web/pull/29001)). Contributed by @t3chguy.
* Clear account idb table on logout ([#28996](https://github.com/element-hq/element-web/pull/28996)). Contributed by @t3chguy.
* Implement new memberlist design with MVVM architecture ([#28874](https://github.com/element-hq/element-web/pull/28874)). Contributed by @MidhunSureshR.
## 🐛 Bug Fixes
* [Backport staging] Switch to secure random strings ([#29035](https://github.com/element-hq/element-web/pull/29035)). Contributed by @RiotRobot.
* React to MatrixEvent sender/target being updated for rendering state events ([#28947](https://github.com/element-hq/element-web/pull/28947)). Contributed by @t3chguy.
Changes in [1.11.90](https://github.com/element-hq/element-desktop/releases/tag/v1.11.90) (2025-01-14)
======================================================================================================
## ✨ Features
* Docker: run as non-root ([#28849](https://github.com/element-hq/element-web/pull/28849)). Contributed by @richvdh.
* Docker: allow configuration of HTTP listen port via env var ([#28840](https://github.com/element-hq/element-web/pull/28840)). Contributed by @richvdh.
* Update matrix-wysiwyg to consume WASM asset ([#28838](https://github.com/element-hq/element-web/pull/28838)). Contributed by @t3chguy.
* OIDC settings tweaks ([#28787](https://github.com/element-hq/element-web/pull/28787)). Contributed by @t3chguy.
* Delabs native OIDC support ([#28615](https://github.com/element-hq/element-web/pull/28615)). Contributed by @t3chguy.
* Move room header info button to right-most position ([#28754](https://github.com/element-hq/element-web/pull/28754)). Contributed by @t3chguy.
* Enable key backup by default ([#28691](https://github.com/element-hq/element-web/pull/28691)). Contributed by @dbkr.
## 🐛 Bug Fixes
* Fix building the automations mermaid diagram ([#28881](https://github.com/element-hq/element-web/pull/28881)). Contributed by @dbkr.
* Playwright: wait for the network listener on the postgres db ([#28808](https://github.com/element-hq/element-web/pull/28808)). Contributed by @dbkr.
Changes in [1.11.89](https://github.com/element-hq/element-desktop/releases/tag/v1.11.89) (2024-12-18)
======================================================================================================
* No changes
## 🐛 Bug Fixes
* Upgrade matrix-sdk-crypto-wasm to 1.11.0 (https://github.com/matrix-org/matrix-js-sdk/pull/4593)
* Fix url preview display ([#28766](https://github.com/element-hq/element-web/pull/28766)).
Changes in [1.11.88](https://github.com/element-hq/element-desktop/releases/tag/v1.11.88) (2024-12-17)
======================================================================================================
## ✨ Features
* Allow trusted Element Call widget to send and receive media encryption key to-device messages ([#28316](https://github.com/element-hq/element-web/pull/28316)). Contributed by @hughns.
* increase ringing timeout from 10 seconds to 90 seconds ([#28630](https://github.com/element-hq/element-web/pull/28630)). Contributed by @fkwp.
* Add `Close` tooltip to dialog ([#28617](https://github.com/element-hq/element-web/pull/28617)). Contributed by @florianduros.
* New UX for Share dialog ([#28598](https://github.com/element-hq/element-web/pull/28598)). Contributed by @florianduros.
* Improve performance of RoomContext in RoomHeader ([#28574](https://github.com/element-hq/element-web/pull/28574)). Contributed by @t3chguy.
* Remove `Features.RustCrypto` flag ([#28582](https://github.com/element-hq/element-web/pull/28582)). Contributed by @florianduros.
* Add Modernizr warning when running in non-secure context ([#28581](https://github.com/element-hq/element-web/pull/28581)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* Fix secret storage not being used due to bad import ([#2029](https://github.com/element-hq/element-desktop/pull/2029)). Contributed by @t3chguy.
* Fix inability to click on non-logged-in modals on macOS ([#2025](https://github.com/element-hq/element-desktop/pull/2025)). Contributed by @t3chguy.
* Fix jumpy timeline when the pinned message banner is displayed ([#28654](https://github.com/element-hq/element-web/pull/28654)). Contributed by @florianduros.
* Fix font \& spaces in settings subsection ([#28631](https://github.com/element-hq/element-web/pull/28631)). Contributed by @florianduros.
* Remove manual device verification which is not supported by the new cryptography stack ([#28588](https://github.com/element-hq/element-web/pull/28588)). Contributed by @florianduros.
* Fix code block highlighting not working reliably with many code blocks ([#28613](https://github.com/element-hq/element-web/pull/28613)). Contributed by @t3chguy.
* Remove remaining reply fallbacks code ([#28610](https://github.com/element-hq/element-web/pull/28610)). Contributed by @t3chguy.
* Provide a way to activate GIFs via the keyboard for a11y ([#28611](https://github.com/element-hq/element-web/pull/28611)). Contributed by @t3chguy.
* Fix format bar position ([#28591](https://github.com/element-hq/element-web/pull/28591)). Contributed by @florianduros.
* Fix room taking long time to load ([#28579](https://github.com/element-hq/element-web/pull/28579)). Contributed by @florianduros.
* Show the correct shield status in tooltip for more conditions ([#28476](https://github.com/element-hq/element-web/pull/28476)). Contributed by @uhoreg.
Changes in [1.11.87](https://github.com/element-hq/element-desktop/releases/tag/v1.11.87) (2024-12-03)
======================================================================================================
## ✨ Features
* Send and respect MSC4230 is\_animated flag ([#28513](https://github.com/element-hq/element-web/pull/28513)). Contributed by @t3chguy.
* Display a warning when an unverified user's identity changes ([#28211](https://github.com/element-hq/element-web/pull/28211)). Contributed by @uhoreg.
* Swap out Twitter link for Mastodon on auth footer ([#28508](https://github.com/element-hq/element-web/pull/28508)). Contributed by @t3chguy.
* Consider `org.matrix.msc3417.call` as video room in create room dialog ([#28497](https://github.com/element-hq/element-web/pull/28497)). Contributed by @t3chguy.
* Standardise icons using Compound Design Tokens ([#28217](https://github.com/element-hq/element-web/pull/28217)). Contributed by @t3chguy.
* Start sending stable `m.marked_unread` events ([#28478](https://github.com/element-hq/element-web/pull/28478)). Contributed by @tulir.
* Upgrade to compound-design-tokens v2 ([#28471](https://github.com/element-hq/element-web/pull/28471)). Contributed by @t3chguy.
* Standardise icons using Compound Design Tokens ([#28286](https://github.com/element-hq/element-web/pull/28286)). Contributed by @t3chguy.
* Remove reply fallbacks as per merged MSC2781 ([#28406](https://github.com/element-hq/element-web/pull/28406)). Contributed by @t3chguy.
* Use React Suspense when rendering async modals ([#28386](https://github.com/element-hq/element-web/pull/28386)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* Add spinner when room encryption is loading in room settings ([#28535](https://github.com/element-hq/element-web/pull/28535)). Contributed by @florianduros.
* Fix getOidcCallbackUrl for Element Desktop ([#28521](https://github.com/element-hq/element-web/pull/28521)). Contributed by @t3chguy.
* Filter out redacted poll votes to avoid crashing the Poll widget ([#28498](https://github.com/element-hq/element-web/pull/28498)). Contributed by @t3chguy.
* Fix force tab complete not working since switching to React 18 createRoot API ([#28505](https://github.com/element-hq/element-web/pull/28505)). Contributed by @t3chguy.
* Fix media captions in bubble layout ([#28480](https://github.com/element-hq/element-web/pull/28480)). Contributed by @tulir.
* Reset cross-signing before backup when resetting both ([#28402](https://github.com/element-hq/element-web/pull/28402)). Contributed by @uhoreg.
* Listen to events so that encryption icon updates when status changes ([#28407](https://github.com/element-hq/element-web/pull/28407)). Contributed by @uhoreg.
* Check that the file the user chose has a MIME type of `image/*` ([#28467](https://github.com/element-hq/element-web/pull/28467)). Contributed by @t3chguy.
* Fix download button size in message action bar ([#28472](https://github.com/element-hq/element-web/pull/28472)). Contributed by @t3chguy.
* Allow tab completing users in brackets ([#28460](https://github.com/element-hq/element-web/pull/28460)). Contributed by @t3chguy.
* Fix React 18 strict mode breaking spotlight dialog ([#28452](https://github.com/element-hq/element-web/pull/28452)). Contributed by @MidhunSureshR.
Changes in [1.11.86](https://github.com/element-hq/element-desktop/releases/tag/v1.11.86) (2024-11-19)
======================================================================================================
## ✨ Features
* Deduplicate icons using Compound Design Tokens ([#28419](https://github.com/element-hq/element-web/pull/28419)). Contributed by @t3chguy.
* Let widget driver send error details ([#28357](https://github.com/element-hq/element-web/pull/28357)). Contributed by @AndrewFerr.
* Deduplicate icons using Compound Design Tokens ([#28381](https://github.com/element-hq/element-web/pull/28381)). Contributed by @t3chguy.
* Auto approvoce `io.element.call.reaction` capability for element call widgets ([#28401](https://github.com/element-hq/element-web/pull/28401)). Contributed by @toger5.
* Show message type prefix in thread root \& reply previews ([#28361](https://github.com/element-hq/element-web/pull/28361)). Contributed by @t3chguy.
* Support sending encrypted to device messages from widgets ([#28315](https://github.com/element-hq/element-web/pull/28315)). Contributed by @hughns.
## 🐛 Bug Fixes
* Feed events to widgets as they are decrypted (even if out of order) ([#28376](https://github.com/element-hq/element-web/pull/28376)). Contributed by @robintown.
* Handle authenticated media when downloading from ImageView ([#28379](https://github.com/element-hq/element-web/pull/28379)). Contributed by @t3chguy.
* Ignore `m.3pid_changes` for Identity service 3PID changes ([#28375](https://github.com/element-hq/element-web/pull/28375)). Contributed by @t3chguy.
* Fix markdown escaping wrongly passing html through ([#28363](https://github.com/element-hq/element-web/pull/28363)). Contributed by @t3chguy.
* Remove "Upgrade your encryption" flow in `CreateSecretStorageDialog` ([#28290](https://github.com/element-hq/element-web/pull/28290)). Contributed by @florianduros.
Changes in [1.11.85](https://github.com/element-hq/element-desktop/releases/tag/v1.11.85) (2024-11-12)
======================================================================================================
# Security
- Fixes for [CVE-2024-51750](https://www.cve.org/CVERecord?id=CVE-2024-51750) / [GHSA-w36j-v56h-q9pc](https://github.com/element-hq/element-web/security/advisories/GHSA-w36j-v56h-q9pc)
- Fixes for [CVE-2024-51749](https://www.cve.org/CVERecord?id=CVE-2024-51749) / [GHSA-5486-384g-mcx2](https://github.com/element-hq/element-web/security/advisories/GHSA-5486-384g-mcx2)
- Update JS SDK with the fixes for [CVE-2024-50336](https://www.cve.org/CVERecord?id=CVE-2024-50336) / [GHSA-xvg8-m4x3-w6xr](https://github.com/matrix-org/matrix-js-sdk/security/advisories/GHSA-xvg8-m4x3-w6xr)
Changes in [1.11.84](https://github.com/element-hq/element-desktop/releases/tag/v1.11.84) (2024-11-05)
======================================================================================================
## ✨ Features
* Support specifying the config location manually (outside of the user's profile) ([#1921](https://github.com/element-hq/element-desktop/pull/1921)). Contributed by @Half-Shot.
* Remove abandoned MSC3886, MSC3903, MSC3906 implementations ([#28274](https://github.com/element-hq/element-web/pull/28274)). Contributed by @t3chguy.
* Update to React 18 ([#24763](https://github.com/element-hq/element-web/pull/24763)). Contributed by @t3chguy.
* Deduplicate icons using Compound ([#28239](https://github.com/element-hq/element-web/pull/28239)). Contributed by @t3chguy.
* Replace legacy Tooltips with Compound tooltips ([#28231](https://github.com/element-hq/element-web/pull/28231)). Contributed by @t3chguy.
* Deduplicate icons using Compound Design Tokens ([#28219](https://github.com/element-hq/element-web/pull/28219)). Contributed by @t3chguy.
* Add reactions to html export ([#28210](https://github.com/element-hq/element-web/pull/28210)). Contributed by @langleyd.
* Remove feature\_dehydration ([#28173](https://github.com/element-hq/element-web/pull/28173)). Contributed by @florianduros.
## 🐛 Bug Fixes
* Improve seshat deleteContents ([#1916](https://github.com/element-hq/element-desktop/pull/1916)). Contributed by @langleyd.
* Remove upgrade encryption in `DeviceListener` and `SetupEncryptionToast` ([#28299](https://github.com/element-hq/element-web/pull/28299)). Contributed by @florianduros.
* Fix 'remove alias' button in room settings ([#28269](https://github.com/element-hq/element-web/pull/28269)). Contributed by @Dev-Gurjar.
* Add back unencrypted path in `StopGapWidgetDriver.sendToDevice` ([#28295](https://github.com/element-hq/element-web/pull/28295)). Contributed by @florianduros.
* Fix other devices not being decorated as such ([#28279](https://github.com/element-hq/element-web/pull/28279)). Contributed by @t3chguy.
* Fix pill contrast in invitation dialog ([#28250](https://github.com/element-hq/element-web/pull/28250)). Contributed by @florianduros.
* Close right panel chat when minimising maximised voip widget ([#28241](https://github.com/element-hq/element-web/pull/28241)). Contributed by @t3chguy.
* Fix develop changelog parsing ([#28232](https://github.com/element-hq/element-web/pull/28232)). Contributed by @t3chguy.
* Fix Ctrl+F shortcut not working with minimised room summary card ([#28223](https://github.com/element-hq/element-web/pull/28223)). Contributed by @t3chguy.
* Fix network dropdown missing checkbox \& aria-checked ([#28220](https://github.com/element-hq/element-web/pull/28220)). Contributed by @t3chguy.
Changes in [1.11.83](https://github.com/element-hq/element-desktop/releases/tag/v1.11.83) (2024-10-29)
======================================================================================================
## ✨ Features
* [Backport staging] Enable Element Call by default on release instances ([#1954](https://github.com/element-hq/element-desktop/pull/1954)). Contributed by @RiotRobot.
* Enable Element Call by default on release instances ([#28314](https://github.com/element-hq/element-web/pull/28314)). Contributed by @t3chguy.
Changes in [1.11.82](https://github.com/element-hq/element-desktop/releases/tag/v1.11.82) (2024-10-22)
======================================================================================================
## ✨ Features
* Add monochrome tray icon ([#1804](https://github.com/element-hq/element-desktop/pull/1804)). Contributed by @SakiiCode.
* Deduplicate more icons using Compound Design Tokens ([#132](https://github.com/element-hq/matrix-react-sdk/pull/132)). Contributed by @t3chguy.
* Always show link new device flow even if unsupported ([#147](https://github.com/element-hq/matrix-react-sdk/pull/147)). Contributed by @t3chguy.
* Update design of files list in right panel ([#144](https://github.com/element-hq/matrix-react-sdk/pull/144)). Contributed by @t3chguy.
* Remove feature\_dehydration ([#138](https://github.com/element-hq/matrix-react-sdk/pull/138)). Contributed by @florianduros.
* Upgrade emojibase-bindings and remove local handling of emoticon variations ([#127](https://github.com/element-hq/matrix-react-sdk/pull/127)). Contributed by @langleyd.
* Add support for rendering media captions ([#43](https://github.com/element-hq/matrix-react-sdk/pull/43)). Contributed by @tulir.
* Replace composer icons with Compound variants ([#123](https://github.com/element-hq/matrix-react-sdk/pull/123)). Contributed by @t3chguy.
* Tweak default right panel size to be 320px except for maximised widgets at 420px ([#110](https://github.com/element-hq/matrix-react-sdk/pull/110)). Contributed by @t3chguy.
* Add a pinned message badge under a pinned message ([#118](https://github.com/element-hq/matrix-react-sdk/pull/118)). Contributed by @florianduros.
* Ditch right panel tabs and re-add close button ([#99](https://github.com/element-hq/matrix-react-sdk/pull/99)). Contributed by @t3chguy.
* Force verification even for refreshed clients ([#44](https://github.com/element-hq/matrix-react-sdk/pull/44)). Contributed by @dbkr.
* Update emoji text, border and background colour in timeline ([#119](https://github.com/element-hq/matrix-react-sdk/pull/119)). Contributed by @florianduros.
* Disable ICE fallback based on well-known configuration ([#111](https://github.com/element-hq/matrix-react-sdk/pull/111)). Contributed by @t3chguy.
* Remove legacy room header and promote beta room header ([#105](https://github.com/element-hq/matrix-react-sdk/pull/105)). Contributed by @t3chguy.
* Respect `io.element.jitsi` `useFor1To1Calls` in well-known ([#112](https://github.com/element-hq/matrix-react-sdk/pull/112)). Contributed by @t3chguy.
* Use Compound close icon in favour of mishmash of x/close icons ([#108](https://github.com/element-hq/matrix-react-sdk/pull/108)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* Correct typo in option documentation ([#28148](https://github.com/element-hq/element-web/pull/28148)). Contributed by @AndrewKvalheim.
* Revert #124 and #135 ([#139](https://github.com/element-hq/matrix-react-sdk/pull/139)). Contributed by @dbkr.
* Add aria-label to e2e icon ([#136](https://github.com/element-hq/matrix-react-sdk/pull/136)). Contributed by @florianduros.
* Fix bell icons on room list hover being black squares ([#135](https://github.com/element-hq/matrix-react-sdk/pull/135)). Contributed by @dbkr.
* Fix vertical overflow on the mobile register screen ([#137](https://github.com/element-hq/matrix-react-sdk/pull/137)). Contributed by @langleyd.
* Allow to unpin redacted event ([#98](https://github.com/element-hq/matrix-react-sdk/pull/98)). Contributed by @florianduros.
Changes in [1.11.81](https://github.com/element-hq/element-desktop/releases/tag/v1.11.81) (2024-10-15)
======================================================================================================
This release fixes High severity vulnerability CVE-2024-47771 / GHSA-963w-49j9-gxj6.
Changes in [1.11.80](https://github.com/element-hq/element-desktop/releases/tag/v1.11.80) (2024-10-08)
======================================================================================================
## ✨ Features
* enable Element Call on desktop nightly ([#1873](https://github.com/element-hq/element-desktop/pull/1873)). Contributed by @fkwp.
* Add doc for 'force\_verification config option ([#28035](https://github.com/element-hq/element-web/pull/28035)). Contributed by @dbkr.
* Roll back change to device isolation mode ([#104](https://github.com/element-hq/matrix-react-sdk/pull/104)). Contributed by @richvdh.
* Remove right panel toggling behaviour on room header buttons ([#100](https://github.com/element-hq/matrix-react-sdk/pull/100)). Contributed by @t3chguy.
* Improve error display for messages sent from insecure devices ([#93](https://github.com/element-hq/matrix-react-sdk/pull/93)). Contributed by @richvdh.
* Add labs option to exclude unverified devices ([#92](https://github.com/element-hq/matrix-react-sdk/pull/92)). Contributed by @richvdh.
* Improve contrast for timestamps, date separators \& spotlight trigger ([#91](https://github.com/element-hq/matrix-react-sdk/pull/91)). Contributed by @t3chguy.
* Open room settings on room header avatar click ([#88](https://github.com/element-hq/matrix-react-sdk/pull/88)). Contributed by @t3chguy.
* Use `strong` over `b` for improved a11y semantics ([#41](https://github.com/element-hq/matrix-react-sdk/pull/41)). Contributed by @t3chguy.
* Grant Element Call widget capabilities for "raise hand" feature ([#82](https://github.com/element-hq/matrix-react-sdk/pull/82)). Contributed by @AndrewFerr.
* Mobile registration optimizations and tests ([#62](https://github.com/element-hq/matrix-react-sdk/pull/62)). Contributed by @langleyd.
* Ignore chat effect when older than 48h ([#48](https://github.com/element-hq/matrix-react-sdk/pull/48)). Contributed by @florianduros.
## 🐛 Bug Fixes
* Update native OIDC callback url to be RFC8252 compliant ([#28096](https://github.com/element-hq/element-web/pull/28096)). Contributed by @t3chguy.
* Update icons to include transparency ([#28040](https://github.com/element-hq/element-web/pull/28040)). Contributed by @t3chguy.
* Fix default\_widget\_container\_height in sample config ([#28034](https://github.com/element-hq/element-web/pull/28034)). Contributed by @dbkr.
* Fix untranslated keys being rendered in `/help` dialog ([#90](https://github.com/element-hq/matrix-react-sdk/pull/90)). Contributed by @t3chguy.
* Ensure timeline search results are visible even in video rooms ([#96](https://github.com/element-hq/matrix-react-sdk/pull/96)). Contributed by @t3chguy.
* Pop right panel timeline when unmaximising widget to avoid double timeline ([#94](https://github.com/element-hq/matrix-react-sdk/pull/94)). Contributed by @t3chguy.
* Fix accessible label on left panel spotlight trigger ([#87](https://github.com/element-hq/matrix-react-sdk/pull/87)). Contributed by @t3chguy.
* Crypto: fix display of device key ([#86](https://github.com/element-hq/matrix-react-sdk/pull/86)). Contributed by @richvdh.
Changes in [1.11.79](https://github.com/element-hq/element-desktop/releases/tag/v1.11.79) (2024-10-01)
======================================================================================================
* No changes

View File

@ -1,5 +1,5 @@
# Contributing code to element-desktop
Everyone is welcome to contribute code to element-desktop, provided that they are willing to license their contributions to Element under a [Contributor License Agreement](https://cla-assistant.io/element-hq/element-desktop) (CLA). This ensures that their contribution will be made available under an approved licence(as described in the [README](/README.md#copyright--license)).
Everyone is welcome to contribute code to element-desktop, provided that they are willing to license their contributions to Element under a [Contributor License Agreement](https://cla-assistant.io/element-hq/element-desktop) (CLA). This ensures that their contribution will be made available under an OSI-approved open-source license, currently licensed under Affero General Public License v3 (AGPLv3) or General Public License v3 (GPLv3) at your choice.
element-desktop follows the same pattern as element-web, please find more contributing guidelines at https://github.com/vector-im/element-web/blob/develop/CONTRIBUTING.md

View File

@ -1,6 +0,0 @@
Licensees holding a valid commercial license with Element may use this
software in accordance with the terms contained in a written agreement
between you and Element.
To purchase a commercial license please contact our sales team at
licensing@element.io

View File

@ -75,10 +75,10 @@ yarn run build
This will do a couple of things:
- Run the `setversion` script to set the local package version to match whatever
version of Element you installed above.
- Run electron-builder to build a package. The package built will match the operating system
you're running the build process on.
- Run the `setversion` script to set the local package version to match whatever
version of Element you installed above.
- Run electron-builder to build a package. The package built will match the operating system
you're running the build process on.
## Docker
@ -101,6 +101,9 @@ After running, the packages should be in `dist/`.
If you'd just like to run the electron app locally for development:
```
# Install electron - we don't normally need electron itself as it's provided
# by electron-builder when building packages
yarn add electron
yarn start
```
@ -131,19 +134,15 @@ Alternatively, a custom location for the profile data can be specified using the
# User-specified config.json
- `%APPDATA%\$NAME\config.json` on Windows
- `$XDG_CONFIG_HOME/$NAME/config.json` or `~/.config/$NAME/config.json` on Linux
- `~/Library/Application Support/$NAME/config.json` on macOS
- `%APPDATA%\$NAME\config.json` on Windows
- `$XDG_CONFIG_HOME/$NAME/config.json` or `~/.config/$NAME/config.json` on Linux
- `~/Library/Application Support/$NAME/config.json` on macOS
In the paths above, `$NAME` is typically `Element`, unless you use `--profile
$PROFILE` in which case it becomes `Element-$PROFILE`, or it is using one of
the above created by a pre-1.7 install, in which case it will be `Riot` or
`Riot-$PROFILE`.
You may also specify a different path entirely for the `config.json` file by
providing the `--config $YOUR_CONFIG_JSON_FILE` to the process, or via the
`ELEMENT_DESKTOP_CONFIG_JSON` environment variable.
# Translations
To add a new translation, head to the [translating doc](https://github.com/vector-im/element-web/blob/develop/docs/translating.md).
@ -155,20 +154,3 @@ For a developer guide, see the [translating dev doc](https://github.com/vector-i
If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.
To help avoid duplicate issues, please [view existing issues](https://github.com/vector-im/element-web/issues?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc) first (and add a +1) or [create a new issue](https://github.com/vector-im/element-web/issues/new/choose) if you can't find it. Please note that this issue tracker is associated with the [element-web](https://github.com/vector-im/element-web) repo, but is also applied to the code in this repo as well.
## Copyright & License
Copyright (c) 2016-2017 OpenMarket Ltd
Copyright (c) 2017 Vector Creations Ltd
Copyright (c) 2017-2025 New Vector Ltd
This software is multi licensed by New Vector Ltd (Element). It can be used either:
(1) for free under the terms of the GNU Affero General Public License (as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version); OR
(2) for free 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); OR
(3) under the terms of a paid-for Element Commercial License agreement between you and Element (the terms of which may vary depending on what you and Element have agreed to).
Unless required by applicable law or agreed to in writing, software distributed under the Licenses is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licenses for the specific language governing permissions and limitations under the Licenses.

View File

@ -1,8 +1,7 @@
# Docker image to facilitate building Element Desktop's native bits using a glibc version (2.31)
# with broader compatibility, down to Debian bullseye & Ubuntu focal.
FROM rust:bullseye
# Docker image to facilitate building Element Desktop's native bits using a glibc version with broader compatibility
FROM rust:buster
ENV DEBIAN_FRONTEND=noninteractive
ENV DEBIAN_FRONTEND noninteractive
RUN curl --proto "=https" -L https://yarnpkg.com/latest.tar.gz | tar xvz && mv yarn-* /yarn && ln -s /yarn/bin/yarn /usr/bin/yarn
RUN apt-get -qq update && apt-get -y -qq dist-upgrade && \
@ -14,15 +13,15 @@ RUN apt-get -qq update && apt-get -y -qq dist-upgrade && \
# Used by seshat (when not SQLCIPHER_STATIC) \
libsqlcipher-dev && \
apt-get purge -y --auto-remove && rm -rf /var/lib/apt/lists/*
RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y wine mono-devel rpm
RUN ln -s /usr/bin/python3 /usr/bin/python & ln -s /usr/bin/pip3 /usr/bin/pip
ENV DEBUG_COLORS=true
ENV FORCE_COLOR=true
ENV DEBUG_COLORS true
ENV FORCE_COLOR true
WORKDIR /project
ENV NODE_VERSION 20.15.1
ARG TARGETOS
ARG TARGETARCH
COPY .node-version dockerbuild/setup.sh /
COPY setup.sh /setup.sh
RUN /setup.sh

View File

@ -3,6 +3,5 @@
set -x
declare -A archMap=(["amd64"]="x64" ["arm64"]="arm64")
ARCH="${archMap["$TARGETARCH"]}"
NODE_VERSION=$(cat /.node-version)
curl --proto "=https" -L "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-$TARGETOS-$ARCH.tar.gz" | tar xz -C /usr/local --strip-components=1 && \
curl --proto "=https" -L "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-$TARGETOS-$ARCH.tar.gz" | tar xz -C /usr/local --strip-components=1 && \
unlink /usr/local/CHANGELOG.md && unlink /usr/local/LICENSE && unlink /usr/local/README.md

View File

@ -1,17 +1,17 @@
# Summary
- [Introduction](../README.md)
- [Introduction](../README.md)
# Build
- [Native Node modules](native-node-modules.md)
- [Windows requirements](windows-requirements.md)
- [Native Node modules](native-node-modules.md)
- [Windows requirements](windows-requirements.md)
# Distribution
- [Updates](updates.md)
- [Packaging](packaging.md)
- [Updates](updates.md)
- [Packaging](packaging.md)
# Setup
- [Config](config.md)
- [Config](config.md)

View File

@ -17,9 +17,9 @@ when releasing.
Install the pre-requisites for your system:
- [Windows pre-requisites](https://github.com/vector-im/element-desktop/blob/develop/docs/windows-requirements.md)
- Linux: TODO
- OS X: TODO
- [Windows pre-requisites](https://github.com/vector-im/element-desktop/blob/develop/docs/windows-requirements.md)
- Linux: TODO
- OS X: TODO
Then optionally, [add seshat and dependencies to support search in E2E rooms](#adding-seshat-for-search-in-e2e-encrypted-rooms).

View File

@ -17,8 +17,8 @@ Simply go to https://github.com/vector-im/element-desktop/actions/workflows/buil
For releasing Element Desktop, we assume the following prerequisites:
- a tag of `element-desktop` repo with the Element Desktop version to be released set in `package.json`.
- an Element Web tarball published to GitHub with a matching version number.
- a tag of `element-desktop` repo with the Element Desktop version to be released set in `package.json`.
- an Element Web tarball published to GitHub with a matching version number.
**Both of these are done automatically when you run the release automation.**

View File

@ -2,30 +2,23 @@
## Requirements to build native modules
We rely on Github Actions `windows-2022` plus a few extra utilities as per [the workflow](https://github.com/vector-im/element-desktop/blob/develop/.github/workflows/build_windows.yaml).
We rely on Github Actions `windows-latest` plus a few extra utilities as per [the workflow](https://github.com/vector-im/element-desktop/blob/develop/.github/workflows/build_windows.yaml).
If you want to build native modules, make sure that the following tools are installed on your system.
- [Git for Windows](https://git-scm.com/download/win)
- [Node 16](https://nodejs.org)
- [Python 3](https://www.python.org/downloads/) (if you type 'python' into command prompt it will offer to install it from the windows store)
- [Strawberry Perl](https://strawberryperl.com/)
- [Rustup](https://rustup.rs/)
- [NASM](https://www.nasm.us/)
You can install the above tools using [Chocolatey](https://chocolatey.org/install):
```cmd
choco install --no-progress -y git nodejs-lts yarn python StrawberryPerl rustup.install nasm magicsplat-tcl-tk
```
- [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019) with the following configuration:
- On the Workloads tab:
- Desktop & Mobile -> C++ build tools
- On the Individual components tab:
- MSVC VS 2019 C++ build tools
- Windows 10 SDK (latest version available)
- C++ CMake tools for Windows
- [Git for Windows](https://git-scm.com/download/win)
- [Node 16](https://nodejs.org)
- [Python 3](https://www.python.org/downloads/) (if you type 'python' into command prompt it will offer to install it from the windows store)
- [Strawberry Perl](https://strawberryperl.com/)
- [Rustup](https://rustup.rs/)
- [NASM](https://www.nasm.us/)
- [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019) with the following configuration:
- On the Workloads tab:
- Desktop & Mobile -> C++ build tools
- On the Individual components tab:
- MSVC VS 2019 C++ build tools
- Windows 10 SDK (latest version available)
- C++ CMake tools for Windows
Once installed make sure all those utilities are accessible in your `PATH`.

View File

@ -1,10 +1,8 @@
import * as os from "node:os";
import * as fs from "node:fs";
import * as path from "node:path";
import * as plist from "plist";
import { AfterPackContext, Arch, Configuration as BaseConfiguration, Platform } from "electron-builder";
import { computeData } from "app-builder-lib/out/asar/integrity";
import { readFile, writeFile } from "node:fs/promises";
import * as os from "os";
import * as fs from "fs";
import * as path from "path";
import { Arch, Configuration as BaseConfiguration, AfterPackContext } from "electron-builder";
import { flipFuses, FuseVersion, FuseV1Options } from "@electron/fuses";
/**
* This script has different outputs depending on your os platform.
@ -12,7 +10,10 @@ import { readFile, writeFile } from "node:fs/promises";
* On Windows:
* Prefixes the nightly version with `0.0.1-nightly.` as it breaks if it is not semver
* Passes $ED_SIGNTOOL_THUMBPRINT and $ED_SIGNTOOL_SUBJECT_NAME to
* build.win.signtoolOptions.signingHashAlgorithms and build.win.signtoolOptions.certificateSubjectName respectively if specified.
* build.win.signingHashAlgorithms and build.win.certificateSubjectName respectively if specified.
*
* On macOS:
* Passes $ED_NOTARYTOOL_TEAM_ID to build.mac.notarize.notarize if specified
*
* On Linux:
* Replaces spaces in the product name with dashes as spaces in paths can cause issues
@ -46,52 +47,49 @@ interface Configuration extends BaseConfiguration {
} & BaseConfiguration["deb"];
}
async function injectAsarIntegrity(context: AfterPackContext) {
const packager = context.packager;
// We only need to re-generate asar on universal Mac builds, due to https://github.com/electron/universal/issues/116
if (packager.platform !== Platform.MAC || context.arch !== Arch.universal) return;
const resourcesPath = packager.getResourcesDir(context.appOutDir);
const asarIntegrity = await computeData({
resourcesPath,
resourcesRelativePath: "Resources",
resourcesDestinationPath: resourcesPath,
extraResourceMatchers: [],
});
const plistPath = path.join(resourcesPath, "..", "Info.plist");
const data = plist.parse(await readFile(plistPath, "utf8")) as unknown as Writable<plist.PlistObject>;
data["ElectronAsarIntegrity"] = asarIntegrity as unknown as Writable<plist.PlistValue>;
await writeFile(plistPath, plist.build(data));
}
/**
* @type {import('electron-builder').Configuration}
* @see https://www.electron.build/configuration/configuration
*/
const config: Omit<Writable<Configuration>, "electronFuses"> & {
// Make all fuses required to ensure they are all explicitly specified
electronFuses: Required<Configuration["electronFuses"]>;
} = {
const config: Writable<Configuration> = {
appId: "im.riot.app",
asarUnpack: "**/*.node",
electronFuses: {
enableCookieEncryption: true,
onlyLoadAppFromAsar: true,
grantFileProtocolExtraPrivileges: false,
runAsNode: false,
enableNodeOptionsEnvironmentVariable: false,
enableNodeCliInspectArguments: false,
// We need to reset the signature if we are not signing on darwin otherwise it won't launch
resetAdHocDarwinSignature: !process.env.APPLE_TEAM_ID,
loadBrowserProcessSpecificV8Snapshot: false,
enableEmbeddedAsarIntegrityValidation: true,
},
afterPack: async (context: AfterPackContext) => {
await injectAsarIntegrity(context);
if (context.electronPlatformName !== "darwin" || context.arch === Arch.universal) {
// Burn in electron fuses for proactive security hardening.
// On macOS, we only do this for the universal package, as the constituent arm64 and amd64 packages are embedded within.
const ext = (<Record<string, string>>{
darwin: ".app",
win32: ".exe",
linux: "",
})[context.electronPlatformName];
let executableName = context.packager.appInfo.productFilename;
if (context.electronPlatformName === "linux") {
// Linux uses the package name as the executable name
executableName = context.packager.appInfo.name;
}
const electronBinaryPath = path.join(context.appOutDir, `${executableName}${ext}`);
console.log(`Flipping fuses for: ${electronBinaryPath}`);
await flipFuses(electronBinaryPath, {
version: FuseVersion.V1,
resetAdHocDarwinSignature: context.electronPlatformName === "darwin" && context.arch === Arch.universal,
[FuseV1Options.EnableCookieEncryption]: true,
[FuseV1Options.OnlyLoadAppFromAsar]: true,
[FuseV1Options.RunAsNode]: false,
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
[FuseV1Options.EnableNodeCliInspectArguments]: false,
// Mac app crashes on arm for us when `LoadBrowserProcessSpecificV8Snapshot` is enabled
[FuseV1Options.LoadBrowserProcessSpecificV8Snapshot]: false,
// https://github.com/electron/fuses/issues/7
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: false,
});
}
},
files: [
"package.json",
@ -140,8 +138,6 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
"Replaces: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)",
"--deb-field",
"Breaks: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)",
"--deb-pre-depends",
"libc6 (>= 2.31)",
],
},
mac: {
@ -149,17 +145,12 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
darkModeSupport: true,
hardenedRuntime: true,
gatekeeperAssess: true,
// XXX: we cannot specify this due to https://github.com/electron/osx-sign/issues/344
// strictVerify: true,
entitlements: "./build/entitlements.mac.plist",
icon: "build/icons/icon.icns",
mergeASARs: true,
},
win: {
target: ["squirrel", "msi"],
signtoolOptions: {
signingHashAlgorithms: ["sha256"],
},
signingHashAlgorithms: ["sha256"],
icon: "build/icons/icon.ico",
},
msi: {
@ -174,9 +165,6 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
schemes: ["io.element.desktop", "element"],
},
],
nativeRebuilder: "sequential",
nodeGypRebuild: false,
npmRebuild: true,
};
/**
@ -185,8 +173,18 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
* @param {string} process.env.ED_SIGNTOOL_THUMBPRINT
*/
if (process.env.ED_SIGNTOOL_SUBJECT_NAME && process.env.ED_SIGNTOOL_THUMBPRINT) {
config.win.signtoolOptions!.certificateSubjectName = process.env.ED_SIGNTOOL_SUBJECT_NAME;
config.win.signtoolOptions!.certificateSha1 = process.env.ED_SIGNTOOL_THUMBPRINT;
config.win.certificateSubjectName = process.env.ED_SIGNTOOL_SUBJECT_NAME;
config.win.certificateSha1 = process.env.ED_SIGNTOOL_THUMBPRINT;
}
/**
* Allow specifying macOS notary team id via env var
* @param {string} process.env.ED_NOTARYTOOL_TEAM_ID
*/
if (process.env.ED_NOTARYTOOL_TEAM_ID) {
config.mac.notarize = {
teamId: process.env.ED_NOTARYTOOL_TEAM_ID,
};
}
/**

View File

@ -47,13 +47,5 @@
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx",
"setting_defaults": {
"RustCrypto.staged_rollout_percent": 60
},
"features": {
"feature_video_rooms": true,
"feature_group_calls": true,
"feature_element_call_video_rooms": true
},
"element_call": {
"url": "https://call.element.io"
}
}

36
hak/keytar/build.ts Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import path from "path";
import childProcess from "child_process";
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
export default async function buildKeytar(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const env = hakEnv.makeGypEnv();
console.log("Running yarn with env", env);
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(
path.join(moduleInfo.nodeModuleBinDir, "node-gyp" + (hakEnv.isWin() ? ".cmd" : "")),
["rebuild", "--arch", hakEnv.getTargetArch()],
{
cwd: moduleInfo.moduleBuildDir,
env,
stdio: "inherit",
// We need shell mode on Windows to be able to launch `.cmd` executables
// See https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
shell: hakEnv.isWin(),
},
);
proc.on("exit", (code) => {
code ? reject(code) : resolve();
});
});
}

31
hak/keytar/check.ts Normal file
View File

@ -0,0 +1,31 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import childProcess from "child_process";
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const tools = [["python", "--version"]]; // node-gyp uses python for reasons beyond comprehension
for (const tool of tools) {
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(tool[0], tool.slice(1), {
stdio: ["ignore"],
});
proc.on("exit", (code) => {
if (code !== 0) {
reject("Can't find " + tool);
} else {
resolve();
}
});
});
}
}

10
hak/keytar/hak.json Normal file
View File

@ -0,0 +1,10 @@
{
"scripts": {
"check": "check.ts",
"build": "build.ts"
},
"copy": "build/Release/keytar.node",
"dependencies": {
"libsecret": "0.20.3"
}
}

View File

@ -2,12 +2,14 @@
Copyright 2024 New Vector Ltd.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import type HakEnv from "../../scripts/hak/hakEnv.js";
import type { DependencyInfo } from "../../scripts/hak/dep.js";
import childProcess from "child_process";
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const env = hakEnv.makeGypEnv();
@ -17,18 +19,30 @@ export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Prom
}
console.log("Running yarn install");
await hakEnv.spawn("yarn", ["install"], {
cwd: moduleInfo.moduleBuildDir,
env,
shell: true,
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn("yarn" + (hakEnv.isWin() ? ".cmd" : ""), ["install"], {
cwd: moduleInfo.moduleBuildDir,
env,
shell: true,
stdio: "inherit",
});
proc.on("exit", (code) => {
code ? reject(code) : resolve();
});
});
const buildTarget = hakEnv.wantsStaticSqlCipher() ? "build-bundled" : "build";
console.log("Running yarn build");
await hakEnv.spawn("yarn", ["run", buildTarget], {
cwd: moduleInfo.moduleBuildDir,
env,
shell: true,
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn("yarn" + (hakEnv.isWin() ? ".cmd" : ""), ["run", buildTarget], {
cwd: moduleInfo.moduleBuildDir,
env,
shell: true,
stdio: "inherit",
});
proc.on("exit", (code) => {
code ? reject(code) : resolve();
});
});
}

View File

@ -2,19 +2,18 @@
Copyright 2024 New Vector Ltd.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import childProcess from "node:child_process";
import fsProm from "node:fs/promises";
import childProcess from "child_process";
import fsProm from "fs/promises";
import type HakEnv from "../../scripts/hak/hakEnv.js";
import type { Tool } from "../../scripts/hak/hakEnv.js";
import type { DependencyInfo } from "../../scripts/hak/dep.js";
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const tools: Tool[] = [
const tools = [
["rustc", "--version"],
["python", "--version"], // node-gyp uses python for reasons beyond comprehension
];
@ -26,7 +25,21 @@ export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Prom
} else {
tools.push(["make", "--version"]);
}
await hakEnv.checkTools(tools);
for (const tool of tools) {
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(tool[0], tool.slice(1), {
stdio: ["ignore"],
});
proc.on("exit", (code) => {
if (code !== 0) {
reject("Can't find " + tool);
} else {
resolve();
}
});
});
}
// Ensure Rust target exists (nb. we avoid depending on rustup)
await new Promise((resolve, reject) => {

View File

@ -7,5 +7,8 @@
"strict": true,
"lib": ["es2022"]
},
"include": ["../scripts/@types/*.d.ts", "./**/*.ts"]
"include": ["../scripts/@types/*.d.ts", "./**/*.ts"],
"ts-node": {
"transpileOnly": true
}
}

View File

@ -5,11 +5,13 @@ export default {
project: ["**/*.{js,ts}"],
ignoreDependencies: [
// Brought in via hak scripts
"keytar",
"matrix-seshat",
// Needed by `electron-builder`
"electron-builder-squirrel-windows",
"@types/yargs",
// Required for `action-validator`
"@action-validator/*",
// Used for git pre-commit hooks
"husky",
],
ignoreBinaries: ["jq", "scripts/in-docker.sh"],
} satisfies KnipConfig;

View File

@ -2,17 +2,15 @@
"name": "element-desktop",
"productName": "Element",
"main": "lib/electron-main.js",
"exports": "./lib/electron-main.js",
"version": "1.11.94",
"description": "Element: the future of secure communication",
"version": "1.11.79",
"description": "A feature-rich client for Matrix.org",
"author": "Element",
"homepage": "https://element.io",
"repository": {
"type": "git",
"url": "https://github.com/vector-im/element-desktop"
},
"license": "SEE LICENSE IN README.md",
"type": "module",
"license": "AGPL-3.0-only OR GPL-3.0-only",
"files": [],
"engines": {
"node": ">=18.0.0"
@ -23,12 +21,20 @@
"i18n:lint": "prettier --log-level=silent --write src/i18n/strings/ --ignore-path /dev/null",
"i18n:diff": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && yarn i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
"mkdirs": "mkdirp packages deploys",
"fetch": "yarn run mkdirs && tsx scripts/fetch-package.ts",
"fetch": "yarn run mkdirs && ts-node scripts/fetch-package.ts",
"asar-webapp": "asar p webapp webapp.asar",
"start": "yarn run build:ts && yarn run build:res && electron .",
"lint": "yarn lint:types && yarn lint:js && yarn lint:workflows",
"lint:js": "eslint --max-warnings 0 src hak playwright scripts && prettier --check .",
"lint:js-fix": "eslint --fix --max-warnings 0 src hak playwright scripts && prettier --log-level=warn --write .",
"lint:js": "yarn lint:js:src && yarn lint:js:test && yarn lint:js:scripts && yarn lint:js:hak && prettier --check .",
"lint:js:src": "eslint --max-warnings 0 src",
"lint:js:test": "eslint --max-warnings 0 --config .eslintrc-test.js playwright",
"lint:js:scripts": "eslint --max-warnings 0 --config .eslintrc-scripts.js scripts",
"lint:js:hak": "eslint --max-warnings 0 --config .eslintrc-hak.js hak",
"lint:js-fix": "yarn lint:js-fix:src &&yarn lint:js-fix:test && yarn lint:js-fix:scripts && yarn lint:js-fix:hak && prettier --log-level=warn --write .",
"lint:js-fix:src": "eslint --fix --max-warnings 0 src",
"lint:js-fix:test": "eslint --fix --max-warnings 0 --config .eslintrc-test.js playwright",
"lint:js-fix:scripts": "eslint --fix --max-warnings 0 --config .eslintrc-scripts.js scripts",
"lint:js-fix:hak": "eslint --fix --max-warnings 0 --config .eslintrc-hak.js hak",
"lint:types": "yarn lint:types:src && yarn lint:types:test && yarn lint:types:scripts && yarn lint:types:hak",
"lint:types:src": "tsc --noEmit",
"lint:types:test": "tsc --noEmit -p playwright/tsconfig.json",
@ -43,30 +49,29 @@
"build:universal": "yarn run build:ts && yarn run build:res && electron-builder --universal",
"build": "yarn run build:ts && yarn run build:res && electron-builder",
"build:ts": "tsc",
"build:res": "tsx scripts/copy-res.ts",
"docker:setup": "docker build --platform linux/amd64 -t element-desktop-dockerbuild -f dockerbuild/Dockerfile .",
"build:res": "ts-node scripts/copy-res.ts",
"docker:setup": "docker build --platform linux/amd64 -t element-desktop-dockerbuild dockerbuild",
"docker:build:native": "scripts/in-docker.sh yarn run hak",
"docker:build": "scripts/in-docker.sh yarn run build",
"docker:install": "scripts/in-docker.sh yarn install",
"clean": "rimraf webapp.asar dist packages deploys lib",
"hak": "tsx scripts/hak/index.ts",
"hak": "ts-node scripts/hak/index.ts",
"test": "playwright test",
"test:open": "yarn test --ui",
"test:screenshots:build": "docker build playwright -t element-desktop-playwright --platform linux/amd64",
"test:screenshots:run": "docker run --rm --network host -v $(pwd):/work/element-desktop -v /var/run/docker.sock:/var/run/docker.sock --platform linux/amd64 -it element-desktop-playwright",
"postinstall": "electron-builder install-app-deps"
"test:screenshots:run": "docker run --rm --network host -v $(pwd):/work/element-desktop -v /var/run/docker.sock:/var/run/docker.sock --platform linux/amd64 -it element-desktop-playwright"
},
"dependencies": {
"@sentry/electron": "^6.0.0",
"@standardnotes/electron-clear-data": "^1.0.5",
"@sentry/electron": "^5.0.0",
"auto-launch": "^5.0.5",
"counterpart": "^0.18.6",
"electron-store": "^10.0.0",
"electron-clear-data": "^1.0.5",
"electron-store": "^8.0.2",
"electron-window-state": "^5.0.3",
"keytar-forked": "7.10.0",
"minimist": "^1.2.6",
"node-fetch": "^2",
"png-to-ico": "^2.1.1",
"uuid": "^11.0.0"
"uuid": "^10.0.0"
},
"devDependencies": {
"@action-validator/cli": "^0.6.0",
@ -74,49 +79,51 @@
"@babel/core": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@electron/asar": "3.3.1",
"@playwright/test": "1.50.1",
"@stylistic/eslint-plugin": "^3.0.0",
"@electron/asar": "^3.2.3",
"@electron/fuses": "^1.7.0",
"@mapbox/node-pre-gyp": "^1.0.11",
"@playwright/test": "1.47.1",
"@types/auto-launch": "^5.0.1",
"@types/counterpart": "^0.18.1",
"@types/minimist": "^1.2.1",
"@types/node": "18.19.79",
"@types/node": "18.19.54",
"@types/pacote": "^11.1.1",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"app-builder-lib": "26.0.10",
"@types/tar": "^6.1.3",
"@types/uuid": "^10.0.0",
"@types/yargs": "^17.0.32",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0",
"app-builder-lib": "24.13.3",
"chokidar": "^4.0.0",
"detect-libc": "^2.0.0",
"electron": "34.3.0",
"electron-builder": "26.0.10",
"electron-builder-squirrel-windows": "26.0.10",
"electron-devtools-installer": "^4.0.0",
"electron": "^32.0.0",
"electron-builder": "24.13.3",
"electron-builder-squirrel-windows": "24.13.3",
"electron-devtools-installer": "^3.2.0",
"eslint": "^8.26.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^10.0.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-matrix-org": "^2.0.1",
"eslint-plugin-n": "^17.12.0",
"eslint-plugin-unicorn": "^56.0.0",
"eslint-plugin-matrix-org": "^1.0.0",
"eslint-plugin-unicorn": "^55.0.0",
"glob": "^11.0.0",
"husky": "^9.1.6",
"knip": "^5.0.0",
"lint-staged": "^15.2.10",
"matrix-web-i18n": "^3.2.1",
"mkdirp": "^3.0.0",
"pacote": "^21.0.0",
"plist": "^3.1.0",
"pacote": "^19.0.0",
"prettier": "^3.0.0",
"rimraf": "^6.0.0",
"tar": "^7.0.0",
"tsx": "^4.19.2",
"typescript": "5.8.2"
"tar": "^6.2.1",
"ts-node": "^10.9.1",
"typescript": "5.5.4"
},
"hakDependencies": {
"matrix-seshat": "^4.0.1"
"matrix-seshat": "^4.0.0",
"keytar": "^7.9.0"
},
"resolutions": {
"@types/node": "18.19.79",
"config-file-ts": "0.2.8-rc1"
"@types/node": "18.19.54",
"config-file-ts": "0.2.8-rc1",
"lru-cache": "11.0.1"
}
}

View File

@ -2,7 +2,7 @@
Copyright 2024 New Vector Ltd.
Copyright 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/playwright:v1.50.1-jammy
FROM mcr.microsoft.com/playwright:v1.46.1-jammy
WORKDIR /work/element-desktop

View File

@ -1,44 +0,0 @@
/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { test, expect } from "../../element-desktop-test.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
test.describe("App config options", () => {
test.describe("Should load custom config via env", () => {
test.slow();
test.use({
extraEnv: {
ELEMENT_DESKTOP_CONFIG_JSON: resolve(__dirname, "../..", "fixtures/custom-config.json"),
},
});
test("should launch and use configured homeserver", async ({ page }) => {
await page.locator("#matrixchat").waitFor();
await page.locator(".mx_Welcome").waitFor();
await expect(page).toHaveURL("vector://vector/webapp/#/welcome");
await page.getByText("Sign in").click();
await page.getByText("matrix.example.org", { exact: true }).waitFor();
});
});
test.describe("Should load custom config via argument", () => {
test.slow();
test.use({
extraArgs: ["--config", resolve(__dirname, "../..", "fixtures/custom-config.json")],
});
test("should launch and use configured homeserver", async ({ page }) => {
await page.locator("#matrixchat").waitFor();
await page.locator(".mx_Welcome").waitFor();
await expect(page).toHaveURL("vector://vector/webapp/#/welcome");
await page.getByText("Sign in").click();
await page.getByText("matrix.example.org", { exact: true }).waitFor();
});
});
});

View File

@ -2,13 +2,11 @@
Copyright 2024 New Vector Ltd.
Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { platform } from "node:os";
import { test, expect } from "../../element-desktop-test.js";
import { test, expect } from "../../element-desktop-test";
declare global {
interface Window {
@ -19,7 +17,6 @@ declare global {
supportsEventIndexing(): Promise<boolean>;
}
| undefined;
createPickleKey(userId: string, deviceId: string): Promise<string | null>;
};
};
}
@ -27,32 +24,17 @@ declare global {
test.describe("App launch", () => {
test.slow();
test.beforeEach(async ({ page }) => {
test("should launch and render the welcome view successfully and support seshat", async ({ page }) => {
await page.locator("#matrixchat").waitFor();
await page.locator(".mx_Welcome").waitFor();
});
test("should launch and render the welcome view successfully", async ({ page }) => {
await expect(page).toHaveURL("vector://vector/webapp/#/welcome");
await expect(page).toHaveScreenshot();
});
test("should launch and render the welcome view successfully and support seshat", async ({ page }) => {
await expect(
page.evaluate<boolean>(async () => {
return window.mxPlatformPeg.get().getEventIndexingManager()?.supportsEventIndexing();
}),
).resolves.toBeTruthy();
});
const supported = await page.evaluate<boolean>(async () => {
const indexManager = window.mxPlatformPeg.get()?.getEventIndexingManager();
return await indexManager?.supportsEventIndexing();
});
test("should launch and render the welcome view successfully and support keytar", async ({ page }) => {
test.skip(platform() === "linux", "This test does not yet support Linux");
await expect(
page.evaluate<string | null>(async () => {
return await window.mxPlatformPeg.get().createPickleKey("@user:server", "ABCDEF");
}),
).resolves.not.toBeNull();
expect(supported).toBe(true);
});
});

View File

@ -2,28 +2,16 @@
Copyright 2024 New Vector Ltd.
Copyright 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { _electron as electron, test as base, expect as baseExpect, type ElectronApplication } from "@playwright/test";
import fs from "node:fs/promises";
import path, { dirname } from "node:path";
import path from "node:path";
import os from "node:os";
import { fileURLToPath } from "node:url";
interface Fixtures {
app: ElectronApplication;
tmpDir: string;
extraEnv: Record<string, string>;
extraArgs: string[];
}
const __dirname = dirname(fileURLToPath(import.meta.url));
export const test = base.extend<Fixtures>({
extraEnv: {},
extraArgs: [],
export const test = base.extend<{ app: ElectronApplication; tmpDir: string }>({
// eslint-disable-next-line no-empty-pattern
tmpDir: async ({}, use) => {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "element-desktop-tests-"));
@ -31,7 +19,7 @@ export const test = base.extend<Fixtures>({
await use(tmpDir);
await fs.rm(tmpDir, { recursive: true });
},
app: async ({ tmpDir, extraEnv, extraArgs }, use) => {
app: async ({ tmpDir }, use) => {
const args = ["--profile-dir", tmpDir];
const executablePath = process.env["ELEMENT_DESKTOP_EXECUTABLE"];
@ -41,25 +29,15 @@ export const test = base.extend<Fixtures>({
}
const app = await electron.launch({
env: {
...process.env,
...extraEnv,
},
env: process.env,
executablePath,
args: [...args, ...extraArgs],
args,
});
app.process().stdout.pipe(process.stdout);
app.process().stderr.pipe(process.stderr);
await app.firstWindow();
// Block matrix.org access to ensure consistent tests
const context = app.context();
await context.route("https://matrix.org/**", async (route) => {
await route.abort();
});
await use(app);
},
page: async ({ app }, use) => {

View File

@ -1,10 +0,0 @@
{
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix.example.org"
},
"m.identity_server": {
"base_url": "https://identity.example.org"
}
}
}

7
release_config.yaml Normal file
View File

@ -0,0 +1,7 @@
signing_id: releases@riot.im
subprojects:
element-web:
includeByDefault: true
# Because element-web is not in our dependencies, but the versions
# follow those of this project (well, vice-versa really)
mirrorVersion: true

11
scripts/@types/node-pre-gyp.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
/*
Copyright 2022-2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
declare module "@mapbox/node-pre-gyp/lib/util/versioning" {
// eslint-disable-next-line @typescript-eslint/naming-convention
export function get_runtime_abi(runtime: string, version: string): string;
}

View File

@ -1,7 +0,0 @@
REM Batch file to aid in cross-compiling sqlcipher for Windows ARM64
REM Full path should be passed to Makefile.msc as NCC env var
setlocal
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %VSCMD_ARG_HOST_ARCH%
cl.exe %*
endlocal

View File

@ -1,20 +1,20 @@
#!/usr/bin/env -S npx tsx
#!/usr/bin/env -S npx ts-node
// copies resources into the lib directory.
import parseArgs from "minimist";
import * as chokidar from "chokidar";
import * as path from "node:path";
import * as fs from "node:fs";
import * as path from "path";
import * as fs from "fs";
const argv = parseArgs(process.argv.slice(2), {});
const watch = argv.w;
const verbose = argv.v;
function errCheck(err: unknown): void {
function errCheck(err?: Error): void {
if (err) {
console.error(err instanceof Error ? err.message : err);
console.error(err.message);
process.exit(1);
}
}

View File

@ -1,14 +1,15 @@
#!/usr/bin/env -S npx tsx --resolveJsonModule
#!/usr/bin/env -S npx ts-node --resolveJsonModule
import * as path from "node:path";
import { createWriteStream, promises as fs } from "node:fs";
import * as childProcess from "node:child_process";
import * as tar from "tar";
import * as path from "path";
import { createWriteStream, promises as fs } from "fs";
import * as childProcess from "child_process";
import tar from "tar";
import * as asar from "@electron/asar";
import { promises as stream } from "node:stream";
import fetch from "node-fetch";
import { promises as stream } from "stream";
import riotDesktopPackageJson from "../package.json";
import { setPackageVersion } from "./set-version.js";
import { setPackageVersion } from "./set-version";
const PUB_KEY_URL = "https://packages.riot.im/element-release-key.asc";
const PACKAGE_URL_PREFIX = "https://github.com/element-hq/element-web/releases/download/";
@ -27,7 +28,7 @@ async function downloadToFile(url: string, filename: string): Promise<void> {
console.error(e);
try {
await fs.unlink(filename);
} catch {}
} catch (_) {}
throw e;
}
}
@ -124,8 +125,6 @@ async function main(): Promise<number | undefined> {
});
fetch(PUB_KEY_URL)
.then((resp) => {
if (!resp.ok) throw new Error(`unexpected response ${resp.statusText}`);
if (!resp.body) throw new Error(`unexpected response has no body ${resp.statusText}`);
stream.pipeline(resp.body, gpgProc.stdin!).catch(reject);
})
.catch(reject);
@ -151,14 +150,14 @@ async function main(): Promise<number | undefined> {
await fs.opendir(expectedDeployDir);
console.log(expectedDeployDir + "already exists");
haveDeploy = true;
} catch {}
} catch (e) {}
if (!haveDeploy) {
const outPath = path.join(pkgDir, filename);
try {
await fs.stat(outPath);
console.log("Already have " + filename + ": not redownloading");
} catch {
} catch (e) {
try {
await downloadToFile(url, outPath);
} catch (e) {
@ -171,7 +170,7 @@ async function main(): Promise<number | undefined> {
try {
await fs.stat(outPath + ".asc");
console.log("Already have " + filename + ".asc: not redownloading");
} catch {
} catch (e) {
try {
await downloadToFile(url + ".asc", outPath + ".asc");
} catch (e) {
@ -207,7 +206,7 @@ async function main(): Promise<number | undefined> {
await fs.stat(ASAR_PATH);
console.log(ASAR_PATH + " already present: removing");
await fs.unlink(ASAR_PATH);
} catch {}
} catch (e) {}
if (cfgDir.length) {
const configJsonSource = path.join(cfgDir, "config.json");

View File

@ -1,4 +1,4 @@
#!/usr/bin/env -S npx tsx
#!/usr/bin/env -S npx ts-node
/**
* Script to generate incremental Nightly build versions, based on the latest Nightly build version of that kind.

View File

@ -1,12 +1,10 @@
#!/usr/bin/env -S npx tsx
#!/usr/bin/env -S npx ts-node
/*
* Checks for the presence of a webapp, inspects its version and prints it
*/
import url from "node:url";
import { versionFromAsar } from "./set-version.js";
import { versionFromAsar } from "./set-version";
async function main(): Promise<number> {
const version = await versionFromAsar();
@ -15,16 +13,13 @@ async function main(): Promise<number> {
return 0;
}
if (import.meta.url.startsWith("file:")) {
const modulePath = url.fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) {
main()
.then((ret) => {
process.exit(ret);
})
.catch((e) => {
console.error(e);
process.exit(1);
});
}
if (require.main === module) {
main()
.then((ret) => {
process.exit(ret);
})
.catch((e) => {
console.error(e);
process.exit(1);
});
}

View File

@ -3,7 +3,7 @@
# Source https://gist.github.com/vladimyr/9a03481154cd3048a486bdf71e5e1535/57e57a6ace6fb2c8bba948bce726df7a96c3f99f
# This scripts lets you check which minimum GLIBC version an executable requires.
# Simply run './glibc-check.sh path/to/your/binary'
MAX_GLIBC="${MAX_GLIBC:-2.28}"
MAX_VER="${MAX_VER:-2.28}"
BINARY="$1"
@ -39,10 +39,10 @@ IFS="
VERS=$(objdump -T "$BINARY" | grep GLIBC_ | sed 's/.*GLIBC_\([.0-9]*\).*/\1/g' | sort -u)
for VER in $VERS; do
vercomp "$VER" "$MAX_GLIBC"
vercomp "$VER" "$MAX_VER"
COMP=$?
if [[ $COMP -eq 1 ]]; then
echo "Error! ${BINARY} requests GLIBC ${VER}, which is higher than target ${MAX_GLIBC}"
echo "Error! ${BINARY} requests GLIBC ${VER}, which is higher than target ${MAX_VER}"
echo "Affected symbols:"
objdump -T "$BINARY" | grep -F "GLIBC_${VER}"
echo "Looking for symbols in libraries..."

View File

@ -5,12 +5,12 @@ documentation for it.
Goals:
- Must build compiled native node modules in a shippable state
(ie. only dynamically linked against libraries that will be on the
target system, all unnecessary files removed).
- Must be able to build any native module, no matter what build system
it uses (electron-rebuild is supposed to do this job but only works
for modules that use gyp).
- Must build compiled native node modules in a shippable state
(ie. only dynamically linked against libraries that will be on the
target system, all unnecessary files removed).
- Must be able to build any native module, no matter what build system
it uses (electron-rebuild is supposed to do this job but only works
for modules that use gyp).
It's also loosely designed to be a general tool and agnostic to what it's
actually building. It's used here to build modules for the electron app
@ -25,13 +25,13 @@ If no dependencies are given, hak runs the command on all dependencies.
There are a lot of files involved:
- scripts/hak/... - The tool itself
- hak/[dependency] - Files provided by the app that tell hak how to build each of its native dependencies.
Contains a hak.json file and also some script files, each of which must be referenced in hak.json.
- .hak/ - Files generated by hak in the course of doing its job. Includes the dependency module itself and
any of the native dependency's native dependencies.
- .hak/[dependency]/build - An extracted copy of the dependency's node module used to build it.
- .hak/[dependency]/out - Another extracted copy of the dependency, this one contains only what will be shipped.
- scripts/hak/... - The tool itself
- hak/[dependency] - Files provided by the app that tell hak how to build each of its native dependencies.
Contains a hak.json file and also some script files, each of which must be referenced in hak.json.
- .hak/ - Files generated by hak in the course of doing its job. Includes the dependency module itself and
any of the native dependency's native dependencies.
- .hak/[dependency]/build - An extracted copy of the dependency's node module used to build it.
- .hak/[dependency]/out - Another extracted copy of the dependency, this one contains only what will be shipped.
# Workings
@ -60,21 +60,21 @@ own in the .hak directory (unless one already exists, in which case this is your
Hak is divided into lifecycle stages, in order:
- fetch - Download and extract the source of the dependency
- link - Link the copy of the dependency into your node_modules directory
- build - The Good Stuff. Configure and build any native dependencies, then the module itself.
- copy - Copy the built artifact from the module build directory to the module output directory.
- fetch - Download and extract the source of the dependency
- link - Link the copy of the dependency into your node_modules directory
- build - The Good Stuff. Configure and build any native dependencies, then the module itself.
- copy - Copy the built artifact from the module build directory to the module output directory.
# hak.json
The scripts section contains scripts used for lifecycle stages that need them (fetch, build).
The scripts section contains scripts used for lifecycle stages that need them (fetch, fetchDeps, build).
It also contains 'prune' and 'copy' which are globs of files to delete from the output module directory
and copy over from the module build directory to the output module directory, respectively.
# Shortcomings
Hak doesn't know about dependencies between lifecycle stages, ie. it doesn't know that you need to
'fetch' before you can 'build', etc. You get to run each individually, and remember
'fetch' and 'fetchDeps' before you can 'build', etc. You get to run each individually, and remember
the right order.
There is also a _lot_ of duplication in the command execution: we should abstract away

View File

@ -2,12 +2,12 @@
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import type { DependencyInfo } from "./dep.js";
import type HakEnv from "./hakEnv.js";
import { DependencyInfo } from "./dep";
import HakEnv from "./hakEnv";
export default async function build(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
await moduleInfo.scripts.build(hakEnv, moduleInfo);

View File

@ -2,13 +2,15 @@
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import type { DependencyInfo } from "./dep.js";
import type HakEnv from "./hakEnv.js";
import { DependencyInfo } from "./dep";
import HakEnv from "./hakEnv";
export default async function check(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
await moduleInfo.scripts.check?.(hakEnv, moduleInfo);
if (moduleInfo.scripts.check) {
await moduleInfo.scripts.check(hakEnv, moduleInfo);
}
}

View File

@ -2,15 +2,15 @@
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import path from "node:path";
import path from "path";
import { rimraf } from "rimraf";
import type { DependencyInfo } from "./dep.js";
import type HakEnv from "./hakEnv.js";
import { DependencyInfo } from "./dep";
import HakEnv from "./hakEnv";
export default async function clean(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
await rimraf(moduleInfo.moduleDotHakDir);

View File

@ -2,20 +2,35 @@
Copyright 2024 New Vector Ltd.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import path from "node:path";
import fsProm from "node:fs/promises";
import childProcess from "node:child_process";
import path from "path";
import fsProm from "fs/promises";
import childProcess from "child_process";
import { rimraf } from "rimraf";
import { glob } from "glob";
import { mkdirp } from "mkdirp";
import type HakEnv from "./hakEnv.js";
import type { DependencyInfo } from "./dep.js";
import HakEnv from "./hakEnv";
import { DependencyInfo } from "./dep";
export default async function copy(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
if (moduleInfo.cfg.prune) {
console.log("Removing " + moduleInfo.cfg.prune + " from " + moduleInfo.moduleOutDir);
// rimraf doesn't have a 'cwd' option: it always uses process.cwd()
// (and if you set glob.cwd it just breaks because it can't find the files)
const oldCwd = process.cwd();
try {
await mkdirp(moduleInfo.moduleOutDir);
process.chdir(moduleInfo.moduleOutDir);
await rimraf(moduleInfo.cfg.prune);
} finally {
process.chdir(oldCwd);
}
}
if (moduleInfo.cfg.copy) {
// If there are multiple moduleBuildDirs, singular moduleBuildDir
// is the same as moduleBuildDirs[0], so we're just listing the contents

View File

@ -2,11 +2,11 @@
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import type HakEnv from "./hakEnv.js";
import HakEnv from "./hakEnv";
export interface DependencyInfo {
name: string;

View File

@ -2,22 +2,23 @@
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import fsProm from "node:fs/promises";
import fsProm from "fs/promises";
import childProcess from "child_process";
import pacote from "pacote";
import type HakEnv from "./hakEnv.js";
import type { DependencyInfo } from "./dep.js";
import HakEnv from "./hakEnv";
import { DependencyInfo } from "./dep";
export default async function fetch(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
let haveModuleBuildDir;
try {
const stats = await fsProm.stat(moduleInfo.moduleBuildDir);
haveModuleBuildDir = stats.isDirectory();
} catch {
} catch (e) {
haveModuleBuildDir = false;
}
@ -31,8 +32,17 @@ export default async function fetch(hakEnv: HakEnv, moduleInfo: DependencyInfo):
});
console.log("Running yarn install in " + moduleInfo.moduleBuildDir);
await hakEnv.spawn("yarn", ["install", "--ignore-scripts"], {
cwd: moduleInfo.moduleBuildDir,
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(hakEnv.isWin() ? "yarn.cmd" : "yarn", ["install", "--ignore-scripts"], {
stdio: "inherit",
cwd: moduleInfo.moduleBuildDir,
// We need shell mode on Windows to be able to launch `.cmd` executables
// See https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
shell: hakEnv.isWin(),
});
proc.on("exit", (code) => {
code ? reject(code) : resolve();
});
});
// also extract another copy to the output directory at this point

19
scripts/hak/fetchDeps.ts Normal file
View File

@ -0,0 +1,19 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { mkdirp } from "mkdirp";
import { DependencyInfo } from "./dep";
import HakEnv from "./hakEnv";
export default async function fetchDeps(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
await mkdirp(moduleInfo.moduleDotHakDir);
if (moduleInfo.scripts.fetchDeps) {
await moduleInfo.scripts.fetchDeps(hakEnv, moduleInfo);
}
}

View File

@ -2,30 +2,34 @@
Copyright 2024 New Vector Ltd.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import path from "node:path";
import os from "node:os";
import { getElectronVersionFromInstalled } from "app-builder-lib/out/electron/electronVersion.js";
import childProcess, { type SpawnOptions } from "node:child_process";
import path from "path";
import os from "os";
import nodePreGypVersioning from "@mapbox/node-pre-gyp/lib/util/versioning";
import { getElectronVersionFromInstalled } from "app-builder-lib/out/electron/electronVersion";
import { type Arch, type Target, TARGETS, getHost, isHostId, type TargetId } from "./target.js";
import { Arch, Target, TARGETS, getHost, isHostId, TargetId } from "./target";
async function getRuntime(projectRoot: string): Promise<string> {
const electronVersion = await getElectronVersionFromInstalled(projectRoot);
return electronVersion ? "electron" : "node-webkit";
}
async function getRuntimeVersion(projectRoot: string): Promise<string> {
const electronVersion = await getElectronVersionFromInstalled(projectRoot);
if (!electronVersion) {
throw new Error("Can't determine Electron version");
if (electronVersion) {
return electronVersion;
} else {
return process.version.substr(1);
}
return electronVersion;
}
export type Tool = [cmd: string, ...args: string[]];
export default class HakEnv {
public readonly target: Target;
public runtime: string = "electron";
public runtime?: string;
public runtimeVersion?: string;
public dotHakDir: string;
@ -43,9 +47,19 @@ export default class HakEnv {
}
public async init(): Promise<void> {
this.runtime = await getRuntime(this.projectRoot);
this.runtimeVersion = await getRuntimeVersion(this.projectRoot);
}
public getRuntimeAbi(): string {
return nodePreGypVersioning.get_runtime_abi(this.runtime!, this.runtimeVersion!);
}
// {node_abi}-{platform}-{arch}
public getNodeTriple(): string {
return this.getRuntimeAbi() + "-" + this.target.platform + "-" + this.target.arch;
}
public getTargetId(): TargetId {
return this.target.id;
}
@ -90,41 +104,4 @@ export default class HakEnv {
public wantsStaticSqlCipher(): boolean {
return !(this.isLinux() || this.isFreeBSD()) || process.env.SQLCIPHER_BUNDLED == "1";
}
public spawn(
cmd: string,
args: string[],
{ ignoreWinCmdlet, ...options }: SpawnOptions & { ignoreWinCmdlet?: boolean } = {},
): Promise<void> {
return new Promise((resolve, reject) => {
const proc = childProcess.spawn(cmd + (!ignoreWinCmdlet && this.isWin() ? ".cmd" : ""), args, {
stdio: "inherit",
// We need shell mode on Windows to be able to launch `.cmd` executables
// See https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
shell: this.isWin(),
...options,
});
proc.on("exit", (code) => {
if (code) {
reject(code);
} else {
resolve();
}
});
});
}
public async checkTools(tools: Tool[]): Promise<void> {
for (const [tool, ...args] of tools) {
try {
await this.spawn(tool, args, {
ignoreWinCmdlet: true,
stdio: ["ignore"],
shell: false,
});
} catch {
throw new Error(`Can't find ${tool}`);
}
}
}
}

View File

@ -2,24 +2,23 @@
Copyright 2024 New Vector Ltd.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import path, { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import path from "path";
import HakEnv from "./hakEnv.js";
import type { TargetId } from "./target.js";
import type { DependencyInfo } from "./dep.js";
import { loadJsonFile } from "../../src/utils.js";
import packageJson from "../../package.json";
import HakEnv from "./hakEnv";
import { TargetId } from "./target";
import { DependencyInfo } from "./dep";
const GENERALCOMMANDS = ["target"];
// These can only be run on specific modules
const MODULECOMMANDS = ["check", "fetch", "link", "build", "copy", "clean"];
// Shortcuts for multiple commands at once (useful for building universal binaries
// because you can run the fetch/build for each arch and then copy/link once)
// because you can run the fetch/fetchDeps/build for each arch and then copy/link once)
const METACOMMANDS: Record<string, string[]> = {
fetchandbuild: ["check", "fetch", "build"],
copyandlink: ["copy", "link"],
@ -28,15 +27,20 @@ const METACOMMANDS: Record<string, string[]> = {
// Scripts valid in a hak.json 'scripts' section
const HAKSCRIPTS = ["check", "fetch", "build"];
const __dirname = dirname(fileURLToPath(import.meta.url));
async function main(): Promise<void> {
const prefix = path.join(__dirname, "..", "..");
let packageJson;
try {
packageJson = require(path.join(prefix, "package.json"));
} catch (e) {
console.error("Can't find a package.json!");
process.exit(1);
}
const targetIds: TargetId[] = [];
// Apply `--target <target>` option if specified
// Can be specified multiple times for the copy command to bundle
// multiple arches into a single universal output module)
// multiple archs into a single universal output module)
for (;;) {
// eslint-disable-line no-constant-condition
const targetIndex = process.argv.indexOf("--target");
@ -61,19 +65,19 @@ async function main(): Promise<void> {
const hakDepsCfg = packageJson.hakDependencies || {};
for (const dep in hakDepsCfg) {
for (const dep of Object.keys(hakDepsCfg)) {
const hakJsonPath = path.join(prefix, "hak", dep, "hak.json");
let hakJson: Record<string, any>;
try {
hakJson = loadJsonFile(hakJsonPath);
} catch {
hakJson = await require(hakJsonPath);
} catch (e) {
console.error("No hak.json found for " + dep + ".");
console.log("Expecting " + hakJsonPath);
process.exit(1);
}
deps[dep] = {
name: dep,
version: hakDepsCfg[dep as keyof typeof hakDepsCfg],
version: hakDepsCfg[dep],
cfg: hakJson,
moduleHakDir: path.join(prefix, "hak", dep),
moduleDotHakDir: path.join(hakEnv.dotHakDir, dep),
@ -87,10 +91,9 @@ async function main(): Promise<void> {
};
for (const s of HAKSCRIPTS) {
if (hakJson.scripts?.[s]) {
// Shockingly, using path.join and backslashes here doesn't work on Windows
const scriptModule = await import(`../../hak/${dep}/${hakJson.scripts[s]}`);
if (scriptModule.default) {
if (hakJson.scripts && hakJson.scripts[s]) {
const scriptModule = await import(path.join(prefix, "hak", dep, hakJson.scripts[s]));
if (scriptModule.__esModule) {
deps[dep].scripts[s] = scriptModule.default;
} else {
deps[dep].scripts[s] = scriptModule;
@ -118,6 +121,13 @@ async function main(): Promise<void> {
if (modules.length === 0) modules = Object.keys(deps);
for (const cmd of cmds) {
if (GENERALCOMMANDS.includes(cmd)) {
if (cmd === "target") {
console.log(hakEnv.getNodeTriple());
}
return;
}
if (!MODULECOMMANDS.includes(cmd)) {
console.error("Unknown command: " + cmd);
console.log("Commands I know about:");

View File

@ -2,16 +2,17 @@
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import path from "node:path";
import os from "node:os";
import fsProm from "node:fs/promises";
import path from "path";
import os from "os";
import fsProm from "fs/promises";
import childProcess from "child_process";
import type HakEnv from "./hakEnv.js";
import { type DependencyInfo } from "./dep.js";
import HakEnv from "./hakEnv";
import { DependencyInfo } from "./dep";
export default async function link(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const yarnrc = path.join(hakEnv.projectRoot, ".yarnrc");
@ -23,7 +24,7 @@ export default async function link(hakEnv: HakEnv, moduleInfo: DependencyInfo):
// Also we do this for each module which is unnecessary, but meh.
try {
await fsProm.stat(yarnrc);
} catch {
} catch (e) {
await fsProm.writeFile(
yarnrc,
// XXX: 1. This must be absolute, as yarn will resolve link directories
@ -38,10 +39,31 @@ export default async function link(hakEnv: HakEnv, moduleInfo: DependencyInfo):
);
}
await hakEnv.spawn("yarn", ["link"], {
cwd: moduleInfo.moduleOutDir,
const yarnCmd = "yarn" + (hakEnv.isWin() ? ".cmd" : "");
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(yarnCmd, ["link"], {
cwd: moduleInfo.moduleOutDir,
stdio: "inherit",
// We need shell mode on Windows to be able to launch `.cmd` executables
// See https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
shell: hakEnv.isWin(),
});
proc.on("exit", (code) => {
code ? reject(code) : resolve();
});
});
await hakEnv.spawn("yarn", ["link", moduleInfo.name], {
cwd: hakEnv.projectRoot,
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(yarnCmd, ["link", moduleInfo.name], {
cwd: hakEnv.projectRoot,
stdio: "inherit",
// We need shell mode on Windows to be able to launch `.cmd` executables
// See https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
shell: hakEnv.isWin(),
});
proc.on("exit", (code) => {
code ? reject(code) : resolve();
});
});
}

View File

@ -2,7 +2,7 @@
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

View File

@ -8,12 +8,9 @@ if [ $? != 0 ]; then
exit 1
fi
echo "${PWD}"
echo $(ls "${PWD}")
# Taken from https://www.electron.build/multi-platform-build#docker
# Pass through any vars prefixed with INDOCKER_, removing the prefix
docker run --rm \
docker run --rm -ti \
--platform linux/amd64 \
--env-file <(env | grep -E '^INDOCKER_' | sed -e 's/^INDOCKER_//') \
--env ELECTRON_CACHE="/root/.cache/electron" \
@ -24,5 +21,4 @@ docker run --rm \
-v ${PWD}/docker/.gnupg:/root/.gnupg \
-v ~/.cache/electron:/root/.cache/electron \
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
--workdir "/project" \
"$IMAGE" "$@"

View File

@ -1,19 +1,18 @@
#!/usr/bin/env -S npx tsx
#!/usr/bin/env -S npx ts-node
/*
* Checks for the presence of a webapp, inspects its version and sets the
* version metadata of the package to match.
*/
import { promises as fs } from "node:fs";
import { promises as fs } from "fs";
import * as asar from "@electron/asar";
import * as childProcess from "node:child_process";
import * as url from "node:url";
import * as childProcess from "child_process";
export async function versionFromAsar(): Promise<string> {
try {
await fs.stat("webapp.asar");
} catch {
} catch (e) {
throw new Error("No 'webapp.asar' found. Run 'yarn run fetch'");
}
@ -58,16 +57,13 @@ async function main(args: string[]): Promise<number> {
return 0;
}
if (import.meta.url.startsWith("file:")) {
const modulePath = url.fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) {
main(process.argv.slice(2))
.then((ret) => {
process.exit(ret);
})
.catch((e) => {
console.error(e);
process.exit(1);
});
}
if (require.main === module) {
main(process.argv.slice(2))
.then((ret) => {
process.exit(ret);
})
.catch((e) => {
console.error(e);
process.exit(1);
});
}

View File

@ -1,14 +1,16 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"moduleResolution": "node16",
"skipLibCheck": true,
"moduleResolution": "node",
"esModuleInterop": true,
"target": "es2022",
"module": "node16",
"target": "es2017",
"module": "commonjs",
"sourceMap": false,
"strict": true,
"lib": ["es2020"]
"lib": ["es2020", "dom"]
},
"include": ["../src/@types", "./**/*.ts"]
"include": ["../src/@types", "./**/*.ts"],
"ts-node": {
"transpileOnly": true
}
}

View File

@ -1,15 +1,15 @@
/*
Copyright 2021-2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { type BrowserWindow } from "electron";
import { BrowserWindow } from "electron";
import Store from "electron-store";
import AutoLaunch from "auto-launch";
import type Store from "electron-store";
import type AutoLaunch from "auto-launch";
import { type AppLocalization } from "../language-helper.js";
import { AppLocalization } from "../language-helper";
// global type extensions need to use var for whatever reason
/* eslint-disable no-var */

54
src/@types/keytar.d.ts vendored Normal file
View File

@ -0,0 +1,54 @@
// Based on https://github.com/atom/node-keytar/blob/master/keytar.d.ts because keytar is a hak-dependency and not a normal one
// Definitions by: Milan Burda <https://github.com/miniak>, Brendan Forster <https://github.com/shiftkey>, Hari Juturu <https://github.com/juturu>
// Adapted from DefinitelyTyped: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/keytar/index.d.ts
declare module "keytar" {
/**
* Get the stored password for the service and account.
*
* @param service The string service name.
* @param account The string account name.
*
* @returns A promise for the password string.
*/
export function getPassword(service: string, account: string): Promise<string | null>;
/**
* Add the password for the service and account to the keychain.
*
* @param service The string service name.
* @param account The string account name.
* @param password The string password.
*
* @returns A promise for the set password completion.
*/
export function setPassword(service: string, account: string, password: string): Promise<void>;
/**
* Delete the stored password for the service and account.
*
* @param service The string service name.
* @param account The string account name.
*
* @returns A promise for the deletion status. True on success.
*/
export function deletePassword(service: string, account: string): Promise<boolean>;
/**
* Find a password for the service in the keychain.
*
* @param service The string service name.
*
* @returns A promise for the password string.
*/
export function findPassword(service: string): Promise<string | null>;
/**
* Find all accounts and passwords for `service` in the keychain.
*
* @param service The string service name.
*
* @returns A promise for the array of found credentials.
*/
export function findCredentials(service: string): Promise<Array<{ account: string; password: string }>>;
}

View File

@ -1,7 +1,7 @@
/*
Copyright 2022-2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

View File

@ -1,11 +1,11 @@
/*
Copyright 2023, 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import type { Streams } from "electron";
import { Streams } from "electron";
type DisplayMediaCallback = (streams: Streams) => void;

View File

@ -4,38 +4,36 @@ Copyright 2017-2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2016 Aviral Dasgupta
Copyright 2016 OpenMarket Ltd
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
// Squirrel on windows starts the app with various flags as hooks to tell us when we've been installed/uninstalled etc.
import "./squirrelhooks.js";
import { app, BrowserWindow, Menu, autoUpdater, protocol, dialog, type Input, type Event, session } from "electron";
// eslint-disable-next-line n/file-extension-in-import
import "./squirrelhooks";
import { app, BrowserWindow, Menu, autoUpdater, protocol, dialog, Input, Event, session } from "electron";
import * as Sentry from "@sentry/electron/main";
import AutoLaunch from "auto-launch";
import path, { dirname } from "node:path";
import path from "path";
import windowStateKeeper from "electron-window-state";
import Store from "electron-store";
import fs, { promises as afs } from "node:fs";
import { URL, fileURLToPath } from "node:url";
import fs, { promises as afs } from "fs";
import { URL } from "url";
import minimist from "minimist";
import "./ipc.js";
import "./seshat.js";
import "./settings.js";
import * as tray from "./tray.js";
import { buildMenuTemplate } from "./vectormenu.js";
import webContentsHandler from "./webcontents-handler.js";
import * as updater from "./updater.js";
import { getProfileFromDeeplink, protocolInit } from "./protocol.js";
import { _t, AppLocalization } from "./language-helper.js";
import { setDisplayMediaCallback } from "./displayMediaCallback.js";
import { setupMacosTitleBar } from "./macos-titlebar.js";
import { loadJsonFile } from "./utils.js";
import { setupMediaAuth } from "./media-auth.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
import "./ipc";
import "./keytar";
import "./seshat";
import "./settings";
import * as tray from "./tray";
import { buildMenuTemplate } from "./vectormenu";
import webContentsHandler from "./webcontents-handler";
import * as updater from "./updater";
import { getProfileFromDeeplink, protocolInit } from "./protocol";
import { _t, AppLocalization } from "./language-helper";
import { setDisplayMediaCallback } from "./displayMediaCallback";
import { setupMacosTitleBar } from "./macos-titlebar";
import { loadJsonFile } from "./utils";
import { setupMediaAuth } from "./media-auth";
const argv = minimist(process.argv, {
alias: { help: "h" },
@ -46,10 +44,6 @@ if (argv["help"]) {
console.log(" --profile-dir {path}: Path to where to store the profile.");
console.log(" --profile {name}: Name of alternate profile to use, allows for running multiple accounts.");
console.log(" --devtools: Install and use react-devtools and react-perf.");
console.log(
` --config: Path to the config.json file. May also be specified via the ELEMENT_DESKTOP_CONFIG_JSON environment variable.\n` +
` Otherwise use the default user location '${app.getPath("userData")}'`,
);
console.log(" --no-update: Disable automatic updating.");
console.log(" --hidden: Start the application hidden in the system tray.");
console.log(" --help: Displays this help message.");
@ -57,8 +51,6 @@ if (argv["help"]) {
app.exit();
}
const LocalConfigLocation = process.env.ELEMENT_DESKTOP_CONFIG_JSON ?? argv["config"];
// Electron creates the user data directory (with just an empty 'Dictionaries' directory...)
// as soon as the app path is set, so pick a random path in it that must exist if it's a
// real user data directory.
@ -105,7 +97,7 @@ async function tryPaths(name: string, root: string, rawPaths: string[]): Promise
try {
await afs.stat(p);
return p + "/";
} catch {}
} catch (e) {}
}
console.log(`Couldn't find ${name} files in any of: `);
for (const p of paths) {
@ -145,7 +137,7 @@ async function loadConfig(): Promise<void> {
try {
global.vectorConfig = loadJsonFile(asarPath, "config.json");
} catch {
} catch (e) {
// it would be nice to check the error code here and bail if the config
// is unparsable, but we get MODULE_NOT_FOUND in the case of a missing
// file or invalid json, so node is just very unhelpful.
@ -155,9 +147,7 @@ async function loadConfig(): Promise<void> {
try {
// Load local config and use it to override values from the one baked with the build
const localConfig = LocalConfigLocation
? loadJsonFile(LocalConfigLocation)
: loadJsonFile(app.getPath("userData"), "config.json");
const localConfig = loadJsonFile(app.getPath("userData"), "config.json");
// If the local config has a homeserver defined, don't use the homeserver from the build
// config. This is to avoid a problem where Riot thinks there are multiple homeservers
@ -375,9 +365,13 @@ app.on("ready", async () => {
if (argv["devtools"]) {
try {
const { installExtension, REACT_DEVELOPER_TOOLS } = await import("electron-devtools-installer");
installExtension(REACT_DEVELOPER_TOOLS)
.then((ext) => console.log(`Added Extension: ${ext.name}`))
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { default: installExt, REACT_DEVELOPER_TOOLS, REACT_PERF } = require("electron-devtools-installer");
installExt(REACT_DEVELOPER_TOOLS)
.then((name: string) => console.log(`Added Extension: ${name}`))
.catch((err: unknown) => console.log("An error occurred: ", err));
installExt(REACT_PERF)
.then((name: string) => console.log(`Added Extension: ${name}`))
.catch((err: unknown) => console.log("An error occurred: ", err));
} catch (e) {
console.log(e);
@ -451,7 +445,7 @@ app.on("ready", async () => {
defaultHeight: 768,
});
const preloadScript = path.normalize(`${__dirname}/preload.cjs`);
const preloadScript = path.normalize(`${__dirname}/preload.js`);
global.mainWindow = new BrowserWindow({
// https://www.electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do
backgroundColor: "#fff",

View File

@ -1,63 +0,0 @@
{
"action": {
"cancel": "Diddymu",
"close": "Cau",
"close_brand": "Cau %(brand)s",
"copy": "Copïo",
"cut": "Torri",
"delete": "Dileu",
"edit": "Golygu",
"minimise": "Lleihau",
"paste": "Gludo",
"paste_match_style": "Gludo a Chyfateb Arddull",
"quit": "Gadael",
"redo": "Ail-wneud",
"select_all": "Dewis y Cyfan",
"show_hide": "Dangos/Cuddio",
"undo": "Dadwneud",
"zoom_in": "Chwyddo i Mewn",
"zoom_out": "Chwyddo Allan"
},
"common": {
"about": "Ynghylch",
"brand_help": "%(brand)s Cymorth",
"help": "Cymorth",
"preferences": "Dewisiadau"
},
"confirm_quit": "Ydych chi'n siŵr eich bod am roi'r gorau iddi?",
"edit_menu": {
"speech": "Lleferydd",
"speech_start_speaking": "Cychwyn Llefaru",
"speech_stop_speaking": "Peidio Llefaru"
},
"file_menu": {
"label": "Ffeil"
},
"menu": {
"hide": "Cuddio",
"hide_others": "Cuddio'r Gweddill",
"services": "Gwasanaethau",
"unhide": "Datguddio"
},
"right_click_menu": {
"add_to_dictionary": "Ychwanegu i'r Geiriadur",
"copy_email": "Copïo cyfeiriad e-bost",
"copy_image": "Copïo delwedd",
"copy_image_url": "Copïo cyfeiriad delwedd",
"copy_link_url": "Copïo cyfeiriad y ddolen",
"save_image_as": "Cadw delwedd fel...",
"save_image_as_error_description": "Methodd y ddelwedd â chadw",
"save_image_as_error_title": "Wedi methu cadw'r ddelwedd"
},
"view_menu": {
"actual_size": "Maint Gwirioneddol",
"toggle_developer_tools": "Toggle Developer Tools",
"toggle_full_screen": "Toglo Sgrin Lawn",
"view": "Golwg"
},
"window_menu": {
"bring_all_to_front": "Popeth i'r Blaen",
"label": "Ffenestr",
"zoom": "Chwyddo"
}
}

View File

@ -22,7 +22,7 @@
"about": "Über",
"brand_help": "%(brand)s Hilfe",
"help": "Hilfe",
"preferences": "Präferenzen"
"preferences": "Einstellungen"
},
"confirm_quit": "Wirklich beenden?",
"edit_menu": {

View File

@ -20,7 +20,6 @@
},
"common": {
"about": "Tietoa",
"brand_help": "%(brand)s-tuki",
"help": "Ohje",
"preferences": "Valinnat"
},

View File

@ -2,7 +2,7 @@
"action": {
"cancel": "Mégse",
"close": "Bezárás",
"close_brand": "Az %(brand)s bezárása",
"close_brand": "%(brand)s bezárása",
"copy": "Másolás",
"cut": "Kivágás",
"delete": "Törlés",
@ -56,7 +56,7 @@
"view": "Megtekintés"
},
"window_menu": {
"bring_all_to_front": "Minden előtérbe hozása",
"bring_all_to_front": "Mindent előtérbe hoz",
"label": "Ablak",
"zoom": "Nagyítás"
}

View File

@ -1,63 +0,0 @@
{
"action": {
"cancel": "გაუქმება",
"close": "დახურვა",
"close_brand": "დახურვა %(brand)s",
"copy": "კოპირება",
"cut": "მოჭრა",
"delete": "წაშალეთ",
"edit": "რედაქტირება",
"minimise": "შეამცირეთ",
"paste": "პასტა",
"paste_match_style": "ჩასვით და მატჩის სტილი",
"quit": "თავი დაანებე",
"redo": "რედო",
"select_all": "აირჩიეთ ყველა",
"show_hide": "ჩვენება/დამალვა",
"undo": "გაუქმება",
"zoom_in": "გაზარდოთ",
"zoom_out": "გაფართოება"
},
"common": {
"about": "შესახებ",
"brand_help": "%(brand)sდახმარება",
"help": "დახმარება",
"preferences": "პრეფერენციები"
},
"confirm_quit": "დარწმუნებული ხართ, რომ გსურთ დატოვება?",
"edit_menu": {
"speech": "გამოსვლა",
"speech_start_speaking": "დაიწყეთ საუბარი",
"speech_stop_speaking": "შეწყვიტე ლაპარ"
},
"file_menu": {
"label": "ფაილი"
},
"menu": {
"hide": "დამალვა",
"hide_others": "სხვების დამალვა",
"services": "მომსახურება",
"unhide": "გამოხატე"
},
"right_click_menu": {
"add_to_dictionary": "ლექსიკონში დამატება",
"copy_email": "ელ. ფოსტის მისამართის",
"copy_image": "სურათის დაკოპირება",
"copy_image_url": "გამოსახულების მისამართის კოპირ",
"copy_link_url": "ბმულის მისამართის კოპირება",
"save_image_as": "შეინახეთ სურათი როგორც...",
"save_image_as_error_description": "სურათის შენახვა ვერ შეძლო",
"save_image_as_error_title": "სურათის შენახვა ვერ შეძლ"
},
"view_menu": {
"actual_size": "რეალური ზომა",
"toggle_developer_tools": "დეველოპერის ინსტრუმენტების",
"toggle_full_screen": "სრული ეკრანის გადართვა",
"view": "ნახვა"
},
"window_menu": {
"bring_all_to_front": "ყველაფერი წინ წამოიყვანეთ",
"label": "ფანჯარა",
"zoom": "გაზუსტება"
}
}

View File

@ -1,63 +0,0 @@
{
"action": {
"cancel": "Atcelt",
"close": "Aizvērt",
"close_brand": "Aizvērt %(brand)s",
"copy": "Kopēt",
"cut": "Izgriezt",
"delete": "Dzēst",
"edit": "Labot",
"minimise": "Samazināt",
"paste": "Ielīmēt",
"paste_match_style": "Ielīmēt un pielāgot stilu",
"quit": "Iziet",
"redo": "Atatsaukt",
"select_all": "Atzīmēt visu",
"show_hide": "Parādīt/paslēpt",
"undo": "Atsaukt",
"zoom_in": "Tuvināt",
"zoom_out": "Tālināt"
},
"common": {
"about": "Par",
"brand_help": "%(brand)s palīdzība",
"help": "Palīdzība",
"preferences": "Iestatījumi"
},
"confirm_quit": "Vai tiešām iziet?",
"edit_menu": {
"speech": "Runa",
"speech_start_speaking": "Uzsākt runāšanu",
"speech_stop_speaking": "Pārtraukt runāšanu"
},
"file_menu": {
"label": "Datne"
},
"menu": {
"hide": "Paslēpt",
"hide_others": "Paslēpt citus",
"services": "Pakalpojumi",
"unhide": "Rādīt"
},
"right_click_menu": {
"add_to_dictionary": "Pievienot vārdnīcai",
"copy_email": "Ievietot e-pasta adresi starpliktuvē",
"copy_image": "Ievietot attēlu starpliktuvē",
"copy_image_url": "Ievietot attēla adresi starpliktuvē",
"copy_link_url": "Ievietot saites adresi starpliktuvē",
"save_image_as": "Saglabāt attēlu kā...",
"save_image_as_error_description": "Attēlu neizdevās saglabāt",
"save_image_as_error_title": "Neizdevās saglabāt attēlu"
},
"view_menu": {
"actual_size": "Īstais izmērs",
"toggle_developer_tools": "Pārslēgt izstrādātāja rīkus",
"toggle_full_screen": "Pārslēgt pilnekrānu",
"view": "Skats"
},
"window_menu": {
"bring_all_to_front": "Iznest visu priekšplānā",
"label": "Logs",
"zoom": "Tālummaiņa"
}
}

View File

@ -1,63 +0,0 @@
{
"action": {
"cancel": "Hanafoana",
"close": "Akatona",
"close_brand": "Anakatona%(brand)s",
"copy": "Dika Mitovy",
"cut": "Tapaina",
"delete": "Fafaina",
"edit": "Anova",
"minimise": "Manamaivana",
"paste": "Koba",
"paste_match_style": "Mametaka sy Mampifanandrify ny fomba",
"quit": "Mialà",
"redo": "Averina atao",
"select_all": "Isafidy ny rehetra",
"show_hide": "Aneho/Anafina",
"undo": "Ravao",
"zoom_in": "Angedao",
"zoom_out": "Hahelezo"
},
"common": {
"about": "Mombamomba",
"brand_help": "%(marques)Fanampiana",
"help": "Fanampiana",
"preferences": "Safidy manokana"
},
"confirm_quit": "Azo Antoka ve fa tena hiala ianao",
"edit_menu": {
"speech": "Fitenenana",
"speech_start_speaking": "Atomboy ny resaka/Manomboha fitenenena",
"speech_stop_speaking": "Atsaharo ny fitenenana"
},
"file_menu": {
"label": "Manapetraka/apetrao"
},
"menu": {
"hide": "Afeno",
"hide_others": "Afeno ny hafa",
"services": "Tolotra",
"unhide": "Asehoy"
},
"right_click_menu": {
"add_to_dictionary": "Ampio ao amin'ny rakibolana",
"copy_email": "Adikao ny adiresy imailaka",
"copy_image": "Andika ny sary",
"copy_image_url": "Adikao ny adiresin'ny sary",
"copy_link_url": "Adikao ny adiresy rohy",
"save_image_as": "Hitahiry ny sary ho",
"save_image_as_error_description": "Tsy voatahiry ilay sary",
"save_image_as_error_title": "Tsy nahahomby ny fitahirizana an'ilay sary"
},
"view_menu": {
"actual_size": "Habe Ankehitriny",
"toggle_developer_tools": "Amadika fitaovana fampandrosoana",
"toggle_full_screen": "Hamadika amin'ny efijery feno",
"view": "Hijery"
},
"window_menu": {
"bring_all_to_front": "Ataovy aloha ny zava-drehetra",
"label": "Varavarankely",
"zoom": "Anakaiky fahitana"
}
}

View File

@ -1,63 +0,0 @@
{
"action": {
"cancel": "Avbryt",
"close": "Lukk",
"close_brand": "Avslutt %(brand)s",
"copy": "Kopier",
"cut": "Klipp",
"delete": "Slett",
"edit": "Rediger",
"minimise": "Minimere",
"paste": "Lim inn",
"paste_match_style": "Lim inn og match stil",
"quit": "Avslutt",
"redo": "Gjør om",
"select_all": "Velg alle",
"show_hide": "Vis/Skjul",
"undo": "Angre",
"zoom_in": "Zoom inn",
"zoom_out": "Zoom ut"
},
"common": {
"about": "Om",
"brand_help": "%(brand)s Hjelp",
"help": "Hjelp",
"preferences": "Brukervalg"
},
"confirm_quit": "Er du sikker på at du vil slutte?",
"edit_menu": {
"speech": "Tale",
"speech_start_speaking": "Begynn å snakke",
"speech_stop_speaking": "Slutt å snakke"
},
"file_menu": {
"label": "Fil"
},
"menu": {
"hide": "Skjul",
"hide_others": "Skjul andre",
"services": "Tjenester",
"unhide": "Slutt å skjule"
},
"right_click_menu": {
"add_to_dictionary": "Legg til i ordbok",
"copy_email": "Kopier e-postadressen",
"copy_image": "Kopier bildet",
"copy_image_url": "Kopier bildeadresse",
"copy_link_url": "Kopier link adresse",
"save_image_as": "Lagre bildet som...",
"save_image_as_error_description": "Bildet kunne ikke lagres",
"save_image_as_error_title": "Kunne ikke lagre bildet"
},
"view_menu": {
"actual_size": "Faktisk størrelse",
"toggle_developer_tools": "Veksle Utvikleralternativer",
"toggle_full_screen": "Veksle Fullskjerm",
"view": "Vis"
},
"window_menu": {
"bring_all_to_front": "Flytt Alt Frem",
"label": "Vindu",
"zoom": "Forstørr"
}
}

View File

@ -20,8 +20,6 @@
},
"common": {
"about": "Over",
"brand_help": "%(brand)s Hulp",
"help": "Hulp",
"preferences": "Voorkeuren"
},
"confirm_quit": "Weet u zeker dat u wilt stoppen?",
@ -57,7 +55,6 @@
},
"window_menu": {
"bring_all_to_front": "Alles naar voren brengen",
"label": "Venster",
"zoom": "Zoom"
"label": "Venster"
}
}

View File

@ -1,63 +0,0 @@
{
"action": {
"cancel": "Cancelar",
"close": "Fechar",
"close_brand": "Fecha %(brand)s",
"copy": "Copiar",
"cut": "Cortar",
"delete": "Apagar",
"edit": "Editar",
"minimise": "Minimizar",
"paste": "Colar",
"paste_match_style": "Colar e combinar o estilo",
"quit": "Desistir",
"redo": "Refazer",
"select_all": "Selecionar tudo",
"show_hide": "Mostrar/ocultar",
"undo": "Desfazer",
"zoom_in": "Ampliar",
"zoom_out": "Reduzir"
},
"common": {
"about": "Sobre",
"brand_help": "%(brand)s Ajuda",
"help": "Ajuda",
"preferences": "Preferências"
},
"confirm_quit": "Tens a certeza de que queres desistir?",
"edit_menu": {
"speech": "Discurso",
"speech_start_speaking": "Começa a falar",
"speech_stop_speaking": "Pára de falar"
},
"file_menu": {
"label": "Ficheiro"
},
"menu": {
"hide": "Ocultar",
"hide_others": "Ocultar Outros",
"services": "Serviços",
"unhide": "Mostrar"
},
"right_click_menu": {
"add_to_dictionary": "Adicionar ao dicionário",
"copy_email": "Copiar endereço de e-mail",
"copy_image": "Copiar imagem",
"copy_image_url": "Copiar endereço da imagem",
"copy_link_url": "Copiar endereço do link",
"save_image_as": "Salvar imagem como...",
"save_image_as_error_description": "A imagem não foi salva",
"save_image_as_error_title": "Falha ao salvar a imagem"
},
"view_menu": {
"actual_size": "Tamanho original",
"toggle_developer_tools": "Alternar ferramentas de desenvolvedor",
"toggle_full_screen": "Alternar ecrã inteiro",
"view": "Ver"
},
"window_menu": {
"bring_all_to_front": "Traz tudo para a frente",
"label": "Janela",
"zoom": "Ampliação"
}
}

Some files were not shown because too many files have changed in this diff Show More