Compare commits

..

1 Commits
test ... v1.9.7

Author SHA1 Message Date
David Baker
6e28c141ab Put electronVersion back (#287)
seems letting electron builder take it from the dependencies confuses
the keytar build process
2021-12-13 16:01:53 +00:00
207 changed files with 5314 additions and 14767 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: ["test/tsconfig.json"],
},
overrides: [
{
files: ["test/**/*.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,
@@ -11,27 +12,24 @@ module.exports = {
// we also have some browser code (ie. the preload script)
browser: true,
},
// NOTE: These rules are frozen and new rules should not be added here.
// New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/
rules: {
"quotes": "off",
"indent": "off",
"prefer-promise-reject-errors": "off",
"no-async-promise-executor": "off",
},
overrides: [
{
files: ["src/**/*.ts"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// Things we do that break the ideal style
"prefer-promise-reject-errors": "off",
"quotes": "off",
overrides: [{
files: ["src/**/*.{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",
},
// We disable this while we're transitioning
"@typescript-eslint/no-explicit-any": "off",
},
],
}],
};

5
.github/CODEOWNERS vendored
View File

@@ -1,4 +1 @@
* @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
* @vector-im/element-web

View File

@@ -1,13 +0,0 @@
<!-- Thanks for submitting a PR! Please ensure the following requirements are met in order for us to review your PR -->
## Checklist
- [ ] 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
-->

View File

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

View File

@@ -1,30 +0,0 @@
name: Backport
on:
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@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 }}

View File

@@ -1,156 +0,0 @@
name: Build and Deploy
on:
# Nightly build
schedule:
- cron: "0 9 * * *"
# 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_32bit:
description: Build Windows 32-bit
required: true
type: boolean
default: true
windows_64bit:
description: Build Windows 64-bit
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
concurrency: ${{ github.workflow }}
env:
R2_BUCKET: "packages-element-io"
jobs:
prepare:
uses: ./.github/workflows/build_prepare.yaml
with:
config: element.io/${{ inputs.mode || 'nightly' }}
version: ${{ inputs.mode == 'release' && '' || 'develop' }}
nightly: ${{ inputs.mode != 'release' }}
secrets:
CF_R2_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
CF_R2_TOKEN: ${{ secrets.CF_R2_TOKEN }}
CF_R2_S3_API: ${{ secrets.CF_R2_S3_API }}
windows_32bit:
if: github.event_name != 'workflow_dispatch' || inputs.windows_32bit
needs: prepare
name: Windows 32-bit
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
sign: true
deploy-mode: true
arch: x86
version: ${{ needs.prepare.outputs.win32-x86-version }}
windows_64bit:
if: github.event_name != 'workflow_dispatch' || inputs.windows_64bit
needs: prepare
name: Windows 64-bit
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
sign: true
deploy-mode: true
arch: x64
version: ${{ needs.prepare.outputs.win32-x64-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
deploy-mode: true
base-url: https://packages.element.io/${{ inputs.mode == 'release' && 'desktop' || 'nightly' }}
version: ${{ needs.prepare.outputs.macos-version }}
# We do not put this call into deploy-mode as we do not want it to add to the packages.element.io artifact
# We ship this build via reprepro only
linux:
if: github.event_name != 'workflow_dispatch' || inputs.linux
needs: prepare
name: Linux (sqlcipher system)
uses: ./.github/workflows/build_linux.yaml
with:
config: element.io/${{ inputs.mode || 'nightly' }}
sqlcipher: system
version: ${{ needs.prepare.outputs.linux-version }}
# We ship the static build via static tarball only
linux_static:
if: github.event_name != 'workflow_dispatch' || inputs.linux
needs: prepare
name: Linux (sqlcipher static)
uses: ./.github/workflows/build_linux.yaml
with:
deploy-mode: true
config: element.io/${{ inputs.mode || 'nightly' }}
sqlcipher: static
version: ${{ needs.prepare.outputs.linux-version }}
# This deploy job only handles Windows, macOS & linux_static as those are stateless and static.
# Linux will be deployed via reprepro after it, but we list it as a dependency to abort if it fails.
deploy:
needs:
- macos
- linux
- linux_static
- windows_32bit
- windows_64bit
runs-on: ubuntu-latest
name: Deploy
if: github.event_name != 'workflow_dispatch' || (inputs.deploy && (inputs.macos || inputs.windows_32bit || inputs.windows_64bit))
environment: packages.element.io
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: packages.element.io
path: packages.element.io
- name: Deploy artifacts
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: ${{ secrets.CF_R2_S3_API }}
DEPLOYMENT_DIR: ${{ inputs.mode == 'release' && 'desktop' || 'nightly' }}
reprepro:
needs:
- linux
# We queue this after the other deploy stage as we want to abort if that fails
- deploy
name: Run reprepro
if: github.event_name != 'workflow_dispatch' || (inputs.deploy && inputs.linux)
uses: ./.github/workflows/reprepro.yaml
secrets: inherit
with:
artifact-name: linux-sqlcipher-system

View File

@@ -1,108 +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, x86]
with:
arch: ${{ matrix.arch }}
linux:
needs: fetch
name: Linux
uses: ./.github/workflows/build_linux.yaml
strategy:
matrix:
sqlcipher: [system, static]
with:
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
sqlcipher: ${{ matrix.sqlcipher }}
macos:
needs: fetch
name: macOS
uses: ./.github/workflows/build_macos.yaml
test:
needs:
- macos
- linux
- windows
strategy:
matrix:
include:
- name: macOS Universal
os: macos
artifact: macos
executable: "./dist/mac-universal/Element.app/Contents/MacOS/Element"
prepare_cmd: "find ./dist/mac-universal/Element.app -type f | perl -lne 'print if -B' | tr '\\n' '\\0' | xargs -0 -n1 chmod 755"
- 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 --frozen-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: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
timeout-minutes: 5
with:
run: "yarn test"
env:
ELEMENT_DESKTOP_EXECUTABLE: ${{ matrix.executable }}
- name: Upload Artifacts
uses: actions/upload-artifact@v3
if: always()
with:
name: ${{ matrix.artifact }}
path: test_artifacts
retention-days: 1

View File

@@ -1,53 +0,0 @@
name: Build Keyring package
on:
workflow_dispatch:
inputs:
deploy:
description: Deploy artifacts
required: true
type: boolean
default: true
fingerprint:
description: The expected gpg fingerprint
required: true
type: string
concurrency: ${{ github.workflow }}
jobs:
build:
name: Build Keyring package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
mkdir -p element-io-archive-keyring/usr/share/keyrings/
cp packages.element.io/debian/element-io-archive-keyring.gpg element-io-archive-keyring/usr/share/keyrings/element-io-archive-keyring.gpg
- name: Check fingerprint
run: |
gpg --import element-io-archive-keyring/usr/share/keyrings/element-io-archive-keyring.gpg
gpg --fingerprint "$FINGERPRINT"
env:
FINGERPRINT: ${{ inputs.fingerprint }}
- name: Build deb package
run: |
chmod u=rw,go=r element-io-archive-keyring/usr/share/keyrings/element-io-archive-keyring.gpg
dpkg-deb -Zxz --root-owner-group --build element-io-archive-keyring element-io-archive-keyring.deb
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: element-io-archive-keyring
path: "*.deb"
retention-days: 1
reprepro:
needs: build
name: Run reprepro
if: inputs.deploy
uses: ./.github/workflows/reprepro.yaml
secrets: inherit
with:
artifact-name: element-io-archive-keyring

View File

@@ -1,137 +0,0 @@
# 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:
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'"
deploy-mode:
type: boolean
required: false
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
jobs:
build:
runs-on: ubuntu-latest
container:
image: ghcr.io/vector-im/element-desktop-dockerbuild:${{ github.ref_name == 'master' && 'master' || 'develop' }}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
id: cache
uses: actions/cache@v3
with:
key: ${{ runner.os }}-${{ inputs.sqlcipher }}-${{ hashFiles('hakDependencies.json', 'electronVersion') }}
path: |
./.hak
- uses: actions/setup-node@v3
with:
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: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: "yarn build:native"
env:
SQLCIPHER_STATIC: ${{ inputs.sqlcipher == 'static' && '1' || '' }}
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
run: |
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
- name: Generate debian files and arguments
id: debian
run: |
if [ -f changelog.Debian ]; then
echo "config-args=--deb-changelog changelog.Debian" >> $GITHUB_OUTPUT
fi
cp "$DIR/control.template" debcontrol
VERSION=${INPUT_VERSION:-$(cat package.json | jq -r .version)}
echo "Version: $VERSION" >> debcontrol
env:
DIR: ${{ inputs.config }}
INPUT_VERSION: ${{ inputs.version }}
- name: Build App
run: |
npx ts-node scripts/generate-builder-config.ts \
${{ steps.nightly.outputs.config-args }} \
${{ steps.debian.outputs.config-args }} \
--deb-custom-control=debcontrol
yarn build --publish never -l --config electron-builder.json
- name: Check ldd
run: |
ldd dist/linux-unpacked/resources/app.asar.unpacked/node_modules/matrix-seshat/native/index.node
if [ "$SQLCIPHER_STATIC" == "1" ]; then
ldd dist/linux-unpacked/resources/app.asar.unpacked/node_modules/matrix-seshat/native/index.node | grep -v libsqlcipher.so.0
ldd dist/linux-unpacked/resources/app.asar.unpacked/node_modules/matrix-seshat/native/index.node | grep libcrypto.so.1.1
else
ldd dist/linux-unpacked/resources/app.asar.unpacked/node_modules/matrix-seshat/native/index.node | grep libsqlcipher.so.0
ldd dist/linux-unpacked/resources/app.asar.unpacked/node_modules/matrix-seshat/native/index.node | grep -v libcrypto.so.1.1
fi
env:
SQLCIPHER_STATIC: ${{ inputs.sqlcipher == 'static' && '1' || '' }}
- name: Stash deb package
if: inputs.deploy-mode
uses: actions/upload-artifact@v3
with:
name: linux-sqlcipher-${{ inputs.sqlcipher }}-deb
path: dist/*.deb
retention-days: 1
- name: Prepare artifacts for deployment
if: inputs.deploy-mode
run: |
mv dist _dist
mkdir -p "dist/install/linux/glibc-x86-64/"
mv _dist/*.tar.gz "dist/install/linux/glibc-x86-64"
# We don't wish to store the tarball for every nightly ever, so we only keep the latest
- name: "[Nightly] Strip version from tarball"
if: inputs.deploy-mode && inputs.version != ''
run: |
mv dist/install/linux/glibc-x86-64/*.tar.gz "dist/install/linux/glibc-x86-64/element-desktop-nightly.tar.gz"
- name: "[Release] Prepare release latest symlink"
if: inputs.deploy-mode && inputs.version == ''
shell: bash
run: |
ln -s "$(find . -type f -iname "*.tar.gz" | xargs -0 -n1 -- basename)" "element-desktop.tar.gz"
working-directory: "dist/install/linux/glibc-x86-64"
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.deploy-mode && 'packages.element.io' || format('linux-sqlcipher-{0}', inputs.sqlcipher) }}
path: dist
retention-days: 1

View File

@@ -1,155 +0,0 @@
# 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"
deploy-mode:
type: boolean
required: false
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
base-url:
type: string
required: false
description: "The URL to which the output will be deployed, required if deploy-mode is enabled."
jobs:
build:
runs-on: macos-latest
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
id: cache
uses: actions/cache@v3
with:
key: ${{ runner.os }}-${{ hashFiles('hakDependencies.json', 'electronVersion') }}
path: |
./.hak
- name: Install Rust
if: steps.cache.outputs.cache-hit != 'true'
uses: actions-rs/toolchain@v1
with:
default: true
toolchain: stable
target: aarch64-apple-darwin
- 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"
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: "yarn build:native:universal"
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
run: |
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
# 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: |
scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }} --notarytool-team-id='${{ secrets.APPLE_TEAM_ID }}'
yarn build:universal --publish never --config electron-builder.json
env:
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
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: |
scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }}
yarn build:universal --publish never --config electron-builder.json
env:
CSC_IDENTITY_AUTO_DISCOVERY: false
- name: Prepare artifacts for deployment
if: inputs.deploy-mode
run: |
mv dist _dist
mkdir -p dist/install/macos dist/update/macos
mv _dist/*-mac.zip dist/update/macos/
mv _dist/*.dmg dist/install/macos/
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/update/macos/releases.json
jq -n --arg url "$URL" '
{ url: $url }
' > dist/update/macos/releases-legacy.json
env:
VERSION: ${{ inputs.version }}
# 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: inputs.deploy-mode && inputs.version != ''
run: |
mv dist/install/macos/*.dmg "dist/install/macos/Element Nightly.dmg"
- name: "[Release] Prepare release latest symlink"
if: inputs.deploy-mode && inputs.version == ''
run: |
ln -s "$(find . -type f -iname "*.dmg" | xargs -0 -n1 -- basename)" "Element.dmg"
working-directory: "dist/install/macos"
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.deploy-mode && 'packages.element.io' || 'macos' }}
path: dist
retention-days: 1

View File

@@ -1,127 +0,0 @@
# 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"
secrets:
# Required if `nightly` is set
CF_R2_ACCESS_KEY_ID:
required: false
# Required if `nightly` is set
CF_R2_TOKEN:
required: false
# Required if `nightly` is set
CF_R2_S3_API:
required: false
outputs:
macos-version:
description: "The version string the next macOS Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.macos-version }}
linux-version:
description: "The version string the next Linux Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.linux-version }}
win32-x64-version:
description: "The version string the next Windows x64 Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.win32-x64-version }}
win32-x86-version:
description: "The version string the next Windows x86 Nightly should use, only output for nightly"
value: ${{ jobs.prepare.outputs.win32-x86-version }}
jobs:
prepare:
name: Prepare
environment: ${{ inputs.nightly && 'packages.element.io' || '' }}
runs-on: ubuntu-latest
outputs:
macos-version: ${{ steps.versions.outputs.macos }}
linux-version: ${{ steps.versions.outputs.linux }}
win32-x64-version: ${{ steps.versions.outputs.win_x64 }}
win32-x86-version: ${{ steps.versions.outputs.win_x86 }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- 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 > hakDependencies.json
- name: "[Nightly] Calculate versions"
id: versions
if: inputs.nightly
run: |
MACOS=$(aws s3 cp s3://$R2_BUCKET/nightly/update/macos/releases.json - --endpoint-url $R2_URL --region auto | jq -r .currentRelease)
echo "macos=$(scripts/generate-nightly-version.ts --latest $MACOS)" >> $GITHUB_OUTPUT
LINUX=$(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')
echo "linux=$(scripts/generate-nightly-version.ts --latest $LINUX)" >> $GITHUB_OUTPUT
WINx64=$(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-)
echo "win_x64=$(scripts/generate-nightly-version.ts --latest $WINx64)" >> $GITHUB_OUTPUT
WINx86=$(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-)
echo "win_x86=$(scripts/generate-nightly-version.ts --latest $WINx86)" >> $GITHUB_OUTPUT
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
R2_BUCKET: "packages-element-io"
R2_URL: ${{ secrets.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 }}
- uses: actions/upload-artifact@v3
with:
name: webapp
retention-days: 1
path: |
webapp.asar
package.json
electronVersion
hakDependencies.json
changelog.Debian

View File

@@ -1,205 +0,0 @@
# 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:
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' | 'x86' | '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"
deploy-mode:
type: boolean
required: false
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
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: kanga333/variable-mapper@master
id: config
with:
key: "${{ inputs.arch }}"
export_to: output
map: |
{
"x64": {
"target": "x86_64-pc-windows-msvc",
"dir": "x64"
},
"arm64": {
"target": "aarch64-pc-windows-msvc",
"build-args": "--arm64",
"arch": "amd64_arm64",
"dir": "arm64"
},
"x86": {
"target": "i686-pc-windows-msvc",
"build-args": "--ia32",
"dir": "ia32"
}
}
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: webapp
- name: Cache .hak
id: cache
uses: actions/cache@v3
with:
key: ${{ runner.os }}-${{ inputs.arch }}-${{ hashFiles('hakDependencies.json', 'electronVersion') }}
path: |
./.hak
- name: Set up build tools
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ steps.config.outputs.arch || inputs.arch }}
# ActiveTCL package on choco is from 2015,
# this one is newer but includes more than we need
- name: Choco install tclsh
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
- 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: Install Rust
if: steps.cache.outputs.cache-hit != 'true'
uses: actions-rs/toolchain@v1
with:
default: true
toolchain: stable
target: ${{ steps.config.outputs.target }}
- 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"
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: |
refreshenv
yarn build:native --target ${{ steps.config.outputs.target }}
- name: Install and configure eSigner CKA
id: esigner
if: inputs.sign
run: |
Set-StrictMode -Version 'Latest'
# Download
Invoke-WebRequest -OutFile eSigner_CKA.exe "https://packages.element.io/tools/SSL.COM%20eSigner%20CKA_1.0.4-build-20230221_signed.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 "config-args=--signtool-thumbprint '$Thumbprint' --signtool-subject-name '$SubjectName'" >> $env:GITHUB_OUTPUT
env:
INSTALL_DIR: C:\Users\runneradmin\eSignerCKA
MASTER_KEY_FILE: C:\Users\runneradmin\eSignerCKA\master.key
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
shell: bash
run: |
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
- name: Build App
run: |
yarn ts-node scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }} ${{ steps.esigner.outputs.config-args }}
yarn build --publish never -w --config electron-builder.json ${{ 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: Prepare artifacts for deployment
if: inputs.deploy-mode
shell: bash
run: |
mv dist _dist
mkdir -p "dist/install/win32/$DIR/msi" "dist/update/win32/$DIR"
mv _dist/squirrel-windows*/*.exe "dist/install/win32/$DIR"
mv _dist/squirrel-windows*/*.nupkg "dist/update/win32/$DIR/"
mv _dist/squirrel-windows*/RELEASES "dist/update/win32/$DIR/"
# mv _dist/*.msi "dist/install/win32/$DIR/msi/"
env:
DIR: ${{ steps.config.outputs.dir }}
# 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: inputs.deploy-mode && inputs.version != ''
shell: bash
run: |
mv dist/install/win32/$DIR/*.exe "dist/install/win32/$DIR/Element Nightly Setup.exe"
# mv dist/install/win32/$DIR/msi/*.msi "dist/install/win32/$DIR/msi/Element Nightly Setup.msi"
env:
DIR: ${{ steps.config.outputs.dir }}
- name: "[Release] Prepare release latest symlink"
if: inputs.deploy-mode && inputs.version == ''
shell: bash
run: |
ln -s "$(find . -type f -iname "*.exe" | xargs -0 -n1 -- basename)" "Element Setup.exe"
working-directory: "dist/install/win32/${{ steps.config.outputs.dir }}"
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.deploy-mode && 'packages.element.io' || format('win-{0}', inputs.arch) }}
path: dist
retention-days: 1

View File

@@ -1,51 +0,0 @@
name: "CodeQL"
on:
push:
branches: [ "develop", master, staging ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "develop" ]
schedule:
- cron: '19 9 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
# We have a single C file for the rebrand_stub which we don't want/need to analyse
# but it prevents us from using the built-in CodeQL scanner
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

View File

@@ -1,43 +0,0 @@
name: Dockerbuild
on:
workflow_dispatch: {}
push:
branches: [master, 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@v3
- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: dockerbuild
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -1,49 +0,0 @@
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 (mac-mini built) Nightly builds
schedule:
- cron: "0 11 * * *"
# Trigger after Nightly builds are deployed
workflow_run:
workflows: ["Build and Deploy"]
types:
- completed
# Manual trigger for rebuilding for releases
workflow_dispatch: {}
jobs:
deploy:
name: "Deploy"
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
environment: packages.element.io
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

@@ -0,0 +1,12 @@
name: Preview Changelog
on:
pull_request_target:
types: [ opened, edited, labeled ]
jobs:
changelog:
runs-on: ubuntu-latest
steps:
- name: Preview Changelog
uses: matrix-org/allchange@main
with:
ghToken: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,9 +0,0 @@
name: Pull Request
on:
pull_request_target:
types: [opened, edited, labeled, unlabeled, synchronize]
jobs:
action:
uses: matrix-org/matrix-js-sdk/.github/workflows/pull_request.yaml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@@ -1,91 +0,0 @@
on:
workflow_call:
inputs:
artifact-name:
type: string
required: true
description: "The name of the artifact containing the debs to include"
secrets:
GPG_PRIVATE_KEY:
required: false
GPG_PASSPHRASE:
required: false
CF_R2_ACCESS_KEY_ID:
required: false
CF_R2_TOKEN:
required: false
CF_R2_S3_API:
required: false
# Protect reprepro database using concurrency
concurrency: reprepro
jobs:
reprepro:
name: Deploy debian package
environment: packages.element.io
runs-on: ubuntu-latest
env:
R2_BUCKET: "packages-element-io"
R2_DB_BUCKET: packages-element-io-db
R2_URL: ${{ secrets.CF_R2_S3_API }}
steps:
- uses: actions/checkout@v3
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: ${{ inputs.artifact-name }}
path: dist
- name: Load GPG key
uses: crazy-max/ghaction-import-gpg@111c56156bcc6918c056dbef52164cfa583dc549 # v5
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
fingerprint: 75741890063E5E9A46135D01C2850B265AC085BD
- name: Install reprepro
run: sudo apt-get install -y reprepro
- name: Fetch database
run: aws s3 cp --recursive s3://$R2_DB_BUCKET debian/db/ --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: Run reprepro
run: |
grep Codename debian/conf/distributions | sed -n 's/Codename: //p' | while read -r target ; do
reprepro -b debian includedeb "$target" ./dist/*.deb
done
- name: Check repository works
run: |
# Download signing keyring
sudo wget -O /usr/share/keyrings/element-io-archive-keyring.gpg https://packages.element.io/debian/element-io-archive-keyring.gpg
# Point apt at local apt repo
echo "deb [signed-by=/usr/share/keyrings/element-io-archive-keyring.gpg] http://127.0.0.1:8000/debian/ default main" | sudo tee /etc/apt/sources.list.d/element-io.list
# Start http server and fetch from it via apt
python3 -m http.server 8000 --bind 127.0.0.1 &
sudo apt-get update --allow-insecure-repositories
killall python3
# Validate the package in the repo quacks like the one we expect
info=$(dpkg --info ../dist/*.deb)
package=$(echo "$info" | grep "Package:" | sed -n 's/ Package: //p')
version=$(echo "$info" | grep "Version:" | sed -n 's/ Version: //p')
apt-cache show "$package" | grep "Version: $version"
working-directory: ./packages.element.io
- name: Deploy debian repo
run: |
aws s3 cp --recursive packages.element.io/debian/ s3://$R2_BUCKET/debian --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: Store database
run: aws s3 cp --recursive debian/db/ s3://$R2_DB_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 }}

View File

@@ -1,43 +0,0 @@
name: Static Analysis
on:
pull_request: {}
push:
branches: [develop, master]
jobs:
ts_lint:
name: "Typescript Syntax Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- 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"
- name: Typecheck
run: "yarn run lint:types"
i18n_lint:
name: "i18n Check"
uses: matrix-org/matrix-react-sdk/.github/workflows/i18n_check.yml@develop
js_lint:
name: "ESLint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- 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"
- name: Run Linter
run: "yarn run lint:js"

View File

@@ -1,8 +0,0 @@
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 }}

8
.gitignore vendored
View File

@@ -4,7 +4,8 @@
/webapp.asar
/packages
/deploys
node_modules/
/node_modules
/docker_node_modules
/pkg/control
/.hak
/.yarnrc
@@ -12,8 +13,3 @@ node_modules/
/.npmrc
.vscode
.vscode/
/test_artifacts/
/coverage/
yarn-error.log
/hak/**/*.js
/scripts/hak/**/*.js

View File

@@ -1,19 +0,0 @@
/build/
/dockerbuild/
/lib/
/node_modules/
/packages.elememt.io/
/webapp
/src/i18n/strings
/CHANGELOG.md
/package-lock.json
/yarn.lock
**/.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

154
README.md
View File

@@ -1,24 +1,18 @@
![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)
[![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 +24,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 +34,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 +42,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 +49,42 @@ ln -s ../element-web/webapp ./
[TODO: add support for fetching develop builds, arbitrary URLs and arbitrary paths]
# Building
## Native Build
Building
========
Now you have a copy of Element, you're ready to build packages. If you'd just like to
run Element locally, skip to the next section.
TODO: List native pre-requisites
If you'd like to build the native modules (for searching in encrypted rooms and
secure storage), do this first. This will take 10 minutes or so, and will
require a number of native tools to be installed, depending on your OS (eg.
rust, tcl, make/nmake).
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.
You'll also to need to make sure you've built the native modules for the same
architecture as your package, so for anything more advanced than just building
the modules and app for the host architecture see 'Other Architectures'.
Then, run
If you don't need these features, you can skip this step.
To just build these for your native architecture:
```
yarn run build:native
```
Now you can build the package:
```
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:
This build step will not build any native modules.
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 +97,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 +107,85 @@ yarn add electron
yarn start
```
# Config
Other Architectures
===================
Building the native modules will build for the host architecture (and only the
host architecture) by default. On Windows, this will automatically determine
the architecture to build for based on the environment. Make sure that you have
all the [tools required to perform the native modules build](docs/windows-requirements.md)
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
```
You'll then need to create a built bundle with the same architecture.
To bundle a universal build for macOS, run:
```
yarn run build:universal
```
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
```
Note that the native module build system keeps the different architectures
separate, so you can keep native modules for several architectures at the same
time and switch which are active using a `yarn run hak copy` command, passing
the appropriate architectures. This will error if you haven't yet built those
architectures. eg:
```
yarn run build:native --target x86_64-apple-darwin
# We've now built & linked into place native modules for Intel
yarn run build:native --target aarch64-apple-darwin
# We've now built Apple Silicon modules too, and linked them into place as the active ones
yarn run hak copy --target x86_64-apple-darwin
# We've now switched back to our Intel modules
yarn run hak copy --target x86_64-apple-darwin --target aarch64-apple-darwin
# Now our native modules are universal x86_64+aarch64 binaries
```
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
```
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,18 +195,20 @@ 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).
@@ -151,8 +216,9 @@ For a developer guide, see the [translating dev doc](https://github.com/vector-i
[<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
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 +0,0 @@
module.exports = {
presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"],
};

5
debian/conf/options vendored
View File

@@ -1,5 +0,0 @@
# don't delete old debs by default
keepunreferencedfiles
# output dir
outdir +b/../packages.element.io/debian

View File

@@ -1,23 +1,19 @@
# Docker image to facilitate building Element Desktop with native bits using a glibc version with broader compatibility
FROM buildpack-deps:bionic-curl
FROM buildpack-deps:xenial-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 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
# 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 \
apt-get -qq install --no-install-recommends qtbase5-dev bsdtar build-essential autoconf libssl-dev gcc-multilib g++-multilib lzip rpm python libcurl3 git git-lfs ssh unzip \
libsecret-1-dev libgnome-keyring-dev \
libopenjp2-tools \
# Used by github actions \
jq grep \
# Used by seshat (when not SQLCIPHER_STATIC) \
# Used by Seshat
libsqlcipher-dev && \
# git-lfs
git lfs install && \
@@ -34,10 +30,10 @@ ENV LC_ALL C.UTF-8
ENV DEBUG_COLORS true
ENV FORCE_COLOR true
ENV NODE_VERSION 16.18.1
ENV NODE_VERSION 14.17.0
# this package is used for snapcraft and we should not clear apt list - to avoid apt-get update during snap build
RUN curl --proto "=https" -L https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz | tar xz -C /usr/local --strip-components=1 && \
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

View File

@@ -10,27 +10,20 @@ modules from source to ensure we can trust the compiled output. In the future,
we may offer a pre-compiled path for those who want to use these features in a
custom build of Element without installing the various build tools required.
Do note that compiling a module for a particular operating system
(Linux/macOS/Windows) will need to be done on that operating system.
Cross-compiling from a host OS for a different target OS may be possible, but
we don't support this flow with Element dependencies at this time.
The process is automated by [vector-im/element-builder](https://github.com/vector-im/element-builder)
when releasing.
## Building
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
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:
when releasing.
The following sections explain the manual steps you can use with a custom build of Element to enable
these features if you'd like to try them out.
It is possible to [build those native modules locally automatically](https://github.com/vector-im/element-desktop#building).
```
yarn run build:native
```
If you need to build for a specific architecture, see [here](#compiling-for-specific-architectures).
## Adding Seshat for search in E2E encrypted rooms
Seshat is a native Node module that adds support for local event indexing and
@@ -48,7 +41,7 @@ using yarn at the root of this project:
yarn add matrix-seshat
You will have to rebuild the native libraries against electron's version
You will have to rebuild the native libraries against electron's version of
of node rather than your system node, using the `electron-build-env` tool.
This is also needed to when pulling in changes to Seshat using `yarn link`.
@@ -66,92 +59,3 @@ After this is done the Electron version of Element can be run from the main fold
as usual using:
yarn start
### Statically linking libsqlcipher
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.
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.
## Compiling for specific architectures
### 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
```
You'll then need to create a built bundle with the same architecture.
To bundle a universal build for macOS, run:
```
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
```
### Cross compiling
Compiling a module for a particular operating system (Linux/macOS/Windows) needs
to be done on that operating system. Cross-compiling from a host OS for a different
target OS may be possible, but we don't support this flow with Element dependencies
at this time.
### Switching between architectures
The native module build system keeps the different architectures
separate, so you can keep native modules for several architectures at the same
time and switch which are active using a `yarn run hak copy` command, passing
the appropriate architectures. This will error if you haven't yet built those
architectures. eg:
```
yarn run build:native --target x86_64-apple-darwin
# We've now built & linked into place native modules for Intel
yarn run build:native --target aarch64-apple-darwin
# We've now built Apple Silicon modules too, and linked them into place as the active ones
yarn run hak copy --target x86_64-apple-darwin
# We've now switched back to our Intel modules
yarn run hak copy --target x86_64-apple-darwin --target aarch64-apple-darwin
# Now our native modules are universal x86_64+aarch64 binaries
```
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
```

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

@@ -1,39 +1,26 @@
# Windows
## 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
- [Node 14](https://nodejs.org)
- [Python 3](https://www.python.org/downloads/)
- [Strawberry Perl](https://strawberryperl.com/)
- [Rust](https://rustup.rs/)
- [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
```
In order to load all the C++ utilities installed by Visual Studio you can run the following in a terminal window.
```
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
```
You can replace `amd64` with `x86` depending on your CPU architecture.

View File

@@ -1,7 +0,0 @@
Package: element-io-archive-keyring
Architecture: all
Section: contrib/meta
Maintainer: support@element.io
Priority: optional
Version: 1.1
Description: The packages.element.io repository keyring

View File

@@ -11,11 +11,20 @@
"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",
"showLabsSettings": true,
"piwik": {
"url": "https://piwik.riot.im/",
"siteId": 1,
"policyUrl": "https://element.io/cookie-policy"
},
"roomDirectory": {
"servers": ["matrix.org", "gitter.im", "libera.chat"]
"servers": [
"matrix.org",
"gitter.im",
"libera.chat"
]
},
"enable_presence_by_hs_url": {
"https://matrix.org": false,
@@ -37,15 +46,9 @@
},
"posthog": {
"projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
"apiHost": "https://posthog.element.io"
"apiHost": "https://posthog.hss.element.io"
},
"privacy_policy_url": "https://element.io/cookie-policy",
"features": {
"feature_spotlight": true,
"feature_video_rooms": true
},
"element_call": {
"url": "https://element-call.netlify.app"
},
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
"feature_spaces_metaspaces": true
}
}

View File

@@ -3,10 +3,10 @@ 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: libsqlcipher0, element-io-archive-keyring
Depends: libgtk-3-0, libnotify4, libnss3, libxss1, libxtst6, xdg-utils, libatspi2.0-0, libuuid1, libsecret-1-0, libsqlcipher0
Recommends: libappindicator3-1
Section: net
Priority: extra
Homepage: https://element.io/
Description:
Description:
riot.im A feature-rich client for Matrix.org (nightly unstable build).

View File

@@ -21,6 +21,14 @@ 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
@@ -50,3 +58,24 @@ 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

@@ -11,12 +11,21 @@
"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",
"roomDirectory": {
"servers": ["matrix.org", "gitter.im", "libera.chat"]
"servers": [
"matrix.org",
"gitter.im",
"libera.chat"
]
},
"showLabsSettings": false,
"piwik": {
"url": "https://piwik.riot.im/",
"siteId": 1,
"policyUrl": "https://element.io/cookie-policy"
},
"enable_presence_by_hs_url": {
"https://matrix.org": false,
"https://matrix-client.matrix.org": false
@@ -30,11 +39,5 @@
"url": "https://element.io/cookie-policy",
"text": "Cookie Policy"
}
],
"posthog": {
"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"
]
}

