Compare commits

..

2 Commits

Author SHA1 Message Date
Michael Telatynski
95b600e49d Merge branch 'develop' of github.com:vector-im/element-desktop into t3chguy/types
# Conflicts:
#	yarn.lock
2022-12-01 06:32:27 +00:00
Michael Telatynski
6d065ed16c Simplify @types/node devDep 2022-12-01 06:29:49 +00:00
230 changed files with 13712 additions and 14211 deletions

View File

@@ -1,22 +0,0 @@
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",
},
},
],
};

View File

@@ -1,22 +0,0 @@
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",
},
},
],
};

View File

@@ -1,22 +0,0 @@
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,9 +1,10 @@
module.exports = {
plugins: ["matrix-org"],
extends: ["plugin:matrix-org/javascript"],
extends: [
"plugin:matrix-org/javascript",
],
parserOptions: {
ecmaVersion: 2021,
project: ["tsconfig.json"],
},
env: {
es6: true,
@@ -19,19 +20,19 @@ module.exports = {
"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",
overrides: [{
files: ["{src,scripts,hak}/**/*.{ts,tsx}"],
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",
},
"@typescript-eslint/no-explicit-any": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
},
],
}],
};

9
.github/CODEOWNERS vendored
View File

@@ -1,5 +1,4 @@
* @element-hq/element-web-reviewers
/.github/workflows/** @element-hq/element-web-team
/package.json @element-hq/element-web-team
/yarn.lock @element-hq/element-web-team
/src/i18n/strings
* @vector-im/element-web
/.github/workflows/** @vector-im/element-web-app-team
/package.json @vector-im/element-web-app-team
/yarn.lock @vector-im/element-web-app-team

View File

@@ -1,76 +0,0 @@
name: Bug report for the Element desktop app (not in a browser)
description: File a bug report if you are using the desktop Element application.
labels: [T-Defect]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please report security issues by email to security@matrix.org
- type: textarea
id: reproduction-steps
attributes:
label: Steps to reproduce
description: Please attach screenshots, videos or logs if you can.
placeholder: Tell us what you see!
value: |
1. Where are you starting? What can you see?
2. What do you click?
3. More steps…
validations:
required: true
- type: textarea
id: result
attributes:
label: Outcome
placeholder: Tell us what went wrong
value: |
#### What did you expect?
#### What happened instead?
validations:
required: true
- type: input
id: os
attributes:
label: Operating system
placeholder: Windows, macOS, Ubuntu, Arch Linux…
validations:
required: false
- type: input
id: version
attributes:
label: Application version
description: You can find the version information in Settings -> Help & About.
placeholder: e.g. Element version 1.7.34, olm version 3.2.3
validations:
required: false
- type: input
id: source
attributes:
label: How did you install the app?
description: Where did you install the app from? Please give a link or a description.
placeholder: e.g. From https://element.io/get-started
validations:
required: false
- type: input
id: homeserver
attributes:
label: Homeserver
description: |
Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
placeholder: e.g. matrix.org or Synapse 1.50.0rc1
validations:
required: false
- type: dropdown
id: rageshake
attributes:
label: Will you send logs?
description: |
Did you know that you can send a /rageshake command from your application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers.
options:
- "Yes"
- "No"
validations:
required: true

View File

@@ -1 +0,0 @@
blank_issues_enabled: false

View File

@@ -1,36 +0,0 @@
name: Enhancement request
description: Do you have a suggestion or feature request?
labels: [T-Enhancement]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to propose an enhancement to an existing feature. If you would like to propose a new feature or a major cross-platform change, please [start a discussion here](https://github.com/vector-im/element-meta/discussions/new?category=ideas).
- type: textarea
id: usecase
attributes:
label: Your use case
description: What would you like to be able to do? Please feel welcome to include screenshots or mock ups.
placeholder: Tell us what you would like to do!
value: |
#### What would you like to do?
#### Why would you like to do it?
#### How would you like to achieve it?
validations:
required: true
- type: textarea
id: alternative
attributes:
label: Have you considered any alternatives?
placeholder: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional context
placeholder: Is there anything else you'd like to add?
validations:
required: false

View File

@@ -2,7 +2,12 @@
## 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.
- [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/vector-im/element-web/blob/develop/CONTRIBUTING.md)).
* [ ] Ensure your code works with manual testing
* [ ] Linter and other CI checks pass
* [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/vector-im/element-desktop/blob/develop/CONTRIBUTING.md))
<!--
If you would like to specify text for the changelog entry other than your PR title, add the following:
Notes: Add super cool feature
-->

31
.github/labels.yml vendored
View File

@@ -1,31 +0,0 @@
- name: "A-Install"
color: "72A447"
- name: "A-Seshat"
color: "8262BE"
- name: "A-Update"
color: "17BE67"
- name: "Story"
description: "A change to the product that generates user value on its own. Unit of delivery."
color: "0BAC47"
- name: "X-Breaking-Change"
color: "ff7979"
- name: "Z-Arch"
color: "D601BE"
- name: "Z-ARM"
color: "5DEC5B"
- name: "Z-Flatpak"
color: "0CA856"
- name: "Z-Linux"
color: "7B4A9C"
- name: "Z-macOS"
color: "500605"
- name: "Z-Official"
color: "1D2B20"
- name: "Z-Snap"
color: "29CD95"
- name: "Z-Suse"
color: "79D07B"
- name: "Z-Wayland"
color: "94C519"
- name: "Z-Windows"
color: "0632DE"

View File

@@ -1 +0,0 @@
_extends: element-hq/element-web

View File

@@ -1,4 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>matrix-org/renovate-config-element-web"]
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"github>matrix-org/renovate-config-element-web"
]
}

View File

@@ -1,30 +1,30 @@
name: Backport
on:
pull_request_target:
types:
- closed
- labeled
branches:
- develop
pull_request_target:
types:
- closed
- labeled
branches:
- develop
jobs:
backport:
name: Backport
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: >
github.event.pull_request.merged
&& (
github.event.action == 'closed'
|| (
github.event.action == 'labeled'
&& contains(github.event.label.name, 'backport')
)
)
steps:
- uses: tibdex/backport@9565281eda0731b1d20c4025c43339fb0a23812e # v2
with:
labels_template: "<%= JSON.stringify([...labels, 'X-Release-Blocker']) %>"
# We can't use GITHUB_TOKEN here or CI won't run on the new PR
github_token: ${{ secrets.ELEMENT_BOT_TOKEN }}
backport:
name: Backport
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: >
github.event.pull_request.merged
&& (
github.event.action == 'closed'
|| (
github.event.action == 'labeled'
&& contains(github.event.label.name, 'backport')
)
)
steps:
- uses: tibdex/backport@v2
with:
labels_template: "<%= JSON.stringify([...labels, 'X-Release-Blocker']) %>"
# We can't use GITHUB_TOKEN here or CI won't run on the new PR
github_token: ${{ secrets.ELEMENT_BOT_TOKEN }}

107
.github/workflows/build.yaml vendored Normal file
View File

@@ -0,0 +1,107 @@
name: Build and Test
on:
pull_request: { }
push:
branches: [ develop, master ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
fetch:
uses: ./.github/workflows/build_prepare.yaml
with:
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
version: ${{ github.event.pull_request.base.ref == 'develop' && 'develop' || '' }}
windows:
needs: fetch
name: Windows
uses: ./.github/workflows/build_windows.yaml
strategy:
matrix:
arch: [ x64, x86 ]
with:
arch: ${{ matrix.arch }}
linux:
needs: fetch
name: Linux
uses: ./.github/workflows/build_linux.yaml
strategy:
matrix:
sqlcipher: [ system, static ]
with:
sqlcipher: ${{ matrix.sqlcipher }}
macos:
needs: fetch
name: macOS
uses: ./.github/workflows/build_macos.yaml
test:
needs:
- macos
- linux
- windows
strategy:
matrix:
include:
# Disable macOS tests for now, they fail to run in CI, needs investigation.
# - name: macOS Universal
# os: macos
# artifact: macos
# executable: "./dist/mac-universal/Element.app/Contents/MacOS/Element"
# prepare_cmd: "chmod +x ./dist/mac-universal/Element.app/Contents/MacOS/Element"
- name: 'Linux (sqlcipher: system)'
os: ubuntu
artifact: linux-sqlcipher-system
executable: "element-desktop"
prepare_cmd: "sudo apt install ./dist/*.deb"
- name: 'Linux (sqlcipher: static)'
os: ubuntu
artifact: linux-sqlcipher-static
executable: "element-desktop"
prepare_cmd: "sudo apt install ./dist/*.deb"
- name: Windows (x86)
os: windows
artifact: win-x86
executable: "./dist/win-ia32-unpacked/Element.exe"
- name: Windows (x64)
os: windows
artifact: win-x64
executable: "./dist/win-unpacked/Element.exe"
name: Test ${{ matrix.name }}
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
cache: "yarn"
- name: Install Deps
run: "yarn install --pure-lockfile"
- uses: actions/download-artifact@v3
with:
name: ${{ matrix.artifact }}
path: dist
- name: Prepare for tests
run: ${{ matrix.prepare_cmd }}
if: matrix.prepare_cmd
- name: Run tests
uses: GabrielBB/xvfb-action@v1
timeout-minutes: 5
with:
run: "yarn test"
env:
ELEMENT_DESKTOP_EXECUTABLE: ${{ matrix.executable }}
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.artifact }}
path: test_artifacts
retention-days: 1

View File

@@ -1,284 +0,0 @@
name: Build and Deploy
on:
# Nightly build
schedule:
- cron: "0 9 * * *"
# Release build
release:
types: [published]
# Manual nightly & release
workflow_dispatch:
inputs:
mode:
description: What type of build to trigger. Release builds MUST be ran from the `master` branch.
required: true
default: nightly
type: choice
options:
- nightly
- release
macos:
description: Build macOS
required: true
type: boolean
default: true
windows:
description: Build Windows
required: true
type: boolean
default: true
linux:
description: Build Linux
required: true
type: boolean
default: true
deploy:
description: Deploy artifacts
required: true
type: boolean
default: true
run-name: Element ${{ inputs.mode != 'release' && github.event_name != 'release' && 'Nightly' || 'Desktop' }}
concurrency: ${{ github.workflow }}
env:
R2_BUCKET: ${{ vars.R2_BUCKET }}
jobs:
prepare:
uses: ./.github/workflows/build_prepare.yaml
with:
config: element.io/${{ inputs.mode || (github.event_name == 'release' && 'release') || 'nightly' }}
version: ${{ (inputs.mode != 'release' && github.event_name != 'release') && 'develop' || '' }}
nightly: ${{ inputs.mode != 'release' && github.event_name != 'release' }}
deploy: ${{ inputs.deploy || (github.event_name != 'workflow_dispatch' && github.event.release.prerelease != true) }}
secrets:
CF_R2_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
CF_R2_TOKEN: ${{ secrets.CF_R2_TOKEN }}
windows:
if: github.event_name != 'workflow_dispatch' || inputs.windows
needs: prepare
name: Windows ${{ matrix.arch }}
strategy:
matrix:
arch: [ia32, x64]
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
sign: true
arch: ${{ matrix.arch }}
version: ${{ needs.prepare.outputs.nightly-version }}
macos:
if: github.event_name != 'workflow_dispatch' || inputs.macos
needs: prepare
name: macOS
uses: ./.github/workflows/build_macos.yaml
secrets: inherit
with:
sign: true
base-url: https://packages.element.io/${{ needs.prepare.outputs.packages-dir }}
version: ${{ needs.prepare.outputs.nightly-version }}
linux:
if: github.event_name != 'workflow_dispatch' || inputs.linux
needs: prepare
name: Linux ${{ matrix.arch }} (sqlcipher ${{ matrix.sqlcipher }})
strategy:
matrix:
arch: [amd64, arm64]
sqlcipher: [static]
uses: ./.github/workflows/build_linux.yaml
with:
arch: ${{ matrix.arch }}
config: ${{ needs.prepare.outputs.config }}
sqlcipher: ${{ matrix.sqlcipher }}
version: ${{ needs.prepare.outputs.nightly-version }}
deploy:
needs:
- prepare
- macos
- linux
- windows
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' || '' }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Prepare artifacts for deployment
run: |
# Windows
for arch in x64 ia32 arm64
do
if [ -d "win-$arch" ]; then
mkdir -p packages.element.io/{install,update}/win32/$arch
mv win-$arch/squirrel-windows*/*.exe "packages.element.io/install/win32/$arch/"
mv win-$arch/squirrel-windows*/*.nupkg "packages.element.io/update/win32/$arch/"
mv win-$arch/squirrel-windows*/RELEASES "packages.element.io/update/win32/$arch/"
fi
done
# macOS
if [ -d macos ]; then
mkdir -p packages.element.io/{install,update}/macos
mv macos/*.dmg packages.element.io/install/macos/
mv macos/*-mac.zip packages.element.io/update/macos/
mv macos/*.json packages.element.io/update/macos/
fi
# Linux
if [ -d linux-amd64-sqlcipher-static ]; then
mkdir -p packages.element.io/install/linux/glibc-x86-64
mv linux-amd64-sqlcipher-static/*.tar.gz packages.element.io/install/linux/glibc-x86-64
fi
if [ -d linux-arm64-sqlcipher-static ]; then
mkdir -p packages.element.io/install/linux/glibc-aarch64
mv linux-arm64-sqlcipher-static/*.tar.gz packages.element.io/install/linux/glibc-aarch64
fi
# We don't wish to store the installer for every nightly ever, so we only keep the latest
- name: "[Nightly] Strip version from installer file"
if: needs.prepare.outputs.nightly-version != ''
run: |
# Windows
for arch in x64 ia32 arm64
do
[ -d "win-$arch" ] && mv packages.element.io/install/win32/$arch/{*,"Element Nightly Setup"}.exe
done
# macOS
[ -d macos ] && mv packages.element.io/install/macos/{*,"Element Nightly"}.dmg
# Linux
[ -d linux-amd64-sqlcipher-static ] && mv packages.element.io/install/linux/glibc-x86-64/{*,element-desktop-nightly}.tar.gz
[ -d linux-arm64-sqlcipher-static ] && mv packages.element.io/install/linux/glibc-aarch64/{*,element-desktop-nightly}.tar.gz
- name: "[Release] Prepare release latest symlink"
if: needs.prepare.outputs.nightly-version == ''
run: |
# Windows
for arch in x64 ia32 arm64
do
if [ -d "win-$arch" ]; then
pushd packages.element.io/install/win32/$arch
ln -s "$(find . -type f -iname "*.exe" | xargs -0 -n1 -- basename)" "Element Setup.exe"
popd
fi
done
# macOS
if [ -d macos ]; then
pushd packages.element.io/install/macos
ln -s "$(find . -type f -iname "*.dmg" | xargs -0 -n1 -- basename)" "Element.dmg"
popd
fi
# Linux
if [ -d linux-amd64-sqlcipher-static ]; then
pushd packages.element.io/install/linux/glibc-x86-64
ln -s "$(find . -type f -iname "*.tar.gz" | xargs -0 -n1 -- basename)" "element-desktop.tar.gz"
popd
fi
if [ -d linux-arm64-sqlcipher-static ]; then
pushd packages.element.io/install/linux/glibc-aarch64
ln -s "$(find . -type f -iname "*.tar.gz" | xargs -0 -n1 -- basename)" "element-desktop.tar.gz"
popd
fi
- name: Stash packages.element.io
if: needs.prepare.outputs.deploy == 'false'
uses: actions/upload-artifact@v4
with:
name: packages.element.io
path: packages.element.io
- name: Deploy artifacts
if: needs.prepare.outputs.deploy == 'true'
run: |
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 }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
R2_URL: ${{ vars.CF_R2_S3_API }}
DEPLOYMENT_DIR: ${{ needs.prepare.outputs.packages-dir }}
- name: Notify packages.element.io of new files
if: needs.prepare.outputs.deploy == 'true'
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
repository: element-hq/packages.element.io
event-type: packages-index
- name: Find debs
id: deb
if: needs.linux.result == 'success'
run: |
for arch in amd64 arm64
do
echo "$arch=$(ls linux-$arch-sqlcipher-static/*.deb | tail -n1)" >> $GITHUB_OUTPUT
done
- name: Stash debs
if: needs.prepare.outputs.deploy == 'false' && needs.linux.result == 'success'
uses: actions/upload-artifact@v4
with:
name: debs
path: |
${{ steps.deb.outputs.amd64 }}
${{ steps.deb.outputs.arm64 }}
- name: Publish amd64 deb to packages.element.io
uses: element-hq/packages.element.io@master
if: needs.prepare.outputs.deploy == 'true' && needs.linux.result == 'success'
with:
file: ${{ steps.deb.outputs.amd64 }}
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
bucket-api: ${{ vars.CF_R2_S3_API }}
bucket-key-id: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
bucket-access-key: ${{ secrets.CF_R2_TOKEN }}
- name: Publish arm64 deb to packages.element.io
uses: element-hq/packages.element.io@master
if: needs.prepare.outputs.deploy == 'true' && needs.linux.result == 'success'
with:
file: ${{ steps.deb.outputs.arm64 }}
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
bucket-api: ${{ vars.CF_R2_S3_API }}
bucket-key-id: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
bucket-access-key: ${{ secrets.CF_R2_TOKEN }}
deploy-ess:
needs: deploy
runs-on: ubuntu-latest
name: Deploy builds to ESS
if: needs.prepare.outputs.deploy == 'true' && github.event_name == 'release'
env:
BUCKET_NAME: "element-desktop-msi.onprem.element.io"
AWS_REGION: "eu-central-1"
permissions:
id-token: write # This is required for requesting the JWT
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::264135176173:role/Push-ElementDesktop-MSI
role-session-name: githubaction-run-${{ github.run_id }}
aws-region: ${{ env.AWS_REGION }}
- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: win-*
- name: Copy files to S3
run: |
PREFIX="${VERSION%.*}"
for file in win-*/*.msi; do
filename=$(basename "$file")
aws s3 cp "$file" "s3://${{ env.BUCKET_NAME }}/$PREFIX/$filename"
done
env:
VERSION: ${{ github.event.release.tag_name }}

