Compare commits

...

515 Commits

Author SHA1 Message Date
RiotRobot
624dad601e Merge branch 'master' into develop 2025-11-18 15:08:17 +00:00
RiotRobot
3aa30ec18c v1.12.4 2025-11-18 15:07:42 +00:00
renovate[bot]
aaf1ace5f3 Update dependency glob to v11.1.0 [SECURITY] (#2696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-18 09:38:40 +00:00
Michael Telatynski
4419f209d5 Update App launch screenshot (#2695) 2025-11-17 10:44:34 +00:00
dependabot[bot]
45c99ff0d4 Bump tmp from 0.2.3 to 0.2.5 (#2691)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-13 16:29:42 +00:00
renovate[bot]
3d078d5389 Update dependency electron to v39.1.1 (#2688)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 11:42:35 +00:00
renovate[bot]
5db23f3a3a Update typescript-eslint monorepo to v8.46.3 (#2686)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 11:42:01 +00:00
renovate[bot]
24425c039b Update all non-major dependencies (#2687)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 11:40:30 +00:00
renovate[bot]
cf94b619b7 Update Node.js to v24 (#2684)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-11 15:54:11 +00:00
renovate[bot]
d3935d45ce Update rust:bullseye Docker digest to 8d9b5e8 (#2683)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-11 15:53:56 +00:00
renovate[bot]
784f1556f4 Update docker (#2682)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-11 15:51:15 +00:00
RiotRobot
25667d7786 v1.12.4-rc.0 2025-11-11 14:52:55 +00:00
Ben Banfield-Zanin
3ad56f27de Merge pull request #2677 from element-hq/bbz/use-dedicated-bug-report-subdomain
Update nightly and release builds to use the dedicated subdomain for 'bug_report_endpoint_url'
2025-11-06 14:33:37 +00:00
Ben Banfield-Zanin
b49e7dfecc Update nightly and release builds to use the dedicated subdomain for 'bug_report_endpoint_url' 2025-11-06 10:13:30 +00:00
RiotRobot
a4099168ac Merge branch 'master' into develop 2025-11-04 14:19:45 +00:00
RiotRobot
686a56d564 v1.12.3 2025-11-04 14:18:54 +00:00
Michael Telatynski
f12d414b1b Use ref input when resolving docker image in reusable workflow (#2675) 2025-11-03 17:06:53 +00:00
renovate[bot]
98f6cbd8a7 Update dependency tar to v7.5.2 [SECURITY] (#2673)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-31 08:07:53 +00:00
renovate[bot]
71a6e77cf1 Update dependency @sentry/electron to v7.2.0 (#2655)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 14:45:17 +00:00
renovate[bot]
7e723e2e47 Update dependency electron to v39 (#2669)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 14:14:52 +00:00
renovate[bot]
a0b40b2047 Update dependency @stylistic/eslint-plugin to v5.5.0 (#2668)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:41:00 +00:00
renovate[bot]
741bdb6244 Update babel monorepo to v7.28.5 (#2664)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:17:15 +00:00
renovate[bot]
5bc7434f50 Update all non-major dependencies (#2667)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:14:53 +00:00
renovate[bot]
ed741394bc Update GitHub Artifact Actions (#2670)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:10:05 +00:00
renovate[bot]
588b709035 Update playwright to v1.56.1 (#2665)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:08:59 +00:00
renovate[bot]
bbe493a696 Update typescript-eslint monorepo to v8.46.2 (#2666)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:06:10 +00:00
renovate[bot]
7e3508e5fb Update rust:bullseye Docker digest to cfb3f58 (#2663)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:04:53 +00:00
renovate[bot]
9c69d07eb6 Update docker/login-action digest to 28fdb31 (#2662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 09:03:43 +00:00
RiotRobot
73b83d055c v1.12.3-rc.0 2025-10-28 15:14:57 +00:00
Michael Telatynski
820c699fb9 Switch back to vendored fpm (#2661) 2025-10-27 12:50:44 +00:00
Michael Telatynski
ac3ccf47a3 Wait for Electron to be ready before we fire syntax error dialog (#2659) 2025-10-24 15:40:58 +01:00
ElementRobot
3c3b1d9ad3 Merge pull request #2653 from element-hq/actions/localazy-download
Localazy Download
2025-10-22 12:04:01 +01:00
t3chguy
ff6dd5e90b [create-pull-request] automated change 2025-10-22 06:08:23 +00:00
RiotRobot
74748cf205 Merge branch 'master' into develop 2025-10-21 11:55:35 +00:00
RiotRobot
55e3fa1652 v1.12.2 2025-10-21 11:54:45 +00:00
Michael Telatynski
1240eb83ec Remove GTK workaround (#2651) 2025-10-20 14:50:32 +01:00
renovate[bot]
25d754db0f Update eslint-plugins (#2646)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-10-15 10:07:23 +00:00
renovate[bot]
7a0a7497b2 Update electron-builder to v26.1.0 (#2639)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 17:40:02 +00:00
renovate[bot]
2004171d3d Update peter-evans/repository-dispatch action to v4 (#2644)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 16:50:35 +00:00
renovate[bot]
250bad90e9 Update actions/stale digest to 5f858e3 (#2631)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 16:50:11 +00:00
renovate[bot]
5c69abb799 Update actions/setup-node action to v6 (#2642)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 17:46:02 +01:00
renovate[bot]
868d873183 Update dependency electron-store to v11 (#2643)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 17:44:32 +01:00
renovate[bot]
339b1c01cc Update rust:bullseye Docker digest to d7cb9ff (#2633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 17:44:24 +01:00
renovate[bot]
ae4ce43204 Update typescript-eslint monorepo to v8.46.0 (#2641)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 17:44:13 +01:00
renovate[bot]
91490db890 Update dependency electron to v38.2.2 (#2636)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 17:43:46 +01:00
renovate[bot]
9fe021a327 Update dependency matrix-web-i18n to v3.4.0 (#2638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 16:40:09 +00:00
renovate[bot]
a106663750 Update dependency typescript to v5.9.3 (#2637)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 16:38:09 +00:00
renovate[bot]
9434f2adf9 Update dependency @types/node to v18.19.130 (#2635)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 16:30:48 +00:00
renovate[bot]
97cb39829a Update playwright to v1.56.0 (#2640)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 17:27:47 +01:00
renovate[bot]
e55f3cfb69 Update all non-major dependencies (#2634)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 17:27:02 +01:00
renovate[bot]
f21767d423 Update aws-actions/configure-aws-credentials digest to 0094301 (#2632)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 16:04:53 +00:00
RiotRobot
86891dcdd4 v1.12.2-rc.0 2025-10-14 14:48:20 +00:00
ElementRobot
55ee9c0053 Merge pull request #2628 from element-hq/actions/localazy-download
Localazy Download
2025-10-13 07:24:08 +01:00
t3chguy
1fd2214951 [create-pull-request] automated change 2025-10-13 06:08:25 +00:00
ElementRobot
fe253172b3 Merge pull request #2625 from element-hq/actions/localazy-download
Localazy Download
2025-10-10 07:36:41 +01:00
t3chguy
c7cdbcf07b [create-pull-request] automated change 2025-10-10 06:08:09 +00:00
Michael Telatynski
5e882f8e08 Allow Desktop app to be auto-started minimised or focused (#2622) 2025-10-09 14:41:12 +01:00
Michael Telatynski
e5f6bd882f Specify strictVerify to electron-builder mac builds (#2624) 2025-10-09 14:22:35 +01:00
Michael Telatynski
e4f75de04c Tidy knip config (#2623) 2025-10-09 09:04:14 +01:00
Michael Telatynski
1c55aa780f Improve workflows for better reusability (#2608) 2025-10-08 11:45:46 +01:00
ElementRobot
5dd1984896 Merge pull request #2620 from element-hq/actions/localazy-download
Localazy Download
2025-10-08 07:30:05 +01:00
t3chguy
3c78634cd5 [create-pull-request] automated change 2025-10-08 06:08:07 +00:00
RiotRobot
155bbe3634 Merge branch 'master' into develop 2025-10-07 12:37:57 +00:00
RiotRobot
3287fec669 v1.12.1 2025-10-07 12:37:12 +00:00
Michael Telatynski
a64ed5428c Fix hardlinks appearing in and breaking deb packages (#2609) 2025-10-06 09:55:54 +01:00
ElementRobot
d0a735b25c Merge pull request #2614 from element-hq/actions/localazy-download
Localazy Download
2025-10-06 07:22:32 +01:00
t3chguy
522c6f95ab [create-pull-request] automated change 2025-10-06 06:08:00 +00:00
David Baker
155b6f284a Merge pull request #2597 from element-hq/renovate/all-minor-patch
Update all non-major dependencies
2025-10-01 16:47:11 +01:00
David Baker
8376cef25a Merge pull request #2598 from element-hq/renovate/eslint-stylistic-monorepo
Update dependency @stylistic/eslint-plugin to v5.4.0
2025-10-01 16:46:45 +01:00
renovate[bot]
15f23d4cf9 Update electron (#2599)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-01 16:36:19 +01:00
David Baker
ea2b160dcc Merge pull request #2595 from element-hq/renovate/playwright
Update playwright to v1.55.1
2025-10-01 16:28:37 +01:00
renovate[bot]
bc0a8f03db Update all non-major dependencies 2025-10-01 15:25:50 +00:00
David Baker
39eddfdc4b Merge pull request #2604 from element-hq/dbkr/v_for_i_have_a_vendetta_against_people_who_cant_just_decide_on_what_the_format_of_the_damn_file_should_be
Support .node-version either with or without leading 'v'
2025-10-01 16:13:43 +01:00
David Baker
e668edbcec Merge pull request #2605 from element-hq/dependabot/npm_and_yarn/tar-fs-2.1.4
Bump tar-fs from 2.1.3 to 2.1.4
2025-10-01 14:59:01 +01:00
dependabot[bot]
763ebc4ca8 Bump tar-fs from 2.1.3 to 2.1.4
Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 2.1.3 to 2.1.4.
- [Commits](https://github.com/mafintosh/tar-fs/compare/v2.1.3...v2.1.4)

---
updated-dependencies:
- dependency-name: tar-fs
  dependency-version: 2.1.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-01 10:20:59 +00:00
David Baker
cfff1c7640 Spell renovate right
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-10-01 11:06:34 +01:00
David Baker
ec1971366a Support .node-version either with or without leading 'v'
As per comment
2025-10-01 10:49:00 +01:00
renovate[bot]
1f803f7051 Update dependency @stylistic/eslint-plugin to v5.4.0 2025-10-01 08:53:49 +00:00
renovate[bot]
c90c79e3ae Update playwright to v1.55.1 2025-10-01 08:53:37 +00:00
David Baker
22100bff80 Merge pull request #2596 from element-hq/renovate/typescript-eslint-monorepo
Update typescript-eslint monorepo to v8.44.1
2025-10-01 09:52:12 +01:00
David Baker
a4b622dd5e Merge pull request #2594 from element-hq/renovate/definitelytyped
Update dependency @types/node to v18.19.127
2025-10-01 09:51:14 +01:00
David Baker
c9a03859bd Merge pull request #2593 from element-hq/renovate/rust-bullseye
Update rust:bullseye Docker digest to 65dd7bb
2025-10-01 09:50:44 +01:00
David Baker
2385c4dd9b Merge pull request #2557 from element-hq/renovate/docker
Update docker/login-action digest to 5e57cd1
2025-10-01 09:50:22 +01:00
David Baker
9d2b1621d6 Merge pull request #2592 from element-hq/renovate/actions-cache-digest
Update actions/cache digest to 0057852
2025-10-01 09:49:59 +01:00
renovate[bot]
35db60092b Update rust:bullseye Docker digest to 65dd7bb 2025-09-30 21:14:12 +00:00
renovate[bot]
0a97f12323 Update typescript-eslint monorepo to v8.44.1 2025-09-30 13:14:17 +00:00
renovate[bot]
cd671919e2 Update dependency @types/node to v18.19.127 2025-09-30 13:13:49 +00:00
renovate[bot]
8e964cd782 Update actions/cache digest to 0057852 2025-09-30 13:13:23 +00:00
RiotRobot
bec7a9be19 v1.12.1-rc.0 2025-09-30 13:00:20 +00:00
renovate[bot]
64d8341deb Update docker/login-action digest to 5e57cd1 2025-09-29 10:48:58 +00:00
ElementRobot
0e22e7dd38 Merge pull request #2589 from element-hq/actions/localazy-download
Localazy Download
2025-09-29 07:26:24 +01:00
t3chguy
7937f4b0ba [create-pull-request] automated change 2025-09-29 06:08:30 +00:00
ElementRobot
9493680a42 Merge pull request #2587 from element-hq/actions/localazy-download
Localazy Download
2025-09-26 07:41:07 +01:00
t3chguy
20f8a32ed4 [create-pull-request] automated change 2025-09-26 06:07:56 +00:00
ElementRobot
44b685a272 Merge pull request #2579 from element-hq/actions/localazy-download
Localazy Download
2025-09-24 07:29:06 +01:00
t3chguy
b84b82f583 [create-pull-request] automated change 2025-09-24 06:08:12 +00:00
RiotRobot
13e036ee4c Merge branch 'master' into develop 2025-09-23 12:47:02 +00:00
RiotRobot
edb79cba9d v1.12.0 2025-09-23 12:46:01 +00:00
ElementRobot
0b8071cdc3 Merge pull request #2572 from element-hq/actions/localazy-download
Localazy Download
2025-09-23 10:46:05 +01:00
t3chguy
54dd920d34 [create-pull-request] automated change 2025-09-19 06:08:15 +00:00
RiotRobot
65b22386fa v1.12.0-rc.0 2025-09-17 09:22:43 +00:00
RiotRobot
2785778fb0 v1.11.113-rc.0 2025-09-17 09:17:46 +00:00
Michael Telatynski
9f6928679a Allow specifying ref on reusable workflows (#2547) 2025-09-17 10:07:27 +02:00
ElementRobot
2e531da3ae Merge pull request #2569 from element-hq/actions/localazy-download
Localazy Download
2025-09-17 07:24:48 +01:00
t3chguy
8c4a57dbff [create-pull-request] automated change 2025-09-17 06:08:19 +00:00
renovate[bot]
ac098fd045 Update dependency @types/node to v18.19.124 (#2561)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 15:42:31 +00:00
renovate[bot]
acb03b6abe Update actions/stale action to v10 (#2566)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 15:38:43 +00:00
renovate[bot]
cf9bf306cf Update dependency @babel/core to v7.28.4 (#2560)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 16:25:34 +01:00
renovate[bot]
46e1a866a3 Update dependency uuid to v13 (#2568)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 16:23:30 +01:00
renovate[bot]
fd1d792589 Update actions/setup-node action to v5 (#2564)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 16:21:34 +01:00
renovate[bot]
31c5fcff9b Update typescript-eslint monorepo to v8.43.0 (#2563)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 16:21:21 +01:00
renovate[bot]
bea98eaff7 Update aws-actions/configure-aws-credentials action to v5 (#2567)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 14:33:50 +00:00
renovate[bot]
23cc2b3884 Update actions/setup-python action to v6 (#2565)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 14:30:33 +00:00
renovate[bot]
a330b64fa6 Update dependency @stylistic/eslint-plugin to v5.3.1 (#2562)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 14:20:39 +00:00
renovate[bot]
87d2f64555 Update all non-major dependencies (#2559)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 14:20:31 +00:00
renovate[bot]
a17abce33b Update rust:bullseye Docker digest to 8f72d97 (#2558)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 14:17:11 +00:00
renovate[bot]
c20cf1b8bc Update dependency @sentry/electron to v7 (#2545)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 14:48:25 +01:00
Johnny Arcitec
78aed022f5 Update Electron to v38.1.0 to fix Kernel crash on multi-GPU systems (#2544) 2025-09-16 14:13:17 +01:00
RiotRobot
2b0a9b83b6 Merge branch 'master' into develop 2025-09-16 12:27:23 +00:00
RiotRobot
15455ad4be v1.11.112 2025-09-16 12:26:45 +00:00
ElementRobot
87c22acaae [Backport staging] Handle unsupported macOS versions better (#2555)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-09-16 13:23:08 +01:00
Michael Telatynski
3961e3d7bb Handle unsupported macOS versions better (#2552) 2025-09-16 12:49:31 +01:00
David Baker
b0a3b9e484 Merge pull request #2554 from element-hq/dbkr/no_drag_on_auth_page
Fix Confirm your identity buttons being unclickable
2025-09-16 12:26:34 +01:00
David Baker
7c5eb799d0 Fix Confirm your identity buttons being unclickable
Exclude the auth pager content from being a draggable area
2025-09-16 11:53:46 +01:00
RiotRobot
2bf3436a5b Merge branch 'master' into develop 2025-09-10 09:49:41 +00:00
RiotRobot
5682c38944 v1.11.111 2025-09-10 09:48:57 +00:00
ElementRobot
f5558add0f Merge pull request #2548 from element-hq/actions/localazy-download
Localazy Download
2025-09-10 07:30:35 +01:00
t3chguy
29dbe3284f [create-pull-request] automated change 2025-09-10 06:08:00 +00:00
byquanton
56e3e8389d Automatically select first source for desktop capture under Wayland (#2526) 2025-09-09 09:46:02 +01:00
Michael Telatynski
f1039d3fc2 Ensure dropdown is not a drag element on macOS (#2540) 2025-09-05 10:17:21 +01:00
Michael Telatynski
15f944581b Apply overrides from prepare artifact (#2503) 2025-09-04 13:18:31 +01:00
Michael Telatynski
b8bedd9c22 Reintroduce "Switch to a build variant config instead of magic env vars" (#2522) 2025-09-03 15:06:29 +01:00
renovate[bot]
5561e2efa3 Update electron-builder to v26.0.20 (#2530)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-03 10:10:12 +01:00
renovate[bot]
46192bd10e Update typescript-eslint monorepo to v8.41.0 (#2534)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-03 10:08:22 +01:00
renovate[bot]
74444237d9 Update all non-major dependencies (#2531)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-09-02 15:18:06 +01:00
renovate[bot]
9b8ebd97ed Update playwright to v1.55.0 (#2533)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-02 15:02:15 +01:00
renovate[bot]
c770ea5e2c Update dependency png-to-ico to v3 (#2535)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-02 14:57:46 +01:00
renovate[bot]
942c4eabc3 Update dependency electron to v37.4.0 (#2532)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-02 13:54:23 +00:00
RiotRobot
d725093b10 v1.11.111-rc.0 2025-09-02 13:09:30 +00:00
ElementRobot
a0185ecf3c Merge pull request #2529 from element-hq/actions/localazy-download
Localazy Download
2025-09-01 08:22:13 +02:00
t3chguy
a969bde5fd [create-pull-request] automated change 2025-09-01 06:08:17 +00:00
Michael Telatynski
bcde9afce9 Revert "Switch to a build variant config instead of magic env vars (#2498)" (#2520) 2025-08-28 11:33:39 +01:00
Michael Telatynski
a50957973b Switch to a build variant config instead of magic env vars (#2498) 2025-08-28 08:28:22 +00:00
RiotRobot
08fc8722f1 Merge branch 'master' into develop 2025-08-27 14:12:47 +00:00
RiotRobot
79f917792a v1.11.110 2025-08-27 14:12:03 +00:00
Michael Telatynski
954e11947e Simplify the number of icons (#2497) 2025-08-20 11:11:46 +00:00
Michael Telatynski
58caf2d337 Load deb maintainer info from package.json to make it easier to override (#2502) 2025-08-20 09:47:47 +01:00
Michael Telatynski
da87f2e5be Remove legacy code for handling Riot->Element autoLauncher migration (#2501) 2025-08-20 09:11:34 +01:00
Michael Telatynski
3a780766de Remove deb fields replaces/breaks riot-desktop (#2500) 2025-08-20 09:10:34 +01:00
Michael Telatynski
4762bc137f Allow specifying the webapp artifact name for the reusable workflows (#2499) 2025-08-20 09:07:51 +01:00
renovate[bot]
e13c6a4797 Update actions/download-artifact action to v5 (#2513)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 17:05:50 +01:00
renovate[bot]
a7ecf597dd Update actions/checkout action to v5 (#2512)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 17:05:43 +01:00
renovate[bot]
d261f95d86 Update typescript-eslint monorepo to v8.39.1 (#2510)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 17:05:35 +01:00
renovate[bot]
108b8574f0 Update dependency @types/node to v18.19.123 (#2509)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 17:05:28 +01:00
renovate[bot]
cf2081effe Update electron (#2511)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 17:05:23 +01:00
renovate[bot]
dd73fcc82e Update rust:bullseye Docker digest to 5b0defc (#2505)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 15:45:13 +00:00
renovate[bot]
3d39d6a1f1 Update dependency @stylistic/eslint-plugin to v5.2.3 (#2508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 16:28:04 +01:00
renovate[bot]
9b7bca653b Update babel monorepo to v7.28.3 (#2507)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 16:27:47 +01:00
renovate[bot]
25e8bd4906 Update all non-major dependencies (#2506)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 16:26:52 +01:00
renovate[bot]
6f6923b9fa Update actions/cache digest to 0400d5f (#2504)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 15:26:36 +00:00
RiotRobot
c58bedb312 v1.11.110-rc.0 2025-08-19 15:20:09 +00:00
renovate[bot]
479b823fdb Update Node.js to v22.18.0 (#2489)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-08-15 13:37:19 +01:00
ElementRobot
2ddced50e2 Merge pull request #2496 from element-hq/actions/localazy-download
Localazy Download
2025-08-13 08:21:41 +02:00
t3chguy
679b6146dd [create-pull-request] automated change 2025-08-13 06:08:21 +00:00
RiotRobot
3d0d131733 Merge branch 'master' into develop 2025-08-11 12:04:22 +00:00
RiotRobot
062f7ea977 v1.11.109 2025-08-11 12:03:47 +00:00
ElementRobot
38e3d473e6 Merge pull request #2492 from element-hq/actions/localazy-download
Localazy Download
2025-08-08 08:22:27 +02:00
t3chguy
5450102047 [create-pull-request] automated change 2025-08-08 06:09:15 +00:00
ElementRobot
5fd8cf189a Merge pull request #2491 from element-hq/actions/localazy-download
Localazy Download
2025-08-06 07:26:03 +01:00
t3chguy
77962c402b [create-pull-request] automated change 2025-08-06 06:09:34 +00:00
renovate[bot]
31bef3860e Update typescript-eslint monorepo to v8.39.0 (#2490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 16:25:31 +01:00
renovate[bot]
81458c29ed Update dependency typescript to v5.9.2 (#2488)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 16:22:03 +01:00
renovate[bot]
c61771de38 Update playwright to v1.54.2 (#2487)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 16:19:23 +01:00
renovate[bot]
2c577bcf84 Update electron (#2486)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 15:09:07 +01:00
renovate[bot]
3360b069d8 Update docker (#2483)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 15:06:35 +01:00
renovate[bot]
bb951131d1 Update dependency @types/node to v18.19.121 (#2485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 15:05:08 +01:00
renovate[bot]
ada93d84e7 Update rust:bullseye Docker digest to b315f98 (#2484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 15:04:50 +01:00
RiotRobot
8cf16397a9 v1.11.109-rc.0 2025-08-05 13:17:13 +00:00
ElementRobot
8bbbdcc2af Merge pull request #2470 from element-hq/actions/localazy-download
Localazy Download
2025-08-01 07:33:18 +01:00
t3chguy
73f5aa0ffb [create-pull-request] automated change 2025-08-01 06:09:20 +00:00
RiotRobot
60c2ebfb19 Merge branch 'master' into develop 2025-07-30 14:42:24 +00:00
RiotRobot
8d39941559 v1.11.108 2025-07-30 14:41:30 +00:00
ElementRobot
4fc2099693 Merge pull request #2465 from element-hq/actions/localazy-download
Localazy Download
2025-07-30 07:34:18 +01:00
t3chguy
05321d2e94 [create-pull-request] automated change 2025-07-30 06:09:08 +00:00
RiotRobot
54a88af28c Merge branch 'master' into develop 2025-07-29 13:25:39 +00:00
RiotRobot
e8b4fc7660 v1.11.107 2025-07-29 13:25:01 +00:00
ElementRobot
85e1e83d1d Merge pull request #2464 from element-hq/actions/localazy-download
Localazy Download
2025-07-28 07:28:05 +01:00
t3chguy
1d09bb0016 [create-pull-request] automated change 2025-07-28 06:09:15 +00:00
ElementRobot
bff219808e Merge pull request #2462 from element-hq/actions/localazy-download
Localazy Download
2025-07-25 07:23:34 +01:00
t3chguy
00475e4bfa [create-pull-request] automated change 2025-07-25 06:08:27 +00:00
renovate[bot]
9b50bdb9a0 Update all non-major dependencies (#2455)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-07-22 16:35:39 +00:00
renovate[bot]
d97a6a743e Update typescript-eslint monorepo to v8.37.0 (#2460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 17:23:46 +01:00
renovate[bot]
5daf37de3e Update dependency @types/node to v18.19.120 (#2456)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 17:11:18 +01:00
renovate[bot]
2cbb6041c8 Update dependency electron to v37.2.3 (#2457)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 17:07:46 +01:00
renovate[bot]
0dc2cafb26 Update playwright to v1.54.1 (#2459)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 17:06:18 +01:00
renovate[bot]
45a7d1564a Update rust:bullseye Docker digest to aaa0999 (#2454)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 17:06:12 +01:00
renovate[bot]
003d813967 Update dependency @stylistic/eslint-plugin to v5.2.0 (#2458)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 16:59:56 +01:00
RiotRobot
cdb0a051e6 v1.11.107-rc.0 2025-07-22 13:34:51 +00:00
dependabot[bot]
cad16c7e3b Bump form-data from 4.0.1 to 4.0.4 (#2453)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-22 09:24:15 +00:00
renovate[bot]
6a61d24fb8 Update electron-builder to v26.0.19 (#2415)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 10:03:56 +01:00
ElementRobot
0bb49702ba Merge pull request #2452 from element-hq/actions/localazy-download
Localazy Download
2025-07-21 08:25:04 +02:00
t3chguy
d1a0196d44 [create-pull-request] automated change 2025-07-21 06:08:39 +00:00
Will Hunt
229e52d809 Merge pull request #2443 from element-hq/hs/add-support-for-windows-badges
Add support for overlaying notification badges on the Windows Taskbar icon.
2025-07-18 08:39:21 +01:00
Will Hunt
0c16caf519 copyrights 2025-07-18 08:22:58 +01:00
ElementRobot
def0864df3 Merge pull request #2448 from element-hq/actions/localazy-download
Localazy Download
2025-07-18 08:27:32 +02:00
t3chguy
2cb99596d2 [create-pull-request] automated change 2025-07-18 06:07:51 +00:00
Half-Shot
812dd20b39 fix i18n 2025-07-17 11:30:39 +01:00
Half-Shot
db78dbec09 Restore tray icon updates for Windows. 2025-07-17 10:05:47 +01:00
Half-Shot
31be440d37 Split out badge 2025-07-17 10:05:08 +01:00
Half-Shot
b13f3ba1bd Update with a proper comment 2025-07-17 09:55:53 +01:00
Florian Duros
82852a0d0b Merge pull request #2446 from element-hq/florianduros/new-room-list/macos-titlebar 2025-07-16 21:34:22 +02:00
Florian Duros
dd45096808 fix: reduce macos titlebar height with the new room list and expand the existing border 2025-07-16 14:14:29 +02:00
ElementRobot
88829a1726 Merge pull request #2445 from element-hq/actions/localazy-download
Localazy Download
2025-07-16 08:31:20 +02:00
t3chguy
205d1609cd [create-pull-request] automated change 2025-07-16 06:08:06 +00:00
RiotRobot
c5a5dab318 Merge branch 'master' into develop 2025-07-15 15:12:14 +00:00
RiotRobot
27582b5d8c v1.11.106 2025-07-15 15:10:13 +00:00
Will Hunt
92a7da38ea lint 2025-07-15 15:35:08 +01:00
Will Hunt
7c19e5f0a8 Move code; drop favicon updating for win32 2025-07-15 13:55:04 +01:00
Will Hunt
f91c07f929 Merge branch 'develop' into hs/add-support-for-windows-badges 2025-07-14 14:32:23 +01:00
Half-Shot
2d21835588 Document why we do this. 2025-07-14 14:32:01 +01:00
Half-Shot
79b9ac896a lint 2025-07-14 13:11:57 +01:00
Half-Shot
7d488cc06d Announce support for badge overlays 2025-07-14 13:11:16 +01:00
Half-Shot
ad8287112b invoke setOverlayIcon for Windows platforms 2025-07-14 13:10:58 +01:00
Michael Telatynski
4629eccb5a Revert "Temporarily disable sandbox signing (#2430)" (#2440) 2025-07-14 10:05:42 +01:00
renovate[bot]
8aba763e3e Update all non-major dependencies (#2432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-07-09 11:13:50 +00:00
renovate[bot]
ec23373969 Update dependency @stylistic/eslint-plugin to v5 (#2437)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-09 08:24:58 +01:00
ElementRobot
c9ec2d2a84 Merge pull request #2421 from element-hq/actions/localazy-download
Localazy Download
2025-07-09 08:24:50 +02:00
t3chguy
e02e0b86e5 [create-pull-request] automated change 2025-07-09 06:08:15 +00:00
renovate[bot]
5dc47b9e77 Update dependency @types/node to v18.19.115 (#2433)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 17:31:32 +01:00
renovate[bot]
267e85cd4e Update playwright to v1.53.2 (#2434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 16:31:22 +00:00
renovate[bot]
17b57d10f5 Update dependency electron to v37 (#2438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 17:31:12 +01:00
renovate[bot]
2debea1f53 Update babel monorepo to v7.28.0 (#2436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 17:30:27 +01:00
renovate[bot]
08d0e076fa Update typescript-eslint monorepo to v8.35.1 (#2435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 17:16:19 +01:00
renovate[bot]
b08adafb62 Update rust:bullseye Docker digest to 8eb96c7 (#2431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 16:13:43 +00:00
Michael Telatynski
c2bb7ebb6d Temporarily disable sandbox signing (#2430) 2025-07-08 16:43:29 +01:00
RiotRobot
3f94cb2619 v1.11.106-rc.0 2025-07-08 13:39:58 +00:00
RiotRobot
48a138102b Merge branch 'master' into develop 2025-07-01 15:33:50 +00:00
RiotRobot
93a72b3d72 v1.11.105 2025-07-01 15:32:42 +00:00
David Baker
343b7d75d0 Merge pull request #2417 from element-hq/renovate/electron
Update electron
2025-06-27 10:36:29 +01:00
David Baker
804933023a Remove mystery change to README 2025-06-25 11:16:25 +01:00
David Baker
5149911e38 Prettier 2025-06-25 11:13:25 +01:00
David Baker
c9a53ba25d Fix types 2025-06-25 11:11:57 +01:00
David Baker
abf15ef471 Merge pull request #2418 from element-hq/renovate/playwright
Update playwright to v1.53.1
2025-06-25 10:41:15 +01:00
David Baker
4d0add6309 Merge pull request #2416 from element-hq/renovate/typescript-eslint-monorepo
Update typescript-eslint monorepo to v8.34.1
2025-06-24 18:45:07 +01:00
David Baker
74f2ecb4a9 Merge pull request #2414 from element-hq/renovate/definitelytyped
Update dependency @types/node to v18.19.112
2025-06-24 18:44:36 +01:00
David Baker
8ce5cf0f10 Merge pull request #2413 from element-hq/renovate/all-minor-patch
Update all non-major dependencies
2025-06-24 18:44:12 +01:00
David Baker
b92d31e7a4 Merge pull request #2412 from element-hq/renovate/rust-bullseye
Update rust:bullseye Docker digest to af1a29a
2025-06-24 18:16:11 +01:00
David Baker
fd29e65112 Merge pull request #2411 from element-hq/renovate/docker
Update docker
2025-06-24 18:15:48 +01:00
renovate[bot]
75f93ab631 Update playwright to v1.53.1 2025-06-24 16:50:22 +00:00
renovate[bot]
4b56f3b1ca Update electron 2025-06-24 16:49:55 +00:00
renovate[bot]
a1b1245c77 Update typescript-eslint monorepo to v8.34.1 2025-06-24 16:49:39 +00:00
renovate[bot]
053bcd10e1 Update dependency @types/node to v18.19.112 2025-06-24 16:49:12 +00:00
renovate[bot]
91036dcd22 Update all non-major dependencies 2025-06-24 16:48:59 +00:00
renovate[bot]
c0f3703c5a Update rust:bullseye Docker digest to af1a29a 2025-06-24 16:48:36 +00:00
renovate[bot]
960a413c8a Update docker 2025-06-24 16:48:31 +00:00
RiotRobot
5e8373d6cd v1.11.105-rc.0 2025-06-24 13:00:18 +00:00
ElementRobot
858e4fdbde Merge pull request #2406 from element-hq/actions/localazy-download
Localazy Download
2025-06-20 08:31:44 +02:00
t3chguy
8e5761be2d [create-pull-request] automated change 2025-06-20 06:07:33 +00:00
RiotRobot
be6565656d Merge branch 'master' into develop 2025-06-17 13:37:27 +00:00
RiotRobot
02f2274765 v1.11.104 2025-06-17 13:36:49 +00:00
Michael Telatynski
0d04e3d2ac Fix element-desktop-ssoid profile deeplinking for OIDC (#2396) 2025-06-13 14:57:41 +01:00
ElementRobot
f4b3816888 Merge pull request #2395 from element-hq/actions/localazy-download
Localazy Download
2025-06-13 01:27:56 -05:00
t3chguy
db153374f0 [create-pull-request] automated change 2025-06-13 06:07:46 +00:00
Michael Telatynski
0d4f02cde6 Add support for migrating to kwallet6 (#2390) 2025-06-11 14:06:25 +01:00
renovate[bot]
0061966718 Update electron (#2388)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-11 11:07:21 +01:00
ElementRobot
9fc64550dd Merge pull request #2389 from element-hq/actions/localazy-download
Localazy Download
2025-06-11 01:23:44 -05:00
t3chguy
51d2f6a29e [create-pull-request] automated change 2025-06-11 06:07:47 +00:00
renovate[bot]
58ef3d277f Update electron-builder to v26.0.16 (#2385)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-06-10 16:33:49 +00:00
renovate[bot]
fd62231856 Update dependency @stylistic/eslint-plugin to v4.4.1 (#2383)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 17:18:11 +01:00
renovate[bot]
0510fa4ee4 Update dependency @babel/core to v7.27.4 (#2382)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 16:47:33 +01:00
renovate[bot]
58d129f565 Update all non-major dependencies (#2387)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 16:21:12 +01:00
renovate[bot]
c72c18e998 Update typescript-eslint monorepo to v8.33.1 (#2386)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 15:05:17 +00:00
renovate[bot]
906125c738 Update dependency @types/node to v18.19.111 (#2384)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 14:47:06 +00:00
RiotRobot
bf97ef4904 v1.11.104-rc.0 2025-06-10 13:43:15 +00:00
RiotRobot
273afae84e Merge branch 'master' into develop 2025-06-10 12:30:59 +00:00
RiotRobot
e18ddee37e v1.11.103 2025-06-10 12:30:14 +00:00
Michael Telatynski
c43e8d684f Wire up setContentProtectionEnable for Windows & macOS (#2379) 2025-06-10 08:55:51 +01:00
ElementRobot
75463f0296 Merge pull request #2378 from element-hq/actions/localazy-download
Localazy Download
2025-06-09 01:21:28 -05:00
t3chguy
2401c1f7ef [create-pull-request] automated change 2025-06-09 06:07:53 +00:00
ElementRobot
fe7d10539b Merge pull request #2375 from element-hq/actions/localazy-download
Localazy Download
2025-06-06 01:28:56 -05:00
t3chguy
cb5f5bc94a [create-pull-request] automated change 2025-06-06 06:07:50 +00:00
David Baker
b123e0f60c Merge pull request #2373 from element-hq/dbkr/safestorage_fixloop
Fix restart loop in safeStorage
2025-06-04 19:30:02 +01:00
David Baker
39f460b636 Actually assign the promise 2025-06-04 18:26:56 +01:00
David Baker
86f6136257 Prettier 2025-06-04 16:23:59 +01:00
David Baker
2e039f4bab Add log message while I'm here 2025-06-04 16:15:08 +01:00
David Baker
8f24f45090 Need to return false here too 2025-06-04 16:12:43 +01:00
David Baker
6901bff548 Fix clear storage not working
It failed because it went looking for the focused / first window to
clear the storage on, but we called it before we had a window. Just
rewrite it without electron-clear-storage which doesn't really seem
necessary as a dependency, and also relaunched the app when clearing
stprage (you-had-one-job.gif). Pass the session in explicitly so it's
clear it needs it.
2025-06-04 16:01:03 +01:00
David Baker
cf88e520a0 Fix restart loop in safeStorage
if we started using a backend but it's now unusable, we need to prompt
the user that we can't migrate: if the override flag is already set then
we'll just restart in a loop.
2025-06-04 14:01:14 +01:00
ElementRobot
3bc59fb6ce Merge pull request #2372 from element-hq/actions/localazy-download
Localazy Download
2025-06-04 01:24:09 -05:00
t3chguy
f136c7aaad [create-pull-request] automated change 2025-06-04 06:07:42 +00:00
dependabot[bot]
5b33e2866d Bump tar-fs from 2.1.2 to 2.1.3 (#2369)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-03 16:28:15 +00:00
RiotRobot
c0ca58e930 Merge branch 'master' into develop 2025-06-03 15:14:12 +00:00
RiotRobot
77038a5a86 v1.11.102 2025-06-03 15:13:27 +00:00
ElementRobot
b22d2480ae Merge pull request #2367 from element-hq/actions/localazy-download
Localazy Download
2025-06-02 01:26:44 -05:00
t3chguy
7142b6fe57 [create-pull-request] automated change 2025-06-02 06:07:44 +00:00
renovate[bot]
b4c2bc7165 Update dependency electron to v36.3.2 (#2364)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-29 08:01:51 +00:00
renovate[bot]
4ea7b679e9 Update dependency @types/node to v18.19.105 (#2363)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-29 07:58:32 +00:00
renovate[bot]
89ead2e56f Update all non-major dependencies (#2358)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-05-29 08:41:58 +01:00
renovate[bot]
360665cd41 Update rust:bullseye Docker digest to eb80936 (#2355)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-05-28 17:41:51 +01:00
renovate[bot]
93c0b81cc4 Update typescript-eslint monorepo to v8.33.0 (#2361)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 17:00:23 +01:00
renovate[bot]
bd194306dd Update dependency @stylistic/eslint-plugin to v4.4.0 (#2359)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 15:15:01 +00:00
renovate[bot]
b4a23ff505 Update dependency electron to v36.3.1 (#2360)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 15:14:33 +00:00
renovate[bot]
8559a740f4 Update dependency @electron/asar to v4 (#2362)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 16:11:37 +01:00
renovate[bot]
dea64f7e38 Update dependency @babel/core to v7.27.3 (#2356)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 14:48:05 +00:00
renovate[bot]
044de246a1 Update dependency @types/node to v18.19.103 (#2357)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 15:46:37 +01:00
RiotRobot
2465607ac5 v1.11.102-rc.0 2025-05-28 13:32:32 +00:00
ElementRobot
d9ad2faac6 Merge pull request #2352 from element-hq/actions/localazy-download
Localazy Download
2025-05-26 01:23:43 -05:00
t3chguy
0c4c950fc7 [create-pull-request] automated change 2025-05-26 06:07:53 +00:00
Michael Telatynski
9660c4b2be Refactor store and fix bugs with it (#2348) 2025-05-23 14:33:17 +01:00
ElementRobot
73ddf2a19b Merge pull request #2344 from element-hq/actions/localazy-download
Localazy Download
2025-05-23 01:21:29 -05:00
t3chguy
cfea34766a [create-pull-request] automated change 2025-05-23 06:07:19 +00:00
R Midhun Suresh
77bea6db7e Merge pull request #2343 from element-hq/midhun/move-further-top
Enable plain text encryption before checking if encryption is available
2025-05-22 18:40:52 +05:30
R Midhun Suresh
abd508fc0d Enable encryption before checking if encryption is available 2025-05-22 18:22:05 +05:30
Michael Telatynski
8e4826b4e9 Fix test for Element Nightly variant (#2342) 2025-05-22 12:24:11 +00:00
R Midhun Suresh
3cd88352b6 Merge pull request #2341 from element-hq/midhun/fix-encryption-basic-text
Enable plain text encryption early if we actually mean to use `basic_text` as backend
2025-05-22 17:11:02 +05:30
R Midhun Suresh
1d79fa633a Enable plain text encryption as early as possible 2025-05-22 16:56:34 +05:30
Michael Telatynski
ec4c610158 Support build-time specified protocol scheme for oidc callback (#2285) 2025-05-22 11:40:28 +01:00
R Midhun Suresh
468d2249d1 Merge pull request #2338 from element-hq/midhun/fix-store
Use `basic_text` as fallback when encryption not available
2025-05-22 15:58:34 +05:30
R Midhun Suresh
63e1e0d894 Move store creation into migration methods 2025-05-22 14:33:48 +05:30
R Midhun Suresh
e326246669 Use basic_text as fallback when encryption not available
Show the user a dialog and fallback to using basic_text temporarily when
a valid backend is available but encryption support is not.
2025-05-22 11:57:51 +05:30
David Baker
53672fadd7 Merge pull request #2336 from element-hq/dbkr/doc_debugging
Add docs for debugging element desktop
2025-05-21 13:34:58 +01:00
David Baker
20f28abb47 prettier 2025-05-21 13:00:45 +01:00
David Baker
a0db96d50d Add docs for debugging element desktop
mostly for the magic to flip the fuses
2025-05-21 12:54:58 +01:00
RiotRobot
2bb1544064 Merge branch 'master' into develop 2025-05-20 14:02:12 +00:00
RiotRobot
827d514628 v1.11.101 2025-05-20 14:01:24 +00:00
Michael Telatynski
28e558162a Add branch matching (#2329) 2025-05-20 14:18:54 +01:00
ElementRobot
85556ecd74 Merge pull request #2326 from element-hq/actions/localazy-download
Localazy Download
2025-05-19 01:22:37 -05:00
t3chguy
46080c66d0 [create-pull-request] automated change 2025-05-19 06:07:51 +00:00
renovate[bot]
80b88583b8 Update dependency @sentry/electron to v6.6.0 (#2324)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-14 15:52:33 +01:00
renovate[bot]
2aaf42b8e8 Pin dependencies (#2322)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 12:38:54 +00:00
renovate[bot]
660ccd414a Pin mcr.microsoft.com/playwright Docker tag to ff29461 (#2323)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 12:32:11 +00:00
renovate[bot]
32cf6b2ebf Update typescript-eslint monorepo to v8.32.0 (#2320)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 11:57:12 +00:00
renovate[bot]
5507f2859f Update babel monorepo (#2319)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 11:55:08 +00:00
renovate[bot]
689179c5ae Update all non-major dependencies (#2321)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 12:52:41 +01:00
renovate[bot]
3116f596f2 Update dependency @types/node to v18.19.100 (#2318)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 11:45:01 +00:00
renovate[bot]
69cfe0bda6 Update dependency electron to v36.2.0 (#2316)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 11:27:16 +00:00
renovate[bot]
194798497f Update dependency lint-staged to v16 (#2317)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 11:15:42 +00:00
RiotRobot
68216568b0 v1.11.101-rc.0 2025-05-13 11:03:12 +00:00
ElementRobot
9cf81e4484 Merge pull request #2313 from element-hq/actions/localazy-download
Localazy Download
2025-05-12 01:23:34 -05:00
t3chguy
bb2435b529 [create-pull-request] automated change 2025-05-12 06:07:37 +00:00
Michael Telatynski
c0efe2334b Rely on @electron/universal for macOS ASAR integrity (#2169) 2025-05-08 08:32:35 +01:00
ElementRobot
0c2c26af75 Merge pull request #2300 from element-hq/actions/localazy-download
Localazy Download
2025-05-07 17:25:20 +02:00
t3chguy
3c9b229664 [create-pull-request] automated change 2025-05-07 14:58:23 +00:00
RiotRobot
e5815f3e3c Merge branch 'master' into develop 2025-05-06 14:20:34 +00:00
RiotRobot
b5febd1a07 v1.11.100 2025-05-06 14:19:52 +00:00
David Baker
747245e63f Merge pull request #2308 from element-hq/dbkr/apply_gtk_workaround_backport
Apply workaround to fix app launching on Linux
2025-05-06 14:20:38 +01:00
David Baker
a1bba6f8d3 Apply workaround to fix app launching on Linux
Manual backport of https://github.com/element-hq/element-desktop/pull/2307
2025-05-06 13:24:49 +01:00
David Baker
3c39998b0a Merge pull request #2307 from element-hq/dbkr/apply_gtk_workaround
Apply workaround to fix app launching on Linux
2025-05-06 12:08:49 +01:00
David Baker
10f09c90c7 Merge pull request #2306 from element-hq/revert-2298-revert-2293-renovate/major-electron
Re-apply "Update dependency electron to v36"
2025-05-06 12:00:08 +01:00
David Baker
cd9b48d87f Prettier 2025-05-06 11:47:45 +01:00
David Baker
10e2c5c1e4 Apply workaround for electron bug
Fixes https://github.com/element-hq/element-desktop/issues/2297
2025-05-06 11:40:32 +01:00
David Baker
0ad720454c Revert "Revert "Update dependency electron to v36"" 2025-05-06 10:44:51 +01:00
David Baker
ccb1c59076 Merge pull request #2298 from element-hq/revert-2293-renovate/major-electron
Revert "Update dependency electron to v36"
2025-05-02 18:14:40 +01:00
David Baker
9e315e9b05 Merge pull request #2299 from element-hq/rav/gdb_docs
Notes on using gdb
2025-05-02 09:59:31 +01:00
Richard van der Hoff
3a8726f953 Notes on using gdb
... because I always forget how to do this, and it takes me ages to remember.
2025-05-01 17:13:49 +01:00
David Baker
abaaadd2eb Revert "Update dependency electron to v36 (#2293)"
This reverts commit 0b167fe278.
2025-05-01 16:24:19 +01:00
Michael Telatynski
2699d04fd1 Update copy for the Electron Linux keyring backend error (#2295) 2025-04-30 12:13:12 +01:00
ElementRobot
00f3777fcf Merge pull request #2294 from element-hq/actions/localazy-download
Localazy Download
2025-04-30 08:23:14 +02:00
t3chguy
2b928c3f50 [create-pull-request] automated change 2025-04-30 06:07:35 +00:00
renovate[bot]
0b167fe278 Update dependency electron to v36 (#2293)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-04-29 12:48:23 +01:00
renovate[bot]
8db9c620df Update all non-major dependencies (#2288)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-04-29 11:33:31 +00:00
RiotRobot
2c60929139 v1.11.100-rc.0 2025-04-29 11:21:56 +00:00
renovate[bot]
9a8ca9980f Update playwright to v1.52.0 (#2291)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 12:08:03 +01:00
renovate[bot]
451129d468 Update typescript-eslint monorepo to v8.31.0 (#2292)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 11:06:17 +00:00
renovate[bot]
42a3b8b68c Update docker (#2287)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 12:00:38 +01:00
renovate[bot]
56bbea995f Update dependency @types/node to v18.19.87 (#2289)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 10:59:37 +00:00
Michael Telatynski
c72d23f995 Migrate from keytar to safeStorage (#2227) 2025-04-29 10:40:06 +00:00
David Baker
570a8bdefe Merge pull request #2275 from Fusseldieb/develop
Notification fixes for Windows - AppID name was messing up handler
2025-04-28 13:44:53 +01:00
renovate[bot]
1d3408bb37 Update dependency electron to v35.2.0 (#2283)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 09:30:12 +01:00
Michael Telatynski
eef66d9795 Improve HTML test report (#2282) 2025-04-23 14:33:20 +01:00
RiotRobot
a70c5e0215 Merge branch 'master' into develop 2025-04-23 11:16:22 +00:00
RiotRobot
d388b1e64a v1.11.99 2025-04-23 11:15:41 +00:00
ElementRobot
216b1c2157 Fix io.element.desktop protocol handler (#2280) (#2281)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-04-23 10:49:47 +00:00
Michael Telatynski
72da1a90db Fix io.element.desktop protocol handler (#2280) 2025-04-23 11:34:44 +01:00
Valentino Stillhart
37bc884d77 Explanation for setAppUserModelId 2025-04-22 12:59:39 -03:00
RiotRobot
a43d087c02 Merge branch 'master' into develop 2025-04-22 13:47:11 +00:00
RiotRobot
906b5bc93c v1.11.98 2025-04-22 13:46:20 +00:00
Valentino Stillhart
41ff61421d AppIDs must match config to properly display notification icon and title 2025-04-18 05:19:41 -03:00
Valentino Stillhart
65cdeaa9de Dashes were breaking notifications 2025-04-18 05:04:59 -03:00
Michael Telatynski
262abf5847 Enable windows arm64 tests using windows-11-arm runner (#2271) 2025-04-16 13:29:19 +01:00
renovate[bot]
4aa0454442 Update dependency windows to v2025 (#2268)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-04-15 16:29:42 +01:00
renovate[bot]
681365fd2f Update all non-major dependencies (#2261)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-04-15 15:13:34 +00:00
renovate[bot]
f566c83c81 Update dependency ubuntu to v24 (#2267)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 15:11:06 +00:00
renovate[bot]
1aab67e874 Update electron (#2265)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 15:39:16 +01:00
renovate[bot]
4ded16f12e Update dependency typescript to v5.8.3 (#2263)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 15:36:11 +01:00
renovate[bot]
12ea5fa91a Update typescript-eslint monorepo to v8.29.1 (#2264)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 15:35:18 +01:00
renovate[bot]
83775c9104 Update dependency @types/node to v18.19.86 (#2262)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 15:34:52 +01:00
RiotRobot
1817e7b216 v1.11.98-rc.0 2025-04-15 13:42:19 +00:00
Michael Telatynski
31868f833a Fix nightly pass in test 2025-04-15 12:47:16 +01:00
David Baker
e02bbf80ff Merge pull request #2231 from nbolton/print-config-path
Update config logging to specify config file path
2025-04-15 12:20:30 +01:00
David Baker
42ac29359c nonexistent 2025-04-15 11:58:55 +01:00
David Baker
db4c544b72 Use console.log
Co-authored-by: Nick Bolton <nick@symless.com>
2025-04-15 11:54:11 +01:00
Michael Telatynski
fca69978aa Attempt to fix tests for Nightly builds
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-04-15 10:41:09 +01:00
Nick Bolton
0559886b77 Reword log line to use 'app' instead of 'global'
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2025-04-15 10:34:04 +01:00
David Baker
f59c38a07e Fix type import 2025-04-15 10:34:04 +01:00
Nick Bolton
bff9c344b6 Log when attempting to load from nonexisting JSON file 2025-04-15 10:34:04 +01:00
Nick Bolton
30a464fcdc Update config logging to specify config file path 2025-04-15 10:34:04 +01:00
Michael Telatynski
2cdf1cf3b6 Attempt to fix tests for Nightly builds
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-04-15 10:20:58 +01:00
Michael Telatynski
0e8785e7ac Test release assets before deploy (#2257) 2025-04-15 08:57:28 +01:00
Michael Telatynski
7ea9bf1944 Fix desktop-web version matching for develop branch test CI
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-04-11 17:28:17 +01:00
Michael Telatynski
4fe0384523 Add tests for fix to getOidcCallbackUrl (#2248) 2025-04-11 16:10:11 +00:00
sj
aabbb8772d Support specifying the profile dir path via env var (#2226) (#2246) 2025-04-11 08:19:26 +00:00
renovate[bot]
dde93f30f4 Update electron (#2245)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-10 08:26:13 +01:00
RiotRobot
4486f6046e Merge branch 'master' into develop 2025-04-08 13:11:23 +00:00
RiotRobot
b2fff67cad v1.11.97 2025-04-08 13:10:32 +00:00
David Baker
575a9fa564 Merge pull request #2151 from element-hq/renovate/major-eslint-stylistic-monorepo
Update dependency @stylistic/eslint-plugin to v4
2025-04-03 14:22:09 +01:00
David Baker
8d78eedb34 Merge pull request #2240 from element-hq/renovate/tj-actions-changed-files-46.x
Update tj-actions/changed-files action to v46
2025-04-03 14:21:40 +01:00
renovate[bot]
791bfc63b3 Update tj-actions/changed-files action to v46 2025-04-03 08:50:01 +00:00
renovate[bot]
c1b2139ca2 Update dependency @stylistic/eslint-plugin to v4 2025-04-03 08:49:56 +00:00
David Baker
559bb5b672 Merge pull request #2238 from element-hq/renovate/electron
Update electron
2025-04-02 16:16:57 +01:00
David Baker
98e865ebae Merge pull request #2239 from element-hq/renovate/typescript-eslint-monorepo
Update typescript-eslint monorepo to v8.28.0
2025-04-02 15:50:41 +01:00
renovate[bot]
df576b8dc5 Update electron 2025-04-02 14:48:50 +00:00
David Baker
76e55014e0 Merge pull request #2237 from element-hq/renovate/babel-monorepo
Update dependency @babel/preset-typescript to v7.27.0
2025-04-02 15:46:58 +01:00
David Baker
6911eb203b Merge pull request #2236 from element-hq/renovate/electron-builder
Update electron-builder to v26.0.12
2025-04-02 15:46:33 +01:00
David Baker
74aebb59e1 Merge pull request #2235 from element-hq/renovate/all-minor-patch
Update dependency knip to v5.46.3
2025-04-02 15:45:38 +01:00
David Baker
e05afba0b5 Merge pull request #2234 from element-hq/renovate/definitelytyped
Update dependency @types/node to v18.19.84
2025-04-02 15:45:10 +01:00
David Baker
0bb6c47e6f Merge pull request #2233 from element-hq/renovate/tj-actions-changed-files-digest
Update tj-actions/changed-files digest to 48d8f15
2025-04-02 15:40:38 +01:00
renovate[bot]
bbfb8d3f47 Update typescript-eslint monorepo to v8.28.0 2025-04-02 14:21:26 +00:00
renovate[bot]
789798e595 Update dependency @babel/preset-typescript to v7.27.0 2025-04-02 14:20:56 +00:00
renovate[bot]
a8a5a955e5 Update electron-builder to v26.0.12 2025-04-02 14:20:43 +00:00
renovate[bot]
07c01e7117 Update dependency knip to v5.46.3 2025-04-02 14:20:32 +00:00
renovate[bot]
e6e46aa45f Update dependency @types/node to v18.19.84 2025-04-02 14:20:20 +00:00
renovate[bot]
11a76d60b1 Update tj-actions/changed-files digest to 48d8f15 2025-04-02 14:20:04 +00:00
RiotRobot
585b5ea5cb v1.11.97-rc.0 2025-04-01 13:08:00 +00:00
Will Hunt
4181c6f95a Merge pull request #2225 from element-hq/hs/remove-32-bit-support-windows
Remove support for 32 bit / ia32 Windows.
2025-04-01 14:06:41 +01:00
Half-Shot
20d3e0af9a Revert build workflows + update notice. 2025-04-01 11:14:28 +01:00
Half-Shot
4fd75b608a add arm64 2025-03-31 10:55:08 +01:00
Half-Shot
1d7a2e632d Revert removing i686 from target 2025-03-31 10:54:12 +01:00
Half-Shot
6be83576eb Stop building ia32 Windows. 2025-03-27 16:42:02 +00:00
RiotRobot
443be796ee Merge branch 'master' into develop 2025-03-25 17:17:50 +00:00
RiotRobot
1e0f25725e v1.11.96 2025-03-25 17:17:07 +00:00
renovate[bot]
1fef39fcf1 Update dependency electron to v35.0.3 (#2223)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-21 08:52:53 +00:00
renovate[bot]
2f872c3548 Update dependency @sentry/electron to v6.2.0 (#2222)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 16:17:45 +00:00
renovate[bot]
424bb8172a Update dependency @playwright/test to v1.51.1 (#2221)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 16:17:12 +00:00
renovate[bot]
0212b77b20 Update dependency @types/node to v18.19.80 (#2217)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 15:08:13 +00:00
renovate[bot]
536918fb1c Update typescript-eslint monorepo to v8.26.1 (#2219)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 14:59:42 +00:00
renovate[bot]
e4d5863606 Update mcr.microsoft.com/playwright Docker tag to v1.51.1 (#2218)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 14:37:50 +00:00
renovate[bot]
21244d454f Update docker/login-action digest to 74a5d14 (#2215)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 14:32:59 +00:00
renovate[bot]
f38e76db01 Update dependency electron to v35 (#2195)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 14:32:13 +00:00
renovate[bot]
50277e00a5 Update all non-major dependencies (#2220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 14:20:59 +00:00
renovate[bot]
4979c8fbed Update dependency @babel/core to v7.26.10 (#2216)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 14:11:22 +00:00
RiotRobot
610cd5d370 v1.11.96-rc.0 2025-03-18 13:36:01 +00:00
Michael Telatynski
7c858d358b Remove temporary awscli s3-r2 workaround (#2170)
* Remove temporary awscli s3-r2 workaround

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update build_and_deploy.yaml

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-03-17 13:53:09 +00:00
Michael Telatynski
7098789689 Fix --no-update command line flag (#2210)
* Fix `--no-update` command line flag

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add test

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* fail-fast: false

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Skip

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-03-17 11:54:07 +00:00
ElementRobot
618c04d613 Merge pull request #2209 from element-hq/actions/localazy-download
Localazy Download
2025-03-17 09:33:43 +00:00
t3chguy
702c9d2b60 [create-pull-request] automated change 2025-03-17 09:01:23 +00:00
ElementRobot
75b77274f5 Merge pull request #2207 from element-hq/actions/localazy-download
Localazy Download
2025-03-14 06:24:20 +00:00
t3chguy
fa9f0f4474 [create-pull-request] automated change 2025-03-14 06:06:48 +00:00
renovate[bot]
11c58a90ca Update dependency electron to v34.3.1 (#2200)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-12 11:50:12 +00:00
renovate[bot]
ef6c8871a2 Update electron-builder to v26.0.11 (#2201)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-12 08:37:44 +00:00
renovate[bot]
bc49c1d58b Update playwright to v1.51.0 (#2202)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-12 08:37:17 +00:00
RiotRobot
e275f9cccb Merge branch 'master' into develop 2025-03-11 14:49:04 +00:00
RiotRobot
b83d666b4c v1.11.95 2025-03-11 14:48:15 +00:00
renovate[bot]
987ce7dde4 Update dependency eslint-plugin-n to v17.16.1 (#2194)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 17:26:08 +00:00
renovate[bot]
a013504e17 Update electron-builder to v26.0.10 (#2193)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 17:25:27 +00:00
renovate[bot]
79abfcfddc Update dependency @types/node to v18.19.79 (#2192)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 17:24:00 +00:00
renovate[bot]
d8f4644ffc Update electron-builder to v26.0.9 (#2187)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 15:17:43 +00:00
renovate[bot]
f1d9b0a847 Update typescript-eslint monorepo to v8.25.0 (#2190)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 15:12:52 +00:00
renovate[bot]
960ff865fb Update dependency @sentry/electron to v6 (#2191)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 14:47:39 +00:00
renovate[bot]
bbcb7c0438 Update dependency typescript to v5.8.2 (#2189)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 14:47:13 +00:00
renovate[bot]
e36b3b3ce1 Update dependency electron to v34.3.0 (#2188)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 14:46:58 +00:00
renovate[bot]
566b32041d Update dependency @types/node to v18.19.78 (#2186)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 14:43:52 +00:00
renovate[bot]
d57ac6f016 Update docker (#2184)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 14:35:48 +00:00
renovate[bot]
76a5dcf5c8 Update all non-major dependencies (#2185)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 14:35:40 +00:00
RiotRobot
2fdd591e09 v1.11.95-rc.0 2025-03-04 12:55:52 +00:00
Will Hunt
50b0a757a8 Merge pull request #2181 from element-hq/hs/deprecate-windows-32bit
Deprecate ia32 Windows builds
2025-03-04 11:38:53 +00:00
Will Hunt
2669b2adeb Update notice 2025-03-04 09:57:29 +00:00
Michael Telatynski
e6ab8743d1 Simplify workflows remove unused parameters (#2182)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-03-04 09:18:37 +00:00
Michael Telatynski
f733c2e942 Switch to shiftkey/node-keytar as it has NAPI 10 updates (#2172)
* Test keytar-forked

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Leverage electron-builder to build keytar rather than hak

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add logging

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update imports

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update knip.ts

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-03-03 11:04:29 +00:00
Half-Shot
5b0ab72745 s/webpack/webapp 2025-03-03 11:00:48 +00:00
Half-Shot
783d0f15b8 lint 2025-03-03 10:32:27 +00:00
Half-Shot
0fc37c929a wait til after deps install 2025-03-03 10:31:42 +00:00
Half-Shot
f2319fc173 quote 2025-03-03 10:29:19 +00:00
Half-Shot
50836358dc another bracket -_- 2025-03-03 10:22:26 +00:00
Half-Shot
d61c284d8e drop newlines 2025-03-03 10:20:13 +00:00
Half-Shot
ae17facfe0 off by one brackets 2025-03-03 10:17:24 +00:00
Half-Shot
63f29006fc escaped 2025-03-03 10:13:43 +00:00
Half-Shot
0bb7ccb054 that's actually a config now 2025-03-03 10:09:19 +00:00
Half-Shot
3c4791f7ce use var mapper 2025-03-03 10:08:22 +00:00
Half-Shot
782ba453cf drop build_and_deploy.yaml changes 2025-03-03 10:08:20 +00:00
Half-Shot
7c17bdcafe switch order 2025-03-03 10:04:10 +00:00
Half-Shot
46e81cd8f8 Add ability to insert extra config for windows builds. 2025-03-03 10:03:01 +00:00
Michael Telatynski
1496f3d64c Remove unused parts of the hak build system (#2174) 2025-02-28 15:15:32 +00:00
Michael Telatynski
7847e53adc Update build to always install setuptools
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-02-28 15:15:19 +00:00
Michael Telatynski
9a1d2291c1 Make keytar mandatory and build it without hak (#2173) 2025-02-28 15:13:35 +00:00
Michael Telatynski
ff7f53fb35 Use modern Dockerfile env format to silence warnings (#2171) 2025-02-28 11:39:31 +00:00
Michael Telatynski
bce251b35b Update node engines, 23.x is broken too 2025-02-28 11:17:07 +00:00
Michael Telatynski
a46985d91e Specify node version to avoid NAPI keytar bug (#2168) 2025-02-28 10:23:49 +00:00
Michael Telatynski
a546b28c62 Pin Node to 22.13.1 for Windows build (#2166) 2025-02-27 18:55:57 +00:00
RiotRobot
9a785738df Merge branch 'master' into develop 2025-02-27 13:31:22 +00:00
RiotRobot
6be60b69e6 v1.11.94 2025-02-27 13:30:48 +00:00
renovate[bot]
ea8bd4e062 Update electron-builder to v26.0.8 (#2159)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-25 18:21:27 +00:00
RiotRobot
37ec2b9f34 Merge branch 'master' into develop 2025-02-25 13:41:26 +00:00
RiotRobot
8ee1a04592 v1.11.93 2025-02-25 13:40:50 +00:00
Michael Telatynski
573c7d4522 Update release.yml permissions 2025-02-25 13:20:10 +00:00
Michael Telatynski
64e5a424ca Add set -x to bash for introspection build_and_deploy.yaml 2025-02-24 15:24:44 +00:00
Michael Telatynski
a02fad52bb Fix macOS nightly builds (#2158) 2025-02-24 14:54:20 +00:00
Michael Telatynski
eb3ae80142 Update triage-stale.yml 2025-02-24 10:37:04 +00:00
Michael Telatynski
12b287d639 Update triage-stale.yml 2025-02-24 10:35:29 +00:00
renovate[bot]
8f31f2ff57 Update all non-major dependencies (#2154)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-19 22:38:30 +00:00
Michael Telatynski
8f464b9450 Improve CI test signing & assert expected files (#2137) 2025-02-19 14:34:43 +00:00
Michael Telatynski
b8bb4d3316 Add Windows ARM 64 package (#624)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-02-19 10:35:53 +00:00
Michael Telatynski
00f08cb443 Simplify CI workflows (#2153)
* Simplify CI workflows

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Simplify further

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Tidy

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-02-19 10:02:49 +00:00
renovate[bot]
6fb5202e86 Update docker (#2142)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-02-18 18:01:11 +00:00
renovate[bot]
e7cda8ee4e Update electron-builder to v26.0.7 (#2146)
* Update electron-builder to v26.0.6

* Update electron-builder to 26.0.7

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-02-18 17:43:51 +00:00
renovate[bot]
c4cddd3591 Update typescript-eslint monorepo to v8.24.0 (#2150)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 15:46:48 +00:00
renovate[bot]
f23b279633 Update electron (#2149)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 14:50:13 +00:00
renovate[bot]
4302d6106e Update dependency @types/node to v18.19.76 (#2145)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 14:49:48 +00:00
renovate[bot]
3c4138326b Update babel monorepo to v7.26.9 (#2144)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 14:49:28 +00:00
renovate[bot]
bf141856d7 Update dependency @stylistic/eslint-plugin to v3.1.0 (#2148)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 14:48:39 +00:00
renovate[bot]
da3698f6d5 Update all non-major dependencies (#2147)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 14:48:13 +00:00
renovate[bot]
c1f55a64a8 Update tj-actions/changed-files digest to dcc7a0c (#2143)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 14:34:45 +00:00
RiotRobot
57aa266320 v1.11.93-rc.0 2025-02-18 13:17:21 +00:00
ElementRobot
81f76fe574 Merge pull request #2138 from element-hq/actions/localazy-download
Localazy Download
2025-02-14 07:33:09 +01:00
t3chguy
af7e8a7e0f [create-pull-request] automated change 2025-02-14 06:06:20 +00:00
97 changed files with 6927 additions and 4319 deletions

35
.github/SSLcom-sandbox.crt vendored Normal file
View File

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

View File

@@ -62,7 +62,7 @@ jobs:
name: Windows ${{ matrix.arch }}
strategy:
matrix:
arch: [ia32, x64]
arch: [x64, arm64]
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
@@ -92,7 +92,6 @@ jobs:
uses: ./.github/workflows/build_linux.yaml
with:
arch: ${{ matrix.arch }}
config: ${{ needs.prepare.outputs.config }}
sqlcipher: ${{ matrix.sqlcipher }}
version: ${{ needs.prepare.outputs.nightly-version }}
@@ -108,12 +107,14 @@ jobs:
environment: ${{ needs.prepare.outputs.deploy == 'true' && 'packages.element.io' || '' }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- name: Prepare artifacts for deployment
run: |
set -x
# Windows
for arch in x64 ia32 arm64
for arch in x64 arm64
do
if [ -d "win-$arch" ]; then
mkdir -p packages.element.io/{install,update}/win32/$arch
@@ -145,8 +146,10 @@ jobs:
- name: "[Nightly] Strip version from installer file"
if: needs.prepare.outputs.nightly-version != ''
run: |
set -x
# Windows
for arch in x64 ia32 arm64
for arch in x64 arm64
do
[ -d "win-$arch" ] && mv packages.element.io/install/win32/$arch/{*,"Element Nightly Setup"}.exe
done
@@ -161,8 +164,10 @@ jobs:
- name: "[Release] Prepare release latest symlink"
if: needs.prepare.outputs.nightly-version == ''
run: |
set -x
# Windows
for arch in x64 ia32 arm64
for arch in x64 arm64
do
if [ -d "win-$arch" ]; then
pushd packages.element.io/install/win32/$arch
@@ -192,23 +197,17 @@ jobs:
- name: Stash packages.element.io
if: needs.prepare.outputs.deploy == 'false'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: packages.element.io
path: packages.element.io
# Workaround for https://www.cloudflarestatus.com/incidents/t5nrjmpxc1cj
- uses: unfor19/install-aws-cli-action@e8b481e524a99f37fbd39fdc1dcb3341ab091367 # v1
if: needs.prepare.outputs.deploy == 'true'
with:
version: 2.22.35
verbose: false
arch: amd64
# Checksum algorithm specified as per https://developers.cloudflare.com/r2/examples/aws/aws-cli/
- name: Deploy artifacts
if: needs.prepare.outputs.deploy == 'true'
run: |
aws s3 cp --recursive packages.element.io/ s3://$R2_BUCKET/$DEPLOYMENT_DIR --endpoint-url $R2_URL --region auto
set -x
aws s3 cp --recursive packages.element.io/ s3://$R2_BUCKET/$DEPLOYMENT_DIR --endpoint-url $R2_URL --region auto --checksum-algorithm CRC32
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
@@ -217,7 +216,7 @@ jobs:
- name: Notify packages.element.io of new files
if: needs.prepare.outputs.deploy == 'true'
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3
uses: peter-evans/repository-dispatch@5fc4efd1a4797ddb68ffd0714a238564e4cc0e6f # v4
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
repository: element-hq/packages.element.io
@@ -227,6 +226,8 @@ jobs:
id: deb
if: needs.linux.result == 'success'
run: |
set -x
for arch in amd64 arm64
do
echo "$arch=$(ls linux-$arch-sqlcipher-static/*.deb | tail -n1)" >> $GITHUB_OUTPUT
@@ -234,7 +235,7 @@ jobs:
- name: Stash debs
if: needs.prepare.outputs.deploy == 'false' && needs.linux.result == 'success'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: debs
path: |
@@ -273,19 +274,21 @@ jobs:
id-token: write # This is required for requesting the JWT
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5
with:
role-to-assume: arn:aws:iam::264135176173:role/Push-ElementDesktop-MSI
role-session-name: githubaction-run-${{ github.run_id }}
aws-region: ${{ env.AWS_REGION }}
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
pattern: win-*
- name: Copy files to S3
run: |
set -x
PREFIX="${VERSION%.*}"
for file in win-*/*.msi; do
filename=$(basename "$file")

View File

@@ -13,8 +13,9 @@ jobs:
permissions:
contents: read
with:
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
version: ${{ github.event.pull_request.base.ref == 'develop' && 'develop' || '' }}
config: ${{ (github.event.pull_request.base.ref || github.ref_name) == 'develop' && 'element.io/nightly' || 'element.io/release' }}
version: ${{ (github.event.pull_request.base.ref || github.ref_name) == 'develop' && 'develop' || '' }}
branch-matching: true
windows:
needs: fetch
@@ -22,9 +23,10 @@ jobs:
uses: ./.github/workflows/build_windows.yaml
strategy:
matrix:
arch: [x64, ia32]
arch: [x64, ia32, arm64]
with:
arch: ${{ matrix.arch }}
blob_report: true
linux:
needs: fetch
@@ -35,110 +37,49 @@ jobs:
sqlcipher: [system, static]
arch: [amd64, arm64]
with:
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
sqlcipher: ${{ matrix.sqlcipher }}
arch: ${{ matrix.arch }}
blob_report: true
macos:
needs: fetch
name: macOS
uses: ./.github/workflows/build_macos.yaml
with:
blob_report: true
test:
needs:
- macos
- linux
- windows
strategy:
matrix:
include:
- name: macOS Universal
os: macos-14
artifact: macos
executable: "/Users/runner/Applications/Element.app/Contents/MacOS/Element"
# We need to mount the DMG and copy the app to the Applications folder as a mounted DMG is
# read-only and thus would not allow us to override the fuses as is required for Playwright.
prepare_cmd: |
hdiutil attach ./dist/*.dmg -mountpoint /Volumes/Element &&
rsync -a /Volumes/Element/Element.app ~/Applications/ &&
hdiutil detach /Volumes/Element
- name: "Linux (amd64) (sqlcipher: system)"
os: ubuntu-22.04
artifact: linux-amd64-sqlcipher-system
executable: "/opt/Element/element-desktop"
prepare_cmd: "sudo apt-get -qq update && sudo apt install ./dist/*.deb"
- name: "Linux (amd64) (sqlcipher: static)"
os: ubuntu-22.04
artifact: linux-amd64-sqlcipher-static
executable: "/opt/Element/element-desktop"
prepare_cmd: "sudo apt-get -qq update && sudo apt install ./dist/*.deb"
- name: "Linux (arm64) (sqlcipher: system)"
os: ubuntu-22.04-arm
artifact: linux-arm64-sqlcipher-system
executable: "/opt/Element/element-desktop"
prepare_cmd: "sudo apt-get -qq update && sudo apt install -y ./dist/*.deb"
- name: "Linux (arm64) (sqlcipher: static)"
os: ubuntu-22.04-arm
artifact: linux-arm64-sqlcipher-static
executable: "/opt/Element/element-desktop"
prepare_cmd: "sudo apt-get -qq update && sudo apt install -y ./dist/*.deb"
- name: Windows (x86)
os: windows-2022
artifact: win-ia32
executable: "./dist/win-ia32-unpacked/Element.exe"
- name: Windows (x64)
os: windows-2022
artifact: win-x64
executable: "./dist/win-unpacked/Element.exe"
name: Test ${{ matrix.name }}
runs-on: ${{ matrix.os }}
tests-done:
needs: [windows, linux, macos]
runs-on: ubuntu-24.04
if: ${{ !cancelled() }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
cache: "yarn"
node-version: "lts/*"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Install dependencies
run: yarn install --frozen-lockfile
- uses: actions/download-artifact@v4
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: ${{ matrix.artifact }}
path: dist
pattern: blob-report-*
path: all-blob-reports
merge-multiple: true
- name: Prepare for tests
run: ${{ matrix.prepare_cmd }}
if: matrix.prepare_cmd
# We previously disabled the `EnableNodeCliInspectArguments` fuse, but Playwright requires
# it to be enabled to test Electron apps, so turn it back on.
- name: Set EnableNodeCliInspectArguments fuse enabled
run: $RUN_AS npx @electron/fuses write --app ${{ matrix.executable }} EnableNodeCliInspectArguments=on
shell: bash
env:
# We need sudo on Linux as it is installed in /opt/
RUN_AS: ${{ runner.os == 'Linux' && 'sudo' || '' }}
- name: Workaround macOS GHA permission issues
if: runner.os == 'macOS'
run: |
sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"
sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/opt/off/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"
- name: Run tests
uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a
timeout-minutes: 5
with:
run: "yarn test ${{ runner.os != 'Linux' && '--ignore-snapshots' || '' }}"
env:
ELEMENT_DESKTOP_EXECUTABLE: ${{ matrix.executable }}
- name: Merge into HTML Report
run: yarn playwright merge-reports -c ./playwright.config.ts --reporter=html ./all-blob-reports
- name: Upload HTML report
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: ${{ matrix.artifact }}-test
path: playwright/html-report
name: html-report
path: playwright-report
retention-days: 14
- if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: exit 1

View File

@@ -4,14 +4,14 @@
on:
workflow_call:
inputs:
ref:
type: string
required: false
description: "The git ref to checkout, defaults to the default branch"
arch:
type: string
required: true
description: "The architecture to build for, one of 'amd64' | 'arm64'"
config:
type: string
required: true
description: "The config directory to use"
version:
type: string
required: false
@@ -20,21 +20,66 @@ on:
type: string
required: true
description: "How to link sqlcipher, one of 'system' | 'static'"
blob_report:
type: boolean
required: false
description: "Whether to run the blob report"
prepare-artifact-name:
type: string
required: false
description: |
The name of the prepare artifact to use, defaults to 'webapp'.
The artifact must contain the following:
+ webapp.asar - the asar archive of the webapp to embed in the desktop app
+ electronVersion - the version of electron to use for cache keying
+ hakHash - the hash of the .hak directory to use for cache keying
+ changelog.Debian - the changelog file to embed in the Debian package
+ variant.json - the variant configuration to use for the build
The artifact can also contain any additional files which will be applied as overrides to the checkout root before building,
for example icons in the `build/` directory to override the app icons.
default: "webapp"
test:
type: boolean
required: false
default: true
description: "Whether to run the test stage after building"
test-args:
type: string
required: false
description: "Additional arguments to pass to playwright"
runs-on:
type: string
required: false
description: "The runner image to use, normally set for you, may be needed for running in private repos."
artifact-prefix:
type: string
required: false
description: "An optional prefix to add to the artifact name, useful for distinguishing builds in private repos."
default: ""
targets:
type: string
required: false
description: "List of targets to build"
default: "tar.gz deb"
env:
SQLCIPHER_BUNDLED: ${{ inputs.sqlcipher == 'static' && '1' || '' }}
MAX_GLIBC: 2.31 # bullseye-era glibc, used by glibc-check.sh
permissions: {} # No permissions required
jobs:
build:
name: Build Linux ${{ inputs.arch }} SQLCipher ${{ inputs.sqlcipher }}
# We build on native infrastructure as matrix-seshat fails to cross-compile properly
# https://github.com/matrix-org/seshat/issues/135
runs-on: ${{ inputs.arch == 'arm64' && 'ubuntu-22.04-arm' || 'ubuntu-22.04' }}
runs-on: ${{ inputs.runs-on || (inputs.arch == 'arm64' && 'ubuntu-22.04-arm' || 'ubuntu-22.04') }}
env:
HAK_DOCKER_IMAGE: ghcr.io/element-hq/element-desktop-dockerbuild
steps:
- name: Resolve docker image tag for push
if: github.event_name == 'push'
run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:$GITHUB_REF_NAME" >> $GITHUB_ENV
run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:$REF" >> $GITHUB_ENV
env:
REF: ${{ inputs.ref || github.ref_name }}
- name: Resolve docker image tag for release
if: github.event_name == 'release'
run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:staging" >> $GITHUB_ENV
@@ -60,23 +105,26 @@ jobs:
}
}
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
name: webapp
repository: element-hq/element-desktop
ref: ${{ inputs.ref }}
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: ${{ inputs.prepare-artifact-name }}
- name: Cache .hak
id: cache
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
key: ${{ runner.os }}-${{ github.ref_name }}-${{ inputs.sqlcipher }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion', 'dockerbuild/*') }}
path: |
./.hak
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
node-version-file: .node-version
cache: "yarn"
env:
# Workaround for https://github.com/actions/setup-node/issues/317
@@ -87,18 +135,18 @@ jobs:
- name: "Get modified files"
id: changed_files
if: steps.cache.outputs.cache-hit != 'true' && github.event_name == 'pull_request'
uses: tj-actions/changed-files@d6e91a2266cdb9d62096cebf1e8546899c6aa18f # v45
if: steps.cache.outputs.cache-hit != 'true' && github.event_name == 'pull_request' && github.repository == 'element-hq/element-desktop'
uses: tj-actions/changed-files@823fcebdb31bb35fdf2229d9f769b400309430d0 # v46
with:
files: |
dockerbuild/**
# This allows contributors to test changes to the dockerbuild image within a pull request
- name: Build docker image
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
if: steps.changed_files.outputs.any_modified == 'true'
with:
context: dockerbuild
file: dockerbuild/Dockerfile
load: true
platforms: linux/${{ inputs.arch }}
tags: ${{ env.HAK_DOCKER_IMAGE }}
@@ -123,27 +171,20 @@ jobs:
./scripts/glibc-check.sh $filename
done
- name: "[Nightly] Resolve version"
if: inputs.version != ''
run: |
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
- name: Generate debian files and arguments
run: |
if [ -f changelog.Debian ]; then
echo "ED_DEBIAN_CHANGELOG=changelog.Debian" >> $GITHUB_ENV
fi
# Workaround for https://github.com/electron-userland/electron-builder/issues/6116
- name: Install fpm
if: inputs.arch == 'arm64'
run: |
sudo apt-get install ruby-dev build-essential
sudo gem install fpm
echo "USE_SYSTEM_FPM=true" >> $GITHUB_ENV
- name: Build App
run: yarn build --publish never -l ${{ steps.config.outputs.build-args }}
run: yarn build --publish never ${{ steps.config.outputs.build-args }} -l ${{ inputs.targets }}
env:
VARIANT_PATH: variant.json
# Only set for Nightly builds
VERSION: ${{ inputs.version }}
# Workaround for https://github.com/electron-userland/electron-builder/issues/5721
USE_HARD_LINKS: false
- name: Check native libraries
run: |
@@ -151,11 +192,9 @@ jobs:
shopt -s globstar
FILES=$(file dist/**/*.node)
echo "$FILES"
echo $FILES
if [ grep -v "$ARCH" ]; then
exit 1
fi
! echo "$FILES" | grep -v "$ARCH"
LIBS=$(readelf -d dist/**/*.node | grep NEEDED)
echo "$LIBS"
@@ -175,10 +214,48 @@ jobs:
# We exclude *-unpacked as it loses permissions and the tarball contains it with correct permissions
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: linux-${{ inputs.arch }}-sqlcipher-${{ inputs.sqlcipher }}
name: ${{ inputs.artifact-prefix }}linux-${{ inputs.arch }}-sqlcipher-${{ inputs.sqlcipher }}
path: |
dist
!dist/*-unpacked/**
retention-days: 1
- name: Assert deb is present and valid
if: contains(inputs.targets, 'deb')
run: |
test -f ./dist/element-desktop*$ARCH.deb
DEB_LISTING=$(dpkg-deb --fsys-tarfile ./dist/element-desktop*.deb | tar -tv)
echo "deb listing: "
echo "$DEB_LISTING"
! echo "$DEB_LISTING" | grep '^h'
env:
ARCH: ${{ inputs.arch }}
- name: Assert tar.gz is present
if: contains(inputs.targets, 'tar.gz')
run: |
test -f ./dist/element-desktop*.tar.gz
TAR_GZ_LISTING=$(tar -tvf ./dist/element-desktop*.tar.gz)
echo "tar.gz listing: "
echo "$TAR_GZ_LISTING"
! echo "$TAR_GZ_LISTING" | grep '^h'
test:
name: Test Linux ${{ inputs.arch }} SQLCipher ${{ inputs.sqlcipher }}
needs: build
if: inputs.test && contains(inputs.targets, 'deb')
uses: ./.github/workflows/build_test.yaml
with:
project: linux-${{ inputs.arch }}-sqlcipher-${{ inputs.sqlcipher }}
artifact: ${{ inputs.artifact-prefix }}linux-${{ inputs.arch }}-sqlcipher-${{ inputs.sqlcipher }}
runs-on: ${{ inputs.runs-on || (inputs.arch == 'arm64' && 'ubuntu-22.04-arm' || 'ubuntu-22.04') }}
executable: /opt/Element*/element-desktop*
prepare_cmd: |
sudo apt-get -qq update
sudo apt install ./dist/*.deb
blob_report: ${{ inputs.blob_report }}
args: ${{ inputs.test-args }}

View File

@@ -15,6 +15,10 @@ on:
APPLE_CSC_LINK:
required: false
inputs:
ref:
type: string
required: false
description: "The git ref to checkout, defaults to the default branch"
version:
type: string
required: false
@@ -27,21 +31,62 @@ on:
type: string
required: false
description: "The URL to which the output will be deployed."
blob_report:
type: boolean
required: false
description: "Whether to run the blob report"
prepare-artifact-name:
type: string
required: false
description: |
The name of the prepare artifact to use, defaults to 'webapp'.
The artifact must contain the following:
+ webapp.asar - the asar archive of the webapp to embed in the desktop app
+ electronVersion - the version of electron to use for cache keying
+ hakHash - the hash of the .hak directory to use for cache keying
+ variant.json - the variant configuration to use for the build
The artifact can also contain any additional files which will be applied as overrides to the checkout root before building,
for example icons in the `build/` directory to override the app icons.
default: "webapp"
test:
type: boolean
required: false
default: true
description: "Whether to run the test stage after building"
test-args:
type: string
required: false
description: "Additional arguments to pass to playwright"
artifact-prefix:
type: string
required: false
description: "An optional prefix to add to the artifact name, useful for distinguishing builds in private repos."
default: ""
targets:
type: string
required: false
description: "List of targets to build"
default: "dmg zip"
permissions: {} # No permissions required
jobs:
build:
name: Build macOS Universal
runs-on: macos-14 # M1
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
name: webapp
repository: element-hq/element-desktop
ref: ${{ inputs.ref }}
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: ${{ inputs.prepare-artifact-name }}
- name: Cache .hak
id: cache
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
key: ${{ runner.os }}-${{ hashFiles('hakHash', 'electronVersion') }}
path: |
@@ -56,42 +101,40 @@ jobs:
rustup target add x86_64-apple-darwin
# M1 macos-14 comes without Python preinstalled
- uses: actions/setup-python@v5
- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
with:
python-version: "3.12"
python-version: "3.13"
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
node-version-file: .node-version
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
# Python 3.12 drops distutils which keytar relies on
- name: Install setuptools
run: pip3 install setuptools
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: |
# Python 3.12 drops distutils which keytar relies on
pip3 install setuptools
yarn build:native:universal
- name: "[Nightly] Resolve version"
if: inputs.version != ''
run: |
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
run: yarn build:native:universal
# We split these because electron-builder gets upset if we set CSC_LINK even to an empty string
- name: "[Signed] Build App"
if: inputs.sign != ''
run: |
yarn build:universal --publish never
yarn build:universal --publish never -m ${{ inputs.targets }}
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
VARIANT_PATH: variant.json
# Only set for Nightly builds
VERSION: ${{ inputs.version }}
- name: Check app was signed & notarised successfully
if: inputs.sign != ''
@@ -104,9 +147,10 @@ jobs:
- name: "[Unsigned] Build App"
if: inputs.sign == ''
run: |
yarn build:universal --publish never
yarn build:universal --publish never -m ${{ inputs.targets }}
env:
CSC_IDENTITY_AUTO_DISCOVERY: false
VARIANT_PATH: variant.json
- name: Generate releases.json
if: inputs.base-url
@@ -136,10 +180,39 @@ jobs:
# We exclude mac-universal as the unpacked app takes forever to upload and zip and dmg already contains it
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: macos
name: ${{ inputs.artifact-prefix }}macos
path: |
dist
!dist/mac-universal/**
retention-days: 1
- name: Assert zip is present
if: contains(inputs.targets, 'zip')
run: |
test -f ./dist/Element*-mac.zip
- name: Assert dmg is present
if: contains(inputs.targets, 'dmg')
run: |
test -f ./dist/Element*.dmg
test:
name: Test macOS Universal
needs: build
if: inputs.test && contains(inputs.targets, 'dmg')
uses: ./.github/workflows/build_test.yaml
with:
project: macos
artifact: ${{ inputs.artifact-prefix }}macos
runs-on: macos-14
executable: /Users/runner/Applications/Element*.app/Contents/MacOS/Element*
# We need to mount the DMG and copy the app to the Applications folder as a mounted DMG is
# read-only and thus would not allow us to override the fuses as is required for Playwright.
prepare_cmd: |
hdiutil attach ./dist/*.dmg -mountpoint /Volumes/Element &&
rsync -a /Volumes/Element/Element*.app ~/Applications/ &&
hdiutil detach /Volumes/Element
blob_report: ${{ inputs.blob_report }}
args: ${{ inputs.test-args }}

View File

@@ -20,6 +20,11 @@ on:
required: false
default: false
description: "Whether the build should be deployed to production"
branch-matching:
type: boolean
required: false
default: false
description: "Whether the branch name should be matched to find the element-web commit"
secrets:
# Required if `nightly` is set
CF_R2_ACCESS_KEY_ID:
@@ -34,12 +39,9 @@ on:
packages-dir:
description: "The directory non-deb packages for this run should live in within packages.element.io"
value: ${{ inputs.nightly && 'nightly' || 'desktop' }}
# These are just simple pass-throughs of the input to simplify reuse of complex inline conditions
config:
description: "The relative path to the config file for this run"
value: ${{ inputs.config }}
# This is just a simple pass-through of the input to simplify reuse of complex inline conditions
deploy:
description: "The relative path to the config file for this run"
description: "Whether the build should be deployed to production"
value: ${{ inputs.deploy }}
permissions: {}
jobs:
@@ -52,19 +54,42 @@ jobs:
outputs:
nightly-version: ${{ steps.versions.outputs.nightly }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
node-version-file: .node-version
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Fetch Element Web
- name: Fetch Element Web (matching branch)
id: branch-matching
if: inputs.branch-matching
continue-on-error: true
run: |
scripts/branch-match.sh
cp "$CONFIG_DIR/config.json" element-web/
yarn --cwd element-web install --frozen-lockfile
yarn --cwd element-web run build
mv element-web/webapp .
yarn asar-webapp
env:
# These must be set for branch-match.sh to get the right branch
REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
CONFIG_DIR: ${{ inputs.config }}
- name: Fetch Element Web (${{ inputs.version }})
if: steps.branch-matching.outcome == 'failure' || steps.branch-matching.outcome == 'skipped'
run: yarn run fetch --noverify -d ${{ inputs.config }} ${{ inputs.version }}
- name: Copy variant config
run: cp "$CONFIG_DIR/build.json" variant.json
env:
CONFIG_DIR: ${{ inputs.config }}
# 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: |
@@ -83,7 +108,7 @@ jobs:
aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-amd64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p' >> VERSIONS
aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-arm64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p' >> VERSIONS
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/x64/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/ia32/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/arm64/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
# Pick the greatest one
VERSION=$(cat VERSIONS | sort -uf | tail -n1)
@@ -93,8 +118,6 @@ jobs:
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
# Workaround for https://www.cloudflarestatus.com/incidents/t5nrjmpxc1cj
AWS_REQUEST_CHECKSUM_CALCULATION: when_required
R2_BUCKET: ${{ vars.R2_BUCKET }}
R2_URL: ${{ vars.CF_R2_S3_API }}
@@ -142,13 +165,13 @@ jobs:
echo "| Element Web | [$WEB_VERSION](https://github.com/element-hq/element-web/commit/$WEB_VERSION) |" >> $GITHUB_STEP_SUMMARY
echo "| JS SDK | [$JS_VERSION](https://github.com/matrix-org/matrix-js-sdk/commit/$JS_VERSION) |" >> $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: webapp
retention-days: 1
path: |
webapp.asar
package.json
electronVersion
hakHash
changelog.Debian
variant.json

101
.github/workflows/build_test.yaml vendored Normal file
View File

@@ -0,0 +1,101 @@
# This action helps run Playwright tests within one of the build_* stages.
on:
workflow_call:
inputs:
runs-on:
type: string
required: true
description: "The runner image to use"
artifact:
type: string
required: true
description: "The name of the artifact to download"
project:
type: string
required: true
description: "The Playwright project to use for testing"
executable:
type: string
required: true
description: "Path to the executable to test"
prepare_cmd:
type: string
required: false
description: "Command to run to prepare the executable or environment for testing"
blob_report:
type: boolean
default: false
description: "Whether to upload a blob report instead of the HTML report"
args:
type: string
required: false
description: "Additional arguments to pass to playwright, for e.g. skipping specific tests"
permissions: {}
jobs:
test:
name: Test ${{ inputs.project }}
runs-on: ${{ inputs.runs-on }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
repository: ${{ github.repository == 'element-hq/element-web-pro' && 'element-hq/element-desktop' || github.repository }}
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: .node-version
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: ${{ inputs.artifact }}
path: dist
- name: Prepare for tests
run: ${{ inputs.prepare_cmd }}
if: inputs.prepare_cmd
- name: Expand executable path
id: executable
shell: bash
env:
EXECUTABLE: ${{ inputs.executable }}
run: |
FILES=($EXECUTABLE)
echo "path=${FILES[0]}" >> $GITHUB_OUTPUT
# We previously disabled the `EnableNodeCliInspectArguments` fuse, but Playwright requires
# it to be enabled to test Electron apps, so turn it back on.
- name: Set EnableNodeCliInspectArguments fuse enabled
run: $RUN_AS npx @electron/fuses write --app "$EXECUTABLE" EnableNodeCliInspectArguments=on
shell: bash
env:
# We need sudo on Linux as it is installed in /opt/
RUN_AS: ${{ runner.os == 'Linux' && 'sudo' || '' }}
EXECUTABLE: ${{ steps.executable.outputs.path }}
- name: Run tests
uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a
timeout-minutes: 20
with:
run: yarn test --project=${{ inputs.project }} ${{ runner.os != 'Linux' && '--ignore-snapshots' || '' }} ${{ inputs.blob_report == false && '--reporter=html' || '' }} ${{ inputs.args }}
env:
ELEMENT_DESKTOP_EXECUTABLE: ${{ steps.executable.outputs.path }}
- name: Upload blob report
if: always() && inputs.blob_report
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: blob-report-${{ inputs.artifact }}
path: blob-report
retention-days: 1
- name: Upload HTML report
if: always() && inputs.blob_report == false
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: ${{ inputs.artifact }}-test
path: playwright-report
retention-days: 14

View File

@@ -18,6 +18,10 @@ on:
ESIGNER_USER_TOTP:
required: false
inputs:
ref:
type: string
required: false
description: "The git ref to checkout, defaults to the default branch"
arch:
type: string
required: true
@@ -30,13 +34,56 @@ on:
type: string
required: false
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
blob_report:
type: boolean
required: false
description: "Whether to run the blob report"
prepare-artifact-name:
type: string
required: false
description: |
The name of the prepare artifact to use, defaults to 'webapp'.
The artifact must contain the following:
+ webapp.asar - the asar archive of the webapp to embed in the desktop app
+ electronVersion - the version of electron to use for cache keying
+ hakHash - the hash of the .hak directory to use for cache keying
+ variant.json - the variant configuration to use for the build
The artifact can also contain any additional files which will be applied as overrides to the checkout root before building,
for example icons in the `build/` directory to override the app icons.
default: "webapp"
test:
type: boolean
required: false
default: true
description: "Whether to run the test stage after building"
test-runs-on:
type: string
required: false
description: "The runner image to use for testing, normally set for you, may be needed for running in private repos."
test-args:
type: string
required: false
description: "Additional arguments to pass to playwright"
artifact-prefix:
type: string
required: false
description: "An optional prefix to add to the artifact name, useful for distinguishing builds in private repos."
default: ""
targets:
type: string
required: false
description: "List of targets to build"
default: "squirrel msi"
permissions: {} # No permissions required
jobs:
build:
runs-on: windows-2022
name: Build Windows ${{ inputs.arch }}
runs-on: windows-2025
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
env:
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.22000.0/x86/signtool.exe"
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.26100.0/x86/signtool.exe"
steps:
- uses: nbucic/variable-mapper@0673f6891a0619ba7c002ecfed0f9f4f39017b6f
id: config
@@ -56,29 +103,28 @@ jobs:
"ia32": {
"target": "i686-pc-windows-msvc",
"build-args": "--ia32",
"arch": "x86"
"arch": "x86",
"extra_config": "{\"user_notice\": {\"title\": \"Your desktop environment is unsupported.\",\"description\": \"Support for 32-bit Windows installations has ended. Transition to the web or mobile app for continued access.\"}}"
}
}
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
name: webapp
repository: element-hq/element-desktop
ref: ${{ inputs.ref }}
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: ${{ inputs.prepare-artifact-name }}
- name: Cache .hak
id: cache
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
key: ${{ runner.os }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion') }}
path: |
./.hak
- name: Set up build tools
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
with:
arch: ${{ steps.config.outputs.arch || inputs.arch }}
# ActiveTCL package on choco is from 2015,
# this one is newer but includes more than we need
- name: Choco install tclsh
@@ -102,15 +148,40 @@ jobs:
rustup default stable
rustup target add ${{ steps.config.outputs.target }}
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
node-version-file: .node-version
cache: "yarn"
# Does not need branch matching as only analyses this layer
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Insert config snippet
if: steps.config.outputs.extra_config != ''
shell: bash
run: |
mkdir config-edit
yarn asar extract webapp.asar config-edit
cd config-edit
mv config.json old-config.json
echo '${{ steps.config.outputs.extra_config }}' | jq -s '.[0] * .[1]' old-config.json - > config.json
rm old-config.json
cd ..
rm webapp.asar
yarn asar pack config-edit/ webapp.asar
- name: Set up sqlcipher macros
if: steps.cache.outputs.cache-hit != 'true' && contains(inputs.arch, 'arm')
shell: pwsh
run: |
echo "NCC=${{ github.workspace }}\scripts\cl.bat" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Set up build tools
if: steps.cache.outputs.cache-hit != 'true'
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
with:
arch: ${{ steps.config.outputs.arch || inputs.arch }}
- name: Build Natives
if: steps.cache.outputs.cache-hit != 'true'
run: |
@@ -160,29 +231,65 @@ jobs:
INSTALL_DIR: C:\Users\runneradmin\eSignerCKA
MASTER_KEY_FILE: C:\Users\runneradmin\eSignerCKA\master.key
- name: "[Nightly] Resolve version"
if: inputs.version != ''
shell: bash
run: |
echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV
# XXX: For whatever reason if we use `yarn build ...` it freezes, but splitting it into parts it is fine
- run: yarn run build:ts
- run: yarn run build:res
- name: Build App
run: yarn build --publish never ${{ steps.config.outputs.build-args }} -w ${{ inputs.targets }}
env:
VARIANT_PATH: variant.json
# Only set for Nightly builds
# The windows packager relies on parsing this as semver, so we have to make it look like one.
# This will give our update packages really stupid names, but we probably can't change that either
# because squirrel windows parses them for the version too. We don't really care: nobody sees them.
# We just give the installer a static name, so you'll just see this in the 'about' dialog.
# Turns out if you use 0.0.0 here it makes Squirrel windows crash, so we use 0.0.1.
VERSION: ${{ inputs.version && format('0.0.1-nightly.{0}', inputs.version) || '' }}
- name: Trust eSigner sandbox cert
if: inputs.sign == ''
run: |
yarn electron-builder --publish never -w ${{ steps.config.outputs.build-args }}
Set-StrictMode -Version 'Latest'
Import-Certificate -CertStoreLocation Cert:\LocalMachine\Root -FilePath .github/SSLcom-sandbox.crt
- name: Check app was signed successfully
if: inputs.sign
run: |
. "$env:SIGNTOOL_PATH" verify /pa (get-item ./dist/squirrel-windows*/*.exe)
Set-StrictMode -Version 'Latest'
Get-ChildItem `
-Recurse dist `
-Include *.exe, *.msi `
| ForEach-Object -Process {. $env:SIGNTOOL_PATH verify /pa $_.FullName; if(!$?) { throw }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
with:
name: win-${{ inputs.arch }}
name: ${{ inputs.artifact-prefix }}win-${{ inputs.arch }}
path: |
dist
retention-days: 1
- name: Assert executable is present
run: |
Test-Path './dist/win-*unpacked/Element*.exe'
- name: Assert all Squirrel files are present
if: contains(inputs.targets, 'squirrel')
run: |
Test-Path './dist/squirrel-windows*/Element Setup*.exe'
Test-Path './dist/squirrel-windows*/element-desktop-*-full.nupkg'
Test-Path './dist/squirrel-windows*/RELEASES'
- name: Assert MSI is present
if: contains(inputs.targets, 'msi')
run: |
Test-Path './dist/Element*.msi'
test:
name: Test Windows ${{ inputs.arch }}
needs: build
if: inputs.test
uses: ./.github/workflows/build_test.yaml
with:
project: win-${{ inputs.arch }}
artifact: ${{ inputs.artifact-prefix }}win-${{ inputs.arch }}
runs-on: ${{ inputs.test-runs-on || (inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2022') }}
executable: ./dist/win*-unpacked/Element*.exe
blob_report: ${{ inputs.blob_report }}
args: ${{ inputs.test-args }}

View File

@@ -19,20 +19,20 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- name: Set up QEMU
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
with:
install: true
- name: Build test image
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
context: dockerbuild
file: dockerbuild/Dockerfile
push: false
load: true
tags: element-desktop-dockerbuild
@@ -42,7 +42,7 @@ jobs:
run: docker run -v $PWD:/project element-desktop-dockerbuild yarn install
- name: Log in to the Container registry
uses: docker/login-action@327cd5a69de6c009b9ce71bce8395f28e651bf99
uses: docker/login-action@28fdb31ff34708d19615a74d67103ddc2ea9725c
if: github.event_name != 'pull_request'
with:
registry: ${{ env.REGISTRY }}
@@ -52,7 +52,7 @@ jobs:
- name: Extract metadata for Docker
id: meta
if: github.event_name != 'pull_request'
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -61,9 +61,9 @@ jobs:
- name: Build and push Docker image
if: github.event_name != 'pull_request'
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
context: dockerbuild
file: dockerbuild/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -19,6 +19,7 @@ jobs:
contents: write
issues: write
pull-requests: read
id-token: write
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}

View File

@@ -9,9 +9,9 @@ jobs:
name: "Typescript Syntax Check"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
cache: "yarn"
@@ -35,9 +35,9 @@ jobs:
name: "ESLint"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
cache: "yarn"
@@ -53,9 +53,9 @@ jobs:
name: "Workflow Lint"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
cache: "yarn"
@@ -71,9 +71,9 @@ jobs:
name: "Analyse Dead Code"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/setup-node@v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: package.json
cache: "yarn"

View File

@@ -12,9 +12,11 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10
with:
operations-per-run: 100
operations-per-run: 250
days-before-issue-stale: -1
days-before-issue-close: -1
days-before-pr-stale: 180
days-before-pr-close: 0
close-pr-message: "This PR has been automatically closed because it has been stale for 180 days. If you wish to continue working on this PR, please ping a maintainer to reopen it."

1
.node-version Normal file
View File

@@ -0,0 +1 @@
24.11.1

View File

@@ -1,3 +1,651 @@
Changes in [1.12.4](https://github.com/element-hq/element-desktop/releases/tag/v1.12.4) (2025-11-18)
====================================================================================================
## ✨ Features
* Update nightly and release builds to use the dedicated subdomain for 'bug\_report\_endpoint\_url' ([#2677](https://github.com/element-hq/element-desktop/pull/2677)). Contributed by @benbz.
* Apply aria-hidden to emoji in SAS verification ([#31204](https://github.com/element-hq/element-web/pull/31204)). Contributed by @t3chguy.
* Add options to hide header and composer of room view for the module api ([#31095](https://github.com/element-hq/element-web/pull/31095)). Contributed by @florianduros.
* Experimental Module API Additions ([#30863](https://github.com/element-hq/element-web/pull/30863)). Contributed by @dbkr.
* Change polls to use fieldset/legend markup ([#31160](https://github.com/element-hq/element-web/pull/31160)). Contributed by @langleyd.
* Use compound Button styles for Jitsi button ([#31159](https://github.com/element-hq/element-web/pull/31159)). Contributed by @Half-Shot.
* Add FocusLock to emoji picker ([#31146](https://github.com/element-hq/element-web/pull/31146)). Contributed by @langleyd.
* Move room name, avatar, and topic to IOpts. ([#30981](https://github.com/element-hq/element-web/pull/30981)). Contributed by @kaylendog.
* Add a devtool for looking at users and their devices ([#30983](https://github.com/element-hq/element-web/pull/30983)). Contributed by @uhoreg.
## 🐛 Bug Fixes
* Fix room list handling of membership changes ([#31197](https://github.com/element-hq/element-web/pull/31197)). Contributed by @t3chguy.
* Fix room list unable to be resized when displayed after a module ([#31186](https://github.com/element-hq/element-web/pull/31186)). Contributed by @florianduros.
* Inhibit keyboard highlights in dialogs when effector is not in focus ([#31181](https://github.com/element-hq/element-web/pull/31181)). Contributed by @t3chguy.
* Strip mentions from forwarded messages ([#30884](https://github.com/element-hq/element-web/pull/30884)). Contributed by @twassman.
* Don't allow pin or edit of messages with a send status ([#31158](https://github.com/element-hq/element-web/pull/31158)). Contributed by @langleyd.
* Hide room header buttons if the room hasn't been created yet. ([#31092](https://github.com/element-hq/element-web/pull/31092)). Contributed by @Half-Shot.
* Fix screen readers not indicating the emoji picker search field is focused. ([#31128](https://github.com/element-hq/element-web/pull/31128)). Contributed by @langleyd.
* Fix emoji picker highlight missing when not active element ([#31148](https://github.com/element-hq/element-web/pull/31148)). Contributed by @t3chguy.
* Add relevant aria attribute for selected emoji in the emoji picker ([#31125](https://github.com/element-hq/element-web/pull/31125)). Contributed by @t3chguy.
* Fix tooltips within context menu portals being unreliable ([#31129](https://github.com/element-hq/element-web/pull/31129)). Contributed by @t3chguy.
* Avoid excessive re-render of room list and member list ([#31131](https://github.com/element-hq/element-web/pull/31131)). Contributed by @florianduros.
* Make emoji picker height responsive. ([#31130](https://github.com/element-hq/element-web/pull/31130)). Contributed by @langleyd.
* Emoji Picker: Focused emoji does not move with the arrow keys ([#30893](https://github.com/element-hq/element-web/pull/30893)). Contributed by @langleyd.
* Fix audio player seek bar position ([#31127](https://github.com/element-hq/element-web/pull/31127)). Contributed by @florianduros.
* Add aria label to emoji picker search ([#31126](https://github.com/element-hq/element-web/pull/31126)). Contributed by @langleyd.
Changes in [1.12.3](https://github.com/element-hq/element-desktop/releases/tag/v1.12.3) (2025-11-04)
====================================================================================================
## 🦖 Deprecations
* Remove allowVoipWithNoMedia feature flag ([#31087](https://github.com/element-hq/element-web/pull/31087)). Contributed by @Half-Shot.
## ✨ Features
* Change module API to be an instance getter ([#31025](https://github.com/element-hq/element-web/pull/31025)). Contributed by @dbkr.
## 🐛 Bug Fixes
* Wait for Electron to be ready before we fire syntax error dialog ([#2659](https://github.com/element-hq/element-desktop/pull/2659)). Contributed by @t3chguy.
* Show hover elements when keyboard focus is within an event tile ([#31078](https://github.com/element-hq/element-web/pull/31078)). Contributed by @t3chguy.
* Ensure toolbar navigation pattern works in MessageActionBar ([#31080](https://github.com/element-hq/element-web/pull/31080)). Contributed by @t3chguy.
* Ensure sent markers are hidden when showing thread summary. ([#31076](https://github.com/element-hq/element-web/pull/31076)). Contributed by @Half-Shot.
* Fix translation in dev mode ([#31045](https://github.com/element-hq/element-web/pull/31045)). Contributed by @florianduros.
* Fix sort order in space hierarchy ([#30975](https://github.com/element-hq/element-web/pull/30975)). Contributed by @t3chguy.
* New Room list: don't display message preview of thread ([#31043](https://github.com/element-hq/element-web/pull/31043)). Contributed by @florianduros.
* Revert "A11y: move focus to right panel when opened" ([#30999](https://github.com/element-hq/element-web/pull/30999)). Contributed by @florianduros.
* Fix highlights in messages (or search results) breaking links ([#30264](https://github.com/element-hq/element-web/pull/30264)). Contributed by @bojidar-bg.
* Add prepare script ([#31030](https://github.com/element-hq/element-web/pull/31030)). Contributed by @dbkr.
* Fix html exports by adding SDKContext ([#30987](https://github.com/element-hq/element-web/pull/30987)). Contributed by @t3chguy.
Changes in [1.12.2](https://github.com/element-hq/element-desktop/releases/tag/v1.12.2) (2025-10-21)
====================================================================================================
## ✨ Features
* Allow Desktop app to be auto-started minimised or focused ([#2622](https://github.com/element-hq/element-desktop/pull/2622)). Contributed by @t3chguy.
* Room List: Extend the viewport to avoid so many black spots when scrolling the room list ([#30867](https://github.com/element-hq/element-web/pull/30867)). Contributed by @langleyd.
* Hide calling buttons in room header before a room is created ([#30816](https://github.com/element-hq/element-web/pull/30816)). Contributed by @Half-Shot.
* Improve invite dialog ui - Part 2 ([#30836](https://github.com/element-hq/element-web/pull/30836)). Contributed by @florianduros.
## 🐛 Bug Fixes
* Fix hardlinks appearing in and breaking deb packages ([#2609](https://github.com/element-hq/element-desktop/pull/2609)). Contributed by @t3chguy.
* Fix platform settings race condition and make auto-launch tri-state ([#30977](https://github.com/element-hq/element-web/pull/30977)). Contributed by @t3chguy.
* Fix: member count in header and member list ([#30982](https://github.com/element-hq/element-web/pull/30982)). Contributed by @florianduros.
* Fix duration of voice message in timeline ([#30973](https://github.com/element-hq/element-web/pull/30973)). Contributed by @florianduros.
* Fix voice notes rendering at 00:00 when playback had not begun. ([#30961](https://github.com/element-hq/element-web/pull/30961)). Contributed by @Half-Shot.
* Improve handling of animated images, add support for AVIF animations ([#30932](https://github.com/element-hq/element-web/pull/30932)). Contributed by @t3chguy.
* Update key storage toggle when key storage status changes ([#30934](https://github.com/element-hq/element-web/pull/30934)). Contributed by @uhoreg.
* Fix jitsi widget popout ([#30908](https://github.com/element-hq/element-web/pull/30908)). Contributed by @dbkr.
* Improve keyboard navigation on invite dialog ([#30930](https://github.com/element-hq/element-web/pull/30930)). Contributed by @florianduros.
* Prefer UIA flows with supported UIA stages ([#30926](https://github.com/element-hq/element-web/pull/30926)). Contributed by @richvdh.
* Enhance accessibility of dropdown ([#30928](https://github.com/element-hq/element-web/pull/30928)). Contributed by @florianduros.
* Improve accessibility of the `\<AvatarSetting> component ([#30907](https://github.com/element-hq/element-web/pull/30907)). Contributed by @MidhunSureshR.
Changes in [1.12.1](https://github.com/element-hq/element-desktop/releases/tag/v1.12.1) (2025-10-07)
====================================================================================================
## ✨ Features
* New Room List: Change the order of filters to match those on mobile ([#30905](https://github.com/element-hq/element-web/pull/30905)). Contributed by @langleyd.
* New Room List: Don't clear filters on space change ([#30903](https://github.com/element-hq/element-web/pull/30903)). Contributed by @langleyd.
* Add release announcement for the sounds ([#30900](https://github.com/element-hq/element-web/pull/30900)). Contributed by @langleyd.
* Rich Text Editor: Add emoji suggestion support ([#30873](https://github.com/element-hq/element-web/pull/30873)). Contributed by @langleyd.
* feat: Disable session lock when running in element-desktop ([#30643](https://github.com/element-hq/element-web/pull/30643)). Contributed by @kaylendog.
* Improve invite dialog ui - Part 1 ([#30764](https://github.com/element-hq/element-web/pull/30764)). Contributed by @florianduros.
* Update Message Sound for Element ([#30804](https://github.com/element-hq/element-web/pull/30804)). Contributed by @beatdemon.
* Add new and improved ringtone ([#30761](https://github.com/element-hq/element-web/pull/30761)). Contributed by @Half-Shot.
* Disable RTE formatting buttons when the content contains a slash command ([#30802](https://github.com/element-hq/element-web/pull/30802)). Contributed by @langleyd.
## 🐛 Bug Fixes
* New Room List: Improve robustness of keyboard navigation ([#30888](https://github.com/element-hq/element-web/pull/30888)). Contributed by @langleyd.
* Fix a11y issue on list in invite dialog ([#30878](https://github.com/element-hq/element-web/pull/30878)). Contributed by @florianduros.
* Switch Export and Import Icons to match intuition ([#30805](https://github.com/element-hq/element-web/pull/30805)). Contributed by @micartey.
* Hide breadcrumb option when new room list is enabled ([#30869](https://github.com/element-hq/element-web/pull/30869)). Contributed by @florianduros.
* Avoid creating multiple call objects for the same widget ([#30839](https://github.com/element-hq/element-web/pull/30839)). Contributed by @robintown.
* Add a test for #29882, which is fixed by matrix-org/matrix-js-sdk#5016 ([#30835](https://github.com/element-hq/element-web/pull/30835)). Contributed by @andybalaam.
* fix: use `help_encryption_url` of config instead of hardcoded `https://element.io/help#encryption5` ([#30746](https://github.com/element-hq/element-web/pull/30746)). Contributed by @florianduros.
* Fix html export when feature\_jump\_to\_date is enabled ([#30828](https://github.com/element-hq/element-web/pull/30828)). Contributed by @langleyd.
* Fix #30439: "Forgot recovery key" should go to "reset" ([#30771](https://github.com/element-hq/element-web/pull/30771)). Contributed by @andybalaam.
Changes in [1.12.0](https://github.com/element-hq/element-desktop/releases/tag/v1.12.0) (2025-09-23)
====================================================================================================
## 🦖 Deprecations
* Remove remaining support for outdated .well-known settings ([#30702](https://github.com/element-hq/element-web/pull/30702)). Contributed by @richvdh.
## ✨ Features
* Automatically select first source for desktop capture under Wayland ([#2526](https://github.com/element-hq/element-desktop/pull/2526)). Contributed by @byquanton.
* Add decline button to call notification toast (use new notification event) ([#30729](https://github.com/element-hq/element-web/pull/30729)). Contributed by @toger5.
* Use the new room list by default ([#30640](https://github.com/element-hq/element-web/pull/30640)). Contributed by @langleyd.
* "Verify this device" redesign ([#30596](https://github.com/element-hq/element-web/pull/30596)). Contributed by @uhoreg.
* Set Element Call "intents" when starting and answering DM calls. ([#30730](https://github.com/element-hq/element-web/pull/30730)). Contributed by @Half-Shot.
* Add axe compliance for new room list ([#30700](https://github.com/element-hq/element-web/pull/30700)). Contributed by @langleyd.
* Stop ringing and remove toast if another device answers a RTC call. ([#30728](https://github.com/element-hq/element-web/pull/30728)). Contributed by @Half-Shot.
* Automatically adjust history visibility when making a room private ([#30713](https://github.com/element-hq/element-web/pull/30713)). Contributed by @Half-Shot.
* Release announcement for new room list ([#30675](https://github.com/element-hq/element-web/pull/30675)). Contributed by @dbkr.
## 🐛 Bug Fixes
* Update Electron to v38.1.0 to fix Kernel crash on multi-GPU systems ([#2544](https://github.com/element-hq/element-desktop/pull/2544)). Contributed by @Arcitec.
* Fix Confirm your identity buttons being unclickable ([#2554](https://github.com/element-hq/element-desktop/pull/2554)). Contributed by @dbkr.
* Ensure dropdown is not a drag element on macOS ([#2540](https://github.com/element-hq/element-desktop/pull/2540)). Contributed by @t3chguy.
* [Backport staging] Room list: make the filter resize correctly ([#30795](https://github.com/element-hq/element-web/pull/30795)). Contributed by @RiotRobot.
* [Backport staging] Avoid flicker of the room list filter on resize ([#30794](https://github.com/element-hq/element-web/pull/30794)). Contributed by @RiotRobot.
* Don't show release announcements while toasts are displayed ([#30770](https://github.com/element-hq/element-web/pull/30770)). Contributed by @dbkr.
* Fix enabling key backup not working if there is an untrusted key backup ([#30707](https://github.com/element-hq/element-web/pull/30707)). Contributed by @Half-Shot.
* Force `preload` to be false when setting an intent on an Element Call. ([#30759](https://github.com/element-hq/element-web/pull/30759)). Contributed by @Half-Shot.
* Fix handling of 413 server response when uploading media ([#30737](https://github.com/element-hq/element-web/pull/30737)). Contributed by @hughns.
* Make landmark navigation work with new room list ([#30747](https://github.com/element-hq/element-web/pull/30747)). Contributed by @dbkr.
* Prevent voice message from displaying spurious errors ([#30736](https://github.com/element-hq/element-web/pull/30736)). Contributed by @florianduros.
* Align default avatar and fix colors in composer pills ([#30739](https://github.com/element-hq/element-web/pull/30739)). Contributed by @florianduros.
* Use configured URL for link to desktop app in message search settings ([#30742](https://github.com/element-hq/element-web/pull/30742)). Contributed by @t3chguy.
* Fix history visibility when creating space rooms ([#30745](https://github.com/element-hq/element-web/pull/30745)). Contributed by @dbkr.
* Check HTML-encoded quotes when handling translations for embedded pages (such as welcome.html) ([#30743](https://github.com/element-hq/element-web/pull/30743)). Contributed by @Half-Shot.
* Fix local room encryption status always not enabled ([#30461](https://github.com/element-hq/element-web/pull/30461)). Contributed by @BillCarsonFr.
* fix: make url in topic in room intro clickable ([#30686](https://github.com/element-hq/element-web/pull/30686)). Contributed by @florianduros.
* Block change recovery key button while a change is ongoing. ([#30664](https://github.com/element-hq/element-web/pull/30664)). Contributed by @Half-Shot.
* Hide advanced settings during room creation when `UIFeature.advancedSettings=false` ([#30684](https://github.com/element-hq/element-web/pull/30684)). Contributed by @florianduros.
* A11y: improve accessibility of pinned messages ([#30558](https://github.com/element-hq/element-web/pull/30558)). Contributed by @florianduros.
Changes in [1.11.112](https://github.com/element-hq/element-desktop/releases/tag/v1.11.112) (2025-09-16)
========================================================================================================
Fix [CVE-2025-59161](https://www.cve.org/CVERecord?id=CVE-2025-59161) / [GHSA-m6c8-98f4-75rr](https://github.com/element-hq/element-web/security/advisories/GHSA-m6c8-98f4-75rr)
## This is the last release compatible with macOS Big Sur. It will not update further. Big Sur is End of Life for almost 2 years and the next version of Electron crashes upon startup on Big Sur.
## ✨ Features
* [Backport staging] Handle unsupported macOS versions better ([#2555](https://github.com/element-hq/element-desktop/pull/2555)). Contributed by @RiotRobot.
Changes in [1.11.111](https://github.com/element-hq/element-desktop/releases/tag/v1.11.111) (2025-09-10)
========================================================================================================
## ✨ Features
* Do not hide media from your own user by default ([#29797](https://github.com/element-hq/element-web/pull/29797)). Contributed by @Half-Shot.
* Remember whether sidebar is shown for calls when switching rooms ([#30262](https://github.com/element-hq/element-web/pull/30262)). Contributed by @bojidar-bg.
* Open the proper integration settings on integrations disabled error ([#30538](https://github.com/element-hq/element-web/pull/30538)). Contributed by @Half-Shot.
* Show a "progress" dialog while invites are being sent ([#30561](https://github.com/element-hq/element-web/pull/30561)). Contributed by @richvdh.
* Move the room list to the new ListView(backed by react-virtuoso) ([#30515](https://github.com/element-hq/element-web/pull/30515)). Contributed by @langleyd.
## 🐛 Bug Fixes
* [Backport staging] Ensure container starts if it is mounted with an empty /modules directory. ([#30705](https://github.com/element-hq/element-web/pull/30705)). Contributed by @RiotRobot.
* Fix room joining over federation not specifying vias or using aliases ([#30641](https://github.com/element-hq/element-web/pull/30641)). Contributed by @t3chguy.
* Fix stable-suffixed MSC4133 support ([#30649](https://github.com/element-hq/element-web/pull/30649)). Contributed by @dbkr.
* Fix i18n of message when a setting is disabled ([#30646](https://github.com/element-hq/element-web/pull/30646)). Contributed by @dbkr.
* ListView should not handle the arrow keys if there is a modifier applied ([#30633](https://github.com/element-hq/element-web/pull/30633)). Contributed by @langleyd.
* Make BaseDialog's div keyboard focusable and fix test. ([#30631](https://github.com/element-hq/element-web/pull/30631)). Contributed by @langleyd.
* Fix: Allow triple-click text selection to flow around pills ([#30349](https://github.com/element-hq/element-web/pull/30349)). Contributed by @AlirezaMrtz.
* Watch for a 'join' action to know when the call is connected ([#29492](https://github.com/element-hq/element-web/pull/29492)). Contributed by @robintown.
* Fix: add missing tooltip and aria-label to lock icon next to composer ([#30623](https://github.com/element-hq/element-web/pull/30623)). Contributed by @florianduros.
* Don't render context menu when scrolling ([#30613](https://github.com/element-hq/element-web/pull/30613)). Contributed by @langleyd.
Changes in [1.11.110](https://github.com/element-hq/element-desktop/releases/tag/v1.11.110) (2025-08-27)
========================================================================================================
## ✨ Features
* Hide recovery key when re-entering it while creating or changing it ([#30499](https://github.com/element-hq/element-web/pull/30499)). Contributed by @andybalaam.
* Add `?no_universal_links=true` to OIDC url so EX doesn't try to handle it ([#29439](https://github.com/element-hq/element-web/pull/29439)). Contributed by @t3chguy.
* Show a blue lock for unencrypted rooms and hide the grey shield for encrypted rooms ([#30440](https://github.com/element-hq/element-web/pull/30440)). Contributed by @langleyd.
* Add support for Module API 1.4 ([#30185](https://github.com/element-hq/element-web/pull/30185)). Contributed by @t3chguy.
* MVVM - Introduce some helpers for snapshot management ([#30398](https://github.com/element-hq/element-web/pull/30398)). Contributed by @MidhunSureshR.
## 🐛 Bug Fixes
* A11y: move focus to right panel when opened ([#30553](https://github.com/element-hq/element-web/pull/30553)). Contributed by @florianduros.
* Fix e2e warning icon should be white ([#30539](https://github.com/element-hq/element-web/pull/30539)). Contributed by @florianduros.
* Remove NoOneHere disabled reason. ([#30524](https://github.com/element-hq/element-web/pull/30524)). Contributed by @toger5.
* Fix downloading files with authenticated media API ([#30520](https://github.com/element-hq/element-web/pull/30520)). Contributed by @t3chguy.
* Fix call permissions check confusion around element call ([#30521](https://github.com/element-hq/element-web/pull/30521)). Contributed by @t3chguy.
* Fix line wrap around emoji verification ([#30523](https://github.com/element-hq/element-web/pull/30523)). Contributed by @t3chguy.
* Don't highlight redacted events ([#30519](https://github.com/element-hq/element-web/pull/30519)). Contributed by @t3chguy.
* Fix matrix.to links not being handled in the app ([#30522](https://github.com/element-hq/element-web/pull/30522)). Contributed by @t3chguy.
* Fix issue of new room list taking up the full width ([#30459](https://github.com/element-hq/element-web/pull/30459)). Contributed by @langleyd.
* Fix widget persistence in React development mode ([#30509](https://github.com/element-hq/element-web/pull/30509)). Contributed by @robintown.
* Fix widget initialization in React development mode ([#30463](https://github.com/element-hq/element-web/pull/30463)). Contributed by @robintown.
Changes in [1.11.109](https://github.com/element-hq/element-desktop/releases/tag/v1.11.109) (2025-08-11)
========================================================================================================
This release supports the upcoming v12 ("hydra") Matrix room version and is necessary to view and participate in these rooms.
## ✨ Features
* [Backport staging] Allow /upgraderoom command without developer mode enabled ([#30529](https://github.com/element-hq/element-web/pull/30529)). Contributed by @RiotRobot.
* [Backport staging] Support for creator/owner power level ([#30526](https://github.com/element-hq/element-web/pull/30526)). Contributed by @RiotRobot.
* New room list: change icon and label of menu item for to start a DM ([#30470](https://github.com/element-hq/element-web/pull/30470)). Contributed by @florianduros.
* Implement the member list with virtuoso ([#29869](https://github.com/element-hq/element-web/pull/29869)). Contributed by @langleyd.
* Add labs option for history sharing on invite ([#30313](https://github.com/element-hq/element-web/pull/30313)). Contributed by @richvdh.
* Bump wysiwyg to 2.39.0 adding support for pasting rich text content in the Rich Text Edtior ([#30421](https://github.com/element-hq/element-web/pull/30421)). Contributed by @langleyd.
* Support `EventShieldReason.MISMATCHED_SENDER` ([#30403](https://github.com/element-hq/element-web/pull/30403)). Contributed by @richvdh.
* Change unencrypted and public pills to blue ([#30399](https://github.com/element-hq/element-web/pull/30399)). Contributed by @florianduros.
* Change color of public room icon ([#30390](https://github.com/element-hq/element-web/pull/30390)). Contributed by @florianduros.
* Script for updating storybook screenshots ([#30340](https://github.com/element-hq/element-web/pull/30340)). Contributed by @dbkr.
* Add toggle to hide empty state in devtools ([#30352](https://github.com/element-hq/element-web/pull/30352)). Contributed by @toger5.
## 🐛 Bug Fixes
* [Backport staging] Use userId to filter users in non-federated rooms when showing the InviteDialog ([#30537](https://github.com/element-hq/element-web/pull/30537)). Contributed by @RiotRobot.
* [Backport staging] Catch error when encountering invalid m.room.pinned\_events event ([#30536](https://github.com/element-hq/element-web/pull/30536)). Contributed by @RiotRobot.
* Update for compatibility with v12 rooms ([#30452](https://github.com/element-hq/element-web/pull/30452)). Contributed by @dbkr.
* New room list: fix tooltip on presence ([#30474](https://github.com/element-hq/element-web/pull/30474)). Contributed by @florianduros.
* New room list: add tooltip for presence and room status ([#30472](https://github.com/element-hq/element-web/pull/30472)). Contributed by @florianduros.
* Fix: Clicking on an item in the member list causes it to scroll to the top rather than show the profile view ([#30455](https://github.com/element-hq/element-web/pull/30455)). Contributed by @langleyd.
* Put the 'decrypting' tooltip back ([#30446](https://github.com/element-hq/element-web/pull/30446)). Contributed by @dbkr.
* Use server name explicitly for via. ([#30362](https://github.com/element-hq/element-web/pull/30362)). Contributed by @Half-Shot.
* fix: replace hardcoded string in poll history dialog ([#30402](https://github.com/element-hq/element-web/pull/30402)). Contributed by @florianduros.
* fix: replace hardcoded string on qr code back button ([#30401](https://github.com/element-hq/element-web/pull/30401)). Contributed by @florianduros.
* Fix color of icon button with outline ([#30361](https://github.com/element-hq/element-web/pull/30361)). Contributed by @florianduros.
Changes in [1.11.108](https://github.com/element-hq/element-desktop/releases/tag/v1.11.108) (2025-07-30)
========================================================================================================
## 🐛 Bug Fixes
* [Backport staging] Fix downloaded attachments not being decrypted ([#30434](https://github.com/element-hq/element-web/pull/30434)). Contributed by @RiotRobot.
Changes in [1.11.107](https://github.com/element-hq/element-desktop/releases/tag/v1.11.107) (2025-07-29)
========================================================================================================
## ✨ Features
* Add support for overlaying notification badges on the Windows Taskbar icon. ([#2443](https://github.com/element-hq/element-desktop/pull/2443)). Contributed by @Half-Shot.
* Reduce macos titlebar height with the new room list and expand the existing border ([#2446](https://github.com/element-hq/element-desktop/pull/2446)). Contributed by @florianduros.
* Message preview should show tooltip with the full message on hover ([#30265](https://github.com/element-hq/element-web/pull/30265)). Contributed by @MidhunSureshR.
* Support rendering notification badges on platforms that do their own icon overlays ([#30315](https://github.com/element-hq/element-web/pull/30315)). Contributed by @Half-Shot.
* Add SubscriptionViewModel base class ([#30297](https://github.com/element-hq/element-web/pull/30297)). Contributed by @dbkr.
* Enhancement: Save image on CTRL+S ([#30330](https://github.com/element-hq/element-web/pull/30330)). Contributed by @ioalexander.
* Add quote functionality to MessageContextMenu (#29893) ([#30323](https://github.com/element-hq/element-web/pull/30323)). Contributed by @AlirezaMrtz.
* Initial structure for shared component views ([#30216](https://github.com/element-hq/element-web/pull/30216)). Contributed by @dbkr.
## 🐛 Bug Fixes
* Reduce macos titlebar height with the new room list and expand the existing border ([#2446](https://github.com/element-hq/element-desktop/pull/2446)). Contributed by @florianduros.
* [Backport staging] Fix e2e shield being invisible in white mode for encrypted room ([#30411](https://github.com/element-hq/element-web/pull/30411)). Contributed by @RiotRobot.
* Force ED titlebar color for new room list ([#30332](https://github.com/element-hq/element-web/pull/30332)). Contributed by @florianduros.
* Add a background color to left panel for macos titlebar in element desktop ([#30328](https://github.com/element-hq/element-web/pull/30328)). Contributed by @florianduros.
* Fix: Prevent page refresh on Enter key in right panel member search ([#30312](https://github.com/element-hq/element-web/pull/30312)). Contributed by @AlirezaMrtz.
Changes in [1.11.106](https://github.com/element-hq/element-desktop/releases/tag/v1.11.106) (2025-07-15)
========================================================================================================
## ✨ Features
* [Backport staging] Fix e2e icon colour ([#30304](https://github.com/element-hq/element-web/pull/30304)). Contributed by @RiotRobot.
* Add support for module message hint `allowDownloadingMedia` ([#30252](https://github.com/element-hq/element-web/pull/30252)). Contributed by @Half-Shot.
* Update the mobile\_guide page to the new design and link out to Element X by default. ([#30172](https://github.com/element-hq/element-web/pull/30172)). Contributed by @pixlwave.
* Filter settings exported when rageshaking ([#30236](https://github.com/element-hq/element-web/pull/30236)). Contributed by @Half-Shot.
* Allow Element Call to learn the room name ([#30213](https://github.com/element-hq/element-web/pull/30213)). Contributed by @robintown.
## 🐛 Bug Fixes
* [Backport staging] Fix missing image download button ([#30322](https://github.com/element-hq/element-web/pull/30322)). Contributed by @RiotRobot.
* Fix transparent verification checkmark in dark mode ([#30235](https://github.com/element-hq/element-web/pull/30235)). Contributed by @Banbuii.
* Fix logic in DeviceListener ([#30230](https://github.com/element-hq/element-web/pull/30230)). Contributed by @uhoreg.
* Disable file drag-and-drop if insufficient permissions ([#30186](https://github.com/element-hq/element-web/pull/30186)). Contributed by @t3chguy.
Changes in [1.11.105](https://github.com/element-hq/element-desktop/releases/tag/v1.11.105) (2025-07-01)
========================================================================================================
## ✨ Features
* Add support for migrating to kwallet6 ([#2390](https://github.com/element-hq/element-desktop/pull/2390)). Contributed by @t3chguy.
* New room list: add context menu to room list item ([#29952](https://github.com/element-hq/element-web/pull/29952)). Contributed by @florianduros.
* Support for custom message components via Module API ([#30074](https://github.com/element-hq/element-web/pull/30074)). Contributed by @Half-Shot.
* Prompt users to set up recovery ([#30075](https://github.com/element-hq/element-web/pull/30075)). Contributed by @uhoreg.
* Update `IconButton` colors ([#30124](https://github.com/element-hq/element-web/pull/30124)). Contributed by @florianduros.
* New room list: filter list can be collapsed ([#29992](https://github.com/element-hq/element-web/pull/29992)). Contributed by @florianduros.
* Show `EmptyRoomListView` when low priority filter matches zero rooms ([#30122](https://github.com/element-hq/element-web/pull/30122)). Contributed by @MidhunSureshR.
## 🐛 Bug Fixes
* Fix element-desktop-ssoid profile deeplinking for OIDC ([#2396](https://github.com/element-hq/element-desktop/pull/2396)). Contributed by @t3chguy.
* Add support for migrating to kwallet6 ([#2390](https://github.com/element-hq/element-desktop/pull/2390)). Contributed by @t3chguy.
* Fix untranslatable string "People" in notifications beta ([#30165](https://github.com/element-hq/element-web/pull/30165)). Contributed by @t3chguy.
* Force verification even after logging in via delegate ([#30141](https://github.com/element-hq/element-web/pull/30141)). Contributed by @andybalaam.
* Hide add integrations button based on UIComponent.AddIntegrations ([#30140](https://github.com/element-hq/element-web/pull/30140)). Contributed by @t3chguy.
* Use nav for new room list and label sections ([#30134](https://github.com/element-hq/element-web/pull/30134)). Contributed by @dbkr.
* Spacestore should emit event after rebuilding home space ([#30132](https://github.com/element-hq/element-web/pull/30132)). Contributed by @MidhunSureshR.
* Handle m.room.pinned\_events being invalid ([#30129](https://github.com/element-hq/element-web/pull/30129)). Contributed by @t3chguy.
Changes in [1.11.104](https://github.com/element-hq/element-desktop/releases/tag/v1.11.104) (2025-06-17)
========================================================================================================
## ✨ Features
* Update the mobile\_guide page to the new design. ([#30006](https://github.com/element-hq/element-web/pull/30006)). Contributed by @pixlwave.
* Provide a devtool for manually verifying other devices ([#30094](https://github.com/element-hq/element-web/pull/30094)). Contributed by @andybalaam.
* Implement MSC4155: Invite filtering ([#29603](https://github.com/element-hq/element-web/pull/29603)). Contributed by @Half-Shot.
* Add low priority avatar decoration to room tile ([#30065](https://github.com/element-hq/element-web/pull/30065)). Contributed by @MidhunSureshR.
* Add ability to prevent window content being captured by other apps (Desktop) ([#30098](https://github.com/element-hq/element-web/pull/30098)). Contributed by @t3chguy.
* New room list: move message preview in user settings ([#30023](https://github.com/element-hq/element-web/pull/30023)). Contributed by @florianduros.
* New room list: change room options icon ([#30029](https://github.com/element-hq/element-web/pull/30029)). Contributed by @florianduros.
* RoomListStore: Sort low priority rooms to the bottom of the list ([#30070](https://github.com/element-hq/element-web/pull/30070)). Contributed by @MidhunSureshR.
* Add low priority filter pill to the room list UI ([#30060](https://github.com/element-hq/element-web/pull/30060)). Contributed by @MidhunSureshR.
* New room list: remove color gradient in space panel ([#29721](https://github.com/element-hq/element-web/pull/29721)). Contributed by @florianduros.
* /share?msg=foo endpoint using forward message dialog ([#29874](https://github.com/element-hq/element-web/pull/29874)). Contributed by @ara4n.
## 🐛 Bug Fixes
* Fix restart loop in safeStorage ([#2373](https://github.com/element-hq/element-desktop/pull/2373)). Contributed by @dbkr.
* Do not send empty auth when setting up cross-signing keys ([#29914](https://github.com/element-hq/element-web/pull/29914)). Contributed by @gnieto.
* Settings: flip local video feed by default ([#29501](https://github.com/element-hq/element-web/pull/29501)). Contributed by @jbtrystram.
* AccessSecretStorageDialog: various fixes ([#30093](https://github.com/element-hq/element-web/pull/30093)). Contributed by @richvdh.
* AccessSecretStorageDialog: fix inability to enter recovery key ([#30090](https://github.com/element-hq/element-web/pull/30090)). Contributed by @richvdh.
* Fix failure to upload thumbnail causing image to send as file ([#30086](https://github.com/element-hq/element-web/pull/30086)). Contributed by @t3chguy.
* Low priority menu item should be a toggle ([#30071](https://github.com/element-hq/element-web/pull/30071)). Contributed by @MidhunSureshR.
* Add sanity checks to prevent users from ignoring themselves ([#30079](https://github.com/element-hq/element-web/pull/30079)). Contributed by @MidhunSureshR.
* Fix issue with duplicate images ([#30073](https://github.com/element-hq/element-web/pull/30073)). Contributed by @fatlewis.
* Handle errors returned from Seshat ([#30083](https://github.com/element-hq/element-web/pull/30083)). Contributed by @richvdh.
Changes in [1.11.103](https://github.com/element-hq/element-desktop/releases/tag/v1.11.103) (2025-06-10)
========================================================================================================
## 🐛 Bug Fixes
+ Check the sender of an event matches owner of session, preventing sender spoofing by homeserver owners.
[13c1d20](https://github.com/matrix-org/matrix-rust-sdk/commit/13c1d2048286bbabf5e7bc6b015aafee98f04d55) (High, [GHSA-x958-rvg6-956w](https://github.com/matrix-org/matrix-rust-sdk/security/advisories/GHSA-x958-rvg6-956w)).
Changes in [1.11.102](https://github.com/element-hq/element-desktop/releases/tag/v1.11.102) (2025-06-03)
========================================================================================================
## ✨ Features
* Support build-time specified protocol scheme for oidc callback ([#2285](https://github.com/element-hq/element-desktop/pull/2285)). Contributed by @t3chguy.
* EW: Modernize the recovery key input modal ([#29819](https://github.com/element-hq/element-web/pull/29819)). Contributed by @uhoreg.
* New room list: move secondary filters into primary filters ([#29972](https://github.com/element-hq/element-web/pull/29972)). Contributed by @florianduros.
* Prompt the user when key storage is unexpectedly off ([#29912](https://github.com/element-hq/element-web/pull/29912)). Contributed by @andybalaam.
* New room list: move sort menu in room list header ([#29983](https://github.com/element-hq/element-web/pull/29983)). Contributed by @florianduros.
* New room list: rework spacing of room list item ([#29965](https://github.com/element-hq/element-web/pull/29965)). Contributed by @florianduros.
* RLS: Remove forgotten room from skiplist ([#29933](https://github.com/element-hq/element-web/pull/29933)). Contributed by @MidhunSureshR.
* Add room list sorting ([#29951](https://github.com/element-hq/element-web/pull/29951)). Contributed by @dbkr.
* Don't use the minimised width(68px) on the new room list ([#29778](https://github.com/element-hq/element-web/pull/29778)). Contributed by @langleyd.
## 🐛 Bug Fixes
* Enable plain text encryption before checking if encryption is available ([#2343](https://github.com/element-hq/element-desktop/pull/2343)). Contributed by @MidhunSureshR.
* Enable plain text encryption early if we actually mean to use `basic_text` as backend ([#2341](https://github.com/element-hq/element-desktop/pull/2341)). Contributed by @MidhunSureshR.
* [Backport staging] Close call options popup menu when option has been selected ([#30054](https://github.com/element-hq/element-web/pull/30054)). Contributed by @RiotRobot.
* RoomListStoreV3: Only add new rooms that pass `VisibilityProvider` check ([#29974](https://github.com/element-hq/element-web/pull/29974)). Contributed by @MidhunSureshR.
* Re-order primary filters ([#29957](https://github.com/element-hq/element-web/pull/29957)). Contributed by @dbkr.
* Fix leaky CSS adding `!` to all H1 elements ([#29964](https://github.com/element-hq/element-web/pull/29964)). Contributed by @t3chguy.
* Fix extensions panel style ([#29273](https://github.com/element-hq/element-web/pull/29273)). Contributed by @langleyd.
* Fix state events being hidden from widgets in read\_events actions ([#29954](https://github.com/element-hq/element-web/pull/29954)). Contributed by @robintown.
* Remove old filter test ([#29963](https://github.com/element-hq/element-web/pull/29963)). Contributed by @dbkr.
Changes in [1.11.101](https://github.com/element-hq/element-desktop/releases/tag/v1.11.101) (2025-05-20)
========================================================================================================
## ✨ Features
* Migrate from keytar to safeStorage ([#2227](https://github.com/element-hq/element-desktop/pull/2227)). Contributed by @t3chguy.
* New room list: add keyboard navigation support ([#29805](https://github.com/element-hq/element-web/pull/29805)). Contributed by @florianduros.
* Use the JoinRuleSettings component for the guest link access prompt. ([#28614](https://github.com/element-hq/element-web/pull/28614)). Contributed by @toger5.
* Add loading state to the new room list view ([#29725](https://github.com/element-hq/element-web/pull/29725)). Contributed by @langleyd.
* Make OIDC identity reset consistent with EX ([#29854](https://github.com/element-hq/element-web/pull/29854)). Contributed by @andybalaam.
* Support error code for email / phone adding unsupported (MSC4178) ([#29855](https://github.com/element-hq/element-web/pull/29855)). Contributed by @dbkr.
* Update identity reset UI (Make consistent with EX) ([#29701](https://github.com/element-hq/element-web/pull/29701)). Contributed by @andybalaam.
* Add secondary filters to the new room list ([#29818](https://github.com/element-hq/element-web/pull/29818)). Contributed by @dbkr.
* Fix battery drain from Web Audio ([#29203](https://github.com/element-hq/element-web/pull/29203)). Contributed by @mbachry.
## 🐛 Bug Fixes
* Fix go home shortcut on macos and change toggle action events shortcut ([#29929](https://github.com/element-hq/element-web/pull/29929)). Contributed by @florianduros.
* New room list: fix outdated message preview when space or filter change ([#29925](https://github.com/element-hq/element-web/pull/29925)). Contributed by @florianduros.
* Stop migrating to MSC4278 if the config exists. ([#29924](https://github.com/element-hq/element-web/pull/29924)). Contributed by @Half-Shot.
* Ensure consistent download file name on download from ImageView ([#29913](https://github.com/element-hq/element-web/pull/29913)). Contributed by @t3chguy.
* Add error toast when service worker registration fails ([#29895](https://github.com/element-hq/element-web/pull/29895)). Contributed by @t3chguy.
* New Room List: Prevent old tombstoned rooms from appearing in the list ([#29881](https://github.com/element-hq/element-web/pull/29881)). Contributed by @MidhunSureshR.
* Remove lag in search field ([#29885](https://github.com/element-hq/element-web/pull/29885)). Contributed by @florianduros.
* Respect UIFeature.Voip ([#29873](https://github.com/element-hq/element-web/pull/29873)). Contributed by @langleyd.
* Allow jumping to message search from spotlight ([#29850](https://github.com/element-hq/element-web/pull/29850)). Contributed by @t3chguy.
Changes in [1.11.100](https://github.com/element-hq/element-desktop/releases/tag/v1.11.100) (2025-05-06)
========================================================================================================
## ✨ Features
* Move rich topics out of labs / stabilise MSC3765 ([#29817](https://github.com/element-hq/element-web/pull/29817)). Contributed by @Johennes.
* Spell out that Element Web does \*not\* work on mobile. ([#29211](https://github.com/element-hq/element-web/pull/29211)). Contributed by @ara4n.
* Add message preview support to the new room list ([#29784](https://github.com/element-hq/element-web/pull/29784)). Contributed by @dbkr.
* Global configuration flag for media previews ([#29582](https://github.com/element-hq/element-web/pull/29582)). Contributed by @Half-Shot.
* New room list: add partial keyboard shortcuts support ([#29783](https://github.com/element-hq/element-web/pull/29783)). Contributed by @florianduros.
* MVVM RoomSummaryCard Topic ([#29710](https://github.com/element-hq/element-web/pull/29710)). Contributed by @MarcWadai.
* Warn on self change from settings > roles ([#28926](https://github.com/element-hq/element-web/pull/28926)). Contributed by @MarcWadai.
* New room list: new visual for invitation ([#29773](https://github.com/element-hq/element-web/pull/29773)). Contributed by @florianduros.
## 🐛 Bug Fixes
* Apply workaround to fix app launching on Linux ([#2308](https://github.com/element-hq/element-desktop/pull/2308)). Contributed by @dbkr.
* Notification fixes for Windows - AppID name was messing up handler ([#2275](https://github.com/element-hq/element-desktop/pull/2275)). Contributed by @Fusseldieb.
* Fix incorrect display of the user info display name ([#29826](https://github.com/element-hq/element-web/pull/29826)). Contributed by @langleyd.
* RoomListStore: Remove invite rooms on decline ([#29804](https://github.com/element-hq/element-web/pull/29804)). Contributed by @MidhunSureshR.
* Fix the buttons not being displayed with long preview text ([#29811](https://github.com/element-hq/element-web/pull/29811)). Contributed by @dbkr.
* New room list: fix missing/incorrect notification decoration ([#29796](https://github.com/element-hq/element-web/pull/29796)). Contributed by @florianduros.
* New Room List: Prevent potential scroll jump/flicker when switching spaces ([#29781](https://github.com/element-hq/element-web/pull/29781)). Contributed by @MidhunSureshR.
* New room list: fix incorrect decoration ([#29770](https://github.com/element-hq/element-web/pull/29770)). Contributed by @florianduros.
Changes in [1.11.99](https://github.com/element-hq/element-desktop/releases/tag/v1.11.99) (2025-04-23)
======================================================================================================
## 🐛 Bug Fixes
* [Backport staging] Fix `io.element.desktop` protocol handler ([#2281](https://github.com/element-hq/element-desktop/pull/2281)). Contributed by @RiotRobot.
Changes in [1.11.98](https://github.com/element-hq/element-desktop/releases/tag/v1.11.98) (2025-04-22)
======================================================================================================
## 🦖 Deprecations
* Remove support for 32 bit / ia32 Windows. ([#2225](https://github.com/element-hq/element-desktop/pull/2225)). Contributed by @Half-Shot.
## ✨ Features
* Update config logging to specify config file path ([#2231](https://github.com/element-hq/element-desktop/pull/2231)). Contributed by @nbolton.
* Support specifying the profile dir path via env var (#2226) ([#2246](https://github.com/element-hq/element-desktop/pull/2246)). Contributed by @schuhj.
* print better errors in the search view instead of a blocking modal ([#29724](https://github.com/element-hq/element-web/pull/29724)). Contributed by @Jujure.
* New room list: video room and video call decoration ([#29693](https://github.com/element-hq/element-web/pull/29693)). Contributed by @florianduros.
* Remove Secure Backup, Cross-signing and Cryptography sections in `Security & Privacy` user settings ([#29088](https://github.com/element-hq/element-web/pull/29088)). Contributed by @florianduros.
* Allow reporting a room when rejecting an invite. ([#29570](https://github.com/element-hq/element-web/pull/29570)). Contributed by @Half-Shot.
* RoomListViewModel: Reset primary and secondary filters on space change ([#29672](https://github.com/element-hq/element-web/pull/29672)). Contributed by @MidhunSureshR.
* RoomListStore: Support specific sorting requirements for muted rooms ([#29665](https://github.com/element-hq/element-web/pull/29665)). Contributed by @MidhunSureshR.
* New room list: add notification options menu ([#29639](https://github.com/element-hq/element-web/pull/29639)). Contributed by @florianduros.
* Room List: Scroll to top of the list when active room is not in the list ([#29650](https://github.com/element-hq/element-web/pull/29650)). Contributed by @MidhunSureshR.
## 🐛 Bug Fixes
* Fix unwanted form submit behaviour in memberlist ([#29747](https://github.com/element-hq/element-web/pull/29747)). Contributed by @MidhunSureshR.
* New room list: fix public room icon visibility when filter change ([#29737](https://github.com/element-hq/element-web/pull/29737)). Contributed by @florianduros.
* Fix custom theme support for short hex \& rgba hex strings ([#29726](https://github.com/element-hq/element-web/pull/29726)). Contributed by @t3chguy.
* New room list: minor visual fixes ([#29723](https://github.com/element-hq/element-web/pull/29723)). Contributed by @florianduros.
* Fix getOidcCallbackUrl for Element Desktop ([#29711](https://github.com/element-hq/element-web/pull/29711)). Contributed by @t3chguy.
* Fix some webp images improperly marked as animated ([#29713](https://github.com/element-hq/element-web/pull/29713)). Contributed by @Petersmit27.
* Revert deletion of hydrateSession ([#29703](https://github.com/element-hq/element-web/pull/29703)). Contributed by @Jujure.
* Fix converttoroom \& converttodm not working ([#29705](https://github.com/element-hq/element-web/pull/29705)). Contributed by @t3chguy.
* Ensure forceCloseAllModals also closes priority/static modals ([#29706](https://github.com/element-hq/element-web/pull/29706)). Contributed by @t3chguy.
* Continue button is disabled when uploading a recovery key file ([#29695](https://github.com/element-hq/element-web/pull/29695)). Contributed by @Giwayume.
* Catch errors after syncing recovery ([#29691](https://github.com/element-hq/element-web/pull/29691)). Contributed by @andybalaam.
* New room list: fix multiple visual issues ([#29673](https://github.com/element-hq/element-web/pull/29673)). Contributed by @florianduros.
* New Room List: Fix mentions filter matching rooms with any highlight ([#29668](https://github.com/element-hq/element-web/pull/29668)). Contributed by @MidhunSureshR.
* Fix truncated emoji label during emoji SAS ([#29643](https://github.com/element-hq/element-web/pull/29643)). Contributed by @florianduros.
* Remove duplicate jitsi link ([#29642](https://github.com/element-hq/element-web/pull/29642)). Contributed by @dbkr.
Changes in [1.11.97](https://github.com/element-hq/element-desktop/releases/tag/v1.11.97) (2025-04-08)
======================================================================================================
## ✨ Features
* New room list: reduce padding between avatar and room list border ([#29634](https://github.com/element-hq/element-web/pull/29634)). Contributed by @florianduros.
* Bundle Element Call with Element Web packages ([#29309](https://github.com/element-hq/element-web/pull/29309)). Contributed by @t3chguy.
* Hide an event notification if it is redacted ([#29605](https://github.com/element-hq/element-web/pull/29605)). Contributed by @Half-Shot.
* Docker: Use nginx-unprivileged as base image ([#29353](https://github.com/element-hq/element-web/pull/29353)). Contributed by @AndrewFerr.
* Switch away from nesting React trees and mangling the DOM ([#29586](https://github.com/element-hq/element-web/pull/29586)). Contributed by @t3chguy.
* New room list: add notification decoration ([#29552](https://github.com/element-hq/element-web/pull/29552)). Contributed by @florianduros.
* RoomListStore: Unread filter should match rooms that were marked as unread ([#29580](https://github.com/element-hq/element-web/pull/29580)). Contributed by @MidhunSureshR.
* Add support for hiding videos ([#29496](https://github.com/element-hq/element-web/pull/29496)). Contributed by @Half-Shot.
* Use an outline icon for the report room button ([#29573](https://github.com/element-hq/element-web/pull/29573)). Contributed by @robintown.
* Generate/load pickle key on SSO ([#29568](https://github.com/element-hq/element-web/pull/29568)). Contributed by @Jujure.
* Add report room dialog button/dialog. ([#29513](https://github.com/element-hq/element-web/pull/29513)). Contributed by @Half-Shot.
* RoomListViewModel: Make the active room sticky in the list ([#29551](https://github.com/element-hq/element-web/pull/29551)). Contributed by @MidhunSureshR.
* Replace checkboxes with Compound checkboxes, and appropriately label each checkbox. ([#29363](https://github.com/element-hq/element-web/pull/29363)). Contributed by @Half-Shot.
* New room list: add selection decoration ([#29531](https://github.com/element-hq/element-web/pull/29531)). Contributed by @florianduros.
* Simplified Sliding Sync ([#28515](https://github.com/element-hq/element-web/pull/28515)). Contributed by @dbkr.
* Add ability to hide images after clicking "show image" ([#29467](https://github.com/element-hq/element-web/pull/29467)). Contributed by @Half-Shot.
## 🐛 Bug Fixes
* Fix scroll issues in memberlist ([#29392](https://github.com/element-hq/element-web/pull/29392)). Contributed by @MidhunSureshR.
* Ensure clicks on spoilers do not get handled by the hidden content ([#29618](https://github.com/element-hq/element-web/pull/29618)). Contributed by @t3chguy.
* New room list: add cursor pointer on room list item ([#29627](https://github.com/element-hq/element-web/pull/29627)). Contributed by @florianduros.
* Fix missing ambiguous url tooltips on Element Desktop ([#29619](https://github.com/element-hq/element-web/pull/29619)). Contributed by @t3chguy.
* New room list: fix spacing and padding ([#29607](https://github.com/element-hq/element-web/pull/29607)). Contributed by @florianduros.
* Make fetchdep check out matching branch name ([#29601](https://github.com/element-hq/element-web/pull/29601)). Contributed by @dbkr.
* Fix MFileBody fileName not considering `filename` ([#29589](https://github.com/element-hq/element-web/pull/29589)). Contributed by @t3chguy.
* Fix token expiry racing with login causing wrong error to be shown ([#29566](https://github.com/element-hq/element-web/pull/29566)). Contributed by @t3chguy.
* Fix bug which caused startup to hang if the clock was wound back since a previous session ([#29558](https://github.com/element-hq/element-web/pull/29558)). Contributed by @richvdh.
* RoomListViewModel: Reset any primary filter on secondary filter change ([#29562](https://github.com/element-hq/element-web/pull/29562)). Contributed by @MidhunSureshR.
* RoomListStore: Unread filter should only filter rooms having unread counts ([#29555](https://github.com/element-hq/element-web/pull/29555)). Contributed by @MidhunSureshR.
* In force-verify mode, prevent bypassing by cancelling device verification ([#29487](https://github.com/element-hq/element-web/pull/29487)). Contributed by @andybalaam.
* Add title attribute to user identifier ([#29547](https://github.com/element-hq/element-web/pull/29547)). Contributed by @arpitbatra123.
Changes in [1.11.96](https://github.com/element-hq/element-desktop/releases/tag/v1.11.96) (2025-03-25)
======================================================================================================
## ✨ Features
* RoomListViewModel: Track the index of the active room in the list ([#29519](https://github.com/element-hq/element-web/pull/29519)). Contributed by @MidhunSureshR.
* New room list: add empty state ([#29512](https://github.com/element-hq/element-web/pull/29512)). Contributed by @florianduros.
* Implement `MessagePreviewViewModel` ([#29514](https://github.com/element-hq/element-web/pull/29514)). Contributed by @MidhunSureshR.
* RoomListViewModel: Add functionality to toggle message preview setting ([#29511](https://github.com/element-hq/element-web/pull/29511)). Contributed by @MidhunSureshR.
* New room list: add more options menu on room list item ([#29445](https://github.com/element-hq/element-web/pull/29445)). Contributed by @florianduros.
* RoomListViewModel: Provide a way to resort the room list and track the active sort method ([#29499](https://github.com/element-hq/element-web/pull/29499)). Contributed by @MidhunSureshR.
* Change \*All rooms\* meta space name to \*All Chats\* ([#29498](https://github.com/element-hq/element-web/pull/29498)). Contributed by @florianduros.
* Add setting to hide avatars of rooms you have been invited to. ([#29497](https://github.com/element-hq/element-web/pull/29497)). Contributed by @Half-Shot.
* Room List Store: Save preferred sorting algorithm and use that on app launch ([#29493](https://github.com/element-hq/element-web/pull/29493)). Contributed by @MidhunSureshR.
* Add key storage toggle to Encryption settings ([#29310](https://github.com/element-hq/element-web/pull/29310)). Contributed by @dbkr.
* New room list: add primary filters ([#29481](https://github.com/element-hq/element-web/pull/29481)). Contributed by @florianduros.
* Implement MSC4142: Remove unintentional intentional mentions in replies ([#28209](https://github.com/element-hq/element-web/pull/28209)). Contributed by @tulir.
* White background for 'They do not match' button ([#29470](https://github.com/element-hq/element-web/pull/29470)). Contributed by @andybalaam.
* RoomListViewModel: Support secondary filters in the view model ([#29465](https://github.com/element-hq/element-web/pull/29465)). Contributed by @MidhunSureshR.
* RoomListViewModel: Support primary filters in the view model ([#29454](https://github.com/element-hq/element-web/pull/29454)). Contributed by @MidhunSureshR.
* Room List Store: Implement secondary filters ([#29458](https://github.com/element-hq/element-web/pull/29458)). Contributed by @MidhunSureshR.
* Room List Store: Implement rest of the primary filters ([#29444](https://github.com/element-hq/element-web/pull/29444)). Contributed by @MidhunSureshR.
* Room List Store: Support filters by implementing just the favourite filter ([#29433](https://github.com/element-hq/element-web/pull/29433)). Contributed by @MidhunSureshR.
* Move toggle switch for integration manager for a11y ([#29436](https://github.com/element-hq/element-web/pull/29436)). Contributed by @Half-Shot.
* New room list: basic flat list ([#29368](https://github.com/element-hq/element-web/pull/29368)). Contributed by @florianduros.
* Improve rageshake upload experience by providing useful error information ([#29378](https://github.com/element-hq/element-web/pull/29378)). Contributed by @Half-Shot.
* Add more functionality to the room list vm ([#29402](https://github.com/element-hq/element-web/pull/29402)). Contributed by @MidhunSureshR.
## 🐛 Bug Fixes
* Fix `--no-update` command line flag ([#2210](https://github.com/element-hq/element-desktop/pull/2210)). Contributed by @t3chguy.
* New room list: fix compose menu action in space ([#29500](https://github.com/element-hq/element-web/pull/29500)). Contributed by @florianduros.
* Change ToggleHiddenEventVisibility \& GoToHome KeyBindingActions ([#29374](https://github.com/element-hq/element-web/pull/29374)). Contributed by @gy-mate.
* Fix Docker Healthcheck ([#29471](https://github.com/element-hq/element-web/pull/29471)). Contributed by @benbz.
* Room List Store: Fetch rooms after space store is ready + attach store to window ([#29453](https://github.com/element-hq/element-web/pull/29453)). Contributed by @MidhunSureshR.
* Room List Store: Fix bug where left rooms appear in room list ([#29452](https://github.com/element-hq/element-web/pull/29452)). Contributed by @MidhunSureshR.
* Add space to the bottom of the room summary actions below leave room ([#29270](https://github.com/element-hq/element-web/pull/29270)). Contributed by @langleyd.
* Show error screens in group calls ([#29254](https://github.com/element-hq/element-web/pull/29254)). Contributed by @robintown.
* Prevent user from accidentally triggering multiple identity resets ([#29388](https://github.com/element-hq/element-web/pull/29388)). Contributed by @uhoreg.
* Remove buggy tooltip on room intro \& homepage ([#29406](https://github.com/element-hq/element-web/pull/29406)). Contributed by @t3chguy.
Changes in [1.11.95](https://github.com/element-hq/element-desktop/releases/tag/v1.11.95) (2025-03-11)
======================================================================================================
## ✨ Features
* Switch to shiftkey/node-keytar as it has NAPI 10 updates ([#2172](https://github.com/element-hq/element-desktop/pull/2172)). Contributed by @t3chguy.
* Add support for Windows arm64 ([#624](https://github.com/element-hq/element-desktop/pull/624)). Contributed by @t3chguy.
* Room List Store: Filter rooms by active space ([#29399](https://github.com/element-hq/element-web/pull/29399)). Contributed by @MidhunSureshR.
* Room List - Update the room list store on actions from the dispatcher ([#29397](https://github.com/element-hq/element-web/pull/29397)). Contributed by @MidhunSureshR.
* Room List - Implement a minimal view model ([#29357](https://github.com/element-hq/element-web/pull/29357)). Contributed by @MidhunSureshR.
* New room list: add space menu in room header ([#29352](https://github.com/element-hq/element-web/pull/29352)). Contributed by @florianduros.
* Room List - Store sorted rooms in skip list ([#29345](https://github.com/element-hq/element-web/pull/29345)). Contributed by @MidhunSureshR.
* New room list: add dial to search section ([#29359](https://github.com/element-hq/element-web/pull/29359)). Contributed by @florianduros.
* New room list: add compose menu for spaces in header ([#29347](https://github.com/element-hq/element-web/pull/29347)). Contributed by @florianduros.
* Use EditInPlace control for Identity Server picker to improve a11y ([#29280](https://github.com/element-hq/element-web/pull/29280)). Contributed by @Half-Shot.
* First step to add header to new room list ([#29320](https://github.com/element-hq/element-web/pull/29320)). Contributed by @florianduros.
* Add Windows 64-bit arm link and remove 32-bit link on compatibility page ([#29312](https://github.com/element-hq/element-web/pull/29312)). Contributed by @t3chguy.
* Honour the backup disable flag from Element X ([#29290](https://github.com/element-hq/element-web/pull/29290)). Contributed by @dbkr.
## 🐛 Bug Fixes
* Fix edited code block width ([#29394](https://github.com/element-hq/element-web/pull/29394)). Contributed by @florianduros.
* new room list: keep space name in one line in header ([#29369](https://github.com/element-hq/element-web/pull/29369)). Contributed by @florianduros.
* Dismiss "Key storage out of sync" toast when secrets received ([#29348](https://github.com/element-hq/element-web/pull/29348)). Contributed by @richvdh.
* Minor CSS fixes for the new room list ([#29334](https://github.com/element-hq/element-web/pull/29334)). Contributed by @florianduros.
* Add padding to room header icon ([#29271](https://github.com/element-hq/element-web/pull/29271)). Contributed by @langleyd.
Changes in [1.11.94](https://github.com/element-hq/element-desktop/releases/tag/v1.11.94) (2025-02-27)
======================================================================================================
* No changes
## 🐛 Bug Fixes
* [Backport staging] fix: /tmp/element-web-config may already exist preventing the container from booting up ([#29377](https://github.com/element-hq/element-web/pull/29377)). Contributed by @RiotRobot.
Changes in [1.11.93](https://github.com/element-hq/element-desktop/releases/tag/v1.11.93) (2025-02-25)
======================================================================================================
## ✨ Features
* [backport] Dynamically load Element Web modules in Docker entrypoint ([#29358](https://github.com/element-hq/element-web/pull/29358)). Contributed by @t3chguy.
* ChangeRecoveryKey: error handling ([#29262](https://github.com/element-hq/element-web/pull/29262)). Contributed by @richvdh.
* Dehydration: enable dehydrated device on "Set up recovery" ([#29265](https://github.com/element-hq/element-web/pull/29265)). Contributed by @richvdh.
* Render reason for invite rejection. ([#29257](https://github.com/element-hq/element-web/pull/29257)). Contributed by @Half-Shot.
* New room list: add search section ([#29251](https://github.com/element-hq/element-web/pull/29251)). Contributed by @florianduros.
* New room list: hide favourites and people meta spaces ([#29241](https://github.com/element-hq/element-web/pull/29241)). Contributed by @florianduros.
* New Room List: Create new labs flag ([#29239](https://github.com/element-hq/element-web/pull/29239)). Contributed by @MidhunSureshR.
* Stop URl preview from covering message box ([#29215](https://github.com/element-hq/element-web/pull/29215)). Contributed by @edent.
* Rename "security key" into "recovery key" ([#29217](https://github.com/element-hq/element-web/pull/29217)). Contributed by @florianduros.
* Add new verification section to user profile ([#29200](https://github.com/element-hq/element-web/pull/29200)). Contributed by @MidhunSureshR.
* Initial support for runtime modules ([#29104](https://github.com/element-hq/element-web/pull/29104)). Contributed by @t3chguy.
* Add `Forgot recovery key?` button to encryption tab ([#29202](https://github.com/element-hq/element-web/pull/29202)). Contributed by @florianduros.
* Add KeyIcon to key storage out of sync toast ([#29201](https://github.com/element-hq/element-web/pull/29201)). Contributed by @florianduros.
* Improve rendering of empty topics in the timeline ([#29152](https://github.com/element-hq/element-web/pull/29152)). Contributed by @Half-Shot.
## 🐛 Bug Fixes
* Fix font scaling in member list ([#29285](https://github.com/element-hq/element-web/pull/29285)). Contributed by @florianduros.
* Grow member list search field when resizing the right panel ([#29267](https://github.com/element-hq/element-web/pull/29267)). Contributed by @langleyd.
* Don't reload roomview on offline connectivity check ([#29243](https://github.com/element-hq/element-web/pull/29243)). Contributed by @dbkr.
* Respect user's 12/24 hour preference consistently ([#29237](https://github.com/element-hq/element-web/pull/29237)). Contributed by @t3chguy.
* Restore the accessibility role on call views ([#29225](https://github.com/element-hq/element-web/pull/29225)). Contributed by @robintown.
* Revert `GoToHome` keyboard shortcut to `Ctrl``Shift``H` on macOS ([#28577](https://github.com/element-hq/element-web/pull/28577)). Contributed by @gy-mate.
* Encryption tab: display correct encryption panel when user cancels the reset identity flow ([#29216](https://github.com/element-hq/element-web/pull/29216)). Contributed by @florianduros.
Changes in [1.11.92](https://github.com/element-hq/element-desktop/releases/tag/v1.11.92) (2025-02-11)
======================================================================================================
## ✨ Features

View File

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,8 +1,8 @@
# Docker image to facilitate building Element Desktop's native bits using a glibc version (2.31)
# with broader compatibility, down to Debian bullseye & Ubuntu focal.
FROM rust:bullseye
FROM rust:bullseye@sha256:8d9b5e80062dcdb7f037b4eef92a6649632034d6811652e028706ea93db64159
ENV DEBIAN_FRONTEND noninteractive
ENV DEBIAN_FRONTEND=noninteractive
RUN curl --proto "=https" -L https://yarnpkg.com/latest.tar.gz | tar xvz && mv yarn-* /yarn && ln -s /yarn/bin/yarn /usr/bin/yarn
RUN apt-get -qq update && apt-get -y -qq dist-upgrade && \
@@ -16,13 +16,12 @@ RUN apt-get -qq update && apt-get -y -qq dist-upgrade && \
apt-get purge -y --auto-remove && rm -rf /var/lib/apt/lists/*
RUN ln -s /usr/bin/python3 /usr/bin/python & ln -s /usr/bin/pip3 /usr/bin/pip
ENV DEBUG_COLORS true
ENV FORCE_COLOR true
ENV DEBUG_COLORS=true
ENV FORCE_COLOR=true
WORKDIR /project
ENV NODE_VERSION 20.18.2
ARG TARGETOS
ARG TARGETARCH
COPY setup.sh /setup.sh
COPY .node-version dockerbuild/setup.sh /
RUN /setup.sh

View File

@@ -3,5 +3,9 @@
set -x
declare -A archMap=(["amd64"]="x64" ["arm64"]="arm64")
ARCH="${archMap["$TARGETARCH"]}"
# The .node-version file generally doesn't have the 'v' (renovate does not put the 'v' and will
# strip it on upgrade if it's there) but the 'v' is also widely supported so we probably ought
# to just work either way.
NODE_VERSION=$(cat /.node-version | sed -e 's/^v//')
curl --proto "=https" -L "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-$TARGETOS-$ARCH.tar.gz" | tar xz -C /usr/local --strip-components=1 && \
unlink /usr/local/CHANGELOG.md && unlink /usr/local/LICENSE && unlink /usr/local/README.md

View File

@@ -2,10 +2,12 @@
- [Introduction](../README.md)
# Build
# Build/Debug
- [Native Node modules](native-node-modules.md)
- [Windows requirements](windows-requirements.md)
- [Debugging](debugging.md)
- [Using gdb](gdb.md)
# Distribution

28
docs/debugging.md Normal file
View File

@@ -0,0 +1,28 @@
# Debugging Element-Desktop
There are two parts of the desktop app that you might want to debug.
## The renderer process
This is the regular element-web codeand can be debugged by just selecting 'toggle developer tools'
from the menu, even on ppackaged builds. This then works the same as chrome dev tools for element web.
## The main process
This is debugged as a node app, so:
1. Open any chrome dev tools window
1. Start element with the `--inspect-brk` flag
1. Notice that you now have a little green icon in the top left of your chrome devtools window, click it.
You are now debugging the code of the desktop app itself.
## The main process of a package app
When the app is shipped, electron's "fuses" are flipped, editing the electron binary itself to prevent certain features from being usable, one of which is debugging using `--inspect-brk` as above. You can flip the fuse back on Linux as follows:
```
sudo npx @electron/fuses write --app /opt/Element/element-desktop EnableNodeCliInspectArguments=on
```
A similar command will work, in theory, on mac and windows, except that this will break code signing (which is the point of fuses) so you would have to re-sign the app or somesuch.

46
docs/gdb.md Normal file
View File

@@ -0,0 +1,46 @@
# Using gdb against Element-Desktop
Occasionally it is useful to be able to connect to a running Element-Desktop
with [`gdb`](https://sourceware.org/gdb/), or to analayze a coredump. For this,
you will need debug symbols.
1. If you don't already have the right version of Element-Desktop (eg because
you are analyzing someone else's coredump), download and unpack the tarball
from https://packages.element.io/desktop/install/linux/. If it was a
nightly, your best bet may be to download the deb from
https://packages.element.io/debian/pool/main/e/element-nightly/ and unpack
it.
2. Figure out which version of Electron your Element-Desktop is based on. The
best way to do this is to figure out the version of Element-Desktop, then
look at
[`yarn.lock`](https://github.com/element-hq/element-desktop/blob/develop/yarn.lock)
for the corresponding version. There should be an entry starting
`electron@`, and under it a `version` line: this will tell you the version
of Electron that was used for that version of Element-Desktop.
3. Go to [Electron's releases page](https://github.com/electron/electron/releases/)
and find the version you just identified. Under "Assets", download
`electron-v<version>-linux-x64-debug.zip` (or, the -debug zip corresponding to your
architecture).
4. The debug zip has a structure like:
```
.
├── debug
│   ├── chrome_crashpad_handler.debug
│   ├── electron.debug
│   ├── libEGL.so.debug
│   ├── libffmpeg.so.debug
│   ├── libGLESv2.so.debug
│   └── libvk_swiftshader.so.debug
├── LICENSE
├── LICENSES.chromium.html
└── version
```
Take all the contents of `debug`, and copy them into the Element-Desktop directory,
so that `electron.debug` is alongside the `element-desktop-nightly` executable.
5. You now have a thing you can gdb as normal, either as `gdb --args element-desktop-nightly`, or
`gdb element-desktop-nightly core`.

View File

@@ -12,6 +12,13 @@ If you want to build native modules, make sure that the following tools are inst
- [Strawberry Perl](https://strawberryperl.com/)
- [Rustup](https://rustup.rs/)
- [NASM](https://www.nasm.us/)
You can install the above tools using [Chocolatey](https://chocolatey.org/install):
```cmd
choco install --no-progress -y git nodejs-lts yarn python StrawberryPerl rustup.install nasm magicsplat-tcl-tk
```
- [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019) with the following configuration:
- On the Workloads tab:
- Desktop & Mobile -> C++ build tools

View File

@@ -1,16 +1,12 @@
import * as os from "node:os";
import * as fs from "node:fs";
import * as path from "node:path";
import * as plist from "plist";
import { AfterPackContext, Arch, Configuration as BaseConfiguration, Platform } from "electron-builder";
import { computeData } from "app-builder-lib/out/asar/integrity";
import { readFile, writeFile } from "node:fs/promises";
import { type Configuration as BaseConfiguration, type Protocol } from "electron-builder";
/**
* This script has different outputs depending on your os platform.
*
* On Windows:
* Prefixes the nightly version with `0.0.1-nightly.` as it breaks if it is not semver
* Passes $ED_SIGNTOOL_THUMBPRINT and $ED_SIGNTOOL_SUBJECT_NAME to
* build.win.signtoolOptions.signingHashAlgorithms and build.win.signtoolOptions.certificateSubjectName respectively if specified.
*
@@ -20,24 +16,68 @@ import { readFile, writeFile } from "node:fs/promises";
* Passes $ED_DEBIAN_CHANGELOG to build.deb.fpm if specified
*/
const NIGHTLY_APP_ID = "im.riot.nightly";
const NIGHTLY_DEB_NAME = "element-nightly";
/**
* Interface describing relevant fields of the package.json file.
*/
interface Pkg {
version: string;
}
/**
* Base metadata fields, used in both package.json and the variant configuration.
*/
interface Metadata {
name: string;
productName: string;
description: string;
version: string;
}
/**
* Extra metadata fields that are injected into the build to pass to the app at runtime.
*/
interface ExtraMetadata extends Metadata {
electron_appId: string;
electron_protocol: string;
}
/**
* Interface describing the variant configuration format.
*/
interface Variant extends Metadata {
"appId": string;
"linux.executableName"?: string;
"linux.deb.name"?: string;
"protocols": string[];
}
type Writable<T> = NonNullable<
T extends Function ? T : T extends object ? { -readonly [K in keyof T]: Writable<T[K]> } : T
>;
const pkg: Pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
// Load the default variant as a base configuration
const DEFAULT_VARIANT = path.join("element.io", "release", "build.json");
let variant: Variant = JSON.parse(fs.readFileSync(DEFAULT_VARIANT, "utf8"));
/**
* If a variant is specified, we will use it to override the build-specific values.
* This allows us to have different builds for different purposes (e.g. stable, nightly).
*/
if (process.env.VARIANT_PATH) {
console.log(`Using variant configuration from '${process.env.VARIANT_PATH}':`);
variant = {
...variant,
...JSON.parse(fs.readFileSync(`${process.env.VARIANT_PATH}`, "utf8")),
};
} else {
console.warn(`No VARIANT_PATH specified, using default variant configuration '${DEFAULT_VARIANT}':`);
}
for (const key in variant) {
console.log(`${key}: ${variant[key]}`);
}
interface Configuration extends BaseConfiguration {
extraMetadata: Partial<Pick<Pkg, "version">> & Omit<Pkg, "version">;
extraMetadata: Partial<Pick<Pkg, "version">> & ExtraMetadata;
linux: BaseConfiguration["linux"];
win: BaseConfiguration["win"];
mac: BaseConfiguration["mac"];
@@ -46,26 +86,6 @@ interface Configuration extends BaseConfiguration {
} & BaseConfiguration["deb"];
}
async function injectAsarIntegrity(context: AfterPackContext) {
const packager = context.packager;
// We only need to re-generate asar on universal Mac builds, due to https://github.com/electron/universal/issues/116
if (packager.platform !== Platform.MAC || context.arch !== Arch.universal) return;
const resourcesPath = packager.getResourcesDir(context.appOutDir);
const asarIntegrity = await computeData({
resourcesPath,
resourcesRelativePath: "Resources",
resourcesDestinationPath: resourcesPath,
extraResourceMatchers: [],
});
const plistPath = path.join(resourcesPath, "..", "Info.plist");
const data = plist.parse(await readFile(plistPath, "utf8")) as unknown as Writable<plist.PlistObject>;
data["ElectronAsarIntegrity"] = asarIntegrity as unknown as Writable<plist.PlistValue>;
await writeFile(plistPath, plist.build(data));
}
/**
* @type {import('electron-builder').Configuration}
* @see https://www.electron.build/configuration/configuration
@@ -74,7 +94,7 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
// Make all fuses required to ensure they are all explicitly specified
electronFuses: Required<Configuration["electronFuses"]>;
} = {
appId: "im.riot.app",
appId: variant.appId,
asarUnpack: "**/*.node",
electronFuses: {
enableCookieEncryption: true,
@@ -90,9 +110,6 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
loadBrowserProcessSpecificV8Snapshot: false,
enableEmbeddedAsarIntegrityValidation: true,
},
afterPack: async (context: AfterPackContext) => {
await injectAsarIntegrity(context);
},
files: [
"package.json",
{
@@ -101,23 +118,19 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
},
"lib/**",
],
extraResources: [
{
from: "res/img",
to: "img",
},
"webapp.asar",
],
extraResources: ["build/icon.*", "webapp.asar"],
extraMetadata: {
name: pkg.name,
productName: pkg.productName,
description: pkg.description,
name: variant.name,
productName: variant.productName,
description: variant.description,
electron_appId: variant.appId,
electron_protocol: variant.protocols[0],
},
linux: {
target: ["tar.gz", "deb"],
category: "Network;InstantMessaging;Chat",
maintainer: "support@element.io",
icon: "build/icons",
icon: "icon.png",
executableName: variant.name, // element-desktop or element-desktop-nightly
},
deb: {
packageCategory: "net",
@@ -135,32 +148,26 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
"libgbm1",
],
recommends: ["libsqlcipher0", "element-io-archive-keyring"],
fpm: [
"--deb-field",
"Replaces: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)",
"--deb-field",
"Breaks: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)",
"--deb-pre-depends",
"libc6 (>= 2.31)",
],
fpm: ["--deb-pre-depends", "libc6 (>= 2.31)"],
},
mac: {
target: ["dmg", "zip"],
category: "public.app-category.social-networking",
darkModeSupport: true,
hardenedRuntime: true,
gatekeeperAssess: true,
// XXX: we cannot specify this due to https://github.com/electron/osx-sign/issues/344
// strictVerify: true,
strictVerify: true,
entitlements: "./build/entitlements.mac.plist",
icon: "build/icons/icon.icns",
icon: "build/icon.icns",
mergeASARs: true,
x64ArchFiles: "**/matrix-seshat/*.node", // hak already runs lipo
},
win: {
target: ["squirrel", "msi"],
signtoolOptions: {
signingHashAlgorithms: ["sha256"],
},
icon: "build/icons/icon.ico",
icon: "build/icon.ico",
},
msi: {
perMachine: true,
@@ -168,14 +175,28 @@ const config: Omit<Writable<Configuration>, "electronFuses"> & {
directories: {
output: "dist",
},
protocols: [
{
name: "element",
schemes: ["io.element.desktop", "element"],
},
],
protocols: {
name: variant.productName,
schemes: variant.protocols,
},
nativeRebuilder: "sequential",
nodeGypRebuild: false,
npmRebuild: true,
};
/**
* Allow specifying the version via env var.
* If unspecified, it will default to the version in package.json.
* @param {string} process.env.VERSION
*/
if (process.env.VERSION) {
config.extraMetadata.version = process.env.VERSION;
}
if (variant["linux.deb.name"]) {
config.deb.fpm.push("--name", variant["linux.deb.name"]);
}
/**
* Allow specifying windows signing cert via env vars
* @param {string} process.env.ED_SIGNTOOL_SUBJECT_NAME
@@ -186,31 +207,6 @@ if (process.env.ED_SIGNTOOL_SUBJECT_NAME && process.env.ED_SIGNTOOL_THUMBPRINT)
config.win.signtoolOptions!.certificateSha1 = process.env.ED_SIGNTOOL_THUMBPRINT;
}
/**
* Allow specifying nightly version via env var
* @param {string} process.env.ED_NIGHTLY
*/
if (process.env.ED_NIGHTLY) {
config.deb.fpm = []; // Clear the fpm as the breaks deb fields don't apply to nightly
config.appId = NIGHTLY_APP_ID;
config.extraMetadata.productName += " Nightly";
config.extraMetadata.name += "-nightly";
config.extraMetadata.description += " (nightly unstable build)";
config.deb.fpm.push("--name", NIGHTLY_DEB_NAME);
let version = process.env.ED_NIGHTLY;
if (os.platform() === "win32") {
// The windows packager relies on parsing this as semver, so we have to make it look like one.
// This will give our update packages really stupid names, but we probably can't change that either
// because squirrel windows parses them for the version too. We don't really care: nobody sees them.
// We just give the installer a static name, so you'll just see this in the 'about' dialog.
// Turns out if you use 0.0.0 here it makes Squirrel windows crash, so we use 0.0.1.
version = "0.0.1-nightly." + version;
}
config.extraMetadata.version = version;
}
if (os.platform() === "linux") {
// Electron crashes on debian if there's a space in the path.
// https://github.com/vector-im/element-web/issues/13171

View File

@@ -0,0 +1,9 @@
{
"appId": "im.riot.nightly",
"name": "element-desktop-nightly",
"productName": "Element Nightly",
"description": "Element: the future of secure communication (nightly unstable build)",
"protocols": ["io.element.nightly", "element"],
"linux.executableName": "element-desktop-nightly",
"linux.deb.name": "element-nightly"
}

View File

@@ -19,7 +19,7 @@
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
"bug_report_endpoint_url": "https://rageshakes.element.io/api/submit",
"uisi_autorageshake_app": "element-auto-uisi",
"show_labs_settings": true,
"room_directory": {

View File

@@ -0,0 +1,7 @@
{
"appId": "im.riot.app",
"name": "element-desktop",
"productName": "Element",
"description": "Element: the future of secure communication",
"protocols": ["io.element.desktop", "element"]
}

View File

@@ -19,7 +19,7 @@
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
"bug_report_endpoint_url": "https://rageshakes.element.io/api/submit",
"uisi_autorageshake_app": "element-auto-uisi",
"room_directory": {
"servers": ["matrix.org", "gitter.im"]

View File

@@ -1,26 +0,0 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import path from "node:path";
import type HakEnv from "../../scripts/hak/hakEnv.js";
import type { DependencyInfo } from "../../scripts/hak/dep.js";
export default async function buildKeytar(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
const env = hakEnv.makeGypEnv();
console.log("Running yarn with env", env);
await hakEnv.spawn(
path.join(moduleInfo.nodeModuleBinDir, "node-gyp"),
["rebuild", "--arch", hakEnv.getTargetArch()],
{
cwd: moduleInfo.moduleBuildDir,
env,
},
);
}

View File

@@ -1,15 +0,0 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type HakEnv from "../../scripts/hak/hakEnv.js";
import type { DependencyInfo } from "../../scripts/hak/dep.js";
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
// node-gyp uses python for reasons beyond comprehension
await hakEnv.checkTools([["python", "--version"]]);
}

View File

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

View File

@@ -1,16 +1,17 @@
import { KnipConfig } from "knip";
export default {
entry: ["src/electron-main.ts", "src/preload.ts", "electron-builder.ts", ".eslintrc-*.js", "scripts/**", "hak/**"],
entry: ["src/preload.cts", "electron-builder.ts", "scripts/**", "hak/**"],
project: ["**/*.{js,ts}"],
ignoreDependencies: [
// Brought in via hak scripts
"keytar",
"matrix-seshat",
// Required for `action-validator`
"@action-validator/*",
// Used for git pre-commit hooks
"husky",
// Required for `patch-package`
"postinstall-postinstall",
],
ignoreBinaries: ["jq", "scripts/in-docker.sh"],
} satisfies KnipConfig;

View File

@@ -3,9 +3,12 @@
"productName": "Element",
"main": "lib/electron-main.js",
"exports": "./lib/electron-main.js",
"version": "1.11.91",
"version": "1.12.4",
"description": "Element: the future of secure communication",
"author": "Element",
"author": {
"name": "Element",
"email": "support@element.io"
},
"homepage": "https://element.io",
"repository": {
"type": "git",
@@ -44,7 +47,7 @@
"build": "yarn run build:ts && yarn run build:res && electron-builder",
"build:ts": "tsc",
"build:res": "tsx scripts/copy-res.ts",
"docker:setup": "docker build --platform linux/amd64 -t element-desktop-dockerbuild dockerbuild",
"docker:setup": "docker build --platform linux/amd64 -t element-desktop-dockerbuild -f dockerbuild/Dockerfile .",
"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",
@@ -53,18 +56,19 @@
"test": "playwright test",
"test:open": "yarn test --ui",
"test:screenshots:build": "docker build playwright -t element-desktop-playwright --platform linux/amd64",
"test:screenshots:run": "docker run --rm --network host -v $(pwd):/work/element-desktop -v /var/run/docker.sock:/var/run/docker.sock --platform linux/amd64 -it element-desktop-playwright"
"test:screenshots:run": "docker run --rm --network host -v $(pwd):/work/element-desktop -v /var/run/docker.sock:/var/run/docker.sock --platform linux/amd64 -it element-desktop-playwright",
"postinstall": "patch-package && electron-builder install-app-deps"
},
"dependencies": {
"@sentry/electron": "^5.0.0",
"@standardnotes/electron-clear-data": "^1.0.5",
"@sentry/electron": "^7.0.0",
"auto-launch": "^5.0.5",
"counterpart": "^0.18.6",
"electron-store": "^10.0.0",
"electron-store": "^11.0.0",
"electron-window-state": "^5.0.3",
"keytar-forked": "7.10.0",
"minimist": "^1.2.6",
"png-to-ico": "^2.1.1",
"uuid": "^11.0.0"
"png-to-ico": "^3.0.0",
"uuid": "^13.0.0"
},
"devDependencies": {
"@action-validator/cli": "^0.6.0",
@@ -72,50 +76,51 @@
"@babel/core": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@electron/asar": "3.2.18",
"@playwright/test": "1.50.1",
"@stylistic/eslint-plugin": "^3.0.0",
"@electron/asar": "4.0.1",
"@playwright/test": "1.56.1",
"@stylistic/eslint-plugin": "^5.0.0",
"@types/auto-launch": "^5.0.1",
"@types/counterpart": "^0.18.1",
"@types/minimist": "^1.2.1",
"@types/node": "18.19.74",
"@types/node": "18.19.130",
"@types/pacote": "^11.1.1",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"app-builder-lib": "26.0.1",
"app-builder-lib": "26.1.0",
"chokidar": "^4.0.0",
"detect-libc": "^2.0.0",
"electron": "34.0.2",
"electron-builder": "26.0.1",
"electron-builder-squirrel-windows": "26.0.1",
"electron": "39.1.1",
"electron-builder": "26.1.0",
"electron-builder-squirrel-windows": "26.1.0",
"electron-devtools-installer": "^4.0.0",
"eslint": "^8.26.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-matrix-org": "^2.0.1",
"eslint-plugin-matrix-org": "^3.0.0",
"eslint-plugin-n": "^17.12.0",
"eslint-plugin-unicorn": "^56.0.0",
"glob": "^11.0.0",
"husky": "^9.1.6",
"knip": "^5.0.0",
"lint-staged": "^15.2.10",
"lint-staged": "^16.0.0",
"matrix-web-i18n": "^3.2.1",
"mkdirp": "^3.0.0",
"pacote": "^21.0.0",
"plist": "^3.1.0",
"patch-package": "^8.0.1",
"postinstall-postinstall": "^2.1.0",
"prettier": "^3.0.0",
"rimraf": "^6.0.0",
"tar": "^7.0.0",
"tsx": "^4.19.2",
"typescript": "5.7.3"
"typescript": "5.9.3"
},
"hakDependencies": {
"matrix-seshat": "^4.0.0",
"keytar": "^7.9.0"
"matrix-seshat": "^4.0.1"
},
"resolutions": {
"@types/node": "18.19.74",
"config-file-ts": "0.2.8-rc1"
"@types/node": "18.19.130",
"config-file-ts": "0.2.8-rc1",
"node-abi": "4.17.0"
}
}

View File

@@ -0,0 +1,18 @@
diff --git a/node_modules/@types/auto-launch/index.d.ts b/node_modules/@types/auto-launch/index.d.ts
index a30a77c..e512ce1 100644
--- a/node_modules/@types/auto-launch/index.d.ts
+++ b/node_modules/@types/auto-launch/index.d.ts
@@ -25,6 +25,13 @@ interface AutoLaunchOptions {
declare class AutoLaunch {
constructor(options: AutoLaunchOptions);
+ /**
+ * This type describes the internal options of the `auto-launch` package which allows us to update options after initialization.
+ */
+ readonly opts: {
+ isHiddenOnLaunch: boolean;
+ };
+
/**
* Enables auto-launch at start up.
*/

View File

@@ -8,7 +8,25 @@ Please see LICENSE files in the repository root for full details.
import { defineConfig } from "@playwright/test";
const projects = [
"macos",
"win-x64",
"win-ia32",
"win-arm64",
"linux-amd64-sqlcipher-system",
"linux-amd64-sqlcipher-static",
"linux-arm64-sqlcipher-system",
"linux-arm64-sqlcipher-static",
];
export default defineConfig({
// Allows the GitHub action to specify a project name (OS + arch) for the combined report to make sense
// workaround for https://github.com/microsoft/playwright/issues/33521
projects: process.env.CI
? projects.map((name) => ({
name,
}))
: undefined,
use: {
viewport: { width: 1280, height: 720 },
video: "retain-on-failure",
@@ -18,7 +36,7 @@ export default defineConfig({
outputDir: "playwright/test-results",
workers: 1,
retries: process.env.CI ? 2 : 0,
reporter: [["html", { outputFolder: "playwright/html-report" }]],
reporter: process.env.CI ? [["blob"], ["github"]] : [["html", { outputFolder: "playwright/html-report" }]],
snapshotDir: "playwright/snapshots",
snapshotPathTemplate: "{snapshotDir}/{testFilePath}/{arg}-{platform}{ext}",
timeout: 30 * 1000,

View File

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

View File

@@ -6,21 +6,24 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import { platform } from "node:os";
import keytar from "keytar-forked";
import { test, expect } from "../../element-desktop-test.js";
declare global {
interface ElectronPlatform {
getEventIndexingManager():
| {
supportsEventIndexing(): Promise<boolean>;
}
| undefined;
getPickleKey(userId: string, deviceId: string): Promise<string | null>;
createPickleKey(userId: string, deviceId: string): Promise<string | null>;
}
interface Window {
mxPlatformPeg: {
get(): {
getEventIndexingManager():
| {
supportsEventIndexing(): Promise<boolean>;
}
| undefined;
createPickleKey(userId: string, deviceId: string): Promise<string | null>;
};
get(): ElectronPlatform;
};
}
}
@@ -46,13 +49,57 @@ test.describe("App launch", () => {
).resolves.toBeTruthy();
});
test("should launch and render the welcome view successfully and support keytar", async ({ page }) => {
test.skip(platform() === "linux", "This test does not yet support Linux");
test.describe("safeStorage", () => {
const userId = "@user:server";
const deviceId = "ABCDEF";
await expect(
page.evaluate<string | null>(async () => {
return await window.mxPlatformPeg.get().createPickleKey("@user:server", "ABCDEF");
}),
).resolves.not.toBeNull();
test("should be supported", async ({ page }) => {
await expect(
page.evaluate(
([userId, deviceId]) => window.mxPlatformPeg.get().createPickleKey(userId, deviceId),
[userId, deviceId],
),
).resolves.not.toBeNull();
});
test.describe("migrate from keytar", () => {
test.skip(
process.env.GITHUB_ACTIONS && ["linux", "darwin"].includes(process.platform),
"GitHub Actions hosted runner are not a compatible environment for this test",
);
const pickleKey = "DEADBEEF1234";
const keytarService = "element.io";
const keytarKey = `${userId}|${deviceId}`;
test.beforeAll(async () => {
await keytar.setPassword(keytarService, keytarKey, pickleKey);
await expect(keytar.getPassword(keytarService, keytarKey)).resolves.toBe(pickleKey);
});
test.afterAll(async () => {
await keytar.deletePassword(keytarService, keytarKey);
});
test("should migrate successfully", async ({ page }) => {
await expect(
page.evaluate(
([userId, deviceId]) => window.mxPlatformPeg.get().getPickleKey(userId, deviceId),
[userId, deviceId],
),
).resolves.toBe(pickleKey);
});
});
});
test.describe("--no-update", () => {
test.use({
extraArgs: ["--no-update"],
});
// XXX: this test works fine locally but in CI the app start races with the test plumbing up the stdout/stderr pipes
// which means the logs are missed, disabling for now.
test.skip("should respect option", async ({ page, stdout }) => {
expect(stdout.data.toString()).toContain("Auto update disabled via command line flag");
});
});
});

View File

@@ -0,0 +1,36 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { test, expect } from "../../element-desktop-test.js";
declare global {
interface ElectronPlatform {
getOidcCallbackUrl(): URL;
}
interface Window {
mxPlatformPeg: {
get(): ElectronPlatform;
};
}
}
test.describe("OIDC Native", () => {
test.slow();
test.beforeEach(async ({ page }) => {
await page.locator(".mx_Welcome").waitFor();
});
test("should use OIDC callback URL without authority component", async ({ page }) => {
await expect(
page.evaluate<string>(() => {
return window.mxPlatformPeg.get().getOidcCallbackUrl().toString();
}),
).resolves.toMatch(/io\.element\.(desktop|nightly):\/vector\/webapp\//);
});
});

View File

@@ -11,12 +11,37 @@ import fs from "node:fs/promises";
import path, { dirname } from "node:path";
import os from "node:os";
import { fileURLToPath } from "node:url";
import { PassThrough } from "node:stream";
/**
* A PassThrough stream that captures all data written to it.
*/
class CapturedPassThrough extends PassThrough {
private _chunks = [];
public constructor() {
super();
super.on("data", this.onData);
}
private onData = (chunk): void => {
this._chunks.push(chunk);
};
public get data(): Buffer {
return Buffer.concat(this._chunks);
}
}
interface Fixtures {
app: ElectronApplication;
tmpDir: string;
extraEnv: Record<string, string>;
extraArgs: string[];
// Utilities to capture stdout and stderr for tests to make assertions against
stdout: CapturedPassThrough;
stderr: CapturedPassThrough;
}
const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -24,15 +49,34 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
export const test = base.extend<Fixtures>({
extraEnv: {},
extraArgs: [],
// eslint-disable-next-line no-empty-pattern
stdout: async ({}, use) => {
await use(new CapturedPassThrough());
},
// eslint-disable-next-line no-empty-pattern
stderr: async ({}, use) => {
await use(new CapturedPassThrough());
},
// eslint-disable-next-line no-empty-pattern
tmpDir: async ({}, use) => {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "element-desktop-tests-"));
console.log("Using temp profile directory: ", tmpDir);
await use(tmpDir);
await fs.rm(tmpDir, { recursive: true });
},
app: async ({ tmpDir, extraEnv, extraArgs }, use) => {
const args = ["--profile-dir", tmpDir];
app: async ({ tmpDir, extraEnv, extraArgs, stdout, stderr }, use) => {
const args = ["--profile-dir", tmpDir, ...extraArgs];
if (process.env.GITHUB_ACTIONS) {
if (process.platform === "linux") {
// GitHub Actions hosted runner lacks dbus and a compatible keyring, so we need to force plaintext storage
args.push("--storage-mode", "force-plaintext");
} else if (process.platform === "darwin") {
// GitHub Actions hosted runner has no working default keychain, so allow plaintext storage
args.push("--storage-mode", "allow-plaintext");
}
}
const executablePath = process.env["ELEMENT_DESKTOP_EXECUTABLE"];
if (!executablePath) {
@@ -40,17 +84,19 @@ export const test = base.extend<Fixtures>({
args.unshift(path.join(__dirname, "..", "lib", "electron-main.js"));
}
console.log(`Launching '${executablePath}' with args ${args.join(" ")}`);
const app = await electron.launch({
env: {
...process.env,
...extraEnv,
},
executablePath,
args: [...args, ...extraArgs],
args,
});
app.process().stdout.pipe(process.stdout);
app.process().stderr.pipe(process.stderr);
app.process().stdout.pipe(stdout).pipe(process.stdout);
app.process().stderr.pipe(stderr).pipe(process.stderr);
await app.firstWindow();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

48
scripts/branch-match.sh Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/bash
# Script for downloading a branch of element-web matching the branch a PR is contributed from
set -x
deforg="element-hq"
defrepo="element-web"
# The PR_NUMBER variable must be set explicitly.
default_org_repo=${GITHUB_REPOSITORY:-"$deforg/$defrepo"}
PR_ORG=${PR_ORG:-${default_org_repo%%/*}}
PR_REPO=${PR_REPO:-${default_org_repo##*/}}
# A function that clones a branch of a repo based on the org, repo and branch
clone() {
org=$1
repo=$2
branch=$3
if [ -n "$branch" ]
then
echo "Trying to use $org/$repo#$branch"
# Disable auth prompts: https://serverfault.com/a/665959
GIT_TERMINAL_PROMPT=0 git clone https://github.com/$org/$repo.git $repo --branch "$branch" --depth 1 && exit 0
fi
}
echo "Getting info about a PR with number $PR_NUMBER"
apiEndpoint="https://api.github.com/repos/$PR_ORG/$PR_REPO/pulls/$PR_NUMBER"
head=$(curl "$apiEndpoint" | jq -r '.head.label')
# for forks, $head will be in the format "fork:branch", so we split it by ":"
# into an array. On non-forks, this has the effect of splitting into a single
# element array given ":" shouldn't appear in the head - it'll just be the
# branch name. Based on the results, we clone.
BRANCH_ARRAY=(${head//:/ })
TRY_ORG=$deforg
TRY_BRANCH=${BRANCH_ARRAY[0]}
if [[ "$head" == *":"* ]]; then
# ... but only match that fork if it's a real fork
if [ "${BRANCH_ARRAY[0]}" != "$PR_ORG" ]; then
TRY_ORG=${BRANCH_ARRAY[0]}
fi
TRY_BRANCH=${BRANCH_ARRAY[1]}
fi
clone "$TRY_ORG" "$defrepo" "$TRY_BRANCH"
exit 1

7
scripts/cl.bat Normal file
View File

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

View File

@@ -1,41 +0,0 @@
#!/bin/bash
set -x
deforg="$1"
defrepo="$2"
defbranch="$3"
[ -z "$defbranch" ] && defbranch="develop"
rm -r "$defrepo" || true
clone() {
org=$1
repo=$2
branch=$3
if [ -n "$branch" ]
then
echo "Trying to use $org/$repo#$branch"
# Disable auth prompts: https://serverfault.com/a/665959
GIT_TERMINAL_PROMPT=0 git clone https://github.com/$org/$repo.git $repo --branch "$branch" --depth 1 && exit 0
fi
}
# Try the PR author's branch in case it exists on the deps as well.
# If BUILDKITE_BRANCH is set, it will contain either:
# * "branch" when the author's branch and target branch are in the same repo
# * "author:branch" when the author's branch is in their fork
# We can split on `:` into an array to check.
BUILDKITE_BRANCH_ARRAY=(${BUILDKITE_BRANCH//:/ })
if [[ "${#BUILDKITE_BRANCH_ARRAY[@]}" == "1" ]]; then
clone $deforg $defrepo $BUILDKITE_BRANCH
elif [[ "${#BUILDKITE_BRANCH_ARRAY[@]}" == "2" ]]; then
clone ${BUILDKITE_BRANCH_ARRAY[0]} $defrepo ${BUILDKITE_BRANCH_ARRAY[1]}
fi
# Try the target branch of the push or PR.
clone $deforg $defrepo $BUILDKITE_PULL_REQUEST_BASE_BRANCH
# Try the current branch from Jenkins.
clone $deforg $defrepo `"echo $GIT_BRANCH" | sed -e 's/^origin\///'`
# Use the default branch as the last resort.
clone $deforg $defrepo $defbranch

View File

@@ -67,14 +67,14 @@ Hak is divided into lifecycle stages, in order:
# hak.json
The scripts section contains scripts used for lifecycle stages that need them (fetch, fetchDeps, build).
The scripts section contains scripts used for lifecycle stages that need them (fetch, build).
It also contains 'prune' and 'copy' which are globs of files to delete from the output module directory
and copy over from the module build directory to the output module directory, respectively.
# Shortcomings
Hak doesn't know about dependencies between lifecycle stages, ie. it doesn't know that you need to
'fetch' and 'fetchDeps' before you can 'build', etc. You get to run each individually, and remember
'fetch' before you can 'build', etc. You get to run each individually, and remember
the right order.
There is also a _lot_ of duplication in the command execution: we should abstract away

View File

@@ -10,7 +10,5 @@ import type { DependencyInfo } from "./dep.js";
import type HakEnv from "./hakEnv.js";
export default async function check(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
if (moduleInfo.scripts.check) {
await moduleInfo.scripts.check(hakEnv, moduleInfo);
}
await moduleInfo.scripts.check?.(hakEnv, moduleInfo);
}

View File

@@ -9,7 +9,6 @@ Please see LICENSE files in the repository root for full details.
import path from "node:path";
import fsProm from "node:fs/promises";
import childProcess from "node:child_process";
import { rimraf } from "rimraf";
import { glob } from "glob";
import { mkdirp } from "mkdirp";
@@ -17,20 +16,6 @@ import type HakEnv from "./hakEnv.js";
import type { DependencyInfo } from "./dep.js";
export default async function copy(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
if (moduleInfo.cfg.prune) {
console.log("Removing " + moduleInfo.cfg.prune + " from " + moduleInfo.moduleOutDir);
// rimraf doesn't have a 'cwd' option: it always uses process.cwd()
// (and if you set glob.cwd it just breaks because it can't find the files)
const oldCwd = process.cwd();
try {
await mkdirp(moduleInfo.moduleOutDir);
process.chdir(moduleInfo.moduleOutDir);
await rimraf(moduleInfo.cfg.prune);
} finally {
process.chdir(oldCwd);
}
}
if (moduleInfo.cfg.copy) {
// If there are multiple moduleBuildDirs, singular moduleBuildDir
// is the same as moduleBuildDirs[0], so we're just listing the contents

View File

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

View File

@@ -19,7 +19,7 @@ import packageJson from "../../package.json";
const MODULECOMMANDS = ["check", "fetch", "link", "build", "copy", "clean"];
// Shortcuts for multiple commands at once (useful for building universal binaries
// because you can run the fetch/fetchDeps/build for each arch and then copy/link once)
// because you can run the fetch/build for each arch and then copy/link once)
const METACOMMANDS: Record<string, string[]> = {
fetchandbuild: ["check", "fetch", "build"],
copyandlink: ["copy", "link"],

View File

@@ -8,7 +8,7 @@
"module": "node16",
"sourceMap": false,
"strict": true,
"lib": ["es2020"]
"lib": ["es2021"]
},
"include": ["../src/@types", "./**/*.ts"]
}

View File

@@ -7,30 +7,21 @@ Please see LICENSE files in the repository root for full details.
import { type BrowserWindow } from "electron";
import type Store from "electron-store";
import type AutoLaunch from "auto-launch";
import { type AppLocalization } from "../language-helper.js";
// global type extensions need to use var for whatever reason
/* eslint-disable no-var */
declare global {
type IConfigOptions = Record<string, any>;
var mainWindow: BrowserWindow | null;
var appQuitting: boolean;
var appLocalization: AppLocalization;
var launcher: AutoLaunch;
var vectorConfig: Record<string, any>;
var vectorConfig: IConfigOptions;
var trayConfig: {
// eslint-disable-next-line camelcase
icon_path: string;
brand: string;
};
var store: Store<{
warnBeforeExit?: boolean;
minimizeToTray?: boolean;
spellCheckerEnabled?: boolean;
autoHideMenuBar?: boolean;
locale?: string | string[];
disableHardwareAcceleration?: boolean;
}>;
}
/* eslint-enable no-var */

View File

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

50
src/auto-launch.ts Normal file
View File

@@ -0,0 +1,50 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import BaseAutoLaunch from "auto-launch";
import Store from "./store.js";
export type AutoLaunchState = "enabled" | "minimised" | "disabled";
// Wrapper around auto-launch to get/set the `isHidden` option
export class AutoLaunch extends BaseAutoLaunch {
private static internalInstance?: AutoLaunch;
public static get instance(): AutoLaunch {
if (!AutoLaunch.internalInstance) {
if (!Store.instance) throw new Error("Store not initialized");
AutoLaunch.internalInstance = new AutoLaunch({
name: global.vectorConfig.brand || "Element",
isHidden: Store.instance.get("openAtLoginMinimised"),
mac: {
useLaunchAgent: true,
},
});
}
return AutoLaunch.internalInstance;
}
public async getState(): Promise<AutoLaunchState> {
if (!(await this.isEnabled())) {
return "disabled";
}
return this.opts.isHiddenOnLaunch ? "minimised" : "enabled";
}
public async setState(state: AutoLaunchState): Promise<void> {
const openAtLoginMinimised = state === "minimised";
Store.instance?.set("openAtLoginMinimised", openAtLoginMinimised);
this.opts.isHiddenOnLaunch = openAtLoginMinimised;
if (state !== "disabled") {
return this.enable();
} else {
return this.disable();
}
}
}

49
src/badge.ts Normal file
View File

@@ -0,0 +1,49 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { app, ipcMain, type IpcMainEvent, nativeImage } from "electron";
import { _t } from "./language-helper.js";
// Handles calculating the correct "badge" for the window, for notifications and error states.
// Tray icon updates are handled in tray.ts
if (process.platform === "win32") {
// We only use setOverlayIcon on Windows as it's only supported on that platform, but has good support
// from all the Windows variants we support.
// https://www.electronjs.org/docs/latest/api/browser-window#winsetoverlayiconoverlay-description-windows
ipcMain.on(
"setBadgeCount",
function (_ev: IpcMainEvent, count: number, imageBuffer?: Buffer, isError?: boolean): void {
if (count === 0) {
// Flash frame is set to true in ipc.ts "loudNotification"
global.mainWindow?.flashFrame(false);
}
if (imageBuffer) {
global.mainWindow?.setOverlayIcon(
nativeImage.createFromBuffer(Buffer.from(imageBuffer)),
isError
? _t("icon_overlay|description_error")
: _t("icon_overlay|description_notifications", { count }),
);
} else {
global.mainWindow?.setOverlayIcon(null, "");
}
},
);
} else {
// only set badgeCount on Mac/Linux, the docs say that only those platforms support it but turns out Electron
// has some Windows support too, and in some Windows environments this leads to two badges rendering atop
// each other. See https://github.com/vector-im/element-web/issues/16942
ipcMain.on("setBadgeCount", function (_ev: IpcMainEvent, count: number): void {
if (count === 0) {
// Flash frame is set to true in ipc.ts "loudNotification"
global.mainWindow?.flashFrame(false);
}
app.badgeCount = count;
});
}

26
src/build-config.ts Normal file
View File

@@ -0,0 +1,26 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import path, { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { type JsonObject, loadJsonFile } from "./utils.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
interface BuildConfig {
appId: string;
protocol: string;
}
export function readBuildConfig(): BuildConfig {
const packageJson = loadJsonFile(path.join(__dirname, "..", "package.json")) as JsonObject;
return {
appId: (packageJson["electron_appId"] as string) || "im.riot.app",
protocol: (packageJson["electron_protocol"] as string) || "io.element.desktop",
};
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2018-2024 New Vector Ltd.
Copyright 2018-2025 New Vector Ltd.
Copyright 2017-2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2016 Aviral Dasgupta
Copyright 2016 OpenMarket Ltd
@@ -10,31 +10,42 @@ Please see LICENSE files in the repository root for full details.
// Squirrel on windows starts the app with various flags as hooks to tell us when we've been installed/uninstalled etc.
import "./squirrelhooks.js";
import { app, BrowserWindow, Menu, autoUpdater, protocol, dialog, type Input, type Event, session } from "electron";
import {
app,
BrowserWindow,
Menu,
autoUpdater,
dialog,
type Input,
type Event,
session,
protocol,
desktopCapturer,
} from "electron";
// eslint-disable-next-line n/file-extension-in-import
import * as Sentry from "@sentry/electron/main";
import AutoLaunch from "auto-launch";
import path, { dirname } from "node:path";
import windowStateKeeper from "electron-window-state";
import Store from "electron-store";
import fs, { promises as afs } from "node:fs";
import { URL, fileURLToPath } from "node:url";
import minimist from "minimist";
import "./ipc.js";
import "./keytar.js";
import "./seshat.js";
import "./settings.js";
import "./badge.js";
import * as tray from "./tray.js";
import Store from "./store.js";
import { buildMenuTemplate } from "./vectormenu.js";
import webContentsHandler from "./webcontents-handler.js";
import * as updater from "./updater.js";
import { getProfileFromDeeplink, protocolInit } from "./protocol.js";
import ProtocolHandler from "./protocol.js";
import { _t, AppLocalization } from "./language-helper.js";
import { setDisplayMediaCallback } from "./displayMediaCallback.js";
import { setupMacosTitleBar } from "./macos-titlebar.js";
import { loadJsonFile } from "./utils.js";
import { type Json, loadJsonFile } from "./utils.js";
import { setupMediaAuth } from "./media-auth.js";
import { readBuildConfig } from "./build-config.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -45,7 +56,12 @@ const argv = minimist(process.argv, {
if (argv["help"]) {
console.log("Options:");
console.log(" --profile-dir {path}: Path to where to store the profile.");
console.log(" --profile {name}: Name of alternate profile to use, allows for running multiple accounts.");
console.log(
` --profile {name}: Name of alternate profile to use, allows for running multiple accounts.\n` +
` Ignored if --profile-dir is specified.\n` +
` The ELEMENT_PROFILE_DIR environment variable may be used to change the default profile path.\n` +
` It is overridden by --profile-dir, but can be combined with --profile.`,
);
console.log(" --devtools: Install and use react-devtools and react-perf.");
console.log(
` --config: Path to the config.json file. May also be specified via the ELEMENT_DESKTOP_CONFIG_JSON environment variable.\n` +
@@ -59,6 +75,7 @@ if (argv["help"]) {
}
const LocalConfigLocation = process.env.ELEMENT_DESKTOP_CONFIG_JSON ?? argv["config"];
const LocalConfigFilename = "config.json";
// Electron creates the user data directory (with just an empty 'Dictionaries' directory...)
// as soon as the app path is set, so pick a random path in it that must exist if it's a
@@ -67,16 +84,19 @@ function isRealUserDataDir(d: string): boolean {
return fs.existsSync(path.join(d, "IndexedDB"));
}
const buildConfig = readBuildConfig();
const protocolHandler = new ProtocolHandler(buildConfig.protocol);
// check if we are passed a profile in the SSO callback url
let userDataPath: string;
const userDataPathInProtocol = getProfileFromDeeplink(argv["_"]);
const userDataPathInProtocol = protocolHandler.getProfileFromDeeplink(argv["_"]);
if (userDataPathInProtocol) {
userDataPath = userDataPathInProtocol;
} else if (argv["profile-dir"]) {
userDataPath = argv["profile-dir"];
} else {
let newUserDataPath = app.getPath("userData");
let newUserDataPath = process.env.ELEMENT_PROFILE_DIR ?? app.getPath("userData");
if (argv["profile"]) {
newUserDataPath += "-" + argv["profile"];
}
@@ -137,60 +157,86 @@ function getAsarPath(): Promise<string> {
return asarPathPromise;
}
// Loads the config from asar, and applies a config.json from userData atop if one exists
// Writes config to `global.vectorConfig`. Does nothing if `global.vectorConfig` is already set.
async function loadConfig(): Promise<void> {
if (global.vectorConfig) return;
const asarPath = await getAsarPath();
try {
global.vectorConfig = loadJsonFile(asarPath, "config.json");
} catch {
// it would be nice to check the error code here and bail if the config
// is unparsable, but we get MODULE_NOT_FOUND in the case of a missing
// file or invalid json, so node is just very unhelpful.
// Continue with the defaults (ie. an empty config)
global.vectorConfig = {};
function loadLocalConfigFile(): Json {
if (LocalConfigLocation) {
console.log("Loading local config: " + LocalConfigLocation);
return loadJsonFile(LocalConfigLocation);
} else {
const configDir = app.getPath("userData");
console.log(`Loading local config: ${path.join(configDir, LocalConfigFilename)}`);
return loadJsonFile(configDir, LocalConfigFilename);
}
}
try {
// Load local config and use it to override values from the one baked with the build
const localConfig = LocalConfigLocation
? loadJsonFile(LocalConfigLocation)
: loadJsonFile(app.getPath("userData"), "config.json");
let loadConfigPromise: Promise<void> | undefined;
// Loads the config from asar, and applies a config.json from userData atop if one exists
// Writes config to `global.vectorConfig`. Idempotent, returns the same promise on subsequent calls.
function loadConfig(): Promise<void> {
if (loadConfigPromise) return loadConfigPromise;
// If the local config has a homeserver defined, don't use the homeserver from the build
// config. This is to avoid a problem where Riot thinks there are multiple homeservers
// defined, and panics as a result.
if (Object.keys(localConfig).find((k) => homeserverProps.includes(<any>k))) {
// Rip out all the homeserver options from the vector config
global.vectorConfig = Object.keys(global.vectorConfig)
.filter((k) => !homeserverProps.includes(<any>k))
.reduce(
(obj, key) => {
obj[key] = global.vectorConfig[key];
return obj;
},
{} as Omit<Partial<(typeof global)["vectorConfig"]>, keyof typeof homeserverProps>,
);
async function actuallyLoadConfig(): Promise<void> {
const asarPath = await getAsarPath();
try {
console.log(`Loading app config: ${path.join(asarPath, LocalConfigFilename)}`);
global.vectorConfig = loadJsonFile(asarPath, LocalConfigFilename);
} catch {
// it would be nice to check the error code here and bail if the config
// is unparsable, but we get MODULE_NOT_FOUND in the case of a missing
// file or invalid json, so node is just very unhelpful.
// Continue with the defaults (ie. an empty config)
global.vectorConfig = {};
}
global.vectorConfig = Object.assign(global.vectorConfig, localConfig);
} catch (e) {
if (e instanceof SyntaxError) {
void dialog.showMessageBox({
type: "error",
title: `Your ${global.vectorConfig.brand || "Element"} is misconfigured`,
message:
`Your custom ${global.vectorConfig.brand || "Element"} configuration contains invalid JSON. ` +
`Please correct the problem and reopen ${global.vectorConfig.brand || "Element"}.`,
detail: e.message || "",
try {
// Load local config and use it to override values from the one baked with the build
const localConfig = loadLocalConfigFile();
// If the local config has a homeserver defined, don't use the homeserver from the build
// config. This is to avoid a problem where Riot thinks there are multiple homeservers
// defined, and panics as a result.
if (Object.keys(localConfig).find((k) => homeserverProps.includes(<any>k))) {
// Rip out all the homeserver options from the vector config
global.vectorConfig = Object.keys(global.vectorConfig)
.filter((k) => !homeserverProps.includes(<any>k))
.reduce(
(obj, key) => {
obj[key] = global.vectorConfig[key];
return obj;
},
{} as Omit<Partial<(typeof global)["vectorConfig"]>, keyof typeof homeserverProps>,
);
}
global.vectorConfig = Object.assign(global.vectorConfig, localConfig);
} catch (e) {
if (e instanceof SyntaxError) {
await app.whenReady();
void dialog.showMessageBox({
type: "error",
title: `Your ${global.vectorConfig.brand || "Element"} is misconfigured`,
message:
`Your custom ${global.vectorConfig.brand || "Element"} configuration contains invalid JSON. ` +
`Please correct the problem and reopen ${global.vectorConfig.brand || "Element"}.`,
detail: e.message || "",
});
}
// Could not load local config, this is expected in most cases.
}
// Tweak modules paths as they assume the root is at the same level as webapp, but for `vector://vector/webapp` it is not.
if (Array.isArray(global.vectorConfig.modules)) {
global.vectorConfig.modules = global.vectorConfig.modules.map((m) => {
if (m.startsWith("/")) {
return "/webapp" + m;
}
return m;
});
}
// Could not load local config, this is expected in most cases.
}
loadConfigPromise = actuallyLoadConfig();
return loadConfigPromise;
}
// Configure Electron Sentry and crashReporter using sentry.dsn in config.json if one is present.
@@ -208,58 +254,19 @@ async function configureSentry(): Promise<void> {
}
}
// Set up globals for Tray and AutoLaunch
// Set up globals for Tray
async function setupGlobals(): Promise<void> {
const asarPath = await getAsarPath();
await loadConfig();
// we assume the resources path is in the same place as the asar
const resPath = await tryPaths("res", path.dirname(asarPath), [
// If run from the source checkout
"res",
// if run from packaged application
"",
]);
// The tray icon
// It's important to call `path.join` so we don't end up with the packaged asar in the final path.
const iconFile = `element.${process.platform === "win32" ? "ico" : "png"}`;
// Figure out the tray icon path & brand name
const iconFile = `icon.${process.platform === "win32" ? "ico" : "png"}`;
global.trayConfig = {
icon_path: path.join(resPath, "img", iconFile),
icon_path: path.join(path.dirname(asarPath), "build", iconFile),
brand: global.vectorConfig.brand || "Element",
};
// launcher
global.launcher = new AutoLaunch({
name: global.vectorConfig.brand || "Element",
isHidden: true,
mac: {
useLaunchAgent: true,
},
});
}
// Look for an auto-launcher under 'Riot' and if we find one,
// port its enabled/disabled-ness over to the new 'Element' launcher
async function moveAutoLauncher(): Promise<void> {
if (!global.vectorConfig.brand || global.vectorConfig.brand === "Element") {
const oldLauncher = new AutoLaunch({
name: "Riot",
isHidden: true,
mac: {
useLaunchAgent: true,
},
});
const wasEnabled = await oldLauncher.isEnabled();
if (wasEnabled) {
await oldLauncher.disable();
await global.launcher.enable();
}
}
}
global.store = new Store({ name: "electron-config" });
global.appQuitting = false;
const exitShortcuts: Array<(input: Input, platform: string) => boolean> = [
@@ -269,32 +276,6 @@ const exitShortcuts: Array<(input: Input, platform: string) => boolean> = [
platform === "darwin" && input.meta && !input.control && input.key.toUpperCase() === "Q",
];
const warnBeforeExit = (event: Event, input: Input): void => {
const shouldWarnBeforeExit = global.store.get("warnBeforeExit", true);
const exitShortcutPressed =
input.type === "keyDown" && exitShortcuts.some((shortcutFn) => shortcutFn(input, process.platform));
if (shouldWarnBeforeExit && exitShortcutPressed && global.mainWindow) {
const shouldCancelCloseRequest =
dialog.showMessageBoxSync(global.mainWindow, {
type: "question",
buttons: [
_t("action|cancel"),
_t("action|close_brand", {
brand: global.vectorConfig.brand || "Element",
}),
],
message: _t("confirm_quit"),
defaultId: 1,
cancelId: 0,
}) === 0;
if (shouldCancelCloseRequest) {
event.preventDefault();
}
}
};
void configureSentry();
// handle uncaught errors otherwise it displays
@@ -319,7 +300,7 @@ if (!gotLock) {
}
// do this after we know we are the primary instance of the app
protocolInit();
protocolHandler.initialise(userDataPath);
// Register the scheme the app is served from as 'standard'
// which allows things like relative URLs and IndexedDB to
@@ -351,19 +332,22 @@ app.enableSandbox();
// We disable media controls here. We do this because calls use audio and video elements and they sometimes capture the media keys. See https://github.com/vector-im/element-web/issues/15704
app.commandLine.appendSwitch("disable-features", "HardwareMediaKeyHandling,MediaSessionService");
const store = Store.initialize(argv["storage-mode"]); // must be called before any async actions
// Disable hardware acceleration if the setting has been set.
if (global.store.get("disableHardwareAcceleration", false) === true) {
if (store.get("disableHardwareAcceleration")) {
console.log("Disabling hardware acceleration.");
app.disableHardwareAcceleration();
}
app.on("ready", async () => {
console.debug("Reached Electron ready state");
let asarPath: string;
try {
asarPath = await getAsarPath();
await setupGlobals();
await moveAutoLauncher();
} catch (e) {
console.log("App setup failed: exiting", e);
process.exit(1);
@@ -437,21 +421,28 @@ app.on("ready", async () => {
});
});
if (argv["no-update"]) {
console.log('Auto update disabled via command line flag "--no-update"');
// Minimist parses `--no-`-prefixed arguments as booleans with value `false` rather than verbatim.
if (argv["update"] === false) {
console.log("Auto update disabled via command line flag");
} else if (global.vectorConfig["update_base_url"]) {
console.log(`Starting auto update with base URL: ${global.vectorConfig["update_base_url"]}`);
void updater.start(global.vectorConfig["update_base_url"]);
} else {
console.log("No update_base_url is defined: auto update is disabled");
}
// Set up i18n before loading storage as we need translations for dialogs
global.appLocalization = new AppLocalization({
components: [(): void => tray.initApplicationMenu(), (): void => Menu.setApplicationMenu(buildMenuTemplate())],
store,
});
// Load the previous window state with fallback to defaults
const mainWindowState = windowStateKeeper({
defaultWidth: 1024,
defaultHeight: 768,
});
console.debug("Opening main window");
const preloadScript = path.normalize(`${__dirname}/preload.cjs`);
global.mainWindow = new BrowserWindow({
// https://www.electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do
@@ -462,7 +453,7 @@ app.on("ready", async () => {
icon: global.trayConfig.icon_path,
show: false,
autoHideMenuBar: global.store.get("autoHideMenuBar", true),
autoHideMenuBar: store.get("autoHideMenuBar"),
x: mainWindowState.x,
y: mainWindowState.y,
@@ -476,6 +467,17 @@ app.on("ready", async () => {
webgl: true,
},
});
global.mainWindow.setContentProtection(store.get("enableContentProtection"));
try {
console.debug("Ensuring storage is ready");
if (!(await store.prepareSafeStorage(global.mainWindow.webContents.session))) return;
} catch (e) {
console.error(e);
app.exit(1);
}
void global.mainWindow.loadURL("vector://vector/webapp/");
if (process.platform === "darwin") {
@@ -484,10 +486,10 @@ app.on("ready", async () => {
// Handle spellchecker
// For some reason spellCheckerEnabled isn't persisted, so we have to use the store here
global.mainWindow.webContents.session.setSpellCheckerEnabled(global.store.get("spellCheckerEnabled", true));
global.mainWindow.webContents.session.setSpellCheckerEnabled(store.get("spellCheckerEnabled", true));
// Create trayIcon icon
if (global.store.get("minimizeToTray", true)) tray.create(global.trayConfig);
if (store.get("minimizeToTray")) tray.create(global.trayConfig);
global.mainWindow.once("ready-to-show", () => {
if (!global.mainWindow) return;
@@ -501,7 +503,31 @@ app.on("ready", async () => {
}
});
global.mainWindow.webContents.on("before-input-event", warnBeforeExit);
global.mainWindow.webContents.on("before-input-event", (event: Event, input: Input): void => {
const shouldWarnBeforeExit = store.get("warnBeforeExit", true);
const exitShortcutPressed =
input.type === "keyDown" && exitShortcuts.some((shortcutFn) => shortcutFn(input, process.platform));
if (shouldWarnBeforeExit && exitShortcutPressed && global.mainWindow) {
const shouldCancelCloseRequest =
dialog.showMessageBoxSync(global.mainWindow, {
type: "question",
buttons: [
_t("action|cancel"),
_t("action|close_brand", {
brand: global.vectorConfig.brand || "Element",
}),
],
message: _t("confirm_quit"),
defaultId: 1,
cancelId: 0,
}) === 0;
if (shouldCancelCloseRequest) {
event.preventDefault();
}
}
});
global.mainWindow.on("closed", () => {
global.mainWindow = null;
@@ -539,15 +565,28 @@ app.on("ready", async () => {
webContentsHandler(global.mainWindow.webContents);
global.appLocalization = new AppLocalization({
store: global.store,
components: [(): void => tray.initApplicationMenu(), (): void => Menu.setApplicationMenu(buildMenuTemplate())],
});
session.defaultSession.setDisplayMediaRequestHandler((_, callback) => {
global.mainWindow?.webContents.send("openDesktopCapturerSourcePicker");
setDisplayMediaCallback(callback);
});
session.defaultSession.setDisplayMediaRequestHandler(
(_, callback) => {
if (process.env.XDG_SESSION_TYPE === "wayland") {
// On Wayland, calling getSources() opens the xdg-desktop-portal picker.
// The user can only select a single source there, so Electron will return an array with exactly one entry.
desktopCapturer
.getSources({ types: ["screen", "window"] })
.then((sources) => {
callback({ video: sources[0] });
})
.catch((err) => {
// If the user cancels the dialog an error occurs "Failed to get sources"
console.error("Wayland: failed to get user-selected source:", err);
callback({ video: { id: "", name: "" } }); // The promise does not return if no dummy is passed here as source
});
} else {
global.mainWindow?.webContents.send("openDesktopCapturerSourcePicker");
}
setDisplayMediaCallback(callback);
},
{ useSystemPicker: true },
); // Use Mac OS 15+ native picker
setupMediaAuth(global.mainWindow);
});
@@ -580,8 +619,9 @@ app.on("second-instance", (ev, commandLine, workingDirectory) => {
}
});
// Set the App User Model ID to match what the squirrel
// installer uses for the shortcut icon.
// This makes notifications work on windows 8.1 (and is
// a noop on other platforms).
app.setAppUserModelId("com.squirrel.element-desktop.Element");
// This is required to make notification handlers work
// on Windows 8.1/10/11 (and is a noop on other platforms);
// It must also match the ID found in 'electron-builder'
// in order to get the title and icon to show up correctly.
// Ref: https://stackoverflow.com/a/77314604/3525780
app.setAppUserModelId(buildConfig.appId);

View File

@@ -22,7 +22,9 @@
"about": "O",
"brand_help": "%(brand)s nápověda",
"help": "Nápověda",
"preferences": "Předvolby"
"no": "Ne",
"preferences": "Předvolby",
"yes": "Ano"
},
"confirm_quit": "Opravdu chcete ukončit aplikaci?",
"edit_menu": {
@@ -30,9 +32,22 @@
"speech_start_speaking": "Spustit nahrávání hlasu",
"speech_stop_speaking": "Zastavit nahrávání hlasu"
},
"eol": {
"no_more_updates": "Používáte nepodporovanou verzi systému macOS. Prosím upgradujte %(brand)s pro získání aktualizací.",
"title": "Systém není podporován",
"warning": "Používáte nepodporovanou verzi systému macOS. Proveďte prosím upgrade %(brand)s , aby byl stále funkční."
},
"file_menu": {
"label": "Soubor"
},
"icon_overlay": {
"description_error": "Chyba",
"description_notifications": {
"one": "Máte %(count)s nepřečtené oznámení.",
"few": "Máte %(count)s nepřečtená oznámení.",
"other": "Máte %(count)s nepřečtených oznámení."
}
},
"menu": {
"hide": "Skrýt",
"hide_others": "Skrýt ostatní",
@@ -49,6 +64,21 @@
"save_image_as_error_description": "Obrázek se nepodařilo uložit",
"save_image_as_error_title": "Chyba při ukládání obrázku"
},
"store": {
"error": {
"backend_changed": "Vymazat data a znovu načíst?",
"backend_changed_detail": "Nelze získat přístup k tajnému klíči ze systémové klíčenky, zdá se, že se změnil.",
"backend_changed_title": "Nepodařilo se načíst databázi",
"backend_no_encryption": "Váš systém má podporovanou klíčenku, ale šifrování není k dispozici.",
"backend_no_encryption_detail": "Electron zjistil, že pro vaši klíčenku %(backend)s není k dispozici šifrování. Ujistěte se, že máte nainstalovanou klíčenku. Pokud ji máte, restartujte počítač a zkuste to znovu. Volitelně můžete povolit %(brand)s použít slabší formu šifrování.",
"backend_no_encryption_title": "Bez podpory šifrování",
"unsupported_keyring": "Váš systém má nepodporovanou klíčenku, což znamená, že databázi nelze otevřít.",
"unsupported_keyring_detail": "Detekce klíčenky Electronu nenalezla podporovaný backend. Můžete se pokusit ručně nakonfigurovat backend spuštěním %(brand)s s argumentem příkazového řádku, jednorázovou operací. Viz %(link)s.",
"unsupported_keyring_title": "Systém není podporován",
"unsupported_keyring_use_basic_text": "Používat slabší šifrování",
"unsupported_keyring_use_plaintext": "Nepoužívat žádné šifrování"
}
},
"view_menu": {
"actual_size": "Aktuální velikost",
"toggle_developer_tools": "Přepnout zobrazení nástrojů pro vývojáře",

93
src/i18n/strings/cy.json Normal file
View File

@@ -0,0 +1,93 @@
{
"action": {
"cancel": "Diddymu",
"close": "Cau",
"close_brand": "Cau %(brand)s",
"copy": "Copïo",
"cut": "Torri",
"delete": "Dileu",
"edit": "Golygu",
"minimise": "Lleihau",
"paste": "Gludo",
"paste_match_style": "Arddull Gludo a Chyfateb",
"quit": "Gadael",
"redo": "Ail-wneud",
"select_all": "Dewis y Cyfan",
"show_hide": "Dangos/Cuddio",
"undo": "Dadwneud",
"zoom_in": "Chwyddo i Mewn",
"zoom_out": "Chwyddo Allan"
},
"common": {
"about": "Ynghylch",
"brand_help": "Cymorth %(brand)s",
"help": "Cymorth",
"no": "Na",
"preferences": "Dewisiadau",
"yes": "Iawn"
},
"confirm_quit": "Ydych chi'n siŵr eich bod am roi'r gorau iddi?",
"edit_menu": {
"speech": "Lleferydd",
"speech_start_speaking": "Cychwyn Llefaru",
"speech_stop_speaking": "Peidio Llefaru"
},
"eol": {
"no_more_updates": "Rydych chi'n rhedeg fersiwn o macOS nad yw'n cael ei chefnogi. Uwchraddiwch i dderbyn diweddariadau %(brand)s.",
"title": "System heb ei chefnogi",
"warning": "Rydych chi'n rhedeg fersiwn o macOS nad yw'n cael ei chefnogi. Uwchraddiwch i sicrhau bod %(brand)s yn parhau i weithio."
},
"file_menu": {
"label": "Ffeil"
},
"icon_overlay": {
"description_error": "Gwall",
"description_notifications": {
"Mae gennych chi %(count)s hysbysiadau heb eu darllen.": "zero",
"Mae gennych chi %(count)s hysbysiad heb ei ddarllen.": "one",
"Mae gennych chi %(count)s hysbysiad heb eu darllen.": "other"
}
},
"menu": {
"hide": "Cuddio",
"hide_others": "Cuddio'r Gweddill",
"services": "Gwasanaethau",
"unhide": "Datguddio"
},
"right_click_menu": {
"add_to_dictionary": "Ychwanegu at y geiriadur",
"copy_email": "Copïo cyfeiriad e-bost",
"copy_image": "Copïo delwedd",
"copy_image_url": "Copïo cyfeiriad delwedd",
"copy_link_url": "Copïo cyfeiriad y ddolen",
"save_image_as": "Cadw delwedd fel...",
"save_image_as_error_description": "Methodd cadw'r ddelwedd",
"save_image_as_error_title": "Methodd cadw'r ddelwedd"
},
"store": {
"error": {
"backend_changed": "Clirio data ac ail-lwytho?",
"backend_changed_detail": "Methu cael mynediad at y gyfrinach o allweddi'r system, mae'n ymddangos ei fod wedi newid.",
"backend_changed_title": "Methwyd llwytho'r gronfa ddata",
"backend_no_encryption": "Mae gan eich system cylch allwedd sy'n cael ei gefnogi ond nid yw amgryptio ar gael.",
"backend_no_encryption_detail": "Mae Electron wedi canfod nad yw amgryptio ar gael ar eich cylch allweddi %(backend)s. Gwnewch yn siŵr bod y cylch allweddi wedi'i osod. Os oes y cylch allweddi wedi'i osod, ail gychwynnwch a cheisiwch eto. Yn ddewisol, gallwch ganiatáu i %(brand)s ddefnyddio ffurf wannach o amgryptio.",
"backend_no_encryption_title": "Dim cefnogaeth amgryptio",
"unsupported_keyring": "Mae gan eich system allweddell nad yw'n cael ei chefnogi sy'n golygu nad oes modd agor y gronfa ddata.",
"unsupported_keyring_detail": "Heb ganfod allweddell Electron gefn. Gallwch geisio ffurfweddu'r gefn â llaw trwy gychwyn %(brand)s gyda dadl llinell orchymyn, gweithrediad untro. Gweler %(link)s.",
"unsupported_keyring_title": "System heb ei chefnogi",
"unsupported_keyring_use_basic_text": "Defnyddiwch amgryptio gwannach",
"unsupported_keyring_use_plaintext": "Peidiwch â defnyddio amgryptio"
}
},
"view_menu": {
"actual_size": "Maint Gwirioneddol",
"toggle_developer_tools": "Toglo Offer Datblygwyr",
"toggle_full_screen": "Toglo Sgrin Lawn",
"view": "Golwg"
},
"window_menu": {
"bring_all_to_front": "Popeth i'r Blaen",
"label": "Ffenestr",
"zoom": "Chwyddo"
}
}

View File

@@ -22,7 +22,9 @@
"about": "Über",
"brand_help": "%(brand)s Hilfe",
"help": "Hilfe",
"preferences": "Präferenzen"
"no": "Nein",
"preferences": "Präferenzen",
"yes": "Ja"
},
"confirm_quit": "Wirklich beenden?",
"edit_menu": {
@@ -30,9 +32,21 @@
"speech_start_speaking": "Aufnahme starten",
"speech_stop_speaking": "Aufnahme beenden"
},
"eol": {
"no_more_updates": "Du benutzt eine nicht unterstützte Version von macOS. Bitte aktualisiere, um Updates für %(brand)s zu erhalten.",
"title": "System nicht unterstützt",
"warning": "Du benutzt eine nicht unterstützte Version von macOS. Bitte aktualisiere, damit %(brand)s weiter funktioniert."
},
"file_menu": {
"label": "Datei"
},
"icon_overlay": {
"description_error": "Fehler",
"description_notifications": {
"one": "Du hast %(count)s ungelesene Benachrichtigung.",
"other": "Du hast %(count)s ungelesene Benachrichtigungen."
}
},
"menu": {
"hide": "Verstecken",
"hide_others": "Andere verstecken",
@@ -49,6 +63,21 @@
"save_image_as_error_description": "Das Bild konnte nicht gespeichert werden",
"save_image_as_error_title": "Bild kann nicht gespeichert werden"
},
"store": {
"error": {
"backend_changed": "Daten löschen und neu laden?",
"backend_changed_detail": "Zugriff auf Schlüssel im Systemschlüsselbund nicht möglich, er scheint sich geändert zu haben.",
"backend_changed_title": "Datenbank konnte nicht geladen werden",
"backend_no_encryption": "Ihr System verfügt über einen unterstützten Keyring, aber die Verschlüsselung ist nicht verfügbar.",
"backend_no_encryption_detail": "Electron hat festgestellt, dass der Keyring von %(backend)s keine Verschlüsselung bietet. Wenn du den Keyring installiert hast, starte den Rechner bitte neu und versuche es erneut. Optional kann %(brand)s auch eine abgeschwächte Verschlüsselung nutzen.",
"backend_no_encryption_title": "Keine Verschlüsselungsunterstützung",
"unsupported_keyring": "Der Keyring des Systems wird nicht unterstützt. Daher kann die Datenbank nicht geöffnet werden kann.",
"unsupported_keyring_detail": "Die Keyring-Erkennung von Electron hat kein unterstütztes Backend gefunden. Du kannst einmalig versuchen, eine manuelle Konfiguration von %(brand)s über die Kommandozeile vorzunehmen. Infos unter %(link)s.",
"unsupported_keyring_title": "System nicht unterstützt",
"unsupported_keyring_use_basic_text": "Schwächere Verschlüsselung verwenden",
"unsupported_keyring_use_plaintext": "Verwende keine Verschlüsselung"
}
},
"view_menu": {
"actual_size": "Tatsächliche Größe",
"toggle_developer_tools": "Developer-Tools an/aus",

View File

@@ -22,7 +22,9 @@
"about": "About",
"brand_help": "%(brand)s Help",
"help": "Help",
"preferences": "Preferences"
"no": "No",
"preferences": "Preferences",
"yes": "Yes"
},
"confirm_quit": "Are you sure you want to quit?",
"edit_menu": {
@@ -30,9 +32,21 @@
"speech_start_speaking": "Start Speaking",
"speech_stop_speaking": "Stop Speaking"
},
"eol": {
"no_more_updates": "You are running an unsupported version of macOS. Please upgrade to receive %(brand)s updates.",
"title": "System unsupported",
"warning": "You are running an unsupported version of macOS. Please upgrade to ensure %(brand)s keeps working."
},
"file_menu": {
"label": "File"
},
"icon_overlay": {
"description_error": "Error",
"description_notifications": {
"one": "You have %(count)s unread notification.",
"other": "You have %(count)s unread notifications."
}
},
"menu": {
"hide": "Hide",
"hide_others": "Hide Others",
@@ -49,6 +63,21 @@
"save_image_as_error_description": "The image failed to save",
"save_image_as_error_title": "Failed to save image"
},
"store": {
"error": {
"backend_changed": "Clear data and reload?",
"backend_changed_detail": "Unable to access secret from system keyring, it appears to have changed.",
"backend_changed_title": "Failed to load database",
"backend_no_encryption": "Your system has a supported keyring but encryption is not available.",
"backend_no_encryption_detail": "Electron has detected that encryption is not available on your keyring %(backend)s. Please ensure that you have the keyring installed. If you do have the keyring installed, please reboot and try again. Optionally, you can allow %(brand)s to use a weaker form of encryption.",
"backend_no_encryption_title": "No encryption support",
"unsupported_keyring": "Your system has an unsupported keyring meaning the database cannot be opened.",
"unsupported_keyring_detail": "Electron's keyring detection did not find a supported backend. You can attempt to manually configure the backend by starting %(brand)s with a command-line argument, a one-time operation. See %(link)s.",
"unsupported_keyring_title": "System unsupported",
"unsupported_keyring_use_basic_text": "Use weaker encryption",
"unsupported_keyring_use_plaintext": "Use no encryption"
}
},
"view_menu": {
"actual_size": "Actual Size",
"toggle_developer_tools": "Toggle Developer Tools",

View File

@@ -22,7 +22,9 @@
"about": "Rakenduse teave",
"brand_help": "%(brand)s abiteave",
"help": "Abiteave",
"preferences": "Eelistused"
"no": "Ei",
"preferences": "Eelistused",
"yes": "Jah"
},
"confirm_quit": "Kas sa kindlasti soovid rakendusest väljuda?",
"edit_menu": {
@@ -30,9 +32,21 @@
"speech_start_speaking": "Alusta rääkimist",
"speech_stop_speaking": "Lõpeta rääkimine"
},
"eol": {
"no_more_updates": "Sa kasutad macOS-i toetamata versiooni. %(brand)s rakenduse tulevaste versioonide kasutamiseks palun uuenda operatsioonisüsteemi.",
"title": "Süsteem pole toetatud",
"warning": "Sa kasutad macOS-i toetamata versiooni. Et %(brand)s toimiks ka edaspidi, palun uuenda operatsioonisüsteemi."
},
"file_menu": {
"label": "Fail"
},
"icon_overlay": {
"description_error": "Viga",
"description_notifications": {
"one": "Sul on %(count)s lugemata teavitus",
"other": "Sul on %(count)s lugemata teavitust"
}
},
"menu": {
"hide": "Peida",
"hide_others": "Peida muud",
@@ -49,6 +63,21 @@
"save_image_as_error_description": "Seda pilti ei õnnestunud salvestada",
"save_image_as_error_title": "Pildi salvestamine ei õnnestunud"
},
"store": {
"error": {
"backend_changed": "Kas kustutame andmed ja laadime uuesti?",
"backend_changed_detail": "Süsteemsest võtmerõngast ei õnnestu laadida vajalikku saladust, tundub et ta on muutunud.",
"backend_changed_title": "Andmebaasi ei õnnestunud laadida",
"backend_no_encryption": "Sinu süsteem kasutab toetatud võtmerõngast, kuid krüptimist pole saadaval.",
"backend_no_encryption_detail": "Electron on tuvastanud, et krüptimine pole sinu %(backend)s võtmerõnga jaoks saadaval. Palun kontrolli, et võtmerõngas oleks korrektselt paigaldatud. Kui sul on võtmerõngas paigaldatud, siis palun taaskäivita ta ja proovi uuesti. Lisavõimalusena saad lubada, et %(brand)s kasutab nõrgemat krüptimislahendust.",
"backend_no_encryption_title": "Krüptimise tugi puudub",
"unsupported_keyring": "Sinu süsteemis on kasutusel mittetoetatud võtmerõnga versioon ning see tähendab, et andmebaasi ei saa avada.",
"unsupported_keyring_detail": "Electroni võtmerõnga tuvastamine ei leidnud toetatud taustateenust. Kui käivitad rakenduse %(brand)s käsurealt õigete argumentidega, siis võib taustateenuse käsitsi seadistamine õnnestuda ning seda tegevust peaksid vaid üks kord tegema. Lisateave: %(link)s.",
"unsupported_keyring_title": "Süsteem pole toetatud",
"unsupported_keyring_use_basic_text": "Kasuta nõrgemat krüptimist",
"unsupported_keyring_use_plaintext": "Ära üldse kasuta krüptimist"
}
},
"view_menu": {
"actual_size": "Näita tavasuuruses",
"toggle_developer_tools": "Arendaja töövahendid sisse/välja",

View File

@@ -22,7 +22,9 @@
"about": "Tietoa",
"brand_help": "%(brand)s-tuki",
"help": "Ohje",
"preferences": "Valinnat"
"no": "Ei",
"preferences": "Valinnat",
"yes": "Kyllä"
},
"confirm_quit": "Haluatko varmasti poistua?",
"edit_menu": {
@@ -49,6 +51,12 @@
"save_image_as_error_description": "Kuvan tallennus epäonnistui",
"save_image_as_error_title": "Kuvan tallennus epäonnistui"
},
"store": {
"error": {
"backend_changed_title": "Tietokannan lataaminen epäonnistui",
"unsupported_keyring_title": "Järjestelmä ei ole tuettu"
}
},
"view_menu": {
"actual_size": "Alkuperäinen koko",
"toggle_developer_tools": "Näytä tai piilota kehittäjätyökalut",

View File

@@ -22,7 +22,9 @@
"about": "À propos",
"brand_help": "Aide de %(brand)s",
"help": "Aide",
"preferences": "Préférences"
"no": "Non",
"preferences": "Préférences",
"yes": "Oui"
},
"confirm_quit": "Êtes-vous sûr de vouloir quitter ?",
"edit_menu": {
@@ -30,9 +32,21 @@
"speech_start_speaking": "Commencer la dictée",
"speech_stop_speaking": "Arrêter la dictée"
},
"eol": {
"no_more_updates": "Vous utilisez une version de macOS non prise en charge. Veuillez mettre à jour macOS pour recevoir les mises à jour de %(brand)s.",
"title": "Système non pris en charge",
"warning": "Vous utilisez une version de macOS non prise en charge. Veuillez mettre à jour macOS afin que %(brand)s continue de fonctionner."
},
"file_menu": {
"label": "Fichier"
},
"icon_overlay": {
"description_error": "Erreur",
"description_notifications": {
"one": "Vous avez %(count)s notification non lue.",
"other": "Vous avez %(count)s notifications non lues."
}
},
"menu": {
"hide": "Masquer",
"hide_others": "Masquer les autres",
@@ -46,9 +60,24 @@
"copy_image_url": "Copier l'adresse de l'image",
"copy_link_url": "Copier ladresse du lien",
"save_image_as": "Enregistrer limage sous…",
"save_image_as_error_description": "Limage na pas pu être sauvegardée",
"save_image_as_error_description": "Limage na pas pu être enregistrée",
"save_image_as_error_title": "Échec de la sauvegarde de limage"
},
"store": {
"error": {
"backend_changed": "Effacer les données et recharger ?",
"backend_changed_detail": "Impossible d'accéder aux secrets depuis le trousseau de clés du système, il semble avoir changé.",
"backend_changed_title": "Impossible de charger la base de données",
"backend_no_encryption": "Votre système dispose d'un trousseau de clés compatible mais le chiffrement est indisponible.",
"backend_no_encryption_detail": "Electron a détecté que le chiffrement n'est pas disponible pour le trousseau %(backend)s. Veuillez vérifier que votre trousseau est installé. Si c'est le cas, redémarrez et réessayez. Comme alternative, vous pouvez autoriser %(brand)s à utiliser une option de chiffrement moins sécurisée.",
"backend_no_encryption_title": "Aucune prise en charge du chiffrement",
"unsupported_keyring": "Votre système possède un trousseau de clés non pris en charge, la base de données ne peut pas être ouverte.",
"unsupported_keyring_detail": "La détection du porte-clés par Electron n'a pas permis de trouver de backend compatible. Vous pouvez essayer de configurer manuellement le backend en utilisant %(brand)s avec un argument de ligne de commande. Cette opération doit être effectuer une seule fois. Voir%(link)s.",
"unsupported_keyring_title": "Système non pris en charge",
"unsupported_keyring_use_basic_text": "Utiliser un chiffrement plus faible",
"unsupported_keyring_use_plaintext": "N'utilise pas de chiffrement"
}
},
"view_menu": {
"actual_size": "Taille réelle",
"toggle_developer_tools": "Basculer les outils de développement",

View File

@@ -2,7 +2,7 @@
"action": {
"cancel": "Mégse",
"close": "Bezárás",
"close_brand": "%(brand)s bezárása",
"close_brand": "Az %(brand)s bezárása",
"copy": "Másolás",
"cut": "Kivágás",
"delete": "Törlés",
@@ -22,7 +22,9 @@
"about": "Névjegy",
"brand_help": "%(brand)s Súgó",
"help": "Súgó",
"preferences": "Beállítások"
"no": "Nem",
"preferences": "Beállítások",
"yes": "Igen"
},
"confirm_quit": "Biztos, hogy kilép?",
"edit_menu": {
@@ -30,9 +32,21 @@
"speech_start_speaking": "Kezdjen beszélni",
"speech_stop_speaking": "Fejezze be a beszédet"
},
"eol": {
"no_more_updates": "A macOS egy nem támogatott verzióját futtatja. Frissítse, hogy megkapja az %(brand)s új frissítéseit.",
"title": "A rendszer nem támogatott",
"warning": "A macOS egy nem támogatott verzióját futtatja. Frissítse a rendszert, hogy biztosítsa az %(brand)s további működését."
},
"file_menu": {
"label": "Fájl"
},
"icon_overlay": {
"description_error": "Hiba",
"description_notifications": {
"one": "%(count)s olvasatlan értesítése van.",
"other": "%(count)s olvasatlan értesítése van."
}
},
"menu": {
"hide": "Elrejtés",
"hide_others": "Mások elrejtése",
@@ -49,6 +63,21 @@
"save_image_as_error_description": "A kép mentése sikertelen",
"save_image_as_error_title": "Kép mentése sikertelen"
},
"store": {
"error": {
"backend_changed": "Adatok törlése és újratöltés?",
"backend_changed_detail": "Nem sikerült hozzáférni a rendszerkulcstartó titkos kódjához, úgy tűnik, megváltozott.",
"backend_changed_title": "Nem sikerült betölteni az adatbázist",
"backend_no_encryption": "A rendszer támogatott kulcstartóval rendelkezik, de a titkosítás nem érhető el.",
"backend_no_encryption_detail": "Az Electron észlelte, hogy a titkosítás nem érhető el a(z) %(backend)s kulcstartóján. Győződjön meg róla, hogy telepítve van-e a kulcstartó. Ha telepítve van, indítsa újra és próbálja újra. Esetleg engedélyezheti a gyengébb titkosítást az %(brand)s számára.",
"backend_no_encryption_title": "Nincs titkosítási támogatás",
"unsupported_keyring": "A rendszer nem támogatott kulcstartóval rendelkezik, ami azt jelenti, hogy az adatbázis nem nyitható meg.",
"unsupported_keyring_detail": "Az Electron kulcstartóészlelése nem talált támogatott háttérrendszert. Megpróbálhatja kézileg beállítani a háttérrendszert az %(brand)s egyszeri, parancssori argumentummal való indításával. Lásd: %(link)s.",
"unsupported_keyring_title": "A rendszer nem támogatott",
"unsupported_keyring_use_basic_text": "Gyengébb titkosítás használata",
"unsupported_keyring_use_plaintext": "Ne használjon titkosítást"
}
},
"view_menu": {
"actual_size": "Jelenlegi méret",
"toggle_developer_tools": "Fejlesztői eszközök",
@@ -56,7 +85,7 @@
"view": "Megtekintés"
},
"window_menu": {
"bring_all_to_front": "Mindent előtérbe hoz",
"bring_all_to_front": "Minden előtérbe hozása",
"label": "Ablak",
"zoom": "Nagyítás"
}

87
src/i18n/strings/hy.json Normal file
View File

@@ -0,0 +1,87 @@
{
"action": {
"cancel": "Չեղարկել",
"close": "Փակել",
"close_brand": "Փակել %(brand)s",
"copy": "Պատճենել",
"cut": "Կտրել",
"delete": "Ջնջել",
"edit": "Խմբագրել",
"minimise": "Նվազագույնի հասցնել",
"paste": "Տեղադրել",
"paste_match_style": "Տեղադրել և համապատասխանեցնել ոճը",
"quit": "Դուրս գալ",
"redo": "Կրկնել",
"select_all": "Ընտրել բոլորը",
"show_hide": "Ցուցադրել/Թաքցնել",
"undo": "Հետարկել",
"zoom_in": "Մեծացնել",
"zoom_out": "Փոքրացնել"
},
"common": {
"about": "Կենսագրություն",
"brand_help": "%(brand)s Օգնություն",
"help": "Օգնություն",
"no": "Ոչ",
"preferences": "Նախապատվություններ",
"yes": "Այո"
},
"confirm_quit": "Վստա՞հ եք, որ ուզում եք դուրս գալ։",
"edit_menu": {
"speech": "Խոսք/Ելույթ",
"speech_start_speaking": "Սկսեք խոսել",
"speech_stop_speaking": "Դադարեցրեք խոսելը"
},
"file_menu": {
"label": "Ֆայլ"
},
"icon_overlay": {
"description_error": "Սխալ",
"description_notifications": {
"one": "Դուք ունեք %(count)s չկարդացված ծանուցում։",
"other": "Դուք ունեք %(count)s չկարդացված ծանուցումներ։"
}
},
"menu": {
"hide": "Թաքցնել",
"hide_others": "Թաքցնել մյուսները",
"services": "Ծառայություններ",
"unhide": "Ապաթաքցնել"
},
"right_click_menu": {
"add_to_dictionary": "Ավելացնել բառարանում",
"copy_email": "Պատճենել էլ․ հասցեն",
"copy_image": "Պատճենել պատկերը",
"copy_image_url": "Պատճենել պատկերի հասցեն",
"copy_link_url": "Պատճենել հղման հասցեն",
"save_image_as": "Պահպանել պատկերը որպես...",
"save_image_as_error_description": "Պատկերը չհաջողվեց պահպանել",
"save_image_as_error_title": "Չհաջողվեց պահպանել պատկերը"
},
"store": {
"error": {
"backend_changed": "Մաքրե՞լ տվյալները և վերաբեռնե՞լ",
"backend_changed_detail": "Գաղտնի տվյալները հասանելի չեն համակարգի բանալիների պահոցից(keyring), կարծես թե այն փոխվել է։",
"backend_changed_title": "Չհաջողվեց բեռնել տվյալների բազան",
"backend_no_encryption": "Ձեր համակարգը ունի աջակցվող բանալիների պահոց, բայց գաղտնագրումը հասանելի չէ։",
"backend_no_encryption_detail": "Electron-ը հայտնաբերել է, որ ձեր բանալիների պահոցում %(backend)s գաղտնագրումը հասանելի չէ։ Խնդրում ենք համոզվել, որ բանալիների պահոցը տեղադրված է։ Եթե այն արդեն տեղադրված է, վերագործարկեք համակարգը և փորձեք կրկին։ Ցանկության դեպքում կարող եք թույլատրել %(brand)s-ին կիրառել ավելի թույլ գաղտնագրման տարբերակ։",
"backend_no_encryption_title": "Գաղտնագրման աջակցություն չկա",
"unsupported_keyring": "Համակարգում օգտագործվող բանալիների պահոցը(keyring) չի աջակցվում, ինչը նշանակում է, որ տվյալների բազան հնարավոր չէ բացել։",
"unsupported_keyring_detail": "Electron-ի բանալիների պահոցի ստուգումը չգտավ համատեղելի backend։ Կարող եք փորձել ձեռքով կարգավորել backend-ը` մեկնարկելով %(brand)s-ը command-line արգումենտով, մեկանգամյա գործողությամբ։ Տես %(link)s։",
"unsupported_keyring_title": "Համակարգը չի աջակցվում",
"unsupported_keyring_use_basic_text": "Օգտագործել ավելի թույլ գաղտնագրում",
"unsupported_keyring_use_plaintext": "Չօգտագործել գաղտնագրում"
}
},
"view_menu": {
"actual_size": "Իրական չափս",
"toggle_developer_tools": "Միացնել/անջատել ծրագրավորողի գործիքները",
"toggle_full_screen": "Միացնել/անջատել ամբողջական էկրանը",
"view": "Դիտել"
},
"window_menu": {
"bring_all_to_front": "Բերեք բոլորին առջևի պլան",
"label": "Պատուհան",
"zoom": "Մեծացնել"
}
}

View File

@@ -22,7 +22,9 @@
"about": "Tentang",
"brand_help": "Bantuan %(brand)s",
"help": "Bantuan",
"preferences": "Preferensi"
"no": "Tidak",
"preferences": "Preferensi",
"yes": "Ya"
},
"confirm_quit": "Apakah Anda yakin ingin keluar?",
"edit_menu": {
@@ -30,9 +32,20 @@
"speech_start_speaking": "Mulai Berbicara",
"speech_stop_speaking": "Berhenti Berbicara"
},
"eol": {
"no_more_updates": "Anda menggunakan versi macOS yang tidak didukung. Harap tingkatkan untuk menerima pembaruan %(brand)s.",
"title": "Sistem tidak didukung",
"warning": "Anda menggunakan versi macOS yang tidak didukung. Harap perbarui untuk memastikan%(brand)s terus bekerja."
},
"file_menu": {
"label": "Berkas"
},
"icon_overlay": {
"description_error": "Kesalahan",
"description_notifications": {
"other": "Anda memiliki %(count)s notifikasi yang belum dibaca."
}
},
"menu": {
"hide": "Sembunyikan",
"hide_others": "Sembunyikan yang Lain",
@@ -49,6 +62,21 @@
"save_image_as_error_description": "Gambar gagal disimpan",
"save_image_as_error_title": "Gagal menyimpan gambar"
},
"store": {
"error": {
"backend_changed": "Hapus data dan muat ulang?",
"backend_changed_detail": "Tidak dapat mengakses rahasia dari keyring sistem, tampaknya telah berubah.",
"backend_changed_title": "Gagal memuat basis data",
"backend_no_encryption": "Sistem Anda memiliki keyring yang didukung tetapi enkripsi tidak tersedia.",
"backend_no_encryption_detail": "Electron telah mendeteksi bahwa enkripsi tidak tersedia pada keyring %(backend)s Anda. Harap pastikan bahwa Anda telah memasang keyring. Jika Anda telah memasang keyring, silakan mulai ulang dan coba lagi. Secara opsional, Anda dapat mengizinkan %(brand)s untuk menggunakan bentuk enkripsi yang lebih lemah.",
"backend_no_encryption_title": "Tidak ada dukungan enkripsi",
"unsupported_keyring": "Sistem Anda memiliki keyring yang tidak didukung yang berarti basis data tidak dapat dibuka.",
"unsupported_keyring_detail": "Deteksi keyring Electron tidak menemukan backend yang didukung. Anda dapat mencoba mengonfigurasi backend secara manual dengan memulai %(brand)s dengan argumen baris perintah, operasi satu kali. Lihat %(link)s.",
"unsupported_keyring_title": "Sistem tidak didukung",
"unsupported_keyring_use_basic_text": "Gunakan enkripsi yang lebih lemah",
"unsupported_keyring_use_plaintext": "Jangan gunakan enkripsi"
}
},
"view_menu": {
"actual_size": "Ukuran Sebenarnya",
"toggle_developer_tools": "Beralih Alat Pengembang",

63
src/i18n/strings/ka.json Normal file
View File

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

63
src/i18n/strings/lv.json Normal file
View File

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

View File

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

View File

@@ -0,0 +1,92 @@
{
"action": {
"cancel": "Avbryt",
"close": "Lukk",
"close_brand": "Avslutt %(brand)s",
"copy": "Kopier",
"cut": "Klipp",
"delete": "Slett",
"edit": "Rediger",
"minimise": "Minimere",
"paste": "Lim inn",
"paste_match_style": "Lim inn og match stil",
"quit": "Avslutt",
"redo": "Gjør om",
"select_all": "Velg alle",
"show_hide": "Vis/Skjul",
"undo": "Angre",
"zoom_in": "Zoom inn",
"zoom_out": "Zoom ut"
},
"common": {
"about": "Om",
"brand_help": "%(brand)s Hjelp",
"help": "Hjelp",
"no": "Nei",
"preferences": "Innstillinger",
"yes": "Ja"
},
"confirm_quit": "Er du sikker på at du vil slutte?",
"edit_menu": {
"speech": "Tale",
"speech_start_speaking": "Begynn å snakke",
"speech_stop_speaking": "Slutt å snakke"
},
"eol": {
"no_more_updates": "Du kjører en versjon av macOS som ikke støttes. Oppgrader for å motta oppdateringer fr %(brand)s.",
"title": "Systemet støttes ikke",
"warning": "Du bruker en versjon av macOS som ikke støttes. Oppgrader for å sikre at %(brand)s fortsetter å fungere."
},
"file_menu": {
"label": "Fil"
},
"icon_overlay": {
"description_error": "Feil",
"description_notifications": {
"one": "Du har %(count)s ulest varsel.",
"other": "Du har %(count)s uleste varsler."
}
},
"menu": {
"hide": "Skjul",
"hide_others": "Skjul andre",
"services": "Tjenester",
"unhide": "Slutt å skjule"
},
"right_click_menu": {
"add_to_dictionary": "Legg til i ordbok",
"copy_email": "Kopier e-postadressen",
"copy_image": "Kopier bildet",
"copy_image_url": "Kopier bildeadresse",
"copy_link_url": "Kopier link adresse",
"save_image_as": "Lagre bildet som...",
"save_image_as_error_description": "Bildet kunne ikke lagres",
"save_image_as_error_title": "Kunne ikke lagre bildet"
},
"store": {
"error": {
"backend_changed": "Tøm data og last inn på nytt?",
"backend_changed_detail": "Kan ikke få tilgang til hemmeligheten fra systemnøkkelringen, den ser ut til å ha blitt endret.",
"backend_changed_title": "Kunne ikke laste inn databasen",
"backend_no_encryption": "Systemet ditt har en støttet nøkkelring, men kryptering er ikke tilgjengelig.",
"backend_no_encryption_detail": "Electron har oppdaget at kryptering ikke er tilgjengelig på nøkkelringen %(backend)s din. Forsikre deg om at du har nøkkelringen installert. Hvis du har nøkkelringen installert, vennligst start på nytt og prøv igjen. Eventuelt kan du tillate %(brand)s å bruke en svakere form for kryptering.",
"backend_no_encryption_title": "Ingen støtte for kryptering",
"unsupported_keyring": "Systemet ditt har en nøkkelring som ikke støttes, noe som betyr at databasen ikke kan åpnes.",
"unsupported_keyring_detail": "Electrons nøkkelringdeteksjon fant ikke en støttet backend. Du kan prøve å konfigurere backend manuelt ved å starte %(brand)s med et kommandolinjeargument, en engangsoperasjon. Se%(link)s.",
"unsupported_keyring_title": "Systemet støttes ikke",
"unsupported_keyring_use_basic_text": "Bruk svakere kryptering",
"unsupported_keyring_use_plaintext": "Ikke bruk kryptering"
}
},
"view_menu": {
"actual_size": "Faktisk størrelse",
"toggle_developer_tools": "Veksle Utvikleralternativer",
"toggle_full_screen": "Veksle Fullskjerm",
"view": "Vis"
},
"window_menu": {
"bring_all_to_front": "Flytt Alt Frem",
"label": "Vindu",
"zoom": "Forstørr"
}
}

View File

@@ -22,7 +22,9 @@
"about": "Informacje",
"brand_help": "Pomoc %(brand)s",
"help": "Pomoc",
"preferences": "Preferencje"
"no": "Nie",
"preferences": "Preferencje",
"yes": "Tak"
},
"confirm_quit": "Czy na pewno chcesz zamknąć?",
"edit_menu": {
@@ -30,9 +32,22 @@
"speech_start_speaking": "Zacznij mówić",
"speech_stop_speaking": "Przestań mówić"
},
"eol": {
"no_more_updates": "Korzystasz z nieobsługiwanej wersji systemu macOS. Zaktualizuj system, aby uzyskać aktualizacje %(brand)s.",
"title": "System nie jest obsługiwany",
"warning": "Korzystasz z nieobsługiwanej wersji systemu macOS. Zaktualizuj system, aby dalej korzystać z %(brand)s."
},
"file_menu": {
"label": "Plik"
},
"icon_overlay": {
"description_error": "Błąd",
"description_notifications": {
"one": "Masz %(count)s nieprzeczytane powiadomienie.",
"few": "Masz %(count)s nieprzeczytane powiadomienia.",
"many": "Masz %(count)s nieprzeczytanych powiadomień."
}
},
"menu": {
"hide": "Ukryj",
"hide_others": "Ukryj inne",
@@ -49,6 +64,21 @@
"save_image_as_error_description": "Obraz nie został zapisany",
"save_image_as_error_title": "Nie udało się zapisać obrazu"
},
"store": {
"error": {
"backend_changed": "Wyczyścić dane i przeładować?",
"backend_changed_detail": "Nie można uzyskać dostępu do sekretnego magazynu, wygląda na to, że uległ zmianie.",
"backend_changed_title": "Nie udało się załadować bazy danych",
"backend_no_encryption": "Twój system posiada wspierany keyring, ale szyfrowanie nie jest dostępne.",
"backend_no_encryption_detail": "Elektron wykrył, że szyfrowanie nie jest dostępne w twoim keyring'u %(backend)s. Upewnij się, że keyring został zainstalowany. Jeśli tak, uruchom ponownie urządzenie i spróbuj ponownie. Opcjonalnie, zezwól %(brand)s, aby korzystał ze słabszego szyfrowania.",
"backend_no_encryption_title": "Szyfrowanie nie jest obsługiwane",
"unsupported_keyring": "System zawiera niewspierany keyring, nie można otworzyć bazy danych.",
"unsupported_keyring_detail": "Wykrywanie keyringu Electron nie znalazł wspieranego backendu. Możesz spróbować ręcznie ustawić backed, uruchamiając %(brand)s za pomocą wiesza poleceń. Zobacz %(link)s.",
"unsupported_keyring_title": "System niewspierany",
"unsupported_keyring_use_basic_text": "Użyj słabszego szyfrowania",
"unsupported_keyring_use_plaintext": "Nie używaj szyfrowania"
}
},
"view_menu": {
"actual_size": "Rozmiar rzeczywisty",
"toggle_developer_tools": "Przełącz narzędzia deweloperskie",

View File

@@ -20,8 +20,11 @@
},
"common": {
"about": "Sobre",
"brand_help": "%(brand)s Ajuda",
"help": "Ajuda",
"preferences": "Preferências"
"no": "Não",
"preferences": "Preferências",
"yes": "Sim"
},
"confirm_quit": "Você tem certeza que você quer sair?",
"edit_menu": {
@@ -29,9 +32,21 @@
"speech_start_speaking": "Começar a Falar",
"speech_stop_speaking": "Parar de Falar"
},
"eol": {
"no_more_updates": "Você está usando uma versão não suportada do macOS. Atualize para receber as atualizações d %(brand)s.",
"title": "Sistema não suportado",
"warning": "Você está usando uma versão não compatível do macOS. Faça a atualização para garantir que o %(brand)s continue funcionando."
},
"file_menu": {
"label": "Arquivo"
},
"icon_overlay": {
"description_error": "Erro",
"description_notifications": {
"one": "Você tem %(count)s notificação não lida.",
"other": "Você tem %(count)s notificações não lidas."
}
},
"menu": {
"hide": "Esconder",
"hide_others": "Esconder Outras(os)",
@@ -48,6 +63,21 @@
"save_image_as_error_description": "A imagem falhou para salvar",
"save_image_as_error_title": "Falha para salvar imagem"
},
"store": {
"error": {
"backend_changed": "Limpar dados e recarregar?",
"backend_changed_detail": "Não foi possível acessar o segredo no cofre do sistema, parece que ele foi alterado.",
"backend_changed_title": "Falha ao carregar o banco de dados",
"backend_no_encryption": "Seu sistema tem um cofre compatível, mas a criptografia não está disponível.",
"backend_no_encryption_detail": "O Electron detetou que a encriptação não está disponível no seu cofre %(backend)s. Certifique-se de que tem o cofre instalado. Se tiver o cofre instalado, reinicie e tente novamente. Opcionalmente, você pode permitir que %(brand)s use uma forma mais fraca de criptografia.",
"backend_no_encryption_title": "Sem suporte para criptografia",
"unsupported_keyring": "Seu sistema possui um cofre não compatível, o que impede a abertura do banco de dados.",
"unsupported_keyring_detail": "A detecção de cofre do Electron não encontrou um backend compatível. Você pode tentar configurar manualmente o backend iniciando %(brand)s com um argumento de linha de comando, uma operação única. Consulte %(link)s.",
"unsupported_keyring_title": "Sistema não suportado",
"unsupported_keyring_use_basic_text": "Use criptografia mais fraca",
"unsupported_keyring_use_plaintext": "Não usar criptografia"
}
},
"view_menu": {
"actual_size": "Tamanho de Verdade",
"toggle_developer_tools": "Ativar/Desativar Ferramentas de Desenvolvimento",
@@ -56,6 +86,7 @@
},
"window_menu": {
"bring_all_to_front": "Trazer Todas Para Frente",
"label": "Janela"
"label": "Janela",
"zoom": "Zoom"
}
}

View File

@@ -22,7 +22,9 @@
"about": "О программе",
"brand_help": "Помощь %(brand)s",
"help": "Помощь",
"preferences": "Предпочтения"
"no": "Нет",
"preferences": "Предпочтения",
"yes": "Да"
},
"confirm_quit": "Вы уверены, что хотите выйти?",
"edit_menu": {
@@ -30,9 +32,15 @@
"speech_start_speaking": "Говорите",
"speech_stop_speaking": "Перестаньте говорить"
},
"eol": {
"title": "Система не поддерживается"
},
"file_menu": {
"label": "Файл"
},
"icon_overlay": {
"description_error": "Ошибка"
},
"menu": {
"hide": "Скрыть",
"hide_others": "Скрыть прочие",

View File

@@ -22,7 +22,9 @@
"about": "Informácie",
"brand_help": "%(brand)s Pomoc",
"help": "Pomocník",
"preferences": "Predvoľby"
"no": "Nie",
"preferences": "Predvoľby",
"yes": "Áno"
},
"confirm_quit": "Naozaj chcete zavrieť aplikáciu?",
"edit_menu": {
@@ -30,9 +32,22 @@
"speech_start_speaking": "Spustiť nahrávanie hlasu",
"speech_stop_speaking": "Zastaviť nahrávanie hlasu"
},
"eol": {
"no_more_updates": "Používate nepodporovanú verziu systému macOS. Prosím, aktualizujte systém, aby ste mohli dostávať aktualizácie aplikácie %(brand)s.",
"title": "Systém nie je podporovaný",
"warning": "Používate nepodporovanú verziu systému macOS. Vykonajte prosím aktualizáciu, aby aplikácia %(brand)s mohla správne fungovať."
},
"file_menu": {
"label": "Súbor"
},
"icon_overlay": {
"description_error": "Chyba",
"description_notifications": {
"one": "Máte %(count)s neprečítané oznámenie.",
"few": "Máte %(count)s neprečítané oznámenia.",
"other": "Máte %(count)s neprečítaných oznámení."
}
},
"menu": {
"hide": "Skryť",
"hide_others": "Skryť ostatné",
@@ -49,6 +64,21 @@
"save_image_as_error_description": "Obrázok sa nepodarilo uložiť",
"save_image_as_error_title": "Chyba pri ukladaní obrázka"
},
"store": {
"error": {
"backend_changed": "Vymazať údaje a znova načítať?",
"backend_changed_detail": "Nepodarilo sa získať prístup k tajnému kľúču zo systémového zväzku kľúčov, zdá sa, že sa zmenil.",
"backend_changed_title": "Nepodarilo sa načítať databázu",
"backend_no_encryption": "Váš systém má podporovaný zväzok kľúčov, ale šifrovanie nie je k dispozícii.",
"backend_no_encryption_detail": "Electron zistil, že šifrovanie nie je k dispozícii na vašom zväzku kľúčov %(backend)s. Uistite sa, že máte nainštalovaný zväzok kľúčov. Ak máte zväzok kľúčov nainštalovaný, reštartujte počítač a skúste to znova. Voliteľne môžete povoliť aplikácii %(brand)s používať slabšiu formu šifrovania.",
"backend_no_encryption_title": "Žiadna podpora šifrovania",
"unsupported_keyring": "Váš systém má nepodporovaný zväzok kľúčov, čo znamená, že databázu nemožno otvoriť.",
"unsupported_keyring_detail": "Detekcia zväzku kľúčov aplikácie Electron nenašla podporovaný backend. Môžete sa pokúsiť manuálne nastaviť backend spustením aplikácie %(brand)s s argumentom príkazového riadka, je to jednorazová operácia. Pozrite si %(link)s .",
"unsupported_keyring_title": "Systém nie je podporovaný",
"unsupported_keyring_use_basic_text": "Použiť slabšie šifrovanie",
"unsupported_keyring_use_plaintext": "Nepoužiť žiadne šifrovanie"
}
},
"view_menu": {
"actual_size": "Aktuálna veľkosť",
"toggle_developer_tools": "Nástroje pre vývojárov",

View File

@@ -22,7 +22,9 @@
"about": "Om",
"brand_help": "%(brand)s-hjälp",
"help": "Hjälp",
"preferences": "Inställningar"
"no": "Nej",
"preferences": "Inställningar",
"yes": "Ja"
},
"confirm_quit": "Är du säker att du vill avsluta?",
"edit_menu": {
@@ -33,6 +35,13 @@
"file_menu": {
"label": "Arkiv"
},
"icon_overlay": {
"description_error": "Fel",
"description_notifications": {
"one": "Du har %(count)s oläst avisering.",
"other": "Du har %(count)s olästa aviseringar."
}
},
"menu": {
"hide": "Göm",
"hide_others": "Göm övriga",
@@ -49,6 +58,21 @@
"save_image_as_error_description": "Bilden sparades inte",
"save_image_as_error_title": "Misslyckades med att spara bilden"
},
"store": {
"error": {
"backend_changed": "Rensa data och ladda om?",
"backend_changed_detail": "Kunde inte komma åt hemligheten från systemnyckelringen, det verkar ha ändrats.",
"backend_changed_title": "Misslyckades att ladda databasen",
"backend_no_encryption": "Ditt system har en nyckelring som stöds men kryptering är inte tillgänglig.",
"backend_no_encryption_detail": "Electron har upptäckt att kryptering inte är tillgänglig på din nyckelring %(backend)s. Se till att du har nyckelringen installerad. Om du har nyckelringen installerad, starta om och försök igen. Alternativt kan du tillåta %(brand)s att använda en svagare form av kryptering.",
"backend_no_encryption_title": "Inget krypteringsstöd",
"unsupported_keyring": "Ditt system har en nyckelring som inte stöds, vilket innebär att databasen inte kan öppnas.",
"unsupported_keyring_detail": "Electrons nyckelringsdetektering hittade inte en backend som stöds. Du kan försöka konfigurera backend manuellt genom att starta %(brand)s med ett kommandoradsargument, en engångsåtgärd. Se %(link)s.",
"unsupported_keyring_title": "Systemet stöds inte",
"unsupported_keyring_use_basic_text": "Använd svagare kryptering",
"unsupported_keyring_use_plaintext": "Använd ingen kryptering"
}
},
"view_menu": {
"actual_size": "Verklig storlek",
"toggle_developer_tools": "Växla utvecklarverktyg",

63
src/i18n/strings/tr.json Normal file
View File

@@ -0,0 +1,63 @@
{
"action": {
"cancel": "İptal",
"close": "Kapat",
"close_brand": "Kapat %(brand)s",
"copy": "Kopyala",
"cut": "Kes",
"delete": "Sil",
"edit": "Düzenle",
"minimise": "Küçült",
"paste": "Yapıştır",
"paste_match_style": "Stili Yapıştır ve Eşleştir",
"quit": ık",
"redo": "Yeniden yap",
"select_all": "Tümünü seç",
"show_hide": "Göster/Gizle",
"undo": "Geri al",
"zoom_in": "Yakınlaştır",
"zoom_out": "Uzaklaştır"
},
"common": {
"about": "Hakkında",
"brand_help": "%(brand)s Yardım",
"help": "Yardım",
"preferences": "Tercihler"
},
"confirm_quit": ıkmak istediğinizden emin misiniz?",
"edit_menu": {
"speech": "Konuşma",
"speech_start_speaking": "Konuşmaya başla",
"speech_stop_speaking": "Konuşmayı durdur"
},
"file_menu": {
"label": "Dosya"
},
"menu": {
"hide": "Gizle",
"hide_others": "Diğerlerini gizle",
"services": "Hizmetler",
"unhide": "Göster"
},
"right_click_menu": {
"add_to_dictionary": "Sözlüğe ekle",
"copy_email": "E-posta adresini kopyala",
"copy_image": "Resmi kopyala",
"copy_image_url": "Görsel adresini kopyala",
"copy_link_url": "Bağlantılı adresi kopyala",
"save_image_as": "Resmi farklı kaydet...",
"save_image_as_error_description": "Görüntü kaydedilemedi",
"save_image_as_error_title": "Resim kaydedilemedi"
},
"view_menu": {
"actual_size": "Gerçek boyut",
"toggle_developer_tools": "Geliştirici araçları",
"toggle_full_screen": "Tam ekran",
"view": "Görüntüle"
},
"window_menu": {
"bring_all_to_front": "Hepsini öne getir",
"label": "Pencere",
"zoom": "Yaklaştır"
}
}

View File

@@ -22,7 +22,9 @@
"about": "Про застосунок",
"brand_help": "Довідка %(brand)s",
"help": "Довідка",
"preferences": "Параметри"
"no": "Ні",
"preferences": "Параметри",
"yes": "Так"
},
"confirm_quit": "Ви впевнені, що хочете вийти?",
"edit_menu": {
@@ -33,6 +35,14 @@
"file_menu": {
"label": "Файл"
},
"icon_overlay": {
"description_error": "Помилка",
"description_notifications": {
"one": "У вас є %(count)s непрочитане сповіщення.",
"few": "У вас є %(count)s непрочитані сповіщення.",
"many": "У вас є %(count)s непрочитаних сповіщень."
}
},
"menu": {
"hide": "Сховати",
"hide_others": "Сховати інші",
@@ -49,6 +59,21 @@
"save_image_as_error_description": "Не вдалося зберегти зображення",
"save_image_as_error_title": "Не вдалося зберегти зображення"
},
"store": {
"error": {
"backend_changed": "Очистити дані та перезавантажити?",
"backend_changed_detail": "Не вдається отримати доступ до таємного ключа з системного набору ключів, видається, він змінився.",
"backend_changed_title": "Не вдалося завантажити базу даних",
"backend_no_encryption": "Ваша система підтримує сховище ключів, але шифрування недоступне.",
"backend_no_encryption_detail": "Electron виявив, що шифрування недоступне у вашому сховищі ключів %(backend)s. Переконайтеся, що у вас встановлено сховище ключів. Якщо так, тоді перезавантажте комп'ютер і повторіть спробу. За бажанням, ви можете дозволити %(brand)s використовувати слабшу форму шифрування.",
"backend_no_encryption_title": "Шифрування не підтримується",
"unsupported_keyring": "Ваша система має непідтримуваний набір ключів. Це означає, що базу даних неможливо відкрити.",
"unsupported_keyring_detail": "Electron не виявив підтримуваного бекенда для роботи зі сховищем паролів. Ви можете вручну налаштувати його, запустивши %(brand)s з відповідним аргументом у командному рядку. Цю дію потрібно виконати лише один раз. Докладніше %(link)s.",
"unsupported_keyring_title": "Система не підтримується",
"unsupported_keyring_use_basic_text": "Використовувати слабше шифрування",
"unsupported_keyring_use_plaintext": "Не використовувати шифрування"
}
},
"view_menu": {
"actual_size": "Фактичний розмір",
"toggle_developer_tools": "Перемкнути інструменти розробника",

View File

@@ -1,31 +1,16 @@
/*
Copyright 2022-2024 New Vector Ltd.
Copyright 2022-2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { app, autoUpdater, desktopCapturer, ipcMain, powerSaveBlocker, TouchBar, nativeImage } from "electron";
import { relaunchApp } from "@standardnotes/electron-clear-data";
import IpcMainEvent = Electron.IpcMainEvent;
import { recordSSOSession } from "./protocol.js";
import { randomArray } from "./utils.js";
import { Settings } from "./settings.js";
import { keytar } from "./keytar.js";
import { getDisplayMediaCallback, setDisplayMediaCallback } from "./displayMediaCallback.js";
ipcMain.on("setBadgeCount", function (_ev: IpcMainEvent, count: number): void {
if (process.platform !== "win32") {
// only set badgeCount on Mac/Linux, the docs say that only those platforms support it but turns out Electron
// has some Windows support too, and in some Windows environments this leads to two badges rendering atop
// each other. See https://github.com/vector-im/element-web/issues/16942
app.badgeCount = count;
}
if (count === 0) {
global.mainWindow?.flashFrame(false);
}
});
import Store, { clearDataAndRelaunch } from "./store.js";
let focusHandlerAttached = false;
ipcMain.on("loudNotification", function (): void {
@@ -61,7 +46,8 @@ ipcMain.on("app_onAction", function (_ev: IpcMainEvent, payload) {
});
ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
if (!global.mainWindow) return;
const store = Store.instance;
if (!global.mainWindow || !store) return;
const args = payload.args || [];
let ret: any;
@@ -70,18 +56,6 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
case "getUpdateFeedUrl":
ret = autoUpdater.getFeedURL();
break;
case "getSettingValue": {
const [settingName] = args;
const setting = Settings[settingName];
ret = await setting.read();
break;
}
case "setSettingValue": {
const [settingName, value] = args;
const setting = Settings[settingName];
await setting.write(value);
break;
}
case "setLanguage":
global.appLocalization.setAppLocale(args[0]);
break;
@@ -96,9 +70,7 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
global.mainWindow.focus();
}
break;
case "getConfig":
ret = global.vectorConfig;
break;
case "navigateBack":
if (global.mainWindow.webContents.canGoBack()) {
global.mainWindow.webContents.goBack();
@@ -113,11 +85,11 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
if (typeof args[0] !== "boolean") return;
global.mainWindow.webContents.session.setSpellCheckerEnabled(args[0]);
global.store.set("spellCheckerEnabled", args[0]);
store.set("spellCheckerEnabled", args[0]);
break;
case "getSpellCheckEnabled":
ret = global.store.get("spellCheckerEnabled", true);
ret = store.get("spellCheckerEnabled");
break;
case "setSpellCheckLanguages":
@@ -135,18 +107,9 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
ret = global.mainWindow.webContents.session.availableSpellCheckerLanguages;
break;
case "startSSOFlow":
recordSSOSession(args[0]);
break;
case "getPickleKey":
try {
ret = await keytar?.getPassword("element.io", `${args[0]}|${args[1]}`);
// migrate from riot.im (remove once we think there will no longer be
// logins from the time of riot.im)
if (ret === null) {
ret = await keytar?.getPassword("riot.im", `${args[0]}|${args[1]}`);
}
ret = await store.getSecret(`${args[0]}|${args[1]}`);
} catch {
// if an error is thrown (e.g. keytar can't connect to the keychain),
// then return null, which means the default pickle key will be used
@@ -157,22 +120,20 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
case "createPickleKey":
try {
const pickleKey = await randomArray(32);
// We purposefully throw if keytar is not available so the caller can handle it
// rather than sending them a pickle key we did not store on their behalf.
await keytar!.setPassword("element.io", `${args[0]}|${args[1]}`, pickleKey);
await store.setSecret(`${args[0]}|${args[1]}`, pickleKey);
ret = pickleKey;
} catch {
} catch (e) {
console.error("Failed to create pickle key", e);
ret = null;
}
break;
case "destroyPickleKey":
try {
await keytar?.deletePassword("element.io", `${args[0]}|${args[1]}`);
// migrate from riot.im (remove once we think there will no longer be
// logins from the time of riot.im)
await keytar?.deletePassword("riot.im", `${args[0]}|${args[1]}`);
} catch {}
await store.deleteSecret(`${args[0]}|${args[1]}`);
} catch (e) {
console.error("Failed to destroy pickle key", e);
}
break;
case "getDesktopCapturerSources":
ret = (await desktopCapturer.getSources(args[0])).map((source) => ({
@@ -188,10 +149,7 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
break;
case "clearStorage":
global.store.clear();
global.mainWindow.webContents.session.flushStorageData();
await global.mainWindow.webContents.session.clearStorageData();
relaunchApp();
await clearDataAndRelaunch(global.mainWindow.webContents.session);
return; // the app is about to stop, we don't need to reply to the IPC
case "breadcrumbs": {
@@ -258,3 +216,12 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
reply: ret,
});
});
ipcMain.handle("getConfig", () => global.vectorConfig);
const initialisePromiseWithResolvers = Promise.withResolvers<void>();
export const initialisePromise = initialisePromiseWithResolvers.promise;
ipcMain.once("initialise", () => {
initialisePromiseWithResolvers.resolve();
});

View File

@@ -1,21 +0,0 @@
/*
Copyright 2022-2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type * as Keytar from "keytar"; // Hak dependency type
let keytar: typeof Keytar | undefined;
try {
({ default: keytar } = await import("keytar"));
} catch (e) {
if ((<NodeJS.ErrnoException>e).code === "MODULE_NOT_FOUND") {
console.log("Keytar isn't installed; secure key storage is disabled.");
} else {
console.warn("Keytar unexpected error:", e);
}
}
export { keytar };

View File

@@ -10,9 +10,9 @@ import { type TranslationKey as TKey } from "matrix-web-i18n";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import type Store from "electron-store";
import type EN from "./i18n/strings/en_EN.json";
import { loadJsonFile } from "./utils.js";
import type Store from "./store.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -59,26 +59,24 @@ export function _t(text: TranslationKey, variables: Variables = {}): string {
type Component = () => void;
type TypedStore = Store<{ locale?: string | string[] }>;
export class AppLocalization {
private static readonly STORE_KEY = "locale";
private readonly store: TypedStore;
private readonly localizedComponents?: Set<Component>;
private readonly store: Store;
public constructor({ store, components = [] }: { store: TypedStore; components: Component[] }) {
public constructor({ components = [], store }: { components: Component[]; store: Store }) {
counterpart.registerTranslations(FALLBACK_LOCALE, this.fetchTranslationJson("en_EN"));
counterpart.setFallbackLocale(FALLBACK_LOCALE);
counterpart.setSeparator("|");
this.store = store;
if (Array.isArray(components)) {
this.localizedComponents = new Set(components);
}
this.store = store;
if (this.store.has(AppLocalization.STORE_KEY)) {
const locales = this.store.get(AppLocalization.STORE_KEY);
if (store.has(AppLocalization.STORE_KEY)) {
const locales = store.get(AppLocalization.STORE_KEY);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.setAppLocale(locales!);
}

View File

@@ -52,8 +52,10 @@ export function setupMacosTitleBar(window: BrowserWindow): void {
-webkit-app-region: drag;
}
/* Exclude the main content elements from being drag handles */
.mx_AuthPage .mx_AuthPage_modalContent,
.mx_AuthPage .mx_AuthPage_modalBlur,
.mx_AuthPage .mx_AuthFooter > * {
.mx_AuthPage .mx_AuthFooter > *,
.mx_AuthPage .mx_Dropdown_menu {
-webkit-app-region: no-drag;
}
@@ -117,6 +119,12 @@ export function setupMacosTitleBar(window: BrowserWindow): void {
height: 20px;
-webkit-app-region: drag;
}
.mx_LeftPanel_newRoomList::before {
/* Aligned with the room header */
height: 13px;
border-right: 1px solid var(--cpd-color-bg-subtle-primary);
}
.mx_RoomView::before,
.mx_SpaceRoomView::before {

View File

@@ -32,6 +32,7 @@ const CHANNELS = [
"userAccessToken",
"homeserverUrl",
"serverSupportedVersions",
"showToast",
];
contextBridge.exposeInMainWorld("electron", {
@@ -49,4 +50,30 @@ contextBridge.exposeInMainWorld("electron", {
}
ipcRenderer.send(channel, ...args);
},
async initialise(): Promise<{
protocol: string;
sessionId: string;
config: IConfigOptions;
supportedSettings: Record<string, boolean>;
/**
* Do we need to render badge overlays for new notifications?
*/
supportsBadgeOverlay: boolean;
}> {
ipcRenderer.emit("initialise");
const [{ protocol, sessionId }, config, supportedSettings] = await Promise.all([
ipcRenderer.invoke("getProtocol"),
ipcRenderer.invoke("getConfig"),
ipcRenderer.invoke("getSupportedSettings"),
]);
return { protocol, sessionId, config, supportedSettings, supportsBadgeOverlay: process.platform === "win32" };
},
async setSettingValue(settingName: string, value: any): Promise<void> {
return ipcRenderer.invoke("setSettingValue", settingName, value);
},
async getSettingValue(settingName: string): Promise<any> {
return ipcRenderer.invoke("getSettingValue", settingName);
},
});

View File

@@ -6,119 +6,136 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import { app } from "electron";
import { app, ipcMain } from "electron";
import { URL } from "node:url";
import path from "node:path";
import fs from "node:fs";
import { randomUUID } from "node:crypto";
const LEGACY_PROTOCOL = "element";
const PROTOCOL = "io.element.desktop";
const SEARCH_PARAM = "element-desktop-ssoid";
const STORE_FILE_NAME = "sso-sessions.json";
// we getPath userData before electron-main changes it, so this is the default value
const storePath = path.join(app.getPath("userData"), STORE_FILE_NAME);
function processUrl(url: string): void {
if (!global.mainWindow) return;
export default class ProtocolHandler {
private readonly store: Record<string, string> = {};
private readonly sessionId: string;
const parsed = new URL(url);
// sanity check: we only register for the one protocol, so we shouldn't
// be getting anything else unless the user is forcing a URL to open
// with the Element app.
if (parsed.protocol !== `${PROTOCOL}:` && parsed.protocol !== `${LEGACY_PROTOCOL}:`) {
console.log("Ignoring unexpected protocol: ", parsed.protocol);
return;
public constructor(private readonly protocol: string) {
// get all args except `hidden` as it'd mean the app would not get focused
// XXX: passing args to protocol handlers only works on Windows, so unpackaged deep-linking
// --profile/--profile-dir are passed via the SEARCH_PARAM var in the callback url
const args = process.argv.slice(1).filter((arg) => arg !== "--hidden" && arg !== "-hidden");
if (app.isPackaged) {
app.setAsDefaultProtocolClient(this.protocol, process.execPath, args);
app.setAsDefaultProtocolClient(LEGACY_PROTOCOL, process.execPath, args);
} else if (process.platform === "win32") {
// on Mac/Linux this would just cause the electron binary to open
// special handler for running without being packaged, e.g `electron .` by passing our app path to electron
app.setAsDefaultProtocolClient(this.protocol, process.execPath, [app.getAppPath(), ...args]);
app.setAsDefaultProtocolClient(LEGACY_PROTOCOL, process.execPath, [app.getAppPath(), ...args]);
}
if (process.platform === "darwin") {
// Protocol handler for macos
app.on("open-url", (ev, url) => {
ev.preventDefault();
this.processUrl(url);
});
} else {
// Protocol handler for win32/Linux
app.on("second-instance", (ev, commandLine) => {
const url = commandLine[commandLine.length - 1];
if (!url.startsWith(`${this.protocol}:/`) && !url.startsWith(`${LEGACY_PROTOCOL}://`)) return;
this.processUrl(url);
});
}
this.store = this.readStore();
this.sessionId = randomUUID();
ipcMain.handle("getProtocol", this.onGetProtocol);
}
const urlToLoad = new URL("vector://vector/webapp/");
// ignore anything other than the search (used for SSO login redirect)
// and the hash (for general element deep links)
// There's no reason to allow anything else, particularly other paths,
// since this would allow things like the internal jitsi wrapper to
// be loaded, which would get the app stuck on that page and generally
// be a bit strange and confusing.
urlToLoad.search = parsed.search;
urlToLoad.hash = parsed.hash;
private readonly onGetProtocol = (): { protocol: string; sessionId: string } => {
return {
protocol: this.protocol,
sessionId: this.sessionId,
};
};
console.log("Opening URL: ", urlToLoad.href);
void global.mainWindow.loadURL(urlToLoad.href);
}
private processUrl(url: string): void {
if (!global.mainWindow) return;
function readStore(): Record<string, string> {
try {
const s = fs.readFileSync(storePath, { encoding: "utf8" });
const o = JSON.parse(s);
return typeof o === "object" ? o : {};
} catch {
return {};
const parsed = new URL(url);
// sanity check: we only register for the one protocol, so we shouldn't
// be getting anything else unless the user is forcing a URL to open
// with the Element app.
if (parsed.protocol !== `${this.protocol}:` && parsed.protocol !== `${LEGACY_PROTOCOL}:`) {
console.log("Ignoring unexpected protocol: ", parsed.protocol);
return;
}
const urlToLoad = new URL("vector://vector/webapp/");
// ignore anything other than the search (used for SSO login redirect)
// and the hash (for general element deep links)
// There's no reason to allow anything else, particularly other paths,
// since this would allow things like the internal jitsi wrapper to
// be loaded, which would get the app stuck on that page and generally
// be a bit strange and confusing.
urlToLoad.search = parsed.search;
urlToLoad.hash = parsed.hash;
console.log("Opening URL: ", urlToLoad.href);
void global.mainWindow.loadURL(urlToLoad.href);
}
}
function writeStore(data: Record<string, string>): void {
fs.writeFileSync(storePath, JSON.stringify(data));
}
export function recordSSOSession(sessionID: string): void {
const userDataPath = app.getPath("userData");
const store = readStore();
for (const key in store) {
// ensure each instance only has one (the latest) session ID to prevent the file growing unbounded
if (store[key] === userDataPath) {
delete store[key];
break;
private readStore(): Record<string, string> {
try {
const s = fs.readFileSync(storePath, { encoding: "utf8" });
const o = JSON.parse(s);
return typeof o === "object" ? o : {};
} catch {
return {};
}
}
store[sessionID] = userDataPath;
writeStore(store);
}
export function getProfileFromDeeplink(args: string[]): string | undefined {
// check if we are passed a profile in the SSO callback url
const deeplinkUrl = args.find((arg) => arg.startsWith(`${PROTOCOL}://`) || arg.startsWith(`${LEGACY_PROTOCOL}://`));
if (deeplinkUrl?.includes(SEARCH_PARAM)) {
const parsedUrl = new URL(deeplinkUrl);
if (parsedUrl.protocol === `${PROTOCOL}:` || parsedUrl.protocol === `${LEGACY_PROTOCOL}:`) {
const store = readStore();
let ssoID = parsedUrl.searchParams.get(SEARCH_PARAM);
if (!ssoID) {
// In OIDC, we must shuttle the value in the `state` param rather than `element-desktop-ssoid`
// We encode it as a suffix like `:element-desktop-ssoid:XXYYZZ`
ssoID = parsedUrl.searchParams.get("state")!.split(`:${SEARCH_PARAM}:`)[1];
private writeStore(): void {
fs.writeFileSync(storePath, JSON.stringify(this.store));
}
public initialise(userDataPath: string): void {
for (const key in this.store) {
// ensure each instance only has one (the latest) session ID to prevent the file growing unbounded
if (this.store[key] === userDataPath) {
delete this.store[key];
break;
}
}
this.store[this.sessionId] = userDataPath;
this.writeStore();
}
public getProfileFromDeeplink(args: string[]): string | undefined {
// check if we are passed a profile in the SSO callback url
const deeplinkUrl = args.find(
(arg) => arg.startsWith(`${this.protocol}:/`) || arg.startsWith(`${LEGACY_PROTOCOL}://`),
);
if (deeplinkUrl?.includes(SEARCH_PARAM)) {
const parsedUrl = new URL(deeplinkUrl);
if (parsedUrl.protocol === `${this.protocol}:` || parsedUrl.protocol === `${LEGACY_PROTOCOL}:`) {
const store = this.readStore();
let sessionId = parsedUrl.searchParams.get(SEARCH_PARAM);
if (!sessionId) {
// In OIDC, we must shuttle the value in the `state` param rather than `element-desktop-ssoid`
// We encode it as a suffix like `:element-desktop-ssoid:XXYYZZ`
sessionId = parsedUrl.searchParams.get("state")!.split(`:${SEARCH_PARAM}:`)[1];
}
console.log("Forwarding to profile: ", store[sessionId]);
return store[sessionId];
}
console.log("Forwarding to profile: ", store[ssoID]);
return store[ssoID];
}
}
}
export function protocolInit(): void {
// get all args except `hidden` as it'd mean the app would not get focused
// XXX: passing args to protocol handlers only works on Windows, so unpackaged deep-linking
// --profile/--profile-dir are passed via the SEARCH_PARAM var in the callback url
const args = process.argv.slice(1).filter((arg) => arg !== "--hidden" && arg !== "-hidden");
if (app.isPackaged) {
app.setAsDefaultProtocolClient(PROTOCOL, process.execPath, args);
app.setAsDefaultProtocolClient(LEGACY_PROTOCOL, process.execPath, args);
} else if (process.platform === "win32") {
// on Mac/Linux this would just cause the electron binary to open
// special handler for running without being packaged, e.g `electron .` by passing our app path to electron
app.setAsDefaultProtocolClient(PROTOCOL, process.execPath, [app.getAppPath(), ...args]);
app.setAsDefaultProtocolClient(LEGACY_PROTOCOL, process.execPath, [app.getAppPath(), ...args]);
}
if (process.platform === "darwin") {
// Protocol handler for macos
app.on("open-url", function (ev, url) {
ev.preventDefault();
processUrl(url);
});
} else {
// Protocol handler for win32/Linux
app.on("second-instance", (ev, commandLine) => {
const url = commandLine[commandLine.length - 1];
if (!url.startsWith(`${PROTOCOL}://`) && !url.startsWith(`${LEGACY_PROTOCOL}://`)) return;
processUrl(url);
});
}
}

View File

@@ -16,7 +16,7 @@ import type {
} from "matrix-seshat"; // Hak dependency type
import IpcMainEvent = Electron.IpcMainEvent;
import { randomArray } from "./utils.js";
import { keytar } from "./keytar.js";
import Store from "./store.js";
let seshatSupported = false;
let Seshat: typeof SeshatType;
@@ -40,21 +40,24 @@ try {
let eventIndex: SeshatType | null = null;
const seshatDefaultPassphrase = "DEFAULT_PASSPHRASE";
async function getOrCreatePassphrase(key: string): Promise<string> {
if (keytar) {
try {
const storedPassphrase = await keytar.getPassword("element.io", key);
if (storedPassphrase !== null) {
return storedPassphrase;
} else {
const newPassphrase = await randomArray(32);
await keytar.setPassword("element.io", key, newPassphrase);
return newPassphrase;
}
} catch (e) {
console.log("Error getting the event index passphrase out of the secret store", e);
async function getOrCreatePassphrase(store: Store, key: string): Promise<string> {
try {
const storedPassphrase = await store.getSecret(key);
if (storedPassphrase !== undefined) {
return storedPassphrase;
}
} catch (e) {
console.error("Error getting the event index passphrase out of the secret store", e);
}
try {
const newPassphrase = await randomArray(32);
await store.setSecret(key, newPassphrase);
return newPassphrase;
} catch (e) {
console.error("Error creating new event index passphrase, using default", e);
}
return seshatDefaultPassphrase;
}
@@ -74,7 +77,8 @@ const deleteContents = async (p: string): Promise<void> => {
};
ipcMain.on("seshat", async function (_ev: IpcMainEvent, payload): Promise<void> {
if (!global.mainWindow) return;
const store = Store.instance;
if (!global.mainWindow || !store) return;
// We do this here to ensure we get the path after --profile has been resolved
const eventStorePath = path.join(app.getPath("userData"), "EventStore");
@@ -101,7 +105,7 @@ ipcMain.on("seshat", async function (_ev: IpcMainEvent, payload): Promise<void>
const deviceId = args[1];
const passphraseKey = `seshat|${userId}|${deviceId}`;
const passphrase = await getOrCreatePassphrase(passphraseKey);
const passphrase = await getOrCreatePassphrase(store, passphraseKey);
try {
await afs.mkdir(eventStorePath, { recursive: true });

View File

@@ -5,47 +5,54 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import { ipcMain } from "electron";
import * as tray from "./tray.js";
import Store from "./store.js";
import { AutoLaunch, type AutoLaunchState } from "./auto-launch.js";
interface Setting {
read(): Promise<any>;
write(value: any): Promise<void>;
supported?(): boolean; // if undefined, the setting is always supported
}
export const Settings: Record<string, Setting> = {
const Settings: Record<string, Setting> = {
"Electron.autoLaunch": {
async read(): Promise<any> {
return global.launcher.isEnabled();
async read(): Promise<AutoLaunchState> {
return AutoLaunch.instance.getState();
},
async write(value: any): Promise<void> {
if (value) {
return global.launcher.enable();
} else {
return global.launcher.disable();
}
async write(value: AutoLaunchState): Promise<void> {
return AutoLaunch.instance.setState(value);
},
},
"Electron.warnBeforeExit": {
async read(): Promise<any> {
return global.store.get("warnBeforeExit", true);
return Store.instance?.get("warnBeforeExit");
},
async write(value: any): Promise<void> {
global.store.set("warnBeforeExit", value);
Store.instance?.set("warnBeforeExit", value);
},
},
"Electron.alwaysShowMenuBar": {
// not supported on macOS
// This isn't relevant on Mac as Menu bars don't live in the app window
supported(): boolean {
return process.platform !== "darwin";
},
async read(): Promise<any> {
return !global.mainWindow!.autoHideMenuBar;
},
async write(value: any): Promise<void> {
global.store.set("autoHideMenuBar", !value);
Store.instance?.set("autoHideMenuBar", !value);
global.mainWindow!.autoHideMenuBar = !value;
global.mainWindow!.setMenuBarVisibility(value);
},
},
"Electron.showTrayIcon": {
// not supported on macOS
// Things other than Mac support tray icons
supported(): boolean {
return process.platform !== "darwin";
},
async read(): Promise<any> {
return tray.hasTray();
},
@@ -56,15 +63,54 @@ export const Settings: Record<string, Setting> = {
} else {
tray.destroy();
}
global.store.set("minimizeToTray", value);
Store.instance?.set("minimizeToTray", value);
},
},
"Electron.enableHardwareAcceleration": {
async read(): Promise<any> {
return !global.store.get("disableHardwareAcceleration", false);
return !Store.instance?.get("disableHardwareAcceleration");
},
async write(value: any): Promise<void> {
global.store.set("disableHardwareAcceleration", !value);
Store.instance?.set("disableHardwareAcceleration", !value);
},
},
"Electron.enableContentProtection": {
// Unsupported on Linux https://www.electronjs.org/docs/latest/api/browser-window#winsetcontentprotectionenable-macos-windows
// Broken on macOS https://github.com/electron/electron/issues/19880
supported(): boolean {
return process.platform === "win32";
},
async read(): Promise<any> {
return Store.instance?.get("enableContentProtection");
},
async write(value: any): Promise<void> {
global.mainWindow?.setContentProtection(value);
Store.instance?.set("enableContentProtection", value);
},
},
};
ipcMain.handle("getSupportedSettings", async () => {
const supportedSettings: Record<string, boolean> = {};
for (const [key, setting] of Object.entries(Settings)) {
supportedSettings[key] = setting.supported?.() ?? true;
}
return supportedSettings;
});
ipcMain.handle("setSettingValue", async (_ev, settingName: string, value: any) => {
const setting = Settings[settingName];
if (!setting) {
throw new Error(`Unknown setting: ${settingName}`);
}
console.debug(`Writing setting value for: ${settingName} = ${value}`);
await setting.write(value);
});
ipcMain.handle("getSettingValue", async (_ev, settingName: string) => {
const setting = Settings[settingName];
if (!setting) {
throw new Error(`Unknown setting: ${settingName}`);
}
const value = await setting.read();
console.debug(`Reading setting value for: ${settingName} = ${value}`);
return value;
});

544
src/store.ts Normal file
View File

@@ -0,0 +1,544 @@
/*
Copyright 2022-2025 New Vector Ltd
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 ElectronStore from "electron-store";
import keytar from "keytar-forked";
import { app, safeStorage, dialog, type SafeStorage, type Session } from "electron";
import { _t } from "./language-helper.js";
/**
* Legacy keytar service name for storing secrets.
* @deprecated
*/
const KEYTAR_SERVICE = "element.io";
/**
* Super legacy keytar service name for reading secrets.
* @deprecated
*/
const LEGACY_KEYTAR_SERVICE = "riot.im";
/**
* String union type representing all the safeStorage backends.
* + The "unknown" backend shouldn't exist in practice once the app is ready
* + The "plaintext" is the temporarily-unencrypted backend for migration, data is wholly unencrypted - uses PlaintextStorageWriter
* + The "basic_text" backend is the 'plaintext' backend on Linux, data is encrypted but not using the keychain
* + The "system" backend is the encrypted backend on Windows & macOS, data is encrypted using system keychain
* + All other backends are linux-specific and are encrypted using the keychain
*/
type SafeStorageBackend = ReturnType<SafeStorage["getSelectedStorageBackend"]> | "system" | "plaintext";
/**
* The "unknown" backend is not a valid backend, so we exclude it from the type.
*/
type SaneSafeStorageBackend = Exclude<SafeStorageBackend, "unknown">;
/**
* Map of safeStorage backends to their command line arguments.
* kwallet6 cannot be specified via command line
* https://www.electronjs.org/docs/latest/api/safe-storage#safestoragegetselectedstoragebackend-linux
*/
const safeStorageBackendMap: Omit<Record<SaneSafeStorageBackend, string>, "system" | "plaintext"> = {
basic_text: "basic",
gnome_libsecret: "gnome-libsecret",
kwallet: "kwallet",
kwallet5: "kwallet5",
kwallet6: "kwallet6",
};
function relaunchApp(): void {
console.info("Relaunching app...");
app.relaunch();
app.exit();
}
/**
* Clear all data and relaunch the app.
*/
export async function clearDataAndRelaunch(electronSession: Session): Promise<void> {
Store.instance?.clear();
electronSession.flushStorageData();
await electronSession.clearStorageData();
relaunchApp();
}
interface StoreData {
warnBeforeExit: boolean;
minimizeToTray: boolean;
spellCheckerEnabled: boolean;
autoHideMenuBar: boolean;
locale?: string | string[];
disableHardwareAcceleration: boolean;
enableContentProtection: boolean;
safeStorage?: Record<string, string>;
/** the safeStorage backend used for the safeStorage data as written */
safeStorageBackend?: SafeStorageBackend;
/** whether to explicitly override the safeStorage backend, used for migration */
safeStorageBackendOverride?: boolean;
/** whether to perform a migration of the safeStorage data */
safeStorageBackendMigrate?: boolean;
/** whether to open the app at login minimised, only valid when app.openAtLogin is true */
openAtLoginMinimised: boolean;
}
/**
* Fallback storage writer for secrets, mainly used for automated tests and systems without any safeStorage support.
*/
class StorageWriter {
public constructor(protected readonly store: ElectronStore<StoreData>) {}
public getKey(key: string): `safeStorage.${string}` {
return `safeStorage.${key.replaceAll(".", "-")}`;
}
public set(key: string, secret: string): void {
this.store.set(this.getKey(key), secret);
}
public get(key: string): string | undefined {
return this.store.get(this.getKey(key));
}
public delete(key: string): void {
this.store.delete(this.getKey(key));
}
}
/**
* Storage writer for secrets using safeStorage.
*/
class SafeStorageWriter extends StorageWriter {
public set(key: string, secret: string): void {
this.store.set(this.getKey(key), safeStorage.encryptString(secret).toString("base64"));
}
public get(key: string): string | undefined {
const ciphertext = this.store.get<string, string | undefined>(this.getKey(key));
if (ciphertext) {
try {
return safeStorage.decryptString(Buffer.from(ciphertext, "base64"));
} catch (e) {
console.error("Failed to decrypt secret", e);
console.error("...ciphertext:", JSON.stringify(ciphertext));
}
}
return undefined;
}
}
const enum Mode {
Encrypted = "encrypted", // default
AllowPlaintext = "allow-plaintext",
ForcePlaintext = "force-plaintext",
}
/**
* JSON-backed store for settings which need to be accessible by the main process.
* Secrets are stored within the `safeStorage` object, encrypted with safeStorage.
* Any secrets operations are blocked on Electron app ready emit, and keytar migration if still needed.
*/
class Store extends ElectronStore<StoreData> {
private static internalInstance?: Store;
public static get instance(): Store | undefined {
return Store.internalInstance;
}
/**
* Prepare the store, does not prepare safeStorage, which needs to be done after the app is ready.
* Must be executed in the first tick of the event loop so that it can call Electron APIs before ready state.
*/
public static initialize(mode: Mode | undefined): Store {
if (Store.internalInstance) {
throw new Error("Store already initialized");
}
const store = new Store(mode ?? Mode.Encrypted);
Store.internalInstance = store;
if (
process.platform === "linux" &&
(store.get("safeStorageBackendOverride") || store.get("safeStorageBackendMigrate"))
) {
const backend = store.get("safeStorageBackend")!;
if (backend in safeStorageBackendMap) {
// If the safeStorage backend which was used to write the data is one we can specify via the commandLine
// then do so to ensure we use the same backend for reading the data.
app.commandLine.appendSwitch(
"password-store",
safeStorageBackendMap[backend as keyof typeof safeStorageBackendMap],
);
}
}
return store;
}
// Provides "raw" access to the underlying secrets storage,
// should be avoided in favour of the getSecret/setSecret/deleteSecret methods.
private secrets?: StorageWriter;
private constructor(private mode: Mode) {
super({
name: "electron-config",
clearInvalidConfig: false,
schema: {
warnBeforeExit: {
type: "boolean",
default: true,
},
minimizeToTray: {
type: "boolean",
default: true,
},
spellCheckerEnabled: {
type: "boolean",
default: true,
},
autoHideMenuBar: {
type: "boolean",
default: true,
},
locale: {
anyOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
},
disableHardwareAcceleration: {
type: "boolean",
default: false,
},
enableContentProtection: {
type: "boolean",
default: false,
},
safeStorage: {
type: "object",
},
safeStorageBackend: {
type: "string",
},
safeStorageBackendOverride: {
type: "boolean",
},
safeStorageBackendMigrate: {
type: "boolean",
},
openAtLoginMinimised: {
type: "boolean",
default: true,
},
},
});
}
private safeStorageReadyPromise?: Promise<boolean>;
public async safeStorageReady(): Promise<void> {
if (!this.safeStorageReadyPromise) {
throw new Error("prepareSafeStorage must be called before using storage methods");
}
await this.safeStorageReadyPromise;
}
/**
* Normalise the backend to a sane value (exclude `unknown`), respect forcePlaintext mode,
* and ensure that if an encrypted backend is picked that encryption is available, falling back to plaintext if not.
* @param forcePlaintext - whether to force plaintext mode
* @private
*/
private chooseBackend(forcePlaintext: boolean): SaneSafeStorageBackend {
if (forcePlaintext) {
return "plaintext";
}
if (process.platform === "linux") {
// The following enables plain text encryption if the backend used is basic_text.
// It has no significance for any other backend.
// We do this early so that in case we end up using the basic_text backend (either because that's the only one available
// or as a fallback when the configured backend lacks encryption support), encryption is already turned on.
safeStorage.setUsePlainTextEncryption(true);
// Linux safeStorage support is hellish, the support varies on the Desktop Environment used rather than the store itself.
// https://github.com/electron/electron/issues/39789 https://github.com/microsoft/vscode/issues/185212
const selectedBackend = safeStorage.getSelectedStorageBackend();
if (selectedBackend === "unknown" || !safeStorage.isEncryptionAvailable()) {
return "plaintext";
}
return selectedBackend;
}
return safeStorage.isEncryptionAvailable() ? "system" : "plaintext";
}
/**
* Prepare the safeStorage backend for use.
* We don't eagerly import from keytar as that would bring in data for all Element profiles and not just the current one,
* so we import lazily in getSecret.
*
* This will relaunch the app in some cases, in which case it will return false and the caller should abort startup.
*
* @param electronSession - The Electron session to use for storage (will be used to clear storage if necessary).
* @returns true if safeStorage was initialised successfully or false if the app will be relaunched
*/
public async prepareSafeStorage(electronSession: Session): Promise<boolean> {
this.safeStorageReadyPromise = this.reallyPrepareSafeStorage(electronSession);
return this.safeStorageReadyPromise;
}
private async reallyPrepareSafeStorage(electronSession: Session): Promise<boolean> {
await app.whenReady();
// The backend the existing data is written with if any
let existingSafeStorageBackend = this.get("safeStorageBackend");
// The backend and encryption status of the currently loaded backend
const backend = this.chooseBackend(this.mode === Mode.ForcePlaintext);
// Handle migrations
if (existingSafeStorageBackend) {
if (existingSafeStorageBackend === "basic_text" && backend !== "plaintext" && backend !== "basic_text") {
this.prepareMigrateBasicTextToPlaintext();
return false;
}
if (this.get("safeStorageBackendMigrate") && backend === "basic_text") {
this.migrateBasicTextToPlaintext();
return false;
}
if (existingSafeStorageBackend === "plaintext" && backend !== "plaintext") {
this.migratePlaintextToEncrypted();
// Ensure we update existingSafeStorageBackend so we don't fall into the "backend changed" clause below
existingSafeStorageBackend = this.get("safeStorageBackend");
}
}
if (!existingSafeStorageBackend) {
// First launch of the app or first launch since the update
if (this.mode === Mode.Encrypted && (backend === "plaintext" || backend === "basic_text")) {
// Ask the user for consent to use a degraded mode
await this.consultUserConsentDegradedMode(backend);
}
// Store the backend used for the safeStorage data so we can detect if it changes, and we know how the data is encoded
this.recordSafeStorageBackend(backend);
} else if (existingSafeStorageBackend !== backend) {
// We already appear to have started using a backend other than the one that we picked, so
// set the override flag and relaunch with the backend we were previously using, unless we
// already have the override flag, in which case we must assume the previous backend is no
// longer usable, in which case we should fall into the next block and warn the user we can't
// migrate.
console.warn(`safeStorage backend changed from ${existingSafeStorageBackend} to ${backend}`);
if (existingSafeStorageBackend in safeStorageBackendMap && !this.get("safeStorageBackendOverride")) {
this.set("safeStorageBackendOverride", true);
relaunchApp();
return false;
} else {
// This will either relaunch the app or throw an execption
await this.consultUserBackendChangedUnableToMigrate(electronSession);
return false;
}
}
console.info(`Using storage mode '${this.mode}' with backend '${backend}'`);
if (backend !== "plaintext") {
this.secrets = new SafeStorageWriter(this);
} else {
this.secrets = new StorageWriter(this);
}
return true;
}
private async consultUserBackendChangedUnableToMigrate(electronSession: Session): Promise<void> {
const { response } = await dialog.showMessageBox({
title: _t("store|error|backend_changed_title"),
message: _t("store|error|backend_changed"),
detail: _t("store|error|backend_changed_detail"),
type: "question",
buttons: [_t("common|no"), _t("common|yes")],
defaultId: 0,
cancelId: 0,
});
if (response === 0) {
throw new Error("safeStorage backend changed and cannot migrate");
}
return clearDataAndRelaunch(electronSession);
}
private async consultUserConsentDegradedMode(backend: "plaintext" | "basic_text"): Promise<void> {
if (backend === "plaintext") {
// Sometimes we may have a working backend that for some reason does not support encryption at the moment.
// This may be because electron reported an incorrect backend or because of some known issues with the keyring itself.
// Or the environment specified `--storage-mode=force-plaintext`.
// In any case, when this happens, we give the user an option to use a weaker form of encryption.
const { response } = await dialog.showMessageBox({
title: _t("store|error|backend_no_encryption_title"),
message: _t("store|error|backend_no_encryption"),
detail: _t("store|error|backend_no_encryption_detail", {
backend: safeStorage.getSelectedStorageBackend(),
brand: global.vectorConfig.brand || "Element",
}),
type: "error",
buttons: [_t("action|cancel"), _t("store|error|unsupported_keyring_use_plaintext")],
defaultId: 0,
cancelId: 0,
});
if (response === 0) {
throw new Error("isEncryptionAvailable=false and user rejected plaintext");
}
} else {
// Electron did not identify a compatible encrypted backend, ask user for consent to degraded mode
const { response } = await dialog.showMessageBox({
title: _t("store|error|unsupported_keyring_title"),
message: _t("store|error|unsupported_keyring"),
detail: _t("store|error|unsupported_keyring_detail", {
brand: global.vectorConfig.brand || "Element",
link: "https://www.electronjs.org/docs/latest/api/safe-storage#safestoragegetselectedstoragebackend-linux",
}),
type: "error",
buttons: [_t("action|cancel"), _t("store|error|unsupported_keyring_use_basic_text")],
defaultId: 0,
cancelId: 0,
});
if (response === 0) {
throw new Error("safeStorage backend basic_text and user rejected it");
}
}
}
private recordSafeStorageBackend(backend: SafeStorageBackend): void {
this.set("safeStorageBackend", backend);
}
/**
* Linux support for upgrading the backend from basic_text to one of the encrypted backends,
* this is quite a tricky process as the backend is not known until the app is ready & cannot be changed once it is.
* 1. We restart the app in safeStorageBackendMigrate mode
* 2. Now that we are in the mode which our data is written in we decrypt the data, write it back in plaintext
* & restart back in default backend mode,
* 3. Finally, we load the plaintext data & encrypt it.
*/
private prepareMigrateBasicTextToPlaintext(): void {
console.info(`Starting safeStorage migration to ${safeStorage.getSelectedStorageBackend()}`);
this.set("safeStorageBackendMigrate", true);
relaunchApp();
}
private migrateBasicTextToPlaintext(): void {
const secrets = new SafeStorageWriter(this);
console.info("Performing safeStorage migration");
const data = this.get("safeStorage");
if (data) {
for (const key in data) {
this.set(secrets.getKey(key), secrets.get(key));
}
this.recordSafeStorageBackend("plaintext");
}
this.delete("safeStorageBackendMigrate");
relaunchApp();
}
private migratePlaintextToEncrypted(): void {
const secrets = new SafeStorageWriter(this);
const selectedSafeStorageBackend = safeStorage.getSelectedStorageBackend();
console.info(`Finishing safeStorage migration to ${selectedSafeStorageBackend}`);
const data = this.get("safeStorage");
if (data) {
for (const key in data) {
secrets.set(key, data[key]);
}
}
this.recordSafeStorageBackend(selectedSafeStorageBackend);
}
/**
* Get the stored secret for the key.
* Lazily migrates keys from keytar if they are not yet in the store.
*
* @param key The string key name.
*
* @returns A promise for the secret string.
*/
public async getSecret(key: string): Promise<string | undefined> {
await this.safeStorageReady();
let secret = this.secrets!.get(key);
if (secret) return secret;
try {
secret = await this.getSecretKeytar(key);
} catch (e) {
console.warn(`Failed to read data from keytar with key='${key}'`, e);
}
if (secret) {
console.debug("Migrating secret from keytar", key);
this.secrets!.set(key, secret);
}
return secret;
}
/**
* Add the secret for the key to the keychain.
* We write to both safeStorage & keytar to support downgrading the application.
*
* @param key The string key name.
* @param secret The string password.
*
* @returns A promise for the set password completion.
*/
public async setSecret(key: string, secret: string): Promise<void> {
await this.safeStorageReady();
this.secrets!.set(key, secret);
try {
await keytar.setPassword(KEYTAR_SERVICE, key, secret);
} catch (e) {
console.warn(`Failed to write safeStorage backwards-compatibility key='${key}' data to keytar`, e);
}
}
/**
* Delete the stored password for the key.
* Removes from safeStorage, keytar & keytar legacy.
*
* @param key The string key name.
*/
public async deleteSecret(key: string): Promise<void> {
await this.safeStorageReady();
this.secrets!.delete(key);
try {
await this.deleteSecretKeytar(key);
} catch (e) {
console.warn(`Failed to delete secret with key='${key}' from keytar`, e);
}
}
/**
* @deprecated will be removed in the near future
*/
private async getSecretKeytar(key: string): Promise<string | undefined> {
return (
(await keytar.getPassword(KEYTAR_SERVICE, key)) ??
(await keytar.getPassword(LEGACY_KEYTAR_SERVICE, key)) ??
undefined
);
}
/**
* @deprecated will be removed in the near future
*/
private async deleteSecretKeytar(key: string): Promise<void> {
await keytar.deletePassword(LEGACY_KEYTAR_SERVICE, key);
await keytar.deletePassword(KEYTAR_SERVICE, key);
}
}
export default Store;

View File

@@ -1,5 +1,5 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2024-2025 New Vector Ltd.
Copyright 2017 Karl Glatz <karl@glatz.biz>
Copyright 2017 OpenMarket Ltd
@@ -8,10 +8,10 @@ Please see LICENSE files in the repository root for full details.
*/
import { app, Tray, Menu, nativeImage } from "electron";
import { v5 as uuidv5 } from "uuid";
import { writeFile } from "node:fs/promises";
import pngToIco from "png-to-ico";
import path from "node:path";
import fs from "node:fs";
import { v5 as uuidv5 } from "uuid";
import { _t } from "./language-helper.js";
@@ -38,18 +38,13 @@ function toggleWin(): void {
}
}
interface IConfig {
icon_path: string; // eslint-disable-line camelcase
brand: string;
}
function getUuid(): string {
// The uuid field is optional and only needed on unsigned Windows packages where the executable path changes
// The hardcoded uuid is an arbitrary v4 uuid generated on https://www.uuidgenerator.net/version4
return global.vectorConfig["uuid"] || "eba84003-e499-4563-8e9d-166e34b5cc25";
}
export function create(config: IConfig): void {
export function create(config: (typeof global)["trayConfig"]): void {
// no trays on darwin
if (process.platform === "darwin" || trayIcon) return;
const defaultIcon = nativeImage.createFromPath(config.icon_path);
@@ -71,6 +66,7 @@ export function create(config: IConfig): void {
initApplicationMenu();
trayIcon.on("click", toggleWin);
// See also, badge.ts
let lastFavicon: string | null = null;
global.mainWindow?.webContents.on("page-favicon-updated", async function (ev, favicons) {
if (!favicons || favicons.length <= 0 || !favicons[0].startsWith("data:")) {
@@ -92,15 +88,17 @@ export function create(config: IConfig): void {
if (process.platform === "win32") {
try {
const icoPath = path.join(app.getPath("temp"), "win32_element_icon.ico");
fs.writeFileSync(icoPath, await pngToIco(newFavicon.toPNG()));
await writeFile(icoPath, await pngToIco(newFavicon.toPNG()));
newFavicon = nativeImage.createFromPath(icoPath);
} catch (e) {
console.error("Failed to make win32 ico", e);
}
// Always update the tray icon for Windows.
trayIcon?.setImage(newFavicon);
} else {
trayIcon?.setImage(newFavicon);
global.mainWindow?.setIcon(newFavicon);
}
trayIcon?.setImage(newFavicon);
global.mainWindow?.setIcon(newFavicon);
});
global.mainWindow?.webContents.on("page-title-updated", function (ev, title) {

View File

@@ -7,8 +7,11 @@ Please see LICENSE files in the repository root for full details.
import { app, autoUpdater, ipcMain } from "electron";
import fs from "node:fs/promises";
import os from "node:os";
import { getSquirrelExecutable } from "./squirrelhooks.js";
import { _t } from "./language-helper.js";
import { initialisePromise } from "./ipc.js";
const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000;
const INITIAL_UPDATE_DELAY_MS = 30 * 1000;
@@ -69,7 +72,8 @@ async function pollForUpdates(): Promise<void> {
}
export async function start(updateBaseUrl: string): Promise<void> {
if (!(await available(updateBaseUrl))) return;
if (!(await available())) return;
console.log(`Starting auto update with base URL: ${updateBaseUrl}`);
if (!updateBaseUrl.endsWith("/")) {
updateBaseUrl = updateBaseUrl + "/";
}
@@ -111,10 +115,15 @@ export async function start(updateBaseUrl: string): Promise<void> {
}
}
async function available(updateBaseUrl?: string): Promise<boolean> {
/**
* Check if auto update is available on this platform.
* Has a side effect of firing showToast on EOL platforms so must only be called once!
* @returns True if auto update is available
*/
async function available(): Promise<boolean> {
if (process.platform === "linux") {
// Auto update is not supported on Linux
console.log("Auto update not supported on this platform");
console.warn("Auto update not supported on this platform");
return false;
}
@@ -122,13 +131,42 @@ async function available(updateBaseUrl?: string): Promise<boolean> {
try {
await fs.access(getSquirrelExecutable());
} catch {
console.log("Squirrel not found, auto update not supported");
console.warn("Squirrel not found, auto update not supported");
return false;
}
}
// Otherwise we're either on macOS or Windows with Squirrel
return !!updateBaseUrl;
if (process.platform === "darwin") {
// OS release returns the Darwin kernel version, not the macOS version, see
// https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history to interpret it
const release = os.release();
const major = parseInt(release.split(".")[0], 10);
if (major < 21) {
// If the macOS version is too old for modern Electron support then disable auto update to prevent the app updating and bricking itself.
// The oldest macOS version supported by Chromium/Electron 38 is Monterey (12.x) which started with Darwin 21.0
initialisePromise.then(() => {
ipcMain.emit("showToast", {
title: _t("eol|title"),
description: _t("eol|no_more_updates", { brand: global.trayConfig.brand }),
});
});
console.warn("Auto update not supported, macOS version too old");
return false;
} else if (major < 22) {
// If the macOS version is EOL then show a warning message.
// The oldest macOS version still supported by Apple is Ventura (13.x) which started with Darwin 22.0
initialisePromise.then(() => {
ipcMain.emit("showToast", {
title: _t("eol|title"),
description: _t("eol|warning", { brand: global.trayConfig.brand }),
});
});
}
}
return true;
}
ipcMain.on("install_update", installUpdate);

View File

@@ -23,10 +23,10 @@ export async function randomArray(size: number): Promise<string> {
type JsonValue = null | string | number;
type JsonArray = Array<JsonValue | JsonObject | JsonArray>;
interface JsonObject {
export interface JsonObject {
[key: string]: JsonObject | JsonArray | JsonValue;
}
type Json = JsonArray | JsonObject;
export type Json = JsonArray | JsonObject;
/**
* Synchronously load a JSON file from the local filesystem.
@@ -34,6 +34,13 @@ type Json = JsonArray | JsonObject;
* @param paths - An array of path segments which will be joined using the system's path delimiter.
*/
export function loadJsonFile<T extends Json>(...paths: string[]): T {
const file = fs.readFileSync(path.join(...paths), { encoding: "utf-8" });
const joinedPaths = path.join(...paths);
if (!fs.existsSync(joinedPaths)) {
console.log(`Skipping nonexistent file: ${joinedPaths}`);
return {} as T;
}
const file = fs.readFileSync(joinedPaths, { encoding: "utf-8" });
return JSON.parse(file);
}

View File

@@ -11,7 +11,7 @@
"rootDir": "./src",
"declaration": true,
"typeRoots": ["src/@types", "node_modules/@types"],
"lib": ["es2022"],
"lib": ["es2022", "es2024.promise"],
"types": ["node"],
"strict": true
},

6454
yarn.lock

File diff suppressed because it is too large Load Diff