View File

@@ -3,12 +3,12 @@ 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: libsqlcipher0, element-io-archive-keyring
Depends: libgtk-3-0, libnotify4, libnss3, libxss1, libxtst6, xdg-utils, libatspi2.0-0, libuuid1, libsecret-1-0, libsqlcipher0
Recommends: libappindicator3-1
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:
Description:
A feature-rich client for Matrix.org

View File

@@ -14,27 +14,28 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import path from "path";
import childProcess from "child_process";
const path = require('path');
const childProcess = require('child_process');
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
module.exports = async function(hakEnv, moduleInfo) {
await buildKeytar(hakEnv, moduleInfo);
};
export default async function buildKeytar(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
async function buildKeytar(hakEnv, moduleInfo) {
const env = hakEnv.makeGypEnv();
console.log("Running yarn with env", env);
await new Promise<void>((resolve, reject) => {
await new Promise((resolve, reject) => {
const proc = childProcess.spawn(
path.join(moduleInfo.nodeModuleBinDir, "node-gyp" + (hakEnv.isWin() ? ".cmd" : "")),
["rebuild"],
path.join(moduleInfo.nodeModuleBinDir, 'node-gyp' + (hakEnv.isWin() ? '.cmd' : '')),
['rebuild'],
{
cwd: moduleInfo.moduleBuildDir,
env,
stdio: "inherit",
stdio: 'inherit',
},
);
proc.on("exit", (code) => {
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});

View File

@@ -14,20 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import childProcess from "child_process";
const childProcess = require('child_process');
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const tools = [["python", "--version"]]; // node-gyp uses python for reasons beyond comprehension
module.exports = async function(hakEnv, moduleInfo) {
const tools = [['python', '--version']]; // node-gyp uses python for reasons beyond comprehension
for (const tool of tools) {
await new Promise<void>((resolve, reject) => {
await new Promise((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 {
@@ -36,4 +33,4 @@ export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Prom
});
});
}
}
};

View File

@@ -1,7 +1,7 @@
{
"scripts": {
"check": "check.ts",
"build": "build.ts"
"check": "check.js",
"build": "build.js"
},
"copy": "build/Release/keytar.node",
"dependencies": {

303
hak/matrix-seshat/build.js Normal file
View File

@@ -0,0 +1,303 @@
/*
Copyright 2020-2021 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.
*/
const path = require('path');
const childProcess = require('child_process');
const mkdirp = require('mkdirp');
const fsExtra = require('fs-extra');
module.exports = async function(hakEnv, moduleInfo) {
if (hakEnv.isWin()) {
await buildOpenSslWin(hakEnv, moduleInfo);
await buildSqlCipherWin(hakEnv, moduleInfo);
} else if (hakEnv.isMac()) {
await buildSqlCipherUnix(hakEnv, moduleInfo);
}
await buildMatrixSeshat(hakEnv, moduleInfo);
};
async function buildOpenSslWin(hakEnv, moduleInfo) {
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((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((resolve, reject) => {
const proc = childProcess.spawn(
'nmake',
['build_libs'],
{
cwd: openSslDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
await new Promise((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, moduleInfo) {
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((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, moduleInfo) {
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',
];
if (hakEnv.isMac()) {
args.push('--with-crypto-lib=commoncrypto');
}
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 = [];
if (hakEnv.isMac()) {
ldflags.push('-framework Security');
ldflags.push('-framework Foundation');
}
if (ldflags.length) {
args.push(`LDFLAGS=${ldflags.join(' ')}`);
}
await new Promise((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((resolve, reject) => {
const proc = childProcess.spawn(
'make',
[],
{
cwd: sqlCipherDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
await new Promise((resolve, reject) => {
const proc = childProcess.spawn(
'make',
['install'],
{
cwd: sqlCipherDir,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
}
async function buildMatrixSeshat(hakEnv, moduleInfo) {
// 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()) {
Object.assign(env, {
SQLCIPHER_STATIC: 1,
SQLCIPHER_LIB_DIR: path.join(moduleInfo.depPrefix, 'lib'),
SQLCIPHER_INCLUDE_DIR: path.join(moduleInfo.depPrefix, 'include'),
});
}
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 neon with env", env);
await new Promise((resolve, reject) => {
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

@@ -1,321 +0,0 @@
/*
Copyright 2020-2021 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 mkdirp from "mkdirp";
import fsExtra from "fs-extra";
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
type WinConfiguration =
| "VC-WIN32"
| "VC-WIN64A"
| "VC-WIN64-ARM"
| "VC-WIN64-CLANGASM-ARM"
| "VC-CLANG-WIN64-CLANGASM-ARM"
| "VC-WIN32-HYBRIDCRT"
| "VC-WIN64A-HYBRIDCRT";
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): Promise<void> {
const version = moduleInfo.cfg.dependencies.openssl;
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `openssl-${version}`);
let openSslArch: WinConfiguration;
switch (hakEnv.getTargetArch()) {
case "x64":
openSslArch = "VC-WIN64A";
break;
case "ia32":
openSslArch = "VC-WIN32";
break;
case "arm64":
openSslArch = "VC-WIN64-ARM";
break;
}
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): Promise<void> {
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): Promise<void> {
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): Promise<void> {
// 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 neon with env", env);
await new Promise<void>((resolve, reject) => {
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

@@ -0,0 +1,82 @@
/*
Copyright 2020-2021 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.
*/
const childProcess = require('child_process');
const fsProm = require('fs').promises;
module.exports = async function(hakEnv, moduleInfo) {
// of course tcl doesn't have a --version
if (!hakEnv.isLinux()) {
await new Promise((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();
});
}
const tools = [
['rustc', '--version'],
['python', '--version'], // node-gyp uses python for reasons beyond comprehension
];
if (hakEnv.isWin()) {
tools.push(['perl', '--version']); // for openssl configure
tools.push(['patch', '--version']); // to patch sqlcipher Makefile.msc
tools.push(['nmake', '/?']);
} else {
tools.push(['make', '--version']);
}
for (const tool of tools) {
await new Promise((resolve, reject) => {
const proc = childProcess.spawn(tool[0], tool.slice(1), {
stdio: ['ignore'],
});
proc.on('exit', (code) => {
if (code !== 0) {
reject("Can't find " + tool);
} else {
resolve();
}
});
});
}
// Ensure Rust target exists (nb. we avoid depending on rustup)
await new Promise((resolve, reject) => {
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

@@ -1,91 +0,0 @@
/*
Copyright 2020-2021 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 childProcess from "child_process";
import fsProm from "fs/promises";
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();
});
}
const tools = [
["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", "/?"]);
} else {
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"],
});
proc.on("exit", (code) => {
if (code !== 0) {
reject("Can't find " + tool);
} else {
resolve();
}
});
});
}
// Ensure Rust target exists (nb. we avoid depending on rustup)
await new Promise((resolve, reject) => {
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

@@ -14,39 +14,29 @@ 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 tar from "tar";
import fetch from "node-fetch";
import { promises as stream } from "stream";
const path = require('path');
const childProcess = require('child_process');
import HakEnv from "../../scripts/hak/hakEnv";
import { DependencyInfo } from "../../scripts/hak/dep";
const fs = require('fs');
const fsProm = require('fs').promises;
const needle = require('needle');
const tar = require('tar');
async function download(url: string, filename: string): Promise<void> {
const resp = await fetch(url);
if (!resp.ok) throw new Error(`unexpected response ${resp.statusText}`);
if (!resp.body) throw new Error(`unexpected response has no body ${resp.statusText}`);
await stream.pipeline(resp.body, fs.createWriteStream(filename));
}
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
if (hakEnv.wantsStaticSqlCipher()) {
module.exports = async function(hakEnv, moduleInfo) {
if (!hakEnv.isLinux()) {
await getSqlCipher(hakEnv, moduleInfo);
}
if (hakEnv.isWin()) {
await getOpenSsl(hakEnv, moduleInfo);
}
}
};
async function getSqlCipher(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
async function getSqlCipher(hakEnv, moduleInfo) {
const version = moduleInfo.cfg.dependencies.sqlcipher;
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
let haveSqlcipher: boolean;
let haveSqlcipher;
try {
await fsProm.stat(sqlCipherDir);
haveSqlcipher = true;
@@ -57,7 +47,7 @@ async function getSqlCipher(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise
if (haveSqlcipher) return;
const sqlCipherTarball = path.join(moduleInfo.moduleDotHakDir, `sqlcipher-${version}.tar.gz`);
let haveSqlcipherTar: boolean;
let haveSqlcipherTar;
try {
await fsProm.stat(sqlCipherTarball);
haveSqlcipherTar = true;
@@ -65,7 +55,11 @@ async function getSqlCipher(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise
haveSqlcipherTar = false;
}
if (!haveSqlcipherTar) {
await download(`https://github.com/sqlcipher/sqlcipher/archive/v${version}.tar.gz`, sqlCipherTarball);
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
@@ -80,14 +74,18 @@ async function getSqlCipher(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise
// 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);
await new Promise((resolve, reject) => {
const readStream = fs.createReadStream(patchFile);
const proc = childProcess.spawn("patch", ["-p1"], {
cwd: sqlCipherDir,
stdio: ["pipe", "inherit", "inherit"],
});
proc.on("exit", (code) => {
const proc = childProcess.spawn(
'patch',
['-p1'],
{
cwd: sqlCipherDir,
stdio: ['pipe', 'inherit', 'inherit'],
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
readStream.pipe(proc.stdin);
@@ -95,11 +93,11 @@ async function getSqlCipher(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise
}
}
async function getOpenSsl(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
async function getOpenSsl(hakEnv, moduleInfo) {
const version = moduleInfo.cfg.dependencies.openssl;
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `openssl-${version}`);
let haveOpenSsl: boolean;
let haveOpenSsl;
try {
await fsProm.stat(openSslDir);
haveOpenSsl = true;
@@ -110,7 +108,7 @@ async function getOpenSsl(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<v
if (haveOpenSsl) return;
const openSslTarball = path.join(moduleInfo.moduleDotHakDir, `openssl-${version}.tar.gz`);
let haveOpenSslTar: boolean;
let haveOpenSslTar;
try {
await fsProm.stat(openSslTarball);
haveOpenSslTar = true;
@@ -118,7 +116,10 @@ async function getOpenSsl(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<v
haveOpenSslTar = false;
}
if (!haveOpenSslTar) {
await download(`https://www.openssl.org/source/openssl-${version}.tar.gz`, openSslTarball);
await needle('get', `https://www.openssl.org/source/openssl-${version}.tar.gz`, {
follow: 10,
output: openSslTarball,
});
}
console.log("extracting " + openSslTarball + " in " + moduleInfo.moduleTargetDotHakDir);

View File

@@ -1,8 +1,8 @@
{
"scripts": {
"check": "check.ts",
"fetchDeps": "fetchDeps.ts",
"build": "build.ts"
"check": "check.js",
"fetchDeps": "fetchDeps.js",
"build": "build.js"
},
"prune": "native",
"copy": "native/index.node",

View File

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

View File

@@ -2,7 +2,7 @@
"name": "element-desktop",
"productName": "Element",
"main": "lib/electron-main.js",
"version": "1.11.29",
"version": "1.9.7",
"description": "A feature-rich client for Matrix.org",
"author": "Element",
"repository": {
@@ -11,33 +11,18 @@
},
"license": "Apache-2.0",
"files": [],
"engines": {
"node": ">=16.0.0"
},
"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 && ts-node scripts/fetch-package.ts",
"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": "yarn lint:js:src && yarn lint:js:test && yarn lint:js:scripts && yarn lint:js:hak",
"lint:js:src": "eslint --max-warnings 0 src",
"lint:js:test": "eslint --max-warnings 0 --config .eslintrc-test.js test",
"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",
"lint:js-fix:src": "eslint --fix --max-warnings 0 src",
"lint:js-fix:test": "eslint --fix --max-warnings 0 --config .eslintrc-test.js test",
"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 test/tsconfig.json",
"lint:types:scripts": "tsc --noEmit -p scripts/tsconfig.json",
"lint:types:hak": "tsc --noEmit -p hak/tsconfig.json",
"lint:js": "eslint --max-warnings 0 src scripts hak",
"lint:js-fix": "eslint --fix src scripts hak",
"lint:types": "tsc --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",
@@ -45,86 +30,60 @@
"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",
"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"
"hak": "node scripts/hak/index.js"
},
"dependencies": {
"@sentry/electron": "^4.3.0",
"auto-launch": "^5.0.5",
"counterpart": "^0.18.6",
"electron-clear-data": "^1.0.5",
"electron-store": "^8.0.2",
"electron-store": "^6.0.1",
"electron-window-state": "^5.0.3",
"minimist": "^1.2.6",
"node-fetch": "^2",
"png-to-ico": "^2.1.1"
"minimist": "^1.2.3",
"png-to-ico": "^2.1.1",
"request": "^2.88.2"
},
"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/asar": "^3.2.3",
"@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.18.23",
"@types/pacote": "^11.1.1",
"@types/tar": "^6.1.3",
"@typescript-eslint/eslint-plugin": "^5.42.0",
"@typescript-eslint/parser": "^5.42.0",
"@typescript-eslint/eslint-plugin": "^4.17.0",
"@typescript-eslint/parser": "^4.17.0",
"allchange": "^1.0.6",
"app-builder-lib": "24.0.0",
"babel-jest": "^29.0.0",
"asar": "^2.0.1",
"chokidar": "^3.5.2",
"detect-libc": "^1.0.3",
"electron": "^24.0.0",
"electron-builder": "24.0.0",
"electron-builder-squirrel-windows": "24.1.2",
"electron-devtools-installer": "^3.2.0",
"eslint": "^8.26.0",
"electron": "13.5",
"electron-builder": "22.11.4",
"electron-builder-squirrel-windows": "22.11.4",
"electron-devtools-installer": "^3.1.1",
"electron-notarize": "^1.0.0",
"eslint": "7.18.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-matrix-org": "^1.0.0",
"eslint-plugin-unicorn": "^46.0.0",
"expect-playwright": "^0.8.0",
"eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org#2306b3d4da4eba908b256014b979f1d3d43d2945",
"find-npm-prefix": "^1.0.2",
"fs-extra": "^11.0.0",
"glob": "^9.0.0",
"jest": "^29.0.0",
"matrix-web-i18n": "^1.3.0",
"mkdirp": "^2.0.0",
"node-pre-gyp": "^0.17.0",
"pacote": "^15.0.0",
"playwright": "^1.25.0",
"prettier": "^2.8.1",
"rimraf": "^4.4.1",
"fs-extra": "^8.1.0",
"glob": "^7.1.6",
"matrix-web-i18n": "github:matrix-org/matrix-web-i18n",
"mkdirp": "^1.0.3",
"needle": "^2.5.0",
"node-pre-gyp": "^0.15.0",
"pacote": "^11.3.5",
"rimraf": "^3.0.2",
"tar": "^6.1.2",
"ts-jest": "^29.0.0",
"ts-node": "^10.9.1",
"typescript": "5.0.3"
"typescript": "^4.1.3"
},
"hakDependencies": {
"matrix-seshat": "^2.3.3",
"keytar": "^7.9.0"
},
"resolutions": {
"@types/node": "16.18.23"
"matrix-seshat": "^2.3.0",
"keytar": "^5.6.0"
},
"build": {
"appId": "im.riot.app",
"asarUnpack": "**/*.node",
"electronVersion": "13.5.2",
"files": [
"package.json",
{
@@ -141,27 +100,28 @@
"webapp.asar"
],
"linux": {
"target": [
"tar.gz",
"deb"
],
"target": "deb",
"category": "Network;InstantMessaging;Chat",
"maintainer": "support@element.io"
"maintainer": "support@element.io",
"desktop": {
"StartupWMClass": "element"
}
},
"mac": {
"category": "public.app-category.social-networking",
"darkModeSupport": true,
"gatekeeperAssess": true
"darkModeSupport": true
},
"win": {
"target": [
"squirrel"
]
"target": {
"target": "squirrel"
},
"sign": "scripts/electron_winSign"
},
"directories": {
"output": "dist"
},
"afterPack": "scripts/electron_afterPack",
"afterSign": "scripts/electron_afterSign",
"protocols": [
{
"name": "element",
@@ -170,14 +130,5 @@
]
}
]
},
"jest": {
"testEnvironment": "node",
"testMatch": [
"<rootDir>/test/**/*-test.[jt]s?(x)"
],
"setupFilesAfterEnv": [
"expect-playwright"
]
}
}

View File

@@ -1,92 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
KOQ1/miIFEhO+ksiqQ==
=OOgy
-----END PGP PUBLIC KEY BLOCK-----

View File

Binary file not shown.

View File

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

View File

Binary file not shown.

View File

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

View File

Binary file not shown.

View File

@@ -1,63 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=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.

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

@@ -1,182 +0,0 @@
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 100;
font-display: swap;
src: url("Inter-Thin.woff2?v=3.19") format("woff2"), url("Inter-Thin.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 100;
font-display: swap;
src: url("Inter-ThinItalic.woff2?v=3.19") format("woff2"), url("Inter-ThinItalic.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 200;
font-display: swap;
src: url("Inter-ExtraLight.woff2?v=3.19") format("woff2"), url("Inter-ExtraLight.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 200;
font-display: swap;
src: url("Inter-ExtraLightItalic.woff2?v=3.19") format("woff2"),
url("Inter-ExtraLightItalic.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 300;
font-display: swap;
src: url("Inter-Light.woff2?v=3.19") format("woff2"), url("Inter-Light.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 300;
font-display: swap;
src: url("Inter-LightItalic.woff2?v=3.19") format("woff2"), url("Inter-LightItalic.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("Inter-Regular.woff2?v=3.19") format("woff2"), url("Inter-Regular.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("Inter-Italic.woff2?v=3.19") format("woff2"), url("Inter-Italic.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("Inter-Medium.woff2?v=3.19") format("woff2"), url("Inter-Medium.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 500;
font-display: swap;
src: url("Inter-MediumItalic.woff2?v=3.19") format("woff2"), url("Inter-MediumItalic.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("Inter-SemiBold.woff2?v=3.19") format("woff2"), url("Inter-SemiBold.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 600;
font-display: swap;
src: url("Inter-SemiBoldItalic.woff2?v=3.19") format("woff2"),
url("Inter-SemiBoldItalic.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("Inter-Bold.woff2?v=3.19") format("woff2"), url("Inter-Bold.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("Inter-BoldItalic.woff2?v=3.19") format("woff2"), url("Inter-BoldItalic.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 800;
font-display: swap;
src: url("Inter-ExtraBold.woff2?v=3.19") format("woff2"), url("Inter-ExtraBold.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 800;
font-display: swap;
src: url("Inter-ExtraBoldItalic.woff2?v=3.19") format("woff2"),
url("Inter-ExtraBoldItalic.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 900;
font-display: swap;
src: url("Inter-Black.woff2?v=3.19") format("woff2"), url("Inter-Black.woff?v=3.19") format("woff");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 900;
font-display: swap;
src: url("Inter-BlackItalic.woff2?v=3.19") format("woff2"), url("Inter-BlackItalic.woff?v=3.19") format("woff");
}
/* -------------------------------------------------------
Variable font.
Usage:
html { font-family: 'Inter', sans-serif; }
@supports (font-variation-settings: normal) {
html { font-family: 'Inter var', sans-serif; }
}
*/
@font-face {
font-family: "Inter var";
font-weight: 100 900;
font-display: swap;
font-style: normal;
src: url("Inter-roman.var.woff2?v=3.19") format("woff2");
}
@font-face {
font-family: "Inter var";
font-weight: 100 900;
font-display: swap;
font-style: italic;
src: url("Inter-italic.var.woff2?v=3.19") format("woff2");
}
/* --------------------------------------------------------------------------
[EXPERIMENTAL] Multi-axis, single variable font.
Slant axis is not yet widely supported (as of February 2019) and thus this
multi-axis single variable font is opt-in rather than the default.
When using this, you will probably need to set font-variation-settings
explicitly, e.g.
* { font-variation-settings: "slnt" 0deg }
.italic { font-variation-settings: "slnt" 10deg }
*/
@font-face {
font-family: "Inter var experimental";
font-weight: 100 900;
font-display: swap;
font-style: oblique 0deg 10deg;
src: url("Inter.var.woff2?v=3.19") format("woff2");
}

View File

@@ -1,8 +0,0 @@
<svg width="518" height="112" viewBox="0 0 518 112" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M56 112C86.9279 112 112 86.9279 112 56C112 25.0721 86.9279 0 56 0C25.0721 0 0 25.0721 0 56C0 86.9279 25.0721 112 56 112Z" fill="#0DBD8B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M45.7615 26.093C45.7615 23.8325 47.5977 22.0001 49.8629 22.0001C65.2154 22.0001 77.6611 34.4199 77.6611 49.7406C77.6611 52.001 75.8248 53.8335 73.5597 53.8335C71.2945 53.8335 69.4583 52.001 69.4583 49.7406C69.4583 38.9408 60.6851 30.1859 49.8629 30.1859C47.5977 30.1859 45.7615 28.3534 45.7615 26.093Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M85.8986 45.6477C88.1637 45.6477 89.9999 47.4801 89.9999 49.7406C89.9999 65.0612 77.5543 77.4811 62.2017 77.4811C59.9366 77.4811 58.1003 75.6486 58.1003 73.3882C58.1003 71.1277 59.9366 69.2953 62.2017 69.2953C73.024 69.2953 81.7972 60.5403 81.7972 49.7406C81.7972 47.4801 83.6334 45.6477 85.8986 45.6477Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M66.3031 85.907C66.3031 88.1675 64.4668 89.9999 62.2017 89.9999C46.8492 89.9999 34.4035 77.58 34.4035 62.2594C34.4035 59.9989 36.2398 58.1665 38.5049 58.1665C40.77 58.1665 42.6063 59.9989 42.6063 62.2594C42.6063 73.0592 51.3795 81.8141 62.2017 81.8141C64.4668 81.8141 66.3031 83.6466 66.3031 85.907Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.1014 66.3523C23.8363 66.3523 22.0001 64.5199 22.0001 62.2594C22 46.9388 34.4457 34.5189 49.7983 34.5189C52.0634 34.5189 53.8997 36.3514 53.8997 38.6118C53.8997 40.8723 52.0634 42.7047 49.7983 42.7047C38.976 42.7047 30.2028 51.4597 30.2028 62.2594C30.2028 64.5199 28.3666 66.3523 26.1014 66.3523Z" fill="white"/>
<path d="M197 63.5H157.5C157.967 67.6333 159.467 70.9333 162 73.4C164.533 75.8 167.867 77 172 77C174.733 77 177.2 76.3333 179.4 75C181.6 73.6667 183.167 71.8667 184.1 69.6H196.1C194.5 74.8667 191.5 79.1333 187.1 82.4C182.767 85.6 177.633 87.2 171.7 87.2C163.967 87.2 157.7 84.6333 152.9 79.5C148.167 74.3667 145.8 67.8667 145.8 60C145.8 52.3333 148.2 45.9 153 40.7C157.8 35.5 164 32.9 171.6 32.9C179.2 32.9 185.333 35.4667 190 40.6C194.733 45.6667 197.1 52.0667 197.1 59.8L197 63.5ZM171.6 42.6C167.867 42.6 164.767 43.7 162.3 45.9C159.833 48.1 158.3 51.0333 157.7 54.7H185.3C184.767 51.0333 183.3 48.1 180.9 45.9C178.5 43.7 175.4 42.6 171.6 42.6ZM205.289 70.5V11H217.189V70.7C217.189 73.3667 218.656 74.7 221.589 74.7L223.689 74.6V85.9C222.556 86.1 221.356 86.2 220.089 86.2C214.956 86.2 211.189 84.9 208.789 82.3C206.456 79.7 205.289 75.7667 205.289 70.5ZM279.109 63.5H239.609C240.076 67.6333 241.576 70.9333 244.109 73.4C246.643 75.8 249.976 77 254.109 77C256.843 77 259.309 76.3333 261.509 75C263.709 73.6667 265.276 71.8667 266.209 69.6H278.209C276.609 74.8667 273.609 79.1333 269.209 82.4C264.876 85.6 259.743 87.2 253.809 87.2C246.076 87.2 239.809 84.6333 235.009 79.5C230.276 74.3667 227.909 67.8667 227.909 60C227.909 52.3333 230.309 45.9 235.109 40.7C239.909 35.5 246.109 32.9 253.709 32.9C261.309 32.9 267.443 35.4667 272.109 40.6C276.843 45.6667 279.209 52.0667 279.209 59.8L279.109 63.5ZM253.709 42.6C249.976 42.6 246.876 43.7 244.409 45.9C241.943 48.1 240.409 51.0333 239.809 54.7H267.409C266.876 51.0333 265.409 48.1 263.009 45.9C260.609 43.7 257.509 42.6 253.709 42.6ZM332.798 56.2V86H320.898V54.9C320.898 47.0333 317.632 43.1 311.098 43.1C307.565 43.1 304.732 44.2333 302.598 46.5C300.532 48.7667 299.498 51.8667 299.498 55.8V86H287.598V34.1H298.598V41C299.865 38.6667 301.798 36.7333 304.398 35.2C306.998 33.6667 310.232 32.9 314.098 32.9C321.298 32.9 326.498 35.6333 329.698 41.1C334.098 35.6333 339.965 32.9 347.298 32.9C353.365 32.9 358.032 34.8 361.298 38.6C364.565 42.3333 366.198 47.2667 366.198 53.4V86H354.298V54.9C354.298 47.0333 351.032 43.1 344.498 43.1C340.898 43.1 338.032 44.2667 335.898 46.6C333.832 48.8667 332.798 52.0667 332.798 56.2ZM425.379 63.5H385.879C386.346 67.6333 387.846 70.9333 390.379 73.4C392.912 75.8 396.246 77 400.379 77C403.112 77 405.579 76.3333 407.779 75C409.979 73.6667 411.546 71.8667 412.479 69.6H424.479C422.879 74.8667 419.879 79.1333 415.479 82.4C411.146 85.6 406.012 87.2 400.079 87.2C392.346 87.2 386.079 84.6333 381.279 79.5C376.546 74.3667 374.179 67.8667 374.179 60C374.179 52.3333 376.579 45.9 381.379 40.7C386.179 35.5 392.379 32.9 399.979 32.9C407.579 32.9 413.712 35.4667 418.379 40.6C423.112 45.6667 425.479 52.0667 425.479 59.8L425.379 63.5ZM399.979 42.6C396.246 42.6 393.146 43.7 390.679 45.9C388.212 48.1 386.679 51.0333 386.079 54.7H413.679C413.146 51.0333 411.679 48.1 409.279 45.9C406.879 43.7 403.779 42.6 399.979 42.6ZM444.868 34.1V41C446.068 38.7333 448.035 36.8333 450.768 35.3C453.568 33.7 456.935 32.9 460.868 32.9C467.001 32.9 471.735 34.7667 475.068 38.5C478.468 42.2333 480.168 47.2 480.168 53.4V86H468.268V54.9C468.268 51.2333 467.401 48.3667 465.668 46.3C464.001 44.1667 461.435 43.1 457.968 43.1C454.168 43.1 451.168 44.2333 448.968 46.5C446.835 48.7667 445.768 51.9 445.768 55.9V86H433.868V34.1H444.868ZM514.922 75.4V85.7C513.455 86.1 511.389 86.3 508.722 86.3C498.589 86.3 493.522 81.2 493.522 71V43.6H485.622V34.1H493.522V20.6H505.422V34.1H515.122V43.6H505.422V69.8C505.422 73.8667 507.355 75.9 511.222 75.9L514.922 75.4Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.2 KiB

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