View File

@@ -1,154 +0,0 @@
name: Build and Test
on:
pull_request: {}
push:
branches: [develop, staging, master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
fetch:
uses: ./.github/workflows/build_prepare.yaml
with:
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
version: ${{ github.event.pull_request.base.ref == 'develop' && 'develop' || '' }}
windows:
needs: fetch
name: Windows
uses: ./.github/workflows/build_windows.yaml
strategy:
matrix:
arch: [x64, ia32]
with:
arch: ${{ matrix.arch }}
linux:
needs: fetch
name: "Linux (${{ matrix.arch }}) (sqlcipher: ${{ matrix.sqlcipher }})"
uses: ./.github/workflows/build_linux.yaml
strategy:
matrix:
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 }}
macos:
needs: fetch
name: macOS
uses: ./.github/workflows/build_macos.yaml
test:
needs:
- macos
- linux
- windows
strategy:
matrix:
include:
- name: macOS Universal
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
# read-only and thus would not allow us to override the fuses as is required for Playwright.
prepare_cmd: |
hdiutil attach ./dist/*.dmg -mountpoint /Volumes/Element &&
rsync -a /Volumes/Element/Element.app ~/Applications/ &&
hdiutil detach /Volumes/Element
- name: "Linux (amd64) (sqlcipher: system)"
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-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: 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: 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-latest
artifact: win-ia32
executable: "./dist/win-ia32-unpacked/Element.exe"
- name: Windows (x64)
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: package.json
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- uses: actions/download-artifact@v4
with:
name: ${{ matrix.artifact }}
path: dist
- name: Prepare for tests
run: ${{ matrix.prepare_cmd }}
if: matrix.prepare_cmd
# We previously disabled the `EnableNodeCliInspectArguments` fuse, but Playwright requires
# it to be enabled to test Electron apps, so turn it back on.
- name: Set EnableNodeCliInspectArguments fuse enabled
run: $RUN_AS npx @electron/fuses write --app ${{ matrix.executable }} EnableNodeCliInspectArguments=on
shell: bash
env:
# 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
with:
run: "yarn test ${{ runner.os != 'Linux' && '--ignore-snapshots' || '' }}"
env:
ELEMENT_DESKTOP_EXECUTABLE: ${{ matrix.executable }}
- name: Upload HTML report
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}-test
path: playwright/html-report
retention-days: 14

View File

@@ -1,230 +1,58 @@
# This workflow relies on actions/cache to store the hak dependency artifacts as they take a long time to build
# 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.
on:
workflow_call:
inputs:
arch:
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
description: "Version string to override the one in package.json, used for non-release builds"
sqlcipher:
type: string
required: true
description: "How to link sqlcipher, one of 'system' | 'static'"
env:
SQLCIPHER_BUNDLED: ${{ inputs.sqlcipher == 'static' && '1' || '' }}
workflow_call:
inputs:
sqlcipher:
type: string
required: true
description: "How to link sqlcipher, one of 'system' | 'static'"
jobs:
# 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' }}
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
uses: actions/cache@v3
with:
key: ${{ hashFiles('./yarn.lock') }}
path: |
./.hak
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install libsqlcipher-dev
if: inputs.sqlcipher == 'system'
run: sudo apt-get install -y libsqlcipher-dev
- uses: actions/setup-node@v3
with:
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --pure-lockfile"
- name: Build Natives
run: "yarn build:native"
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
SQLCIPHER_STATIC: ${{ inputs.sqlcipher == 'static' && '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: Build App
run: "yarn build --publish never -l"
- 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
- name: Resolve docker image tag for release
if: github.event_name == 'release'
run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:staging" >> $GITHUB_ENV
- name: Resolve docker image tag for other triggers
if: github.event_name != 'push' && github.event_name != 'release'
run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:develop" >> $GITHUB_ENV
- name: Install .deb
run: "sudo apt install ./dist/*.deb"
- uses: nbucic/variable-mapper@0673f6891a0619ba7c002ecfed0f9f4f39017b6f
id: config
with:
key: "${{ inputs.arch }}"
export_to: output
map: |
{
"amd64": {
"target": "x86_64-unknown-linux-gnu",
"arch": "x86-64"
},
"arm64": {
"target": "aarch64-unknown-linux-gnu",
"arch": "aarch64",
"build-args": "--arm64"
}
}
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
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: ${{ steps.cache-key.outputs.key }}
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: "Get modified files"
id: changed_files
if: steps.cache.outputs.cache-hit != 'true' && github.event_name == 'pull_request'
uses: tj-actions/changed-files@40853de9f8ce2d6cfdc73c1b96f14e22ba44aec4 # 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@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6
if: steps.changed_files.outputs.any_modified == 'true'
with:
context: dockerbuild
load: true
platforms: linux/${{ inputs.arch }}
tags: ${{ env.HAK_DOCKER_IMAGE }}
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: |
docker run \
-v ${{ github.workspace }}:/work -w /work \
-e SQLCIPHER_BUNDLED \
$HAK_DOCKER_IMAGE \
yarn build:native
- 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: |
if [ -f changelog.Debian ]; then
echo "ED_DEBIAN_CHANGELOG=changelog.Debian" >> $GITHUB_ENV
fi
- name: Build App
run: yarn build --publish never -l ${{ needs.hak.outputs.build-args }}
- name: Check native libraries
run: |
set -x
shopt -s globstar
FILES=$(file dist/**/*.node)
echo "$FILES"
if [ grep -v "$ARCH" ]; then
exit 1
fi
LIBS=$(readelf -d dist/**/*.node | grep NEEDED)
echo "$LIBS"
set +x
assert_contains_string() { [[ "$1" == *"$2"* ]]; }
! assert_contains_string "$LIBS" "libcrypto.so.1.1"
if [ "$SQLCIPHER_BUNDLED" == "1" ]; then
! assert_contains_string "$LIBS" "libsqlcipher.so.0"
else
assert_contains_string "$LIBS" "libsqlcipher.so.0"
fi
./scripts/glibc-check.sh dist/linux-*unpacked/element-desktop*
env:
ARCH: ${{ needs.hak.outputs.arch }}
# We exclude *-unpacked as it loses permissions and the tarball contains it with correct permissions
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: linux-${{ inputs.arch }}-sqlcipher-${{ inputs.sqlcipher }}
path: |
dist
!dist/*-unpacked/**
retention-days: 1
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: linux-sqlcipher-${{ inputs.sqlcipher }}
path: dist
retention-days: 1

View File

@@ -1,144 +1,45 @@
# This workflow relies on actions/cache to store the hak dependency artifacts as they take a long time to build
# 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.
on:
workflow_call:
secrets:
APPLE_ID:
required: false
APPLE_ID_PASSWORD:
required: false
APPLE_TEAM_ID:
required: false
APPLE_CSC_KEY_PASSWORD:
required: false
APPLE_CSC_LINK:
required: false
inputs:
version:
type: string
required: false
description: "Version string to override the one in package.json, used for non-release builds"
sign:
type: string
required: false
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
base-url:
type: string
required: false
description: "The URL to which the output will be deployed."
workflow_call:
jobs:
build:
runs-on: macos-14 # M1
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
steps:
- uses: actions/checkout@v4
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v4
with:
name: webapp
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
id: cache
uses: actions/cache@v4
with:
key: ${{ runner.os }}-${{ hashFiles('hakHash', 'electronVersion') }}
path: |
./.hak
- name: Cache .hak
uses: actions/cache@v3
with:
key: ${{ hashFiles('./yarn.lock') }}
path: |
./.hak
- name: Install Rust
if: steps.cache.outputs.cache-hit != 'true'
run: |
rustup toolchain install stable --profile minimal --no-self-update
rustup default stable
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-apple-darwin
# M1 macos-14 comes without Python preinstalled
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: actions/setup-node@v3
with:
cache: "yarn"
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --pure-lockfile"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Build Natives
run: "yarn build:native:universal"
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: |
# Python 3.12 drops distutils which keytar relies on
pip3 install setuptools
yarn build:native:universal
- name: Build App
run: "yarn build:universal --publish never"
- 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"
if: inputs.sign != ''
run: |
yarn build:universal --publish never
env:
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 }}
- name: Check app was signed & notarised successfully
if: inputs.sign != ''
run: |
hdiutil attach dist/*.dmg -mountpoint /Volumes/Element
codesign -dv --verbose=4 /Volumes/Element/*.app
spctl -a -vvv -t install /Volumes/Element/*.app
hdiutil detach /Volumes/Element
- name: "[Unsigned] Build App"
if: inputs.sign == ''
run: |
yarn build:universal --publish never
env:
CSC_IDENTITY_AUTO_DISCOVERY: false
- name: Generate releases.json
if: inputs.base-url
run: |
PKG_JSON_VERSION=$(cat package.json | jq -r .version)
LATEST=$(find dist -type f -iname "*-mac.zip" | xargs -0 -n1 -- basename)
# Encode spaces in the URL as Squirrel.Mac complains about bad JSON otherwise
URL="${{ inputs.base-url }}/update/macos/${LATEST// /%20}"
jq -n --arg version "${VERSION:-$PKG_JSON_VERSION}" --arg url "$URL" '
{
currentRelease: $version,
releases: [{
version: $version,
updateTo: {
version: $version,
url: $url,
},
}],
}
' > dist/releases.json
jq -n --arg url "$URL" '
{ url: $url }
' > dist/releases-legacy.json
env:
VERSION: ${{ inputs.version }}
# We exclude mac-universal as the unpacked app takes forever to upload and zip and dmg already contains it
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: macos
path: |
dist
!dist/mac-universal/**
retention-days: 1
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: macos
path: dist
retention-days: 1

View File

@@ -1,150 +1,35 @@
# This action helps perform common actions before the build_* actions are started in parallel.
on:
workflow_call:
inputs:
config:
type: string
required: true
description: "The config directory to use"
version:
type: string
required: false
description: "The version tag to fetch, or 'develop', will pick automatically if not passed"
nightly:
type: boolean
required: false
default: false
description: "Whether the build is a Nightly and to calculate the version strings new builds should use"
deploy:
type: boolean
required: false
default: false
description: "Whether the build should be deployed to production"
secrets:
# Required if `nightly` is set
CF_R2_ACCESS_KEY_ID:
required: false
# Required if `nightly` is set
CF_R2_TOKEN:
required: false
outputs:
nightly-version:
description: "The version string the next Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.nightly-version }}
packages-dir:
description: "The directory non-deb packages for this run should live in within packages.element.io"
value: ${{ inputs.nightly && 'nightly' || 'desktop' }}
# 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: "The relative path to the config file for this run"
value: ${{ inputs.deploy }}
workflow_call:
inputs:
config:
type: string
required: true
description: "The config directory to use"
version:
type: string
required: false
description: "The version tag to fetch, or 'develop', will pick automatically if not passed"
jobs:
prepare:
name: Prepare
environment: ${{ inputs.nightly && 'packages.element.io' || '' }}
runs-on: ubuntu-latest
outputs:
nightly-version: ${{ steps.versions.outputs.nightly }}
steps:
- uses: actions/checkout@v4
prepare:
name: Prepare
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
- uses: actions/setup-node@v3
with:
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Install Deps
run: "yarn install --pure-lockfile"
- name: Fetch Element Web
run: yarn run fetch --noverify -d ${{ inputs.config }} ${{ inputs.version }}
- name: Fetch Element Web
run: yarn run fetch --noverify -d ${{ inputs.config }} ${{ inputs.version }}
# 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: |
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
- name: "[Nightly] Calculate version"
id: versions
if: inputs.nightly
run: |
# Find all latest Nightly versions
aws s3 cp s3://$R2_BUCKET/nightly/update/macos/releases.json - --endpoint-url $R2_URL --region auto | jq -r .currentRelease >> VERSIONS
aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-amd64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p' >> VERSIONS
aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-arm64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p' >> VERSIONS
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/x64/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/ia32/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
# Pick the greatest one
VERSION=$(cat VERSIONS | sort -uf | tail -n1)
echo "Found latest nightly version $VERSION"
# Increment it
echo "nightly=$(scripts/generate-nightly-version.ts --latest $VERSION)" >> $GITHUB_OUTPUT
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
R2_BUCKET: ${{ vars.R2_BUCKET }}
R2_URL: ${{ vars.CF_R2_S3_API }}
- name: Check version
id: package
run: |
echo "version=$(cat package.json | jq -r .version)" >> $GITHUB_OUTPUT
- name: "[Release] Fetch release"
id: release
if: ${{ !inputs.nightly && inputs.version != 'develop' }}
uses: cardinalby/git-get-release-action@cedef2faf69cb7c55b285bad07688d04430b7ada # v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tag: v${{ steps.package.outputs.version }}
- name: "[Release] Write changelog"
if: ${{ !inputs.nightly && inputs.version != 'develop' }}
run: |
TIME=$(date -d "$PUBLISHED_AT" -R)
echo "element-desktop ($VERSION) default; urgency=medium" >> changelog.Debian
echo "$BODY" | sed 's/^##/\n */g;s/^\*/ */g' | perl -pe 's/\[.+?]\((.+?)\)/\1/g' >> changelog.Debian
echo "" >> changelog.Debian
echo " -- $ACTOR <support@element.io> $TIME" >> changelog.Debian
env:
ACTOR: ${{ github.actor }}
VERSION: v${{ steps.package.outputs.version }}
BODY: ${{ steps.release.outputs.body }}
PUBLISHED_AT: ${{ steps.release.outputs.published_at }}
- name: "[Nightly] Write summary"
if: inputs.nightly
run: |
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}
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
echo "| Component | Version |" >> $GITHUB_STEP_SUMMARY
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
with:
name: webapp
retention-days: 1
path: |
webapp.asar
package.json
electronVersion
hakHash
changelog.Debian
- uses: actions/upload-artifact@v3
with:
name: webapp
retention-days: 1
path: |
webapp.asar
package.json

View File

@@ -1,181 +1,87 @@
# This workflow relies on actions/cache to store the hak dependency artifacts as they take a long time to build
# 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.
# window-latest by default uses the pwsh shell which breaks codeSigningCert in the workflow
defaults:
run:
shell: powershell
on:
workflow_call:
secrets:
ESIGNER_USER_NAME:
required: false
ESIGNER_USER_PASSWORD:
required: false
ESIGNER_USER_TOTP:
required: false
inputs:
arch:
type: string
required: true
description: "The architecture to build for, one of 'x64' | 'ia32' | 'arm64'"
version:
type: string
required: false
description: "Version string to override the one in package.json, used for non-release builds"
sign:
type: string
required: false
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
workflow_call:
inputs:
arch:
type: string
required: true
description: "The architecture to build for, one of 'x64' | 'x86'"
jobs:
build:
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"
steps:
- uses: nbucic/variable-mapper@0673f6891a0619ba7c002ecfed0f9f4f39017b6f
id: config
with:
key: "${{ inputs.arch }}"
export_to: output
map: |
{
"x64": {
"target": "x86_64-pc-windows-msvc"
},
"arm64": {
"target": "aarch64-pc-windows-msvc",
"build-args": "--arm64",
"arch": "amd64_arm64"
},
"ia32": {
"target": "i686-pc-windows-msvc",
"build-args": "--ia32",
"arch": "x86"
}
}
build:
runs-on: windows-latest
steps:
- uses: kanga333/variable-mapper@master
id: config
with:
key: "${{ inputs.arch }}"
export_to: output
map: |
{
"x64": {
"target": "x86_64-pc-windows-msvc"
},
"x86": {
"target": "i686-pc-windows-msvc",
"build-args": "--ia32"
}
}
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: actions/download-artifact@v4
with:
name: webapp
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
id: cache
uses: actions/cache@v4
with:
key: ${{ runner.os }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion') }}
path: |
./.hak
- name: Cache .hak
uses: actions/cache@v3
with:
key: ${{ runner.os }}-${{ hashFiles('./yarn.lock') }}
path: |
./.hak
- name: Set up build tools
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
with:
arch: ${{ steps.config.outputs.arch || inputs.arch }}
- name: Set up build tools
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ inputs.arch }}
# ActiveTCL package on choco is from 2015,
# this one is newer but includes more than we need
- name: Choco install tclsh
if: steps.cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
choco install -y magicsplat-tcl-tk --no-progress
echo "${HOME}/AppData/Local/Apps/Tcl86/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
# ActiveTCL package on choco is from 2015,
# this one is newer but includes more than we need
- name: Choco install tclsh
shell: pwsh
run: |
choco install -y magicsplat-tcl-tk --no-progress
echo "${HOME}/AppData/Local/Apps/Tcl86/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Choco install NetWide Assembler
if: steps.cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
choco install -y nasm --no-progress
echo "C:/Program Files/NASM" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Choco install NetWide Assembler
shell: pwsh
run: |
choco install -y nasm --no-progress
echo "C:/Program Files/NASM" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Install Rust
if: steps.cache.outputs.cache-hit != 'true'
run: |
rustup toolchain install stable --profile minimal --no-self-update
rustup default stable
rustup target add ${{ steps.config.outputs.target }}
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: ${{ steps.config.outputs.target }}
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
- uses: actions/setup-node@v3
with:
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --pure-lockfile"
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: |
refreshenv
yarn build:native --target ${{ steps.config.outputs.target }}
- name: Build Natives
run: |
refreshenv
yarn build:native --target ${{ steps.config.outputs.target }}
- name: Install and configure eSigner CKA
if: inputs.sign
run: |
Set-StrictMode -Version 'Latest'
- name: Build App
run: "yarn build --publish never -w ${{ steps.config.outputs.build-args }}"
# Download, extract, and rename
Invoke-WebRequest -OutFile eSigner_CKA.zip "$env:ESIGNER_URL"
Expand-Archive -Path eSigner_CKA.zip -DestinationPath .
Get-ChildItem -Path * -Include "*_build_*.exe" | Rename-Item -NewName eSigner_CKA.exe
# Install
New-Item -ItemType Directory -Force -Path "$env:INSTALL_DIR"
./eSigner_CKA.exe /CURRENTUSER /VERYSILENT /SUPPRESSMSGBOXES /DIR="${{ env.INSTALL_DIR }}" | Out-Null
# Disable logger
$LogConfig = Get-Content -Path ${{ env.INSTALL_DIR }}/log4net.config
$LogConfig[0] = '<log4net threshold="OFF">'
$LogConfig | Set-Content -Path ${{ env.INSTALL_DIR }}/log4net.config
# 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
# Find certificate
$CodeSigningCert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
echo Certificate: $CodeSigningCert
# Extract thumbprint and subject name
$Thumbprint = $CodeSigningCert.Thumbprint
$SubjectName = ($CodeSigningCert.Subject -replace ", ?", "`n" | ConvertFrom-StringData).CN
echo "ED_SIGNTOOL_THUMBPRINT=$Thumbprint" >> $env:GITHUB_ENV
echo "ED_SIGNTOOL_SUBJECT_NAME=$SubjectName" >> $env:GITHUB_ENV
env:
ESIGNER_URL: https://github.com/SSLcom/eSignerCKA/releases/download/v1.0.6/SSL.COM-eSigner-CKA_1.0.6.zip
INSTALL_DIR: C:\Users\runneradmin\eSignerCKA
MASTER_KEY_FILE: C:\Users\runneradmin\eSignerCKA\master.key
- name: "[Nightly] Resolve version"
if: inputs.version != ''
shell: bash
run: |
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: |
. "$env:SIGNTOOL_PATH" verify /pa (get-item ./dist/squirrel-windows*/*.exe)
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: win-${{ inputs.arch }}
path: |
dist
retention-days: 1
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: win-${{ inputs.arch }}
path: dist
retention-days: 1

View File

@@ -1,52 +0,0 @@
name: Dockerbuild
on:
workflow_dispatch: {}
push:
branches: [master, staging, develop]
paths:
- "dockerbuild/**"
concurrency: ${{ github.workflow }}-${{ github.ref_name }}
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}-dockerbuild
jobs:
build:
name: Docker Build
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3
with:
install: true
- name: Log in to the Container registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
- name: Build and push Docker image
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6
with:
context: dockerbuild
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64

View File

@@ -1,10 +0,0 @@
name: Localazy Download
on:
workflow_dispatch: {}
schedule:
- cron: "0 6 * * 1,3,5" # Every Monday, Wednesday and Friday at 6am UTC
jobs:
download:
uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_download.yaml@main
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,11 +0,0 @@
name: Localazy Upload
on:
push:
branches: [develop]
paths:
- "src/i18n/strings/en_EN.json"
jobs:
upload:
uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_upload.yaml@main
secrets:
LOCALAZY_WRITE_KEY: ${{ secrets.LOCALAZY_WRITE_KEY }}

43
.github/workflows/packages_index.yaml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Generate packages.element.io directory indexes
on:
# Trigger a rebuild of all indexes if the template gets updated
push:
branches: [ develop ]
paths:
- 'packages.element.io/**'
# Trigger a daily rebuild for nightlies
schedule:
- cron: '0 11 * * *'
# Manual trigger for rebuilding for releases
workflow_dispatch: { }
jobs:
deploy:
name: "Deploy"
runs-on: ubuntu-latest
environment: develop
env:
R2_BUCKET: 'packages-element-io'
R2_URL: ${{ secrets.CF_R2_S3_API }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
cache: "yarn"
- name: Install Deps
run: "yarn install --pure-lockfile"
- name: Copy static files
if: github.event_name == 'push'
run: aws s3 cp --recursive packages.element.io/ s3://$R2_BUCKET/ --endpoint-url $R2_URL --region auto
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
- name: Generate directory indexes
run: scripts/generate-packages-index.ts
env:
CF_R2_S3_API: ${{ secrets.CF_R2_S3_API }}
CF_R2_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
CF_R2_TOKEN: ${{ secrets.CF_R2_TOKEN }}

View File

@@ -1,9 +1,12 @@
name: Pull Request
on:
pull_request_target:
types: [opened, edited, labeled, unlabeled, synchronize]
pull_request_target:
types: [ opened, edited, labeled, unlabeled, synchronize ]
concurrency: ${{ github.workflow }}-${{ github.event.pull_request.head.ref }}
jobs:
action:
uses: matrix-org/matrix-js-sdk/.github/workflows/pull_request.yaml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
action:
uses: matrix-org/matrix-js-sdk/.github/workflows/pull_request.yaml@develop
with:
labels: "T-Defect,T-Enhancement,T-Task"
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,11 +0,0 @@
name: Release Drafter
on:
push:
branches: [staging]
workflow_dispatch: {}
concurrency: ${{ github.workflow }}
jobs:
draft:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-drafter-workflow.yml@develop
with:
include-changes: element-hq/element-web~$VERSION

View File

@@ -1,11 +0,0 @@
# Gitflow merge-back master->develop
name: Merge master -> develop
on:
push:
branches: [master]
concurrency: ${{ github.repository }}-${{ github.workflow }}
jobs:
merge:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-gitflow.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,38 +0,0 @@
name: Release Process
on:
workflow_dispatch:
inputs:
mode:
description: What type of release
required: true
default: rc
type: choice
options:
- rc
- final
concurrency: ${{ github.workflow }}
jobs:
release:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
with:
final: ${{ inputs.mode == 'final' }}
gpg-fingerprint: ${{ vars.GPG_FINGERPRINT }}
expected-asset-count: 1
check:
name: Post release checks
needs: release
runs-on: ubuntu-latest
steps:
- name: Wait for desktop packaging
uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork
with:
ref: master
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
check-name: Deploy
allowed-conclusions: success

View File

@@ -1,82 +1,43 @@
name: Static Analysis
on:
pull_request: {}
push:
branches: [develop, master]
pull_request: { }
push:
branches: [ develop, master ]
jobs:
ts_lint:
name: "Typescript Syntax Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
ts_lint:
name: "Typescript Syntax Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v4
with:
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: Typecheck
run: "yarn run lint:types"
i18n_lint:
name: "i18n Check"
uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main
- uses: actions/setup-node@v3
with:
hardcoded-words: "Element"
cache: 'yarn'
js_lint:
name: "ESLint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --pure-lockfile"
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
- name: Typecheck
run: "yarn run lint:types"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
i18n_lint:
name: "i18n Check"
uses: matrix-org/matrix-react-sdk/.github/workflows/i18n_check.yml@develop
- name: Run Linter
run: "yarn run lint:js"
js_lint:
name: "ESLint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
workflow_lint:
name: "Workflow Lint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
cache: 'yarn'
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --pure-lockfile"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Run Linter
run: "yarn lint:workflows"
analyse_dead_code:
name: "Analyse Dead Code"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Run linter
run: "yarn run lint:knip"
- name: Run Linter
run: "yarn run lint:js"

View File

@@ -1,21 +0,0 @@
name: Sync labels
on:
workflow_dispatch: {}
schedule:
- cron: "0 2 * * *" # 2am every day
push:
branches:
- develop
paths:
- .github/labels.yml
jobs:
sync-labels:
uses: element-hq/element-meta/.github/workflows/sync-labels.yml@develop
with:
LABELS: |
element-hq/element-web
.github/labels.yml
DELETE: true
WET: true
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,14 +0,0 @@
name: Move new issues into Issue triage board
on:
issues:
types: [opened]
jobs:
automate-project-columns-next:
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@main
with:
project-url: https://github.com/orgs/element-hq/projects/120
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,10 +0,0 @@
name: Move labelled issues to correct projects
on:
issues:
types: [labeled]
jobs:
call-triage-labelled:
uses: element-hq/element-web/.github/workflows/triage-labelled.yml@develop
secrets: inherit

View File

@@ -0,0 +1,8 @@
name: Upgrade Dependencies
on:
workflow_dispatch: { }
jobs:
upgrade:
uses: matrix-org/matrix-js-sdk/.github/workflows/upgrade_dependencies.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

3
.gitignore vendored
View File

@@ -14,6 +14,3 @@ node_modules/
.vscode/
/test_artifacts/
/coverage/
yarn-error.log
/hak/**/*.js
/scripts/hak/**/*.js

View File

@@ -1,21 +0,0 @@
/build/
/dockerbuild/
/lib/
/node_modules/
/packages.elememt.io/
/webapp
/src/i18n/strings
/CHANGELOG.md
/package-lock.json
/yarn.lock
/playwright/html-report
/playwright/test-results
**/.idea
.vscode
.vscode/
.tmp
.env
/coverage
/.npmrc
/*.log

View File

@@ -1 +0,0 @@
module.exports = require("eslint-plugin-matrix-org/.prettierrc.js");

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,25 @@
![Build](https://github.com/vector-im/element-desktop/actions/workflows/build.yaml/badge.svg)
![Static Analysis](https://github.com/vector-im/element-desktop/actions/workflows/static_analysis.yaml/badge.svg)
[![Localazy](https://img.shields.io/endpoint?url=https%3A%2F%2Fconnect.localazy.com%2Fstatus%2Felement-web%2Fdata%3Fcontent%3Dall%26title%3Dlocalazy%26logo%3Dtrue)](https://localazy.com/p/element-web)
[![Weblate](https://translate.element.io/widgets/element-desktop/-/element-desktop/svg-badge.svg)](https://translate.element.io/engage/element-desktop/)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=element-desktop&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=element-desktop)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=element-desktop&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=element-desktop)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=element-desktop&metric=bugs)](https://sonarcloud.io/summary/new_code?id=element-desktop)
# Element Desktop
Element Desktop
===============
Element Desktop is a Matrix client for desktop platforms with Element Web at its core.
# First Steps
First Steps
===========
Before you do anything else, fetch the dependencies:
```
yarn install
```
# Fetching Element
Fetching Element
================
Since this package is just the Electron wrapper for Element Web, it doesn't contain any of the Element Web code,
so the first step is to get a working copy of Element Web. There are a few ways of doing this:
@@ -30,7 +31,6 @@ yarn run fetch --noverify --cfgdir ""
```
...or if you'd like to use GPG to verify the downloaded package:
```
# Fetch the Element public key from the element.io web server over a secure connection and import
# it into your local GPG keychain (you'll need GPG installed). You only need to to do this
@@ -41,7 +41,6 @@ yarn run fetch --cfgdir ""
```
...or either of the above, but fetching a specific version of Element:
```
# Fetch the prebuilt release Element package from the element-web GitHub releases page. The version
# fetched will be the same as the local element-desktop package.
@@ -50,7 +49,6 @@ yarn run fetch --noverify --cfgdir "" v1.5.6
If you only want to run the app locally and don't need to build packages, you can
provide the `webapp` directory directly:
```
# Assuming you've checked out and built a copy of element-web in ../element-web
ln -s ../element-web/webapp ./
@@ -58,32 +56,29 @@ ln -s ../element-web/webapp ./
[TODO: add support for fetching develop builds, arbitrary URLs and arbitrary paths]
# Building
Building
========
## Native Build
TODO: List native pre-requisites
Optionally, [build the native modules](https://github.com/vector-im/element-desktop/blob/develop/docs/native-node-modules.md),
which include support for searching in encrypted rooms and secure storage. Skipping this step is fine, you just won't have those features.
Optionally, [build the native modules](https://github.com/vector-im/element-desktop/blob/develop/docs/native-node-modules.md),
which include support for searching in encrypted rooms and secure storage. Skipping this step is fine, you just won't have those features.
Then, run
```
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
Alternatively, you can also build using docker, which will always produce the linux package:
```
# Run this once to make the docker image
yarn run docker:setup
@@ -96,10 +91,9 @@ yarn run docker:build
After running, the packages should be in `dist/`.
# Starting
Starting
========
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
@@ -107,22 +101,21 @@ yarn add electron
yarn start
```
# Config
Config
======
If you'd like the packaged Element to have a configuration file, you can create a
config directory and place `config.json` in there, then specify this directory
with the `--cfgdir` option to `yarn run fetch`, eg:
```
mkdir myconfig
cp /path/to/my/config.json myconfig/
yarn run fetch --cfgdir myconfig
```
The config dir for the official Element app is in `element.io`. If you use this,
your app will auto-update itself using builds from element.io.
# Profiles
Profiles
========
To run multiple instances of the desktop app for different accounts, you can
launch the executable with the `--profile` argument followed by a unique
@@ -132,25 +125,30 @@ not interfere with the default one.
Alternatively, a custom location for the profile data can be specified using the
`--profile-dir` flag followed by the desired path.
# User-specified config.json
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`.
# Translations
Translations
==========================
To add a new translation, head to the [translating doc](https://github.com/vector-im/element-web/blob/develop/docs/translating.md).
For a developer guide, see the [translating dev doc](https://github.com/vector-im/element-web/blob/develop/docs/translating-dev.md).
# Report bugs & give feedback
[<img src="https://translate.element.io/widgets/element-desktop/-/multi-auto.svg" alt="translationsstatus" width="340">](https://translate.element.io/engage/element-desktop/?utm_source=widget)
Report bugs & give feedback
==========================
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.
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.

View File

@@ -1,3 +1,6 @@
module.exports = {
presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"],
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};

View File

@@ -9,11 +9,11 @@
Latest electron-builder does, but it appears to be causing issues:
(https://github.com/electron-userland/electron-builder/issues/4390)
-->
<!-- https://github.com/electron/electron-notarize#prerequisites -->
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<!-- https://github.com/electron-userland/electron-builder/issues/3940 -->
<key>com.apple.security.cs.disable-library-validation</key>
<true/>

View File

@@ -0,0 +1,51 @@
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
/*
* This just runs 'Element.exe' with the same args as
* this process was invoked with. This gets around the fact that
* squirrel always tries to run an executable with the same name,
* so fails to restart if the app's name has changed.
*/
void _tmain( int argc, TCHAR *argv[] )
{
LPSTR myCmdLine = GetCommandLineA();
char cmdLine[32767];
LPSTR cmdLinePos = cmdLine;
LPSTR toRun = "\"Element.exe\" ";
strncpy(cmdLinePos, toRun, strlen(toRun));
cmdLinePos += strlen(toRun);
if (myCmdLine[0] == '"') ++myCmdLine;
myCmdLine += strlen(argv[0]);
if (myCmdLine[0] == '"') ++myCmdLine;
if (myCmdLine[0] == ' ') ++myCmdLine;
strncpy(cmdLinePos, myCmdLine, (cmdLine + 32767) - cmdLinePos);
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(NULL,
cmdLine, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
}

View File

Binary file not shown.

View File

@@ -1,27 +1,46 @@
# Docker image to facilitate building Element Desktop's native bits using a glibc version with broader compatibility
FROM rust:buster
FROM buildpack-deps:bionic-curl
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 && \
apt-get -y -qq install --no-install-recommends \
RUN curl -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 -qq dist-upgrade && \
# add repo for git-lfs
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
# git ssh for using as docker image on CircleCI
# python for node-gyp
# rpm is required for FPM to build rpm package
# tclsh is required for building SQLite as part of SQLCipher
tcl \
# libsecret-1-dev is required even for prebuild keytar
libsecret-1-dev \
# libsecret-1-dev and libgnome-keyring-dev are required even for prebuild keytar
apt-get -qq install --no-install-recommends qtbase5-dev bsdtar build-essential autoconf libssl-dev gcc-multilib g++-multilib lzip rpm python libcurl4 git git-lfs ssh unzip tcl \
libsecret-1-dev libgnome-keyring-dev \
libopenjp2-tools \
# Used by seshat (when not SQLCIPHER_STATIC) \
libsqlcipher-dev && \
# git-lfs
git lfs install && \
apt-get purge -y --auto-remove && rm -rf /var/lib/apt/lists/*
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
WORKDIR /project
ENV NODE_VERSION 20.15.1
ARG TARGETOS
ARG TARGETARCH
COPY setup.sh /setup.sh
RUN /setup.sh
# fix error /usr/local/bundle/gems/fpm-1.5.0/lib/fpm/package/freebsd.rb:72:in `encode': "\xE2" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)
# http://jaredmarkell.com/docker-and-locales/
# http://askubuntu.com/a/601498
ENV LANG C.UTF-8
ENV LANGUAGE C.UTF-8
ENV LC_ALL C.UTF-8
ENV DEBUG_COLORS true
ENV FORCE_COLOR true
ENV NODE_VERSION 16.18.1
# this package is used for snapcraft and we should not clear apt list - to avoid apt-get update during snap build
RUN curl -L https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz | tar xz -C /usr/local --strip-components=1 && \
unlink /usr/local/CHANGELOG.md && unlink /usr/local/LICENSE && unlink /usr/local/README.md && \
# https://github.com/npm/npm/issues/4531
npm config set unsafe-perm true
ENV RUSTUP_HOME=/usr/local/rustup \
CARGO_HOME=/usr/local/cargo \
PATH=/usr/local/cargo/bin:$PATH
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal

View File

@@ -1,7 +0,0 @@
#!/usr/bin/env bash
set -x
declare -A archMap=(["amd64"]="x64" ["arm64"]="arm64")
ARCH="${archMap["$TARGETARCH"]}"
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 +0,0 @@
# Summary
- [Introduction](../README.md)
# Build
- [Native Node modules](native-node-modules.md)
- [Windows requirements](windows-requirements.md)
# Distribution
- [Updates](updates.md)
- [Packaging](packaging.md)
# Setup
- [Config](config.md)

View File

@@ -1,15 +0,0 @@
# Configuration
All Element Web options documented [here](https://github.com/vector-im/element-web/blob/develop/docs/config.md) can be used as well as the following:
---
The app contains a configuration file specified at build time using [these instructions](https://github.com/vector-im/element-desktop/#config).
This config can be overwritten by the end using by creating a `config.json` file at the paths described [here](https://github.com/vector-im/element-desktop/#user-specified-configjson).
After changing the config, the app will need to be exited fully (including via the task tray) and re-started.
---
1. `update_base_url`: Specifies the URL of the update server, see [document](https://github.com/vector-im/element-desktop/blob/develop/docs/updates.md).
2. `web_base_url`: Specifies the Element Web URL when performing actions such as popout widget. Defaults to `https://app.element.io/`.

View File

@@ -17,14 +17,13 @@ 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).
Then, to build for an architecture selected automatically based on your system (recommended), run:
```
yarn run build:native
```
@@ -71,9 +70,9 @@ as usual using:
On Windows & macOS we always statically link libsqlcipher for it is not generally available.
On Linux by default we will use a system package, on debian & ubuntu this is `libsqlcipher0`,
but this is problematic for some other packages, and we found that it may crashes for unknown reasons.
By including `SQLCIPHER_BUNDLED=1` in the build environment, the build scripts will fully statically
link sqlcipher, including a static build of OpenSSL.
but this is problematic for some other packages.
By including `SQLCIPHER_STATIC=1` in the build environment, the build scripts will statically link sqlcipher,
note that this will want a `libcrypto1.1` shared library available in the system.
More info can be found at https://github.com/matrix-org/seshat/issues/102
and https://github.com/vector-im/element-web/issues/20926.
@@ -83,19 +82,15 @@ and https://github.com/vector-im/element-web/issues/20926.
### macOS
On macOS, you can build universal native modules too:
```
yarn run build:native:universal
```
...or you can build for a specific architecture:
```
yarn run build:native --target x86_64-apple-darwin
```
or
```
yarn run build:native --target aarch64-apple-darwin
```
@@ -110,13 +105,10 @@ yarn run build:universal
### Windows
If you're on Windows, you can choose to build specifically for 32 or 64 bit:
```
yarn run build:32
```
or
```
yarn run build:64
```
@@ -152,6 +144,6 @@ The current set of native modules are stored in `.hak/hakModules`,
so you can use this to check what architecture is currently in place, eg:
```
$ lipo -info .hak/hakModules/keytar/build/Release/keytar.node
Architectures in the fat file: .hak/hakModules/keytar/build/Release/keytar.node are: x86_64 arm64
$ lipo -info .hak/hakModules/keytar/build/Release/keytar.node
Architectures in the fat file: .hak/hakModules/keytar/build/Release/keytar.node are: x86_64 arm64
```

View File

@@ -1,55 +0,0 @@
## Packaging nightlies
Element Desktop nightly builds are build automatically by the [Github Actions workflow](https://github.com/vector-im/element-desktop/blob/develop/.github/workflows/build_and_deploy.yaml).
The schedule is currently set for once a day at 9am UTC. It will deploy to packages.element.io upon completion.
## Triggering a manual nightly build
Simply go to https://github.com/vector-im/element-desktop/actions/workflows/build_and_deploy.yaml
1. Click `Run workflow`
1. Feel free to make changes to the checkboxes depending on the circumstances
1. Click the green `Run workflow`
## Packaging releases
**Don't do this for RCs! We don't build Element Desktop for RCs.**
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.
**Both of these are done automatically when you run the release automation.**
The packaging is kicked off automagically for you when a Github Release for Element Desktop is published.
### More detail on the github actions
We moved to Github Actions for the following reasons:
1. Removing single point of failure
2. Improving reliability
3. Unblocking the packaging on a single individual
4. Improving parallelism
The Windows builds are signed by SSL.com using their Cloud Key Adapter for eSigner.
This allows us to use Microsoft's signtool to interface with eSigner and send them a hash of the exe along with
credentials in exchange for a signed certificate which we attach onto all the relevant files.
The Apple builds are signed using standard code signing means and then notarised to appease GateKeeper.
The Linux builds are distributed via a signed reprepro repository.
The packages.element.io site is a public Cloudflare R2 bucket which is deployed to solely from Github Actions.
The main bucket in R2 is `packages-element-io` which is a direct mapping of packages.element.io,
we have a workflow which generates the index.html files there to imitate a public index which Cloudflare does not currently support.
The reprepro database lives in `packages-element-io-db`.
There is an additional pair of buckets of same name but appended with `-test` which can be used for testing,
these land on https://packages-element-io-test.element.io/.
### Debian/Ubuntu Distributions
We used to add a new distribution to match each Debian and Ubuntu release. As of April 2020, we have created a `default` distribution that everyone can use (since the packages have never differed by distribution anyway).
The distribution configuration lives in https://github.com/vector-im/packages.element.io/blob/master/debian/conf/distributions as a canonical source.

View File

@@ -1,15 +0,0 @@
The Desktop app is capable of self-updating on macOS and Windows.
The update server base url is configurable as `update_base_url` in config.json and can be served by a static file host,
CDN or object storage.
Currently all packaging & deployment is handled by [Github actions](https://github.com/vector-im/element-desktop/blob/develop/.github/workflows/build_and_deploy.yaml)
# Windows
On Windows the update mechanism used is [Squirrel.Windows](https://github.com/Squirrel/Squirrel.Windows)
and can be served by any compatible Squirrel server, such as https://github.com/Tiliq/squirrel-server
# macOS
On macOS the update mechanism used is [Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac)
using the newer JSON format as documented [here](https://github.com/Squirrel/Squirrel.Mac#update-file-json-format).

View File

@@ -2,28 +2,25 @@
## Requirements to build native modules
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/)
- [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 14](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`.
If you want to be able to build x86 targets from an x64 host install the right toolchain:
```cmd
rustup toolchain install stable-i686-pc-windows-msvc
rustup target add i686-pc-windows-msvc

View File

@@ -1,234 +0,0 @@
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.
*
* 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.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
* Removes libsqlcipher0 recommended dependency if env SQLCIPHER_BUNDLED is asserted.
* Passes $ED_DEBIAN_CHANGELOG to build.deb.fpm if specified
*/
const NIGHTLY_APP_ID = "im.riot.nightly";
const NIGHTLY_DEB_NAME = "element-nightly";
interface Pkg {
name: string;
productName: string;
description: string;
version: string;
}
type Writable<T> = NonNullable<
T extends Function ? T : T extends object ? { -readonly [K in keyof T]: Writable<T[K]> } : T
>;
const pkg: Pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
interface Configuration extends BaseConfiguration {
extraMetadata: Partial<Pick<Pkg, "version">> & Omit<Pkg, "version">;
linux: BaseConfiguration["linux"];
win: BaseConfiguration["win"];
mac: BaseConfiguration["mac"];
deb: {
fpm: string[];
} & BaseConfiguration["deb"];
}
/**
* @type {import('electron-builder').Configuration}
* @see https://www.electron.build/configuration/configuration
*/
const config: Writable<Configuration> = {
appId: "im.riot.app",
asarUnpack: "**/*.node",
afterPack: async (context: AfterPackContext) => {
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",
{
from: ".hak/hakModules",
to: "node_modules",
},
"lib/**",
],
extraResources: [
{
from: "res/img",
to: "img",
},
"webapp.asar",
],
extraMetadata: {
name: pkg.name,
productName: pkg.productName,
description: pkg.description,
},
linux: {
target: ["tar.gz", "deb"],
category: "Network;InstantMessaging;Chat",
maintainer: "support@element.io",
icon: "build/icons",
},
deb: {
packageCategory: "net",
depends: [
"libgtk-3-0",
"libnotify4",
"libnss3",
"libxss1",
"libxtst6",
"xdg-utils",
"libatspi2.0-0",
"libuuid1",
"libsecret-1-0",
"libasound2",
"libgbm1",
],
recommends: ["libsqlcipher0", "element-io-archive-keyring"],
fpm: [
"--deb-field",
"Replaces: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)",
"--deb-field",
"Breaks: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)",
],
},
mac: {
category: "public.app-category.social-networking",
darkModeSupport: true,
hardenedRuntime: true,
gatekeeperAssess: true,
entitlements: "./build/entitlements.mac.plist",
icon: "build/icons/icon.icns",
},
win: {
target: ["squirrel", "msi"],
signingHashAlgorithms: ["sha256"],
icon: "build/icons/icon.ico",
},
msi: {
perMachine: true,
},
directories: {
output: "dist",
},
protocols: [
{
name: "element",
schemes: ["io.element.desktop", "element"],
},
],
};
/**
* Allow specifying windows signing cert via env vars
* @param {string} process.env.ED_SIGNTOOL_SUBJECT_NAME
* @param {string} process.env.ED_SIGNTOOL_THUMBPRINT
*/
if (process.env.ED_SIGNTOOL_SUBJECT_NAME && 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,
};
}
/**
* Allow specifying nightly version via env var
* @param {string} process.env.ED_NIGHTLY
*/
if (process.env.ED_NIGHTLY) {
config.deb.fpm = []; // Clear the fpm as the breaks deb fields don't apply to nightly
config.appId = NIGHTLY_APP_ID;
config.extraMetadata.productName += " Nightly";
config.extraMetadata.name += "-nightly";
config.extraMetadata.description += " (nightly unstable build)";
config.deb.fpm.push("--name", NIGHTLY_DEB_NAME);
let version = process.env.ED_NIGHTLY;
if (os.platform() === "win32") {
// The windows packager relies on parsing this as semver, so we have to make it look like one.
// This will give our update packages really stupid names, but we probably can't change that either
// because squirrel windows parses them for the version too. We don't really care: nobody sees them.
// We just give the installer a static name, so you'll just see this in the 'about' dialog.
// Turns out if you use 0.0.0 here it makes Squirrel windows crash, so we use 0.0.1.
version = "0.0.1-nightly." + version;
}
config.extraMetadata.version = version;
}
if (os.platform() === "linux") {
// Electron crashes on debian if there's a space in the path.
// https://github.com/vector-im/element-web/issues/13171
config.extraMetadata.productName = config.extraMetadata.productName.replace(/ /g, "-");
/**
* Allow specifying deb changelog via env var
* @param {string} process.env.ED_DEB_CHANGELOG
*/
if (process.env.ED_DEBIAN_CHANGELOG) {
config.deb.fpm.push(`--deb-changelog=${process.env.ED_DEBIAN_CHANGELOG}`);
}
if (process.env.SQLCIPHER_BUNDLED) {
// Remove sqlcipher dependency when using bundled
config.deb.recommends = config.deb.recommends?.filter((d) => d !== "libsqlcipher0");
}
}
export default config;

View File

@@ -1,14 +1,6 @@
{
"update_base_url": "https://packages.element.io/nightly/update/",
"default_server_name": "matrix.org",
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix-client.matrix.org"
},
"m.identity_server": {
"base_url": "https://vector.im"
}
},
"brand": "Element Nightly",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
@@ -19,11 +11,16 @@
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"hosting_signup_link": "https://element.io/matrix-services?utm_source=element-web&utm_medium=web",
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
"uisi_autorageshake_app": "element-auto-uisi",
"show_labs_settings": true,
"room_directory": {
"servers": ["matrix.org", "gitter.im"]
"showLabsSettings": true,
"roomDirectory": {
"servers": [
"matrix.org",
"gitter.im",
"libera.chat"
]
},
"enable_presence_by_hs_url": {
"https://matrix.org": false,
@@ -44,22 +41,16 @@
"environment": "nightly"
},
"posthog": {
"project_api_key": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"api_host": "https://posthog.element.io"
"projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"apiHost": "https://posthog.element.io"
},
"privacy_policy_url": "https://element.io/cookie-policy",
"features": {
"threadsActivityCentre": true,
"feature_spotlight": true,
"feature_video_rooms": true,
"feature_element_call_video_rooms": true,
"feature_new_room_decoration_ui": true
},
"setting_defaults": {
"RustCrypto.staged_rollout_percent": 100
"feature_video_rooms": true
},
"element_call": {
"url": "https://call.element.dev"
"url": "https://element-call.netlify.app"
},
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}

View File

@@ -0,0 +1,12 @@
Package: element-nightly
License: Apache-2.0
Vendor: support@element.io
Architecture: amd64
Maintainer: support@element.io
Depends: libgtk-3-0, libnotify4, libnss3, libxss1, libxtst6, xdg-utils, libatspi2.0-0, libuuid1, libsecret-1-0, libasound2, libgbm1
Recommends: libappindicator3-1, libsqlcipher0
Section: net
Priority: extra
Homepage: https://element.io/
Description:
riot.im A feature-rich client for Matrix.org (nightly unstable build).

View File

@@ -0,0 +1,9 @@
Package: riot-nightly
Version: 2020071502
Depends: element-nightly
Maintainer: packages@element.io
Architecture: all
Priority: optional
Section: oldlibs
Description: transitional package
This is a transitional package. It can safely be removed.

View File

@@ -0,0 +1,81 @@
Origin: riot.im
Codename: default
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Suite: oldoldstable
Codename: jessie
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Suite: oldstable
Codename: stretch
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Suite: stable
Codename: buster
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Suite: testing
Codename: bullseye
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Suite: unstable
Codename: sid
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Codename: xenial
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Codename: bionic
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Codename: cosmic
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Codename: disco
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal
Origin: riot.im
Codename: eoan
Architectures: amd64 i386 source
Components: main
SignWith: D7B0B66941D01538
Tracking: minimal

View File

@@ -1,14 +1,6 @@
{
"update_base_url": "https://packages.element.io/desktop/update/",
"default_server_name": "matrix.org",
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix-client.matrix.org"
},
"m.identity_server": {
"base_url": "https://vector.im"
}
},
"brand": "Element",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
@@ -19,12 +11,17 @@
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"hosting_signup_link": "https://element.io/matrix-services?utm_source=element-web&utm_medium=web",
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
"uisi_autorageshake_app": "element-auto-uisi",
"room_directory": {
"servers": ["matrix.org", "gitter.im"]
"roomDirectory": {
"servers": [
"matrix.org",
"gitter.im",
"libera.chat"
]
},
"show_labs_settings": false,
"showLabsSettings": false,
"enable_presence_by_hs_url": {
"https://matrix.org": false,
"https://matrix-client.matrix.org": false
@@ -40,12 +37,9 @@
}
],
"posthog": {
"project_api_key": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"api_host": "https://posthog.element.io"
"projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"apiHost": "https://posthog.element.io"
},
"privacy_policy_url": "https://element.io/cookie-policy",
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx",
"setting_defaults": {
"RustCrypto.staged_rollout_percent": 60
}
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}

View File

@@ -0,0 +1,14 @@
Package: element-desktop
License: Apache-2.0
Vendor: support@element.io
Architecture: amd64
Maintainer: support@element.io
Depends: libgtk-3-0, libnotify4, libnss3, libxss1, libxtst6, xdg-utils, libatspi2.0-0, libuuid1, libsecret-1-0, libasound2, libgbm1
Recommends: libappindicator3-1, libsqlcipher0
Replaces: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)
Breaks: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)
Section: net
Priority: extra
Homepage: https://element.io/
Description:
A feature-rich client for Matrix.org

View File

@@ -0,0 +1,9 @@
Package: riot-desktop
Version: 1.7.0
Depends: element-desktop
Maintainer: packages@element.io
Architecture: all
Priority: optional
Section: oldlibs
Description: transitional package
This is a transitional package. It can safely be removed.

View File

@@ -14,11 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import path from "path";
import childProcess from "child_process";
import path from 'path';
import childProcess from 'child_process';
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
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();
@@ -26,18 +26,15 @@ export default async function buildKeytar(hakEnv: HakEnv, moduleInfo: Dependency
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()],
path.join(moduleInfo.nodeModuleBinDir, 'node-gyp' + (hakEnv.isWin() ? '.cmd' : '')),
['rebuild'],
{
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(),
stdio: 'inherit',
},
);
proc.on("exit", (code) => {
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});

View File

@@ -14,20 +14,20 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import childProcess from "child_process";
import childProcess from 'child_process';
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
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
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"],
stdio: ['ignore'],
});
proc.on("exit", (code) => {
proc.on('exit', (code) => {
if (code !== 0) {
reject("Can't find " + tool);
} else {

View File

@@ -14,42 +14,319 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import childProcess from "child_process";
import path from 'path';
import childProcess from 'child_process';
import mkdirp from 'mkdirp';
import fsExtra from 'fs-extra';
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
import HakEnv from '../../scripts/hak/hakEnv';
import { DependencyInfo } from '../../scripts/hak/dep';
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
export default async function(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
if (hakEnv.isWin()) {
await buildOpenSslWin(hakEnv, moduleInfo);
await buildSqlCipherWin(hakEnv, moduleInfo);
} else if (hakEnv.wantsStaticSqlCipherUnix()) {
await buildSqlCipherUnix(hakEnv, moduleInfo);
}
await buildMatrixSeshat(hakEnv, moduleInfo);
}
async function buildOpenSslWin(hakEnv: HakEnv, moduleInfo: DependencyInfo) {
const version = moduleInfo.cfg.dependencies.openssl;
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `openssl-${version}`);
const openSslArch = hakEnv.getTargetArch() === 'x64' ? 'VC-WIN64A' : 'VC-WIN32';
console.log("Building openssl in " + openSslDir);
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(
'perl',
[
'Configure',
'--prefix=' + moduleInfo.depPrefix,
// sqlcipher only uses about a tiny part of openssl. We link statically
// so will only pull in the symbols we use, but we may as well turn off
// as much as possible to save on build time.
'no-afalgeng',
'no-capieng',
'no-cms',
'no-ct',
'no-deprecated',
'no-dgram',
'no-dso',
'no-ec',
'no-ec2m',
'no-gost',
'no-nextprotoneg',
'no-ocsp',
'no-sock',
'no-srp',
'no-srtp',
'no-tests',
'no-ssl',
'no-tls',
'no-dtls',
'no-shared',
'no-aria',
'no-camellia',
'no-cast',
'no-chacha',
'no-cmac',
'no-des',
'no-dh',
'no-dsa',
'no-ecdh',
'no-ecdsa',
'no-idea',
'no-md4',
'no-mdc2',
'no-ocb',
'no-poly1305',
'no-rc2',
'no-rc4',
'no-rmd160',
'no-scrypt',
'no-seed',
'no-siphash',
'no-sm2',
'no-sm3',
'no-sm4',
'no-whirlpool',
openSslArch,
],
{
cwd: openSslDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(
'nmake',
['build_libs'],
{
cwd: openSslDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(
'nmake',
['install_dev'],
{
cwd: openSslDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
}
async function buildSqlCipherWin(hakEnv: HakEnv, moduleInfo: DependencyInfo) {
const version = moduleInfo.cfg.dependencies.sqlcipher;
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
const buildDir = path.join(sqlCipherDir, 'bld');
await mkdirp(buildDir);
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(
'nmake',
['/f', path.join('..', 'Makefile.msc'), 'libsqlite3.lib', 'TOP=..'],
{
cwd: buildDir,
stdio: 'inherit',
env: Object.assign({}, process.env, {
CCOPTS: "-DSQLITE_HAS_CODEC -I" + path.join(moduleInfo.depPrefix, 'include'),
LTLIBPATHS: "/LIBPATH:" + path.join(moduleInfo.depPrefix, 'lib'),
LTLIBS: "libcrypto.lib",
}),
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
await fsExtra.copy(
path.join(buildDir, 'libsqlite3.lib'),
path.join(moduleInfo.depPrefix, 'lib', 'sqlcipher.lib'),
);
await fsExtra.copy(
path.join(buildDir, 'sqlite3.h'),
path.join(moduleInfo.depPrefix, 'include', 'sqlcipher.h'),
);
}
async function buildSqlCipherUnix(hakEnv: HakEnv, moduleInfo: DependencyInfo) {
const version = moduleInfo.cfg.dependencies.sqlcipher;
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
const args = [
'--prefix=' + moduleInfo.depPrefix + '',
'--enable-tempstore=yes',
'--enable-shared=no',
'--enable-tcl=no',
];
if (hakEnv.isMac()) {
args.push('--with-crypto-lib=commoncrypto');
}
if (hakEnv.wantsStaticSqlCipherUnix()) {
args.push('--enable-tcl=no');
if (hakEnv.isLinux()) {
args.push('--with-pic=yes');
}
}
if (!hakEnv.isHost()) {
// In the nonsense world of `configure`, it is assumed you are building
// a compiler like `gcc`, so the `host` option actually means the target
// the build output runs on.
args.push(`--host=${hakEnv.getTargetId()}`);
}
const cflags = [
'-DSQLITE_HAS_CODEC',
];
if (!hakEnv.isHost()) {
// `clang` uses more logical option naming.
cflags.push(`--target=${hakEnv.getTargetId()}`);
}
if (cflags.length) {
args.push(`CFLAGS=${cflags.join(' ')}`);
}
const ldflags: string[] = [];
if (hakEnv.isMac()) {
ldflags.push('-framework Security');
ldflags.push('-framework Foundation');
}
if (ldflags.length) {
args.push(`LDFLAGS=${ldflags.join(' ')}`);
}
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(
path.join(sqlCipherDir, 'configure'),
args,
{
cwd: sqlCipherDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(
'make',
[],
{
cwd: sqlCipherDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(
'make',
['install'],
{
cwd: sqlCipherDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
}
async function buildMatrixSeshat(hakEnv: HakEnv, moduleInfo: DependencyInfo) {
// seshat now uses n-api so we shouldn't need to specify a node version to
// build against, but it does seems to still need something in here, so leaving
// it for now: we should confirm how much of this it still actually needs.
const env = hakEnv.makeGypEnv();
if (!hakEnv.isLinux() || hakEnv.wantsStaticSqlCipherUnix()) {
Object.assign(env, {
SQLCIPHER_STATIC: 1,
SQLCIPHER_LIB_DIR: path.join(moduleInfo.depPrefix, 'lib'),
SQLCIPHER_INCLUDE_DIR: path.join(moduleInfo.depPrefix, 'include'),
});
}
if (hakEnv.isLinux() && hakEnv.wantsStaticSqlCipherUnix()) {
// Ensure Element uses the statically-linked seshat build, and prevent other applications
// from attempting to use this one. Detailed explanation:
//
// RUSTFLAGS
// An environment variable containing a list of arguments to pass to rustc.
// -Clink-arg=VALUE
// A rustc argument to pass a single argument to the linker.
// -Wl,
// gcc syntax to pass an argument (from gcc) to the linker (ld).
// -Bsymbolic:
// Prefer local/statically linked symbols over those in the environment.
// Prevent overriding native libraries by LD_PRELOAD etc.
// --exclude-libs ALL
// Prevent symbols from being exported by any archive libraries.
// Reduces output filesize and prevents being dynamically linked against.
env.RUSTFLAGS = '-Clink-arg=-Wl,-Bsymbolic -Clink-arg=-Wl,--exclude-libs,ALL';
}
if (hakEnv.isWin()) {
env.RUSTFLAGS = '-Ctarget-feature=+crt-static -Clink-args=libcrypto.lib';
// Note that in general, you can specify targets in Rust without having to have
// the matching toolchain, however for this, cargo gets confused when building
// the build scripts since they run on the host, but vcvarsall.bat sets the c
// compiler in the path to be the one for the target, so we just use the matching
// toolchain for the target architecture which makes everything happy.
env.RUSTUP_TOOLCHAIN = `stable-${hakEnv.getTargetId()}`;
}
if (!hakEnv.isHost()) {
env.CARGO_BUILD_TARGET = hakEnv.getTargetId();
}
console.log("Running yarn install");
console.log("Running neon with env", env);
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 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) => {
const proc = childProcess.spawn(
path.join(moduleInfo.nodeModuleBinDir, 'neon' + (hakEnv.isWin() ? '.cmd' : '')),
['build', '--release'],
{
cwd: moduleInfo.moduleBuildDir,
env,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});

View File

@@ -14,32 +14,49 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import childProcess from "child_process";
import fsProm from "fs/promises";
import childProcess from 'child_process';
import fsProm from 'fs/promises';
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
import HakEnv from '../../scripts/hak/hakEnv';
import { DependencyInfo } from '../../scripts/hak/dep';
export default async function(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
if (hakEnv.wantsStaticSqlCipher()) {
// of course tcl doesn't have a --version
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn('tclsh', [], {
stdio: ['pipe', 'ignore', 'ignore'],
});
proc.on('exit', (code) => {
if (code !== 0) {
reject("Can't find tclsh - have you installed TCL?");
} else {
resolve();
}
});
proc.stdin.end();
});
}
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const tools = [
["rustc", "--version"],
["python", "--version"], // node-gyp uses python for reasons beyond comprehension
['rustc', '--version'],
['python', '--version'], // node-gyp uses python for reasons beyond comprehension
];
if (hakEnv.isWin()) {
tools.push(["perl", "--version"]); // for openssl configure
tools.push(["nasm", "-v"]); // for openssl building
tools.push(["patch", "--version"]); // to patch sqlcipher Makefile.msc
tools.push(["nmake", "/?"]);
tools.push(['perl', '--version']); // for openssl configure
tools.push(['nasm', '-v']); // for openssl building
tools.push(['patch', '--version']); // to patch sqlcipher Makefile.msc
tools.push(['nmake', '/?']);
} else {
tools.push(["make", "--version"]);
tools.push(['make', '--version']);
}
for (const tool of tools) {
await new Promise<void>((resolve, reject) => {
const proc = childProcess.spawn(tool[0], tool.slice(1), {
stdio: ["ignore"],
stdio: ['ignore'],
});
proc.on("exit", (code) => {
proc.on('exit', (code) => {
if (code !== 0) {
reject("Can't find " + tool);
} else {
@@ -51,26 +68,19 @@ export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Prom
// Ensure Rust target exists (nb. we avoid depending on rustup)
await new Promise((resolve, reject) => {
const rustc = childProcess.execFile(
"rustc",
["--target", hakEnv.getTargetId(), "--emit=obj", "-o", "tmp", "-"],
(err, out) => {
if (err) {
reject(
"rustc can't build for target " +
hakEnv.getTargetId() +
": ensure target is installed via `rustup target add " +
hakEnv.getTargetId() +
"` " +
"or your package manager if not using `rustup`",
);
}
fsProm.unlink("tmp").then(resolve);
},
);
rustc.stdin!.write("fn main() {}");
rustc.stdout!.pipe(process.stdout);
rustc.stderr!.pipe(process.stderr);
rustc.stdin!.end();
const rustc = childProcess.execFile('rustc', [
'--target', hakEnv.getTargetId(), '-o', 'tmp', '-',
], (err, out) => {
if (err) {
reject(
"rustc can't build for target " + hakEnv.getTargetId() +
": ensure target is installed via `rustup target add " + hakEnv.getTargetId() + "` " +
"or your package manager if not using `rustup`",
);
}
fsProm.unlink('tmp').then(resolve);
});
rustc.stdin.write('fn main() {}');
rustc.stdin.end();
});
}

View File

@@ -0,0 +1,132 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import path from 'path';
import childProcess from 'child_process';
import fs from 'fs';
import fsProm from 'fs/promises';
import needle from 'needle';
import tar from 'tar';
import HakEnv from '../../scripts/hak/hakEnv';
import { DependencyInfo } from '../../scripts/hak/dep';
export default async function(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
if (hakEnv.wantsStaticSqlCipher()) {
await getSqlCipher(hakEnv, moduleInfo);
}
if (hakEnv.isWin()) {
await getOpenSsl(hakEnv, moduleInfo);
}
}
async function getSqlCipher(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const version = moduleInfo.cfg.dependencies.sqlcipher;
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
let haveSqlcipher: boolean;
try {
await fsProm.stat(sqlCipherDir);
haveSqlcipher = true;
} catch (e) {
haveSqlcipher = false;
}
if (haveSqlcipher) return;
const sqlCipherTarball = path.join(moduleInfo.moduleDotHakDir, `sqlcipher-${version}.tar.gz`);
let haveSqlcipherTar: boolean;
try {
await fsProm.stat(sqlCipherTarball);
haveSqlcipherTar = true;
} catch (e) {
haveSqlcipherTar = false;
}
if (!haveSqlcipherTar) {
const bob = needle('get', `https://github.com/sqlcipher/sqlcipher/archive/v${version}.tar.gz`, {
follow: 10,
output: sqlCipherTarball,
});
await bob;
}
// Extract the tarball to per-target directories, then we avoid cross-contaiminating archs
await tar.x({
file: sqlCipherTarball,
cwd: moduleInfo.moduleTargetDotHakDir,
});
if (hakEnv.isWin()) {
// On Windows, we need to patch the makefile because it forces TEMP_STORE to
// default to files (1) but the README specifically says you '*must*' set it
// set it to 2 (default to memory).
const patchFile = path.join(moduleInfo.moduleHakDir, `sqlcipher-${version}-win.patch`);
await new Promise<void>((resolve, reject) => {
const readStream = fs.createReadStream(patchFile);
const proc = childProcess.spawn(
'patch',
['-p1'],
{
cwd: sqlCipherDir,
stdio: ['pipe', 'inherit', 'inherit'],
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
readStream.pipe(proc.stdin);
});
}
}
async function getOpenSsl(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const version = moduleInfo.cfg.dependencies.openssl;
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `openssl-${version}`);
let haveOpenSsl: boolean;
try {
await fsProm.stat(openSslDir);
haveOpenSsl = true;
} catch (e) {
haveOpenSsl = false;
}
if (haveOpenSsl) return;
const openSslTarball = path.join(moduleInfo.moduleDotHakDir, `openssl-${version}.tar.gz`);
let haveOpenSslTar: boolean;
try {
await fsProm.stat(openSslTarball);
haveOpenSslTar = true;
} catch (e) {
haveOpenSslTar = false;
}
if (!haveOpenSslTar) {
await needle('get', `https://www.openssl.org/source/openssl-${version}.tar.gz`, {
follow: 10,
output: openSslTarball,
});
}
console.log("extracting " + openSslTarball + " in " + moduleInfo.moduleTargetDotHakDir);
await tar.x({
file: openSslTarball,
cwd: moduleInfo.moduleTargetDotHakDir,
});
}

View File

@@ -1,7 +1,13 @@
{
"scripts": {
"check": "check.ts",
"fetchDeps": "fetchDeps.ts",
"build": "build.ts"
},
"copy": "index.node"
"prune": "native",
"copy": "native/index.node",
"dependencies": {
"openssl": "1.1.1f",
"sqlcipher": "4.3.0"
}
}

View File

@@ -0,0 +1,14 @@
diff -Nur sqlcipher-4.3.0-orig/Makefile.msc sqlcipher-4.3.0-mod/Makefile.msc
--- sqlcipher-4.3.0-orig/Makefile.msc 2019-12-20 16:40:26.000000000 +0000
+++ sqlcipher-4.3.0-mod/Makefile.msc 2020-02-14 11:31:39.000000000 +0000
@@ -985,8 +985,8 @@
# default to file, 2 to default to memory, and 3 to force temporary
# tables to always be in memory.
#
-TCC = $(TCC) -DSQLITE_TEMP_STORE=1
-RCC = $(RCC) -DSQLITE_TEMP_STORE=1
+TCC = $(TCC) -DSQLITE_TEMP_STORE=2
+RCC = $(RCC) -DSQLITE_TEMP_STORE=2
# Enable/disable loadable extensions, and other optional features
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).

View File

@@ -1,14 +1,17 @@
{
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true,
"target": "es2022",
"sourceMap": false,
"strict": true,
"lib": ["es2022"]
},
"include": ["../scripts/@types/*.d.ts", "./**/*.ts"],
"ts-node": {
"transpileOnly": true
}
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true,
"target": "es2016",
"sourceMap": false,
"lib": [
"es2019",
]
},
"include": [
"./**/*.ts"
],
"ts-node": {
"transpileOnly": true
}
}

17
knip.ts
View File

@@ -1,17 +0,0 @@
import { KnipConfig } from "knip";
export default {
entry: ["src/electron-main.ts", "src/preload.ts", "electron-builder.ts", ".eslintrc-*.js", "scripts/**", "hak/**"],
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/*",
],
ignoreBinaries: ["jq", "scripts/in-docker.sh"],
} satisfies KnipConfig;

View File

@@ -1,37 +0,0 @@
{
"readKey": "a7688614897667993891-866e2615b0a22e6ccef56aea9b10e815efa3e1296752a7a30bd9925f1a8f33e7",
"upload": {
"type": "json",
"keySeparator": "|",
"deprecate": "file",
"features": ["plural_object", "filter_untranslated"],
"files": [
{
"pattern": "src/i18n/strings/en_EN.json",
"file": "element-desktop.json",
"lang": "inherited"
},
{
"group": "existing",
"pattern": "src/i18n/strings/*.json",
"file": "element-desktop.json",
"excludes": ["src/i18n/strings/en_EN.json"],
"lang": "${autodetectLang}"
}
]
},
"download": {
"files": [
{
"conditions": "equals: ${file}, element-desktop.json",
"output": "src/i18n/strings/${langLsrUnderscore}.json"
}
],
"includeSourceLang": "${includeSourceLang|false}",
"langAliases": {
"en": "en-EN"
}
}
}

View File

@@ -1,128 +1,167 @@
{
"name": "element-desktop",
"productName": "Element",
"main": "lib/electron-main.js",
"version": "1.11.78",
"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"
"name": "element-desktop",
"productName": "Element",
"main": "lib/electron-main.js",
"version": "1.11.15",
"description": "A feature-rich client for Matrix.org",
"author": "Element",
"repository": {
"type": "git",
"url": "https://github.com/vector-im/element-desktop"
},
"license": "Apache-2.0",
"files": [],
"scripts": {
"i18n": "matrix-gen-i18n",
"prunei18n": "matrix-prune-i18n",
"diff-i18n": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && matrix-gen-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 && node scripts/fetch-package.js",
"asar-webapp": "asar p webapp webapp.asar",
"start": "yarn run build:ts && yarn run build:res && electron .",
"lint": "yarn lint:types && yarn lint:js",
"lint:js": "eslint --max-warnings 0 src scripts hak",
"lint:js-fix": "eslint --fix src scripts hak",
"lint:types": "tsc --noEmit && tsc -p scripts/hak/tsconfig.json --noEmit && tsc -p hak/tsconfig.json --noEmit",
"build:native": "yarn run hak",
"build:native:universal": "yarn run hak --target x86_64-apple-darwin fetchandbuild && yarn run hak --target aarch64-apple-darwin fetchandbuild && yarn run hak --target x86_64-apple-darwin --target aarch64-apple-darwin copyandlink",
"build:32": "yarn run build:ts && yarn run build:res && electron-builder --ia32",
"build:64": "yarn run build:ts && yarn run build:res && electron-builder --x64",
"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": "node scripts/copy-res.js",
"docker:setup": "docker build -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",
"debrepo": "scripts/mkrepo.sh",
"clean": "rimraf webapp.asar dist packages deploys lib",
"hak": "ts-node scripts/hak/index.ts",
"test": "jest"
},
"dependencies": {
"auto-launch": "^5.0.5",
"counterpart": "^0.18.6",
"electron-store": "^8.0.2",
"electron-window-state": "^5.0.3",
"minimist": "^1.2.6",
"node-fetch": "^2",
"png-to-ico": "^2.1.1"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.213.0",
"@babel/core": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@electron/notarize": "^1.2.3",
"@types/auto-launch": "^5.0.1",
"@types/counterpart": "^0.18.1",
"@types/detect-libc": "^1.0.0",
"@types/jest": "^29.0.0",
"@types/minimist": "^1.2.1",
"@types/mkdirp": "^1.0.2",
"@types/node": "^16",
"@types/pacote": "^11.1.1",
"@types/rimraf": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^5.42.0",
"@typescript-eslint/parser": "^5.42.0",
"allchange": "^1.0.6",
"app-builder-lib": "^22.14.10",
"asar": "^2.0.1",
"babel-jest": "^29.0.0",
"chokidar": "^3.5.2",
"detect-libc": "^1.0.3",
"electron": "^21",
"electron-builder": "^23.6.0",
"electron-builder-squirrel-windows": "^23.6.0",
"electron-devtools-installer": "^3.1.1",
"eslint": "^8.26.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-matrix-org": "^0.7.0",
"eslint-plugin-unicorn": "^45.0.0",
"expect-playwright": "^0.8.0",
"find-npm-prefix": "^1.0.2",
"fs-extra": "^10.0.0",
"glob": "^7.1.6",
"jest": "^29.0.0",
"matrix-web-i18n": "^1.3.0",
"mkdirp": "^1.0.3",
"needle": "^2.5.0",
"node-pre-gyp": "^0.15.0",
"pacote": "^11.3.5",
"playwright": "^1.25.0",
"rimraf": "^3.0.2",
"tar": "^6.1.2",
"ts-jest": "^29.0.0",
"ts-node": "^10.9.1",
"typescript": "4.5.5"
},
"hakDependencies": {
"matrix-seshat": "^2.3.3",
"keytar": "^7.9.0"
},
"build": {
"appId": "im.riot.app",
"asarUnpack": "**/*.node",
"files": [
"package.json",
{
"from": ".hak/hakModules",
"to": "node_modules"
},
"lib/**"
],
"extraResources": [
{
"from": "res/img",
"to": "img"
},
"webapp.asar"
],
"linux": {
"target": [
"tar.gz",
"deb"
],
"category": "Network;InstantMessaging;Chat",
"maintainer": "support@element.io",
"desktop": {
"StartupWMClass": "element"
}
},
"license": "Apache-2.0",
"files": [],
"engines": {
"node": ">=18.0.0"
"mac": {
"category": "public.app-category.social-networking",
"darkModeSupport": true
},
"scripts": {
"i18n": "matrix-gen-i18n && yarn i18n:sort && yarn i18n:lint",
"i18n:sort": "jq --sort-keys '.' src/i18n/strings/en_EN.json > src/i18n/strings/en_EN.json.tmp && mv src/i18n/strings/en_EN.json.tmp src/i18n/strings/en_EN.json",
"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 && 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": "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",
"lint:types:scripts": "tsc --noEmit -p scripts/tsconfig.json",
"lint:types:hak": "tsc --noEmit -p hak/tsconfig.json",
"lint:workflows": "find .github/workflows -type f \\( -iname '*.yaml' -o -iname '*.yml' \\) | xargs -I {} sh -c 'echo \"Linting {}\"; action-validator \"{}\"'",
"lint:knip": "knip",
"build:native": "yarn run hak",
"build:native:universal": "yarn run hak --target x86_64-apple-darwin fetchandbuild && yarn run hak --target aarch64-apple-darwin fetchandbuild && yarn run hak --target x86_64-apple-darwin --target aarch64-apple-darwin copyandlink",
"build:32": "yarn run build:ts && yarn run build:res && electron-builder --ia32",
"build:64": "yarn run build:ts && yarn run build:res && electron-builder --x64",
"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": "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": "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"
"win": {
"target": [
"squirrel"
],
"sign": "scripts/electron_winSign"
},
"dependencies": {
"@sentry/electron": "^5.0.0",
"auto-launch": "^5.0.5",
"counterpart": "^0.18.6",
"electron-clear-data": "^1.0.5",
"electron-store": "^8.0.2",
"electron-window-state": "^5.0.3",
"minimist": "^1.2.6",
"node-fetch": "^2",
"png-to-ico": "^2.1.1",
"uuid": "^10.0.0"
"directories": {
"output": "dist"
},
"devDependencies": {
"@action-validator/cli": "^0.6.0",
"@action-validator/core": "^0.6.0",
"@babel/core": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@electron/asar": "^3.2.3",
"@electron/fuses": "^1.7.0",
"@mapbox/node-pre-gyp": "^1.0.11",
"@playwright/test": "1.46.1",
"@types/auto-launch": "^5.0.1",
"@types/counterpart": "^0.18.1",
"@types/minimist": "^1.2.1",
"@types/node": "18.19.45",
"@types/pacote": "^11.1.1",
"@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": "^3.5.2",
"detect-libc": "^2.0.0",
"electron": "^31.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": "^9.0.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-matrix-org": "^1.0.0",
"eslint-plugin-unicorn": "^55.0.0",
"glob": "^11.0.0",
"knip": "^5.0.0",
"matrix-web-i18n": "^3.2.1",
"mkdirp": "^3.0.0",
"pacote": "^18.0.0",
"prettier": "^3.0.0",
"rimraf": "^6.0.0",
"tar": "^6.2.1",
"ts-node": "^10.9.1",
"typescript": "5.5.4"
},
"hakDependencies": {
"matrix-seshat": "^4.0.0",
"keytar": "^7.9.0"
},
"resolutions": {
"@types/node": "18.19.45",
"config-file-ts": "0.2.8-rc1"
}
"afterPack": "scripts/electron_afterPack",
"afterSign": "scripts/electron_afterSign",
"protocols": [
{
"name": "element",
"schemes": [
"element"
]
}
]
},
"jest": {
"testEnvironment": "node",
"testMatch": [
"<rootDir>/test/**/*-test.[jt]s?(x)"
],
"setupFilesAfterEnv": [
"expect-playwright"
]
}
}

View File

@@ -0,0 +1,58 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=JVma
-----END PGP PUBLIC KEY BLOCK-----

View File

Binary file not shown.

View File

@@ -0,0 +1,58 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=JVma
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -0,0 +1,65 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
l91/+ZrRJQ==
=kDqh
-----END PGP PUBLIC KEY BLOCK-----

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -0,0 +1,58 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=LKM4
-----END PGP PUBLIC KEY BLOCK-----

View File

Binary file not shown.

View File

@@ -0,0 +1,63 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGCALb4BEAC7W/JDi9IO6B+YfZPVryXUev9tMeC/57Ar9VaxRJhfxPouAdTg
XGa5f7TIjq2I5gVDo/2RJiA57psMk+wS0+ZL2iTWX1DBtvBv7V4HKCcJ+23JZO6j
vVq1TEDBIX7GAEBiLRz/4nVEuOkABlMHURDjL6g8eSAYHQNfHMVz64pM/0Afr0eA
6RpUl7pWyRu0Uj6yPzUCzXsFp1lVuchXgy3B6EtzckWkVkyCt/8EXTjQVLnjCOo4
XqAjl/mqGLMbxuVl0+eIR4RaHWLCPGvo6QTCzETOnUt2gaWKCMhgOzhAtfkkvGw/
AB35yQGa9YXYGmT6jDeomzOUCjPk3wJZ54t4dBeYHaTgYM5vSsUuSz0yLXl7pdD8
PMuKkyvi1spg0mdT+c3EgWO3sdzeRtZfajtYKySasSN9egcUk6NJxsC2nk6mzVYh
aeYW7/egCnjuPgidKLtWuwj8myLwKDxTZ6VLgzk41ffr5SkhUh1otrkdlYhM82OT
nalG6ZrFcJgoRLLk+xStf6nzfMy5wEqBwiB5jQ9j7h+fl5ScNxe5terb9/MbUpRS
6ZavcatlGDHUIREhVin9/UF05OFGMMUjCpw1t6rW7t/XDFgP/lXHkdL2TZ8R3c1G
dKykzla/qMSoSi2lJGxEjI+zXt0Qc7W4TT+XgmBK4V4vEIgO4IylgR8qowARAQAB
tCNFbGVtZW50IFJlbGVhc2VzIDxyZWxlYXNlc0ByaW90LmltPokCUQQTAQgAOwIb
AwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBHEr++6S3KRSUtsX18e+l++hebEA
BQJggE7WAhkBAAoJEMe+l++hebEARlEQAIdrsqy2X7uFCiVck4b4iiALYAGP/ZBr
68jtGBBAc/MuBSJnU6mlaX8rpn3KiBBLuPm73Ij88WoHD8BHZOqQfWtCgoxMMhVe
qRCczUgHQOQkrnoW7cKoJhgmj+dqiZC5pN8dd4CBx1xa+GVN53sGzpgj/CGy3paD
y1pZzlJXFsZCsQV2na7ddSOwC91f0uXgQcVD3un6vqdIBYdjTpQ8cAPV2CQoalY2
Yc00tpphdssNRvW4DEW0zx0oD8xXEckw8msuGRYe+4zEHYEyBU86alMRY5bXbSJh
fP0U0M0EpDz6JdN4m4d/C3kNym++30/LTnavzvv4grlVfAXt1IX5l8u2mB2twKSY
Q1fpv2eQ8Uo+S26Bvc2xsJJEBQSOeYRXsqyKIFQg6/ADeDgApt/d0aqnPUBpRg+G
WxpwXY+/etCInRvOSAV60XvhWCp8hj16y7m4keS2oWq4K4ciQ4MsJH2VCgPk9gO3
+J+btL5mGML8BjKgVkRqRthCjMeZ/bGBZj6aDW2+RLgQO7sMKXESpIC/1IA+ep5v
izi3B7QthwZ/vrPKA40JzuMu3gt3O65riYLoS4RMKbsOoqf5IDKoBNkMLmYEMhGy
D3glLOVajs+Ei1hcIA5n00p3VePGAs607/D8tQYm4gymYaCT+acQaylTY8FhdRIk
tdGDxce7pRQXuQINBGCALb4BEAC0AizzUrVn1d4PqeewKeWmxNwDSp0ycpIXAzqJ
k8QHMy1zwzGbsz9lcJ3I2V4Ml0+hc2yMrbLHG1D0uffyjGh7Xqxt94l1J/Fm4/qA
Si5wsMYCnzOTPGP1EC3uZed9LTozgm1uH9T6th7JvaG1BiXd3lTI64LNHXea1tas
t8UC0a7pu4xWJ+jduIdgVxVvT9V0m8Z/i97ifpkw7NxLs+qpMtOAY101K0Xl9VEk
GLsg0vGvFbm2xsU4gfPvo6BGS9IUfeUuJXVnutX6D5r50Me6Q3Dv3kjKh0YGY3aB
TVKcpTB2ad8SvOSw3yBCVwcUsH0V59XRqX8yFHmDUpLBubmEp6tw+/RGw3W5HCfe
RvevjnFed+te2dApewtcri4w4tFLQ1p4CYbIXvZFdv8BCW92z6DPlgvKAQLHsM9x
FhPdzyUQ0dwYTxo55CYkSJoQ/i53aaIRLQdl7+zvwbj83pcOC3+0RXwhi1rIlo3j
b0TicSK1U7sFqb2gjMZ1NMtoZMIB4wQl9FxHiR3IBsRXziK4etMWpVBOu88Nt0Mf
aNJIPW8bwoEIBcQBchL1Q1eYRWbk97PQufGf6g1RqX89nQPQdI7CQQ9nrGNiDC2X
vHlYepDzXKKLO0PLAQ7oloY3XwyxxUZUvB1HY+LpqTuoF3zxfb/k5D5TLSkv5T2/
RBNtLQARAQABiQRsBBgBCAAgAhsCFiEEcSv77pLcpFJS2xfXx76X76F5sQAFAmCA
VPkCQMF0IAQZAQgAHRYhBOlbdpnoC2ip6tmhmiuqm4VSvZBHBQJggFTaAAoJECuq
m4VSvZBHOIoQAJSqXoDzjYVVo3c0gmBVZ9r19VIq6ZQb1JFrQSySE8uq6WTiHrLn
uYbIFsOj1dwpcTIDIXEgHCXoPTJKR/OzwoVJakyyLYyjf0A1VKoHQA7t261+1kc0
a6QSWpgC1lEt3tz05MDtpSwfawbeHbwqmwcl+gzCH1muJnyLV4VIdHnliBM17pbM
qitKhn69U7pqdeSFqrnx+iaGpblZbD0Q7ZRBG+IvGLgE4MyJnXkf6lNjQIwVto/S
4Y0iY6IXSVXjkoGIEdCI+601mn+lsk6BqJ4T1whILBOT3vt8Z+5xM7p88u5XPid7
2AfE2UtK/zQQgmVL3ourL/LlaUKl5M3HLnODxnusmPOL4Wt9ABbVKe4k9ksGFQ3K
R58/dbBXWjlaFULD9zI51mh87Ou95Grlf7DoQ0zLh9t1KRuGSzJK1s5QSQ0J9xs4
netrNs/rpjTR3dNTXZDApAo+XcGLPv7dYfqqCcfwT5FHH9NpHOvXNFPlvMjOeRlV
UwCXs+V20RSwpvykXPJRrKOGlJ2RAZdaHS36jImXWFK7O2uGxpuMUkz/1+uUW175
MlZ7muW+BM2pGpNIrKHs1LXRHpcw3FTWL7zeawtGzuuiVHeyYa2RehFC7mNj1Za3
vjXm7fnd8owQCjLko2sOkCcg9GcuS1K+1KpukvoGAIV6Tg7zK3jkuoCRCRDHvpfv
oXmxAEhwD/9EsMF1VwHnftPZLSt0tdyXHHxHcHGQHdUOYbz6jude1eK6MVutbj2y
LwMR93A0EZEhGNIzUN7mloId8W48JfpXA/NbSicAkgXpAf3wD+AhCZW7p5SlE4Gj
AtfVGVRDGvHoITD2a1fy4QajfUjwrVluC1trmyOI7ybnmlkq1mbRlUcwqjZG/v6u
LomVvtVbwhBvJpie1h3qsv9Rge0w7qrbU5pzoa6arWWFx1qHr7/j/6eESb2nDrXl
bEpwMX8XEi4KmJAAYOgllRZR8nCT6d6Kuury862Ia46nvKE+CpL4JCvVNDImo8yN
l3kQL7tztg0qzctld/9NNjxa3bHneTW43qRPK+iO+8j1fyIXfveuUih6usfeL6pM
ol+k8Y1cohIMnf6T+hsp5Q4alPtC6ERfYHTfDBOWAjwCJ9gznAkNO1+5+2VaaPGx
2TvevYCtqNRyKQQctW/GceKKvpB1LHeUw4ygyo20zli2JqOL/jc8qZxua4MeJgk+
2tkvb0wbKZng0PycZuGGDetkfYdepXW9Fudn97vhJty0XX/5JNiCLYBaV5A/oxiU
ms3DjIdlIrKw1X6bthLNRaAK/iyNV7JToAG49vL5dh91PCoxRpoZgiCnGoQ94YaI
zE5IZlTLWmTqA815NoSaNQYGX5avi1CXSsf49cbfNPoAnSKrid82mw==
=DjWl
-----END PGP PUBLIC KEY BLOCK-----

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

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