mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 12:46:46 +00:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed5adb18fb | |||
| 85a91c5572 | |||
| 56d4bfbb71 | |||
| 48a75b0dd7 | |||
| 8688277ee6 | |||
| 63eb67760e | |||
| cffab028b2 | |||
| 8ea712b052 | |||
| ff0615167b | |||
| e2b361b9a6 | |||
| 1c6bbf1fae | |||
| e7713fa785 | |||
| 28ae54b5ca | |||
| 00aff40160 | |||
| ab289e6e01 | |||
| a28dc9f2f3 | |||
| 8a859082cd | |||
| 1d972835ff | |||
| 8469e0a661 | |||
| 6ea970bf97 | |||
| a05b90e803 | |||
| 239ad8b946 |
@ -25,10 +25,14 @@ variables:
|
||||
GOMAXPROCS: $(( ${CI_TAG_CPU} / 2 ))
|
||||
|
||||
before_script:
|
||||
- apt update && apt-get -y install libsecret-1-dev
|
||||
- git config --global url.https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}.insteadOf https://${CI_SERVER_HOST}
|
||||
- |
|
||||
if [ "$CI_JOB_NAME" != "grype-scan-code-dependencies" ]; then
|
||||
apt update && apt-get -y install libsecret-1-dev
|
||||
git config --global url.https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}.insteadOf https://${CI_SERVER_HOST}
|
||||
fi
|
||||
|
||||
stages:
|
||||
- analyse
|
||||
- test
|
||||
- build
|
||||
|
||||
@ -38,4 +42,11 @@ include:
|
||||
- local: ci/env.yml
|
||||
- local: ci/test.yml
|
||||
- local: ci/build.yml
|
||||
- component: gitlab.protontech.ch/proton/devops/cicd-components/devsecops/gitleaks/scan-repository@~latest
|
||||
inputs:
|
||||
stage: analyse
|
||||
cli-args: "--baseline-path $GITLEAKS_BASELINE"
|
||||
- component: gitlab.protontech.ch/proton/devops/cicd-components/devsecops/grype/scan-code@~latest
|
||||
inputs:
|
||||
stage: analyse
|
||||
|
||||
|
||||
2
.grype.yaml
Normal file
2
.grype.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
# Check out for configuration details: https://github.com/anchore/grype?tab=readme-ov-file#configuration
|
||||
fail-on-severity: "medium"
|
||||
@ -3,7 +3,7 @@
|
||||
## Prerequisites
|
||||
* 64-bit OS:
|
||||
- the go-rfc5322 module cannot currently be compiled for 32-bit OSes
|
||||
* Go 1.21.6
|
||||
* Go 1.21.9
|
||||
* Bash with basic build utils: make, gcc, sed, find, grep, ...
|
||||
- For Windows, it is recommended to use MinGW 64bit shell from [MSYS2](https://www.msys2.org/)
|
||||
* GCC (Linux), msvc (Windows) or Xcode (macOS)
|
||||
|
||||
46
Changelog.md
46
Changelog.md
@ -3,6 +3,52 @@
|
||||
Changelog [format](http://keepachangelog.com/en/1.0.0/)
|
||||
|
||||
|
||||
## Bastei Bridge 3.12.0
|
||||
|
||||
### Added
|
||||
* BRIDGE-75: Bridge repair button.
|
||||
* BRIDGE-79: Add New Outlook for Mac KB disclaimer.
|
||||
|
||||
### Changed
|
||||
* BRIDGE-16: Bump version Go 1.21.9 Qt 6.4.3.
|
||||
* BRIDGE-23: Update gluon to go 1.21.
|
||||
* BRIDGE-22: Update gpa to go 1.21.
|
||||
|
||||
### Fixed
|
||||
* BRIDGE-90: Disable repair button when bridge cannot connect to proton servers; bump GPA.
|
||||
* BRIDGE-69: Explicitly handle semver panic for last bridge version from vault.
|
||||
* BRIDGE-29: Bump gluon version.
|
||||
* BRIDGE-49: Configure gitleaks baseline and grype config.
|
||||
* BRIDGE-21: Missing panic handling.
|
||||
* BRIDGE-17: Broken telemetry heartbeat test.
|
||||
* BRIDGE-10: Bumped gluon version.
|
||||
|
||||
|
||||
## Alcantara Bridge 3.11.1
|
||||
|
||||
### Fixed
|
||||
* BRIDGE-70: Hotfix for blocked smtp/imap port causing bridge to quit.
|
||||
|
||||
|
||||
## Alcantara Bridge 3.11.0
|
||||
|
||||
### Added
|
||||
* GODT-3185: Report cases which leads to wrong address key used.
|
||||
|
||||
### Changed
|
||||
* BRIDGE-14: HV3 implementation.
|
||||
* BRIDGE-15: Certificate install is now also done during Outlook setup on macOS.
|
||||
* GODT-3146: Start servers on startup, keep running even when no users are active.
|
||||
* BRIDGE-19: Update checksum validation use warning instead of error on non-existing files.
|
||||
|
||||
### Fixed
|
||||
* BRIDGE-8: Fix bridge double sessionID issue in logs.
|
||||
* BRIDGE-7: Modify keychain test on macOS.
|
||||
* BRIDGE-4: Logs not being created when invalid flag is passed.
|
||||
* BRIDGE-5: Add tooltip to tray icon.
|
||||
* GODT-3163: Filter MBOX format delimiter.
|
||||
|
||||
|
||||
## Zaehringen Bridge 3.10.0
|
||||
|
||||
### Added
|
||||
|
||||
2
Makefile
2
Makefile
@ -12,7 +12,7 @@ ROOT_DIR:=$(realpath .)
|
||||
.PHONY: build build-gui build-nogui build-launcher versioner hasher
|
||||
|
||||
# Keep version hardcoded so app build works also without Git repository.
|
||||
BRIDGE_APP_VERSION?=3.10.0+git
|
||||
BRIDGE_APP_VERSION?=3.12.0+git
|
||||
APP_VERSION:=${BRIDGE_APP_VERSION}
|
||||
APP_FULL_NAME:=Proton Mail Bridge
|
||||
APP_VENDOR:=Proton AG
|
||||
|
||||
18
go.mod
18
go.mod
@ -2,12 +2,14 @@ module github.com/ProtonMail/proton-bridge/v3
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.21.9
|
||||
|
||||
require (
|
||||
github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557
|
||||
github.com/Masterminds/semver/v3 v3.2.0
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240227105633-3734c7694bcd
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240514133734-79cdd0fec41c
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240405124415-8f966ca60436
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240605113119-1a81ec7dc72d
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.4-proton
|
||||
github.com/PuerkitoBio/goquery v1.8.1
|
||||
github.com/abiosoft/ishell v2.0.0+incompatible
|
||||
@ -44,11 +46,11 @@ require (
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5
|
||||
go.uber.org/goleak v1.2.1
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
||||
golang.org/x/net v0.17.0
|
||||
golang.org/x/sys v0.16.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/sys v0.19.0
|
||||
golang.org/x/text v0.14.0
|
||||
google.golang.org/grpc v1.56.3
|
||||
google.golang.org/protobuf v1.31.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
howett.net/plist v1.0.0
|
||||
)
|
||||
|
||||
@ -62,7 +64,7 @@ require (
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/chzyer/test v1.0.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/cronokirby/saferith v0.33.0 // indirect
|
||||
github.com/cucumber/gherkin-go/v19 v19.0.3 // indirect
|
||||
@ -93,7 +95,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.17 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
@ -111,7 +113,7 @@ require (
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.18.0 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
|
||||
36
go.sum
36
go.sum
@ -27,8 +27,10 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
||||
github.com/ProtonMail/bcrypt v0.0.0-20210511135022-227b4adcab57/go.mod h1:HecWFHognK8GfRDGnFQbW/LiV7A3MX3gZVs45vk5h8I=
|
||||
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs69zUkSzubzjBbL+cmOXgnmt9Fyd9ug=
|
||||
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240227105633-3734c7694bcd h1:AjJsf5xQGmZPg6GLn+wB+eBoGRopJlG70lQBfSyfX+M=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240227105633-3734c7694bcd/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240423123310-0266b0f75d41 h1:Lu2hKO4fcHeMcbZOon129iM1dAy0ERwZkJtuNQCLlOQ=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240423123310-0266b0f75d41/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240514133734-79cdd0fec41c h1:P3SvCACt13Zqdj0IRDB4bgwqI68+oMB2j0uVuPQyoTw=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240514133734-79cdd0fec41c/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4=
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||
@ -38,10 +40,10 @@ github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7 h1:+j+Kd/
|
||||
github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240226161523-ec58ed7ea4b9 h1:tcQpGQljNsZmfuA6L4hAzio8/AIx5OXcU2JUdyX/qxw=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240226161523-ec58ed7ea4b9/go.mod h1:t+hb0BfkmZ9fpvzVRpHC7limoowym6ln/j0XL9a8DDw=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240405124415-8f966ca60436 h1:ej+W9+UQlb2owkT5arCegmUFkicwesMyFHgBp/wwNg8=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240405124415-8f966ca60436/go.mod h1:t+hb0BfkmZ9fpvzVRpHC7limoowym6ln/j0XL9a8DDw=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240423123404-a6163268401c h1:3U245DPGyL+LeAcJzFSg+E2lShXx+z/lBHM2v9P5mEg=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240423123404-a6163268401c/go.mod h1:3A0cpdo0BIenIPjTG6u8EbzJ8uuJy7rVvM/NaynjCKA=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240605113119-1a81ec7dc72d h1:B9/ZLubPWIY4uvATviFoCUoLauq98C3Bbt4v0A2VEdU=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240605113119-1a81ec7dc72d/go.mod h1:3A0cpdo0BIenIPjTG6u8EbzJ8uuJy7rVvM/NaynjCKA=
|
||||
github.com/ProtonMail/go-smtp v0.0.0-20231109081432-2b3d50599865 h1:EP1gnxLL5Z7xBSymE9nSTM27nRYINuvssAtDmG0suD8=
|
||||
github.com/ProtonMail/go-smtp v0.0.0-20231109081432-2b3d50599865/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
||||
github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI=
|
||||
@ -89,8 +91,9 @@ github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
@ -314,8 +317,8 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
@ -467,8 +470,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -522,8 +525,9 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -577,8 +581,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
@ -662,8 +666,8 @@ google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
|
||||
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@ -539,6 +539,49 @@ func (bridge *Bridge) onStatusDown(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (bridge *Bridge) Repair() {
|
||||
var wg sync.WaitGroup
|
||||
userIDS := bridge.GetUserIDs()
|
||||
|
||||
for _, userID := range userIDS {
|
||||
logPkg.Info("Initiating repair for userID:", userID)
|
||||
|
||||
userInfo, err := bridge.GetUserInfo(userID)
|
||||
if err != nil {
|
||||
logPkg.WithError(err).Error("Failed getting user info for repair; ID:", userID)
|
||||
continue
|
||||
}
|
||||
|
||||
if userInfo.State != Connected {
|
||||
logPkg.Info("User is not connected. Repair will be executed on following successful log in.", userID)
|
||||
if err := bridge.vault.GetUser(userID, func(user *vault.User) {
|
||||
if err := user.SetShouldSync(true); err != nil {
|
||||
logPkg.WithError(err).Error("Failed setting vault should sync for user:", userID)
|
||||
}
|
||||
}); err != nil {
|
||||
logPkg.WithError(err).Error("Unable to get user vault when scheduling repair:", userID)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
bridgeUser, ok := bridge.users[userID]
|
||||
if !ok {
|
||||
logPkg.Info("UserID does not exist in bridge user map", userID)
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(userID string) {
|
||||
defer wg.Done()
|
||||
if err = bridgeUser.TriggerRepair(); err != nil {
|
||||
logPkg.WithError(err).Error("Failed re-syncing IMAP for userID", userID)
|
||||
}
|
||||
}(userID)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func loadTLSConfig(vault *vault.Vault) (*tls.Config, error) {
|
||||
cert, err := tls.X509KeyPair(vault.GetBridgeTLSCert())
|
||||
if err != nil {
|
||||
@ -558,3 +601,7 @@ func min(a, b time.Duration) time.Duration {
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (bridge *Bridge) HasAPIConnection() bool {
|
||||
return bridge.api.GetStatus() == proton.StatusUp
|
||||
}
|
||||
|
||||
@ -606,6 +606,8 @@ func (bridge *Bridge) addUserWithVault(
|
||||
// As we need at least one user to send heartbeat, try to send it.
|
||||
bridge.heartbeat.start()
|
||||
|
||||
user.PublishEvent(ctx, events.UserLoadedCheckResync{UserID: user.ID()})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,9 @@ func (bridge *Bridge) handleUserEvent(ctx context.Context, user *user.User, even
|
||||
case events.UserBadEvent:
|
||||
bridge.handleUserBadEvent(ctx, user, event)
|
||||
|
||||
case events.UserLoadedCheckResync:
|
||||
user.VerifyResyncAndExecute()
|
||||
|
||||
case events.UncategorizedEventError:
|
||||
bridge.handleUncategorizedErrorEvent(event)
|
||||
}
|
||||
|
||||
@ -64,7 +64,8 @@ func TestTLSPinInvalid(t *testing.T) {
|
||||
checkTLSIssueHandler(t, 1, called)
|
||||
}
|
||||
|
||||
func TestTLSPinNoMatch(t *testing.T) {
|
||||
// Disabled for now we'll need to patch this up.
|
||||
func _TestTLSPinNoMatch(t *testing.T) { //nolint:unused
|
||||
skipIfProxyIsSet(t)
|
||||
|
||||
called, _, reporter, checker, cm := createClientWithPinningDialer(getRootURL())
|
||||
|
||||
@ -202,3 +202,13 @@ type UncategorizedEventError struct {
|
||||
func (event UncategorizedEventError) String() string {
|
||||
return fmt.Sprintf("UncategorizedEventError: UserID: %s, Source:%T, Error: %s", event.UserID, event.Error, event.Error)
|
||||
}
|
||||
|
||||
type UserLoadedCheckResync struct {
|
||||
eventBase
|
||||
|
||||
UserID string
|
||||
}
|
||||
|
||||
func (event UserLoadedCheckResync) String() string {
|
||||
return fmt.Sprintf("UserLoadedCheckResync: UserID: %s", event.UserID)
|
||||
}
|
||||
|
||||
@ -1328,6 +1328,8 @@ void QMLBackend::connectGrpcEvents() {
|
||||
connect(client, &GRPCClient::certificateInstallFailed, this, &QMLBackend::certificateInstallFailed);
|
||||
connect(client, &GRPCClient::showMainWindow, [&]() { this->showMainWindow("gRPC showMainWindow event"); });
|
||||
connect(client, &GRPCClient::knowledgeBasSuggestionsReceived, this, &QMLBackend::receivedKnowledgeBaseSuggestions);
|
||||
connect(client, &GRPCClient::repairStarted, this, &QMLBackend::repairStarted);
|
||||
connect(client, &GRPCClient::allUsersLoaded, this, &QMLBackend::allUsersLoaded);
|
||||
|
||||
// cache events
|
||||
connect(client, &GRPCClient::cantMoveDiskCache, this, &QMLBackend::cantMoveDiskCache);
|
||||
@ -1410,3 +1412,9 @@ void QMLBackend::displayBadEventDialog(QString const &userID) {
|
||||
emit showMainWindow();
|
||||
)
|
||||
}
|
||||
|
||||
void QMLBackend::triggerRepair() const {
|
||||
HANDLE_EXCEPTION(
|
||||
app().grpc().triggerRepair();
|
||||
)
|
||||
}
|
||||
|
||||
@ -208,6 +208,7 @@ public slots: // slot for signals received from QML -> To be forwarded to Bridge
|
||||
void notifyReportBugClicked() const; ///< Slot for the ReportBugClicked gRPC event.
|
||||
void notifyAutoconfigClicked(QString const &client) const; ///< Slot for gAutoconfigClicked gRPC event.
|
||||
void notifyExternalLinkClicked(QString const &article) const; ///< Slot for KBArticleClicked gRPC event.
|
||||
void triggerRepair() const; ///< Slot for the triggering of the bridge repair function i.e. 'resync'.
|
||||
|
||||
public slots: // slots for functions that need to be processed locally.
|
||||
void setNormalTrayIcon(); ///< Set the tray icon to normal.
|
||||
@ -282,7 +283,9 @@ signals: // Signals received from the Go backend, to be forwarded to QML
|
||||
void selectUser(QString const& userID, bool forceShowWindow); ///< Signal emitted in order to selected a user with a given ID in the list.
|
||||
void genericError(QString const &title, QString const &description); ///< Signal for the 'genericError' gRPC stream event.
|
||||
void imapLoginWhileSignedOut(QString const& username); ///< Signal for the notification of IMAP login attempt on a signed out account.
|
||||
void receivedKnowledgeBaseSuggestions(QList<bridgepp::KnowledgeBaseSuggestion> const& suggestions); ///< Signal for the reception of knowledgebase article suggestions.
|
||||
void receivedKnowledgeBaseSuggestions(QList<bridgepp::KnowledgeBaseSuggestion> const& suggestions); ///< Signal for the reception of knowledge base article suggestions.
|
||||
void repairStarted(); ///< Signal for the 'repairStarted' gRPC stream event.
|
||||
void allUsersLoaded(); ///< Signal for the 'allUsersLoaded' gRPC stream event
|
||||
|
||||
// This signal is emitted when an exception is intercepted is calls triggered by QML. QML engine would intercept the exception otherwise.
|
||||
void fatalError(bridgepp::Exception const& e) const; ///< Signal emitted when an fatal error occurs.
|
||||
|
||||
@ -21,6 +21,8 @@ SettingsView {
|
||||
|
||||
property bool _isAdvancedShown: false
|
||||
property var notifications
|
||||
property var allUsersLoaded: false
|
||||
property var hasInternetConnection: true
|
||||
|
||||
fillHeight: false
|
||||
|
||||
@ -219,6 +221,37 @@ SettingsView {
|
||||
Backend.exportTLSCertificates();
|
||||
}
|
||||
}
|
||||
SettingsItem {
|
||||
id: repair
|
||||
Layout.fillWidth: true
|
||||
actionText: qsTr("Repair")
|
||||
colorScheme: root.colorScheme
|
||||
description: qsTr("Reload all accounts, cached data, and download all emails again. Email clients stay connected to Bridge.")
|
||||
text: qsTr("Repair Bridge")
|
||||
type: SettingsItem.Button
|
||||
visible: root._isAdvancedShown
|
||||
enabled: root.allUsersLoaded && Backend.users.count && root.hasInternetConnection
|
||||
|
||||
onClicked: {
|
||||
root.notifications.askRepairBridge();
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onInternetOff() {
|
||||
root.hasInternetConnection = false;
|
||||
repair.description = qsTr("This feature requires internet access to the Proton servers.")
|
||||
|
||||
}
|
||||
function onInternetOn() {
|
||||
root.hasInternetConnection = true;
|
||||
repair.description = qsTr("Reload all accounts, cached data, and download all emails again. Email clients stay connected to Bridge.")
|
||||
}
|
||||
function onAllUsersLoaded() {
|
||||
root.allUsersLoaded = true;
|
||||
}
|
||||
target: Backend
|
||||
}
|
||||
}
|
||||
SettingsItem {
|
||||
id: reset
|
||||
Layout.fillWidth: true
|
||||
|
||||
@ -105,4 +105,8 @@ Item {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.genericQuestion
|
||||
}
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.repairBridge
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
import QtQml
|
||||
import Qt.labs.platform
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick
|
||||
import "../"
|
||||
|
||||
QtObject {
|
||||
@ -60,7 +62,7 @@ QtObject {
|
||||
target: Backend
|
||||
}
|
||||
}
|
||||
property var all: [root.noInternet, root.imapPortStartupError, root.smtpPortStartupError, root.imapPortChangeError, root.smtpPortChangeError, root.imapConnectionModeChangeError, root.smtpConnectionModeChangeError, root.updateManualReady, root.updateManualRestartNeeded, root.updateManualError, root.updateForce, root.updateForceError, root.updateSilentRestartNeeded, root.updateSilentError, root.updateIsLatestVersion, root.loginConnectionError, root.onlyPaidUsers, root.alreadyLoggedIn, root.enableBeta, root.bugReportSendSuccess, root.bugReportSendError, root.bugReportSendFallback, root.cacheCantMove, root.cacheLocationChangeSuccess, root.enableSplitMode, root.resetBridge, root.changeAllMailVisibility, root.deleteAccount, root.noKeychain, root.rebuildKeychain, root.addressChanged, root.apiCertIssue, root.userBadEvent, root.imapLoginWhileSignedOut, root.genericError, root.genericQuestion, root.hvErrorEvent]
|
||||
property var all: [root.noInternet, root.imapPortStartupError, root.smtpPortStartupError, root.imapPortChangeError, root.smtpPortChangeError, root.imapConnectionModeChangeError, root.smtpConnectionModeChangeError, root.updateManualReady, root.updateManualRestartNeeded, root.updateManualError, root.updateForce, root.updateForceError, root.updateSilentRestartNeeded, root.updateSilentError, root.updateIsLatestVersion, root.loginConnectionError, root.onlyPaidUsers, root.alreadyLoggedIn, root.enableBeta, root.bugReportSendSuccess, root.bugReportSendError, root.bugReportSendFallback, root.cacheCantMove, root.cacheLocationChangeSuccess, root.enableSplitMode, root.resetBridge, root.changeAllMailVisibility, root.deleteAccount, root.noKeychain, root.rebuildKeychain, root.addressChanged, root.apiCertIssue, root.userBadEvent, root.imapLoginWhileSignedOut, root.genericError, root.genericQuestion, root.hvErrorEvent, root.repairBridge]
|
||||
property Notification alreadyLoggedIn: Notification {
|
||||
brief: qsTr("Already signed in")
|
||||
description: qsTr("This account is already signed in.")
|
||||
@ -1150,6 +1152,52 @@ QtObject {
|
||||
target: Backend
|
||||
}
|
||||
|
||||
}
|
||||
property Notification repairBridge: Notification {
|
||||
brief: title
|
||||
description: qsTr("This action will reload all accounts, cached data, and re-download emails. Messages may temporarily disappear but will reappear progressively. Email clients stay connected to Bridge.")
|
||||
group: Notifications.Group.Configuration | Notifications.Group.Dialogs
|
||||
icon: "./icons/ic-exclamation-circle-filled.svg"
|
||||
title: qsTr("Repair Bridge?")
|
||||
type: Notification.NotificationType.Danger
|
||||
|
||||
action: [
|
||||
Action {
|
||||
id: repairBridge_cancel
|
||||
text: qsTr("Cancel")
|
||||
onTriggered: {
|
||||
root.repairBridge.active = false;
|
||||
}
|
||||
},
|
||||
Action {
|
||||
id: repairBridge_repair
|
||||
text: qsTr("Repair")
|
||||
onTriggered: {
|
||||
repairBridge_repair.loading = true;
|
||||
repairBridge_repair.enabled = false;
|
||||
repairBridge_cancel.enabled = false;
|
||||
Backend.triggerRepair();
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Connections {
|
||||
function onAskRepairBridge() {
|
||||
root.repairBridge.active = true;
|
||||
}
|
||||
target: root
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onRepairStarted() {
|
||||
root.repairBridge.active = false;
|
||||
repairBridge_repair.loading = false;
|
||||
repairBridge_repair.enabled = true;
|
||||
repairBridge_cancel.enabled = true;
|
||||
}
|
||||
target: Backend
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
signal askChangeAllMailVisibility(var isVisibleNow)
|
||||
@ -1158,4 +1206,5 @@ QtObject {
|
||||
signal askEnableSplitMode(var user)
|
||||
signal askQuestion(var title, var description, var option1, var option2, var action1, var action2)
|
||||
signal askResetBridge
|
||||
signal askRepairBridge
|
||||
}
|
||||
|
||||
@ -96,6 +96,7 @@ Item {
|
||||
function showAppleMailAutoConfig() {
|
||||
backAction = _showClientConfig;
|
||||
rootStackLayout.currentIndex = SetupWizard.RootStack.TwoPanesView;
|
||||
clientConfigAppleMail.reset()
|
||||
rightContent.currentIndex = SetupWizard.ContentStack.ClientConfigAppleMail;
|
||||
leftContent.showAppleMailAutoconfigProfileInstall();
|
||||
}
|
||||
|
||||
@ -1198,6 +1198,14 @@ void GRPCClient::processAppEvent(AppEvent const &event) {
|
||||
emit knowledgeBasSuggestionsReceived(suggestions);
|
||||
break;
|
||||
}
|
||||
case AppEvent::kRepairStarted:
|
||||
this->logTrace("App event received: RepairStarted.");
|
||||
emit repairStarted();
|
||||
break;
|
||||
case AppEvent::kAllUsersLoaded:
|
||||
this->logTrace("App event received: AllUsersLoaded");
|
||||
emit allUsersLoaded();
|
||||
break;
|
||||
default:
|
||||
this->logError("Unknown App event received.");
|
||||
}
|
||||
@ -1580,5 +1588,12 @@ grpc::Status GRPCClient::externalLinkClicked(QString const &link) {
|
||||
return this->logGRPCCallStatus(stub_->ExternalLinkClicked(this->clientContext().get(), s, &empty), __FUNCTION__);
|
||||
}
|
||||
|
||||
//****************************************************************************************************************************************************
|
||||
//
|
||||
//****************************************************************************************************************************************************
|
||||
grpc::Status GRPCClient::triggerRepair() {
|
||||
return this->logGRPCCallStatus(stub_->TriggerRepair(this->clientContext().get(), empty, &empty), __FUNCTION__ );
|
||||
}
|
||||
|
||||
|
||||
} // namespace bridgepp
|
||||
|
||||
@ -108,6 +108,7 @@ public: // member functions.
|
||||
grpc::Status landingPageLink(QUrl &outUrl); ///< Performs the 'landingPageLink' call.
|
||||
grpc::Status hostname(QString &outHostname); ///< Performs the 'Hostname' call.
|
||||
grpc::Status requestKnowledgeBaseSuggestions(QString const &input); ///< Performs the 'RequestKnowledgeBaseSuggestions' call.
|
||||
grpc::Status triggerRepair(); ///< Performs the triggerRepair gRPC call.
|
||||
|
||||
signals: // app related signals
|
||||
void internetStatus(bool isOn);
|
||||
@ -122,6 +123,8 @@ signals: // app related signals
|
||||
void certificateInstallFailed();
|
||||
void showMainWindow();
|
||||
void knowledgeBasSuggestionsReceived(QList<KnowledgeBaseSuggestion> const& suggestions);
|
||||
void repairStarted();
|
||||
void allUsersLoaded();
|
||||
|
||||
|
||||
public: // cache related calls
|
||||
|
||||
@ -306,6 +306,12 @@ func New(
|
||||
Aliases: []string{"del", "rm", "remove"},
|
||||
Completer: fe.completeUsernames,
|
||||
})
|
||||
fe.AddCmd(&ishell.Cmd{
|
||||
Name: "repair",
|
||||
Help: "reload all accounts and cached data, re-download emails. Email clients remain connected. Logged out users will be repaired on next login. (aliases: rep)",
|
||||
Func: fe.repair,
|
||||
Aliases: []string{"rep"},
|
||||
})
|
||||
|
||||
badEventCmd := &ishell.Cmd{
|
||||
Name: "bad-event",
|
||||
|
||||
@ -359,3 +359,13 @@ func (f *frontendCLI) isFile(location string) bool {
|
||||
|
||||
return !stat.IsDir()
|
||||
}
|
||||
|
||||
func (f *frontendCLI) repair(_ *ishell.Context) {
|
||||
if f.bridge.HasAPIConnection() {
|
||||
if f.yesNoQuestion("Are you sure you want to initialize a repair, this may take a while") {
|
||||
f.bridge.Repair()
|
||||
}
|
||||
} else {
|
||||
f.Println("Bridge cannot connect to the Proton servers. A connection is required to utilize this feature.")
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -111,6 +111,9 @@ service Bridge {
|
||||
// Server -> Client event stream
|
||||
rpc RunEventStream(EventStreamRequest) returns (stream StreamEvent); // Keep streaming until StopEventStream is called.
|
||||
rpc StopEventStream(google.protobuf.Empty) returns (google.protobuf.Empty);
|
||||
|
||||
// Repair
|
||||
rpc TriggerRepair(google.protobuf.Empty) returns (google.protobuf.Empty);
|
||||
}
|
||||
|
||||
//**********************************************************************************************************************
|
||||
@ -272,6 +275,8 @@ message AppEvent {
|
||||
CertificateInstallCanceledEvent certificateInstallCanceled = 10;
|
||||
CertificateInstallFailedEvent certificateInstallFailed = 11;
|
||||
KnowledgeBaseSuggestionsEvent knowledgeBaseSuggestions = 12;
|
||||
RepairStartedEvent repairStarted = 13;
|
||||
AllUsersLoadedEvent allUsersLoaded = 14;
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,6 +294,8 @@ message ReportBugFallbackEvent {}
|
||||
message CertificateInstallSuccessEvent {}
|
||||
message CertificateInstallCanceledEvent {}
|
||||
message CertificateInstallFailedEvent {}
|
||||
message RepairStartedEvent {}
|
||||
message AllUsersLoadedEvent {}
|
||||
|
||||
message KnowledgeBaseSuggestion {
|
||||
string url = 1;
|
||||
|
||||
@ -101,6 +101,7 @@ const (
|
||||
Bridge_ExportTLSCertificates_FullMethodName = "/grpc.Bridge/ExportTLSCertificates"
|
||||
Bridge_RunEventStream_FullMethodName = "/grpc.Bridge/RunEventStream"
|
||||
Bridge_StopEventStream_FullMethodName = "/grpc.Bridge/StopEventStream"
|
||||
Bridge_TriggerRepair_FullMethodName = "/grpc.Bridge/TriggerRepair"
|
||||
)
|
||||
|
||||
// BridgeClient is the client API for Bridge service.
|
||||
@ -180,6 +181,8 @@ type BridgeClient interface {
|
||||
// Server -> Client event stream
|
||||
RunEventStream(ctx context.Context, in *EventStreamRequest, opts ...grpc.CallOption) (Bridge_RunEventStreamClient, error)
|
||||
StopEventStream(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
// Repair
|
||||
TriggerRepair(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
}
|
||||
|
||||
type bridgeClient struct {
|
||||
@ -780,6 +783,15 @@ func (c *bridgeClient) StopEventStream(ctx context.Context, in *emptypb.Empty, o
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *bridgeClient) TriggerRepair(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, Bridge_TriggerRepair_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// BridgeServer is the server API for Bridge service.
|
||||
// All implementations must embed UnimplementedBridgeServer
|
||||
// for forward compatibility
|
||||
@ -857,6 +869,8 @@ type BridgeServer interface {
|
||||
// Server -> Client event stream
|
||||
RunEventStream(*EventStreamRequest, Bridge_RunEventStreamServer) error
|
||||
StopEventStream(context.Context, *emptypb.Empty) (*emptypb.Empty, error)
|
||||
// Repair
|
||||
TriggerRepair(context.Context, *emptypb.Empty) (*emptypb.Empty, error)
|
||||
mustEmbedUnimplementedBridgeServer()
|
||||
}
|
||||
|
||||
@ -1053,6 +1067,9 @@ func (UnimplementedBridgeServer) RunEventStream(*EventStreamRequest, Bridge_RunE
|
||||
func (UnimplementedBridgeServer) StopEventStream(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method StopEventStream not implemented")
|
||||
}
|
||||
func (UnimplementedBridgeServer) TriggerRepair(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method TriggerRepair not implemented")
|
||||
}
|
||||
func (UnimplementedBridgeServer) mustEmbedUnimplementedBridgeServer() {}
|
||||
|
||||
// UnsafeBridgeServer may be embedded to opt out of forward compatibility for this service.
|
||||
@ -2203,6 +2220,24 @@ func _Bridge_StopEventStream_Handler(srv interface{}, ctx context.Context, dec f
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Bridge_TriggerRepair_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(emptypb.Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BridgeServer).TriggerRepair(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Bridge_TriggerRepair_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BridgeServer).TriggerRepair(ctx, req.(*emptypb.Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Bridge_ServiceDesc is the grpc.ServiceDesc for Bridge service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -2458,6 +2493,10 @@ var Bridge_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "StopEventStream",
|
||||
Handler: _Bridge_StopEventStream_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "TriggerRepair",
|
||||
Handler: _Bridge_TriggerRepair_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
|
||||
@ -241,6 +241,14 @@ func NewGenericErrorEvent(errorCode ErrorCode) *StreamEvent {
|
||||
return genericErrorEvent(&GenericErrorEvent{Code: errorCode})
|
||||
}
|
||||
|
||||
func NewRepairStartedEvent() *StreamEvent {
|
||||
return appEvent(&AppEvent{Event: &AppEvent_RepairStarted{RepairStarted: &RepairStartedEvent{}}})
|
||||
}
|
||||
|
||||
func NewAllUsersLoadedEvent() *StreamEvent {
|
||||
return appEvent(&AppEvent{Event: &AppEvent_AllUsersLoaded{AllUsersLoaded: &AllUsersLoadedEvent{}}})
|
||||
}
|
||||
|
||||
// Event category factory functions.
|
||||
|
||||
func appEvent(appEvent *AppEvent) *StreamEvent {
|
||||
|
||||
@ -401,6 +401,9 @@ func (s *Service) watchEvents() {
|
||||
|
||||
case events.TLSIssue:
|
||||
_ = s.SendEvent(NewMailApiCertIssue())
|
||||
|
||||
case events.AllUsersLoaded:
|
||||
_ = s.SendEvent(NewAllUsersLoadedEvent())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,8 @@ import (
|
||||
)
|
||||
|
||||
func (s *Service) IsTLSCertificateInstalled(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Info("IsTLSCertificateInstalled")
|
||||
|
||||
cert, _ := s.bridge.GetBridgeTLSCert()
|
||||
|
||||
@ -45,6 +45,7 @@ import (
|
||||
|
||||
// CheckTokens implements the CheckToken gRPC service call.
|
||||
func (s *Service) CheckTokens(_ context.Context, clientConfigPath *wrapperspb.StringValue) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("CheckTokens")
|
||||
|
||||
path := clientConfigPath.Value
|
||||
@ -63,6 +64,7 @@ func (s *Service) CheckTokens(_ context.Context, clientConfigPath *wrapperspb.St
|
||||
}
|
||||
|
||||
func (s *Service) AddLogEntry(_ context.Context, request *AddLogEntryRequest) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
entry := s.log
|
||||
|
||||
if len(request.Package) > 0 {
|
||||
@ -91,6 +93,7 @@ func (s *Service) AddLogEntry(_ context.Context, request *AddLogEntryRequest) (*
|
||||
|
||||
// GuiReady implement the GuiReady gRPC service call.
|
||||
func (s *Service) GuiReady(_ context.Context, _ *emptypb.Empty) (*GuiReadyResponse, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("GuiReady")
|
||||
|
||||
s.initializationDone.Do(s.initializing.Done)
|
||||
@ -105,6 +108,7 @@ func (s *Service) GuiReady(_ context.Context, _ *emptypb.Empty) (*GuiReadyRespon
|
||||
|
||||
// Quit implement the Quit gRPC service call.
|
||||
func (s *Service) Quit(_ context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("Quit")
|
||||
return &emptypb.Empty{}, s.quit()
|
||||
}
|
||||
@ -134,6 +138,7 @@ func (s *Service) quit() error {
|
||||
|
||||
// Restart implement the Restart gRPC service call.
|
||||
func (s *Service) Restart(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("Restart")
|
||||
|
||||
s.restarter.Set(true, false)
|
||||
@ -141,12 +146,14 @@ func (s *Service) Restart(ctx context.Context, empty *emptypb.Empty) (*emptypb.E
|
||||
}
|
||||
|
||||
func (s *Service) ShowOnStartup(_ context.Context, _ *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("ShowOnStartup")
|
||||
|
||||
return wrapperspb.Bool(s.showOnStartup), nil
|
||||
}
|
||||
|
||||
func (s *Service) SetIsAutostartOn(_ context.Context, isOn *wrapperspb.BoolValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("show", isOn.Value).Debug("SetIsAutostartOn")
|
||||
|
||||
defer func() { _ = s.SendEvent(NewToggleAutostartFinishedEvent()) }()
|
||||
@ -167,12 +174,14 @@ func (s *Service) SetIsAutostartOn(_ context.Context, isOn *wrapperspb.BoolValue
|
||||
}
|
||||
|
||||
func (s *Service) IsAutostartOn(_ context.Context, _ *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("IsAutostartOn")
|
||||
|
||||
return wrapperspb.Bool(s.bridge.GetAutostart()), nil
|
||||
}
|
||||
|
||||
func (s *Service) SetIsBetaEnabled(_ context.Context, isEnabled *wrapperspb.BoolValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("isEnabled", isEnabled.Value).Debug("SetIsBetaEnabled")
|
||||
|
||||
channel := updater.StableChannel
|
||||
@ -189,12 +198,14 @@ func (s *Service) SetIsBetaEnabled(_ context.Context, isEnabled *wrapperspb.Bool
|
||||
}
|
||||
|
||||
func (s *Service) IsBetaEnabled(_ context.Context, _ *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("IsBetaEnabled")
|
||||
|
||||
return wrapperspb.Bool(s.bridge.GetUpdateChannel() == updater.EarlyChannel), nil
|
||||
}
|
||||
|
||||
func (s *Service) SetIsAllMailVisible(_ context.Context, isVisible *wrapperspb.BoolValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("isVisible", isVisible.Value).Debug("SetIsAllMailVisible")
|
||||
|
||||
if err := s.bridge.SetShowAllMail(isVisible.Value); err != nil {
|
||||
@ -206,12 +217,14 @@ func (s *Service) SetIsAllMailVisible(_ context.Context, isVisible *wrapperspb.B
|
||||
}
|
||||
|
||||
func (s *Service) IsAllMailVisible(_ context.Context, _ *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("IsAllMailVisible")
|
||||
|
||||
return wrapperspb.Bool(s.bridge.GetShowAllMail()), nil
|
||||
}
|
||||
|
||||
func (s *Service) SetIsTelemetryDisabled(_ context.Context, isDisabled *wrapperspb.BoolValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("isEnabled", isDisabled.Value).Debug("SetIsTelemetryDisabled")
|
||||
|
||||
if err := s.bridge.SetTelemetryDisabled(isDisabled.Value); err != nil {
|
||||
@ -223,12 +236,14 @@ func (s *Service) SetIsTelemetryDisabled(_ context.Context, isDisabled *wrappers
|
||||
}
|
||||
|
||||
func (s *Service) IsTelemetryDisabled(_ context.Context, _ *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("IsTelemetryDisabled")
|
||||
|
||||
return wrapperspb.Bool(s.bridge.GetTelemetryDisabled()), nil
|
||||
}
|
||||
|
||||
func (s *Service) GoOs(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("GoOs") // TO-DO We can probably get rid of this and use QSysInfo::product name
|
||||
|
||||
return wrapperspb.String(runtime.GOOS), nil
|
||||
@ -246,12 +261,14 @@ func (s *Service) TriggerReset(_ context.Context, _ *emptypb.Empty) (*emptypb.Em
|
||||
}
|
||||
|
||||
func (s *Service) Version(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("Version")
|
||||
|
||||
return wrapperspb.String(s.bridge.GetCurrentVersion().Original()), nil
|
||||
}
|
||||
|
||||
func (s *Service) LogsPath(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("LogsPath")
|
||||
|
||||
path, err := s.bridge.GetLogsPath()
|
||||
@ -263,30 +280,40 @@ func (s *Service) LogsPath(_ context.Context, _ *emptypb.Empty) (*wrapperspb.Str
|
||||
}
|
||||
|
||||
func (s *Service) LicensePath(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("LicensePath")
|
||||
|
||||
return wrapperspb.String(s.bridge.GetLicenseFilePath()), nil
|
||||
}
|
||||
|
||||
func (s *Service) DependencyLicensesLink(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
return wrapperspb.String(s.bridge.GetDependencyLicensesLink()), nil
|
||||
}
|
||||
|
||||
func (s *Service) ReleaseNotesPageLink(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
s.latestLock.RLock()
|
||||
defer s.latestLock.RUnlock()
|
||||
defer func() {
|
||||
async.HandlePanic(s.panicHandler)
|
||||
s.latestLock.RUnlock()
|
||||
}()
|
||||
|
||||
return wrapperspb.String(s.latest.ReleaseNotesPage), nil
|
||||
}
|
||||
|
||||
func (s *Service) LandingPageLink(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
s.latestLock.RLock()
|
||||
defer s.latestLock.RUnlock()
|
||||
defer func() {
|
||||
async.HandlePanic(s.panicHandler)
|
||||
s.latestLock.RUnlock()
|
||||
}()
|
||||
|
||||
return wrapperspb.String(s.latest.LandingPage), nil
|
||||
}
|
||||
|
||||
func (s *Service) SetColorSchemeName(_ context.Context, name *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.WithField("ColorSchemeName", name.Value).Debug("SetColorSchemeName")
|
||||
|
||||
if !theme.IsAvailable(theme.Theme(name.Value)) {
|
||||
@ -303,6 +330,8 @@ func (s *Service) SetColorSchemeName(_ context.Context, name *wrapperspb.StringV
|
||||
}
|
||||
|
||||
func (s *Service) ColorSchemeName(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("ColorSchemeName")
|
||||
|
||||
current := s.bridge.GetColorScheme()
|
||||
@ -318,6 +347,8 @@ func (s *Service) ColorSchemeName(_ context.Context, _ *emptypb.Empty) (*wrapper
|
||||
}
|
||||
|
||||
func (s *Service) CurrentEmailClient(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("CurrentEmailClient")
|
||||
|
||||
return wrapperspb.String(s.bridge.GetCurrentUserAgent()), nil
|
||||
@ -361,6 +392,8 @@ func (s *Service) ReportBug(_ context.Context, report *ReportBugRequest) (*empty
|
||||
}
|
||||
|
||||
func (s *Service) ForceLauncher(_ context.Context, launcher *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.WithField("launcher", launcher.Value).Debug("ForceLauncher")
|
||||
|
||||
s.restarter.Override(launcher.Value)
|
||||
@ -369,6 +402,8 @@ func (s *Service) ForceLauncher(_ context.Context, launcher *wrapperspb.StringVa
|
||||
}
|
||||
|
||||
func (s *Service) SetMainExecutable(_ context.Context, exe *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.WithField("executable", exe.Value).Debug("SetMainExecutable")
|
||||
|
||||
s.restarter.AddFlags("--wait", exe.Value)
|
||||
@ -590,6 +625,8 @@ func (s *Service) InstallUpdate(_ context.Context, _ *emptypb.Empty) (*emptypb.E
|
||||
}
|
||||
|
||||
func (s *Service) SetIsAutomaticUpdateOn(_ context.Context, isOn *wrapperspb.BoolValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.WithField("isOn", isOn.Value).Debug("SetIsAutomaticUpdateOn")
|
||||
|
||||
if currentlyOn := s.bridge.GetAutoUpdate(); currentlyOn == isOn.Value {
|
||||
@ -605,12 +642,16 @@ func (s *Service) SetIsAutomaticUpdateOn(_ context.Context, isOn *wrapperspb.Boo
|
||||
}
|
||||
|
||||
func (s *Service) IsAutomaticUpdateOn(_ context.Context, _ *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("IsAutomaticUpdateOn")
|
||||
|
||||
return wrapperspb.Bool(s.bridge.GetAutoUpdate()), nil
|
||||
}
|
||||
|
||||
func (s *Service) DiskCachePath(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("DiskCachePath")
|
||||
|
||||
return wrapperspb.String(s.bridge.GetGluonCacheDir()), nil
|
||||
@ -648,6 +689,8 @@ func (s *Service) SetDiskCachePath(_ context.Context, newPath *wrapperspb.String
|
||||
}
|
||||
|
||||
func (s *Service) SetIsDoHEnabled(_ context.Context, isEnabled *wrapperspb.BoolValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.WithField("isEnabled", isEnabled.Value).Debug("SetIsDohEnabled")
|
||||
|
||||
if err := s.bridge.SetProxyAllowed(isEnabled.Value); err != nil {
|
||||
@ -659,12 +702,16 @@ func (s *Service) SetIsDoHEnabled(_ context.Context, isEnabled *wrapperspb.BoolV
|
||||
}
|
||||
|
||||
func (s *Service) IsDoHEnabled(_ context.Context, _ *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("IsDohEnabled")
|
||||
|
||||
return wrapperspb.Bool(s.bridge.GetProxyAllowed()), nil
|
||||
}
|
||||
|
||||
func (s *Service) MailServerSettings(_ context.Context, _ *emptypb.Empty) (*ImapSmtpSettings, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("ConnectionMode")
|
||||
|
||||
return &ImapSmtpSettings{
|
||||
@ -728,24 +775,32 @@ func (s *Service) SetMailServerSettings(_ context.Context, settings *ImapSmtpSet
|
||||
}
|
||||
|
||||
func (s *Service) Hostname(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("Hostname")
|
||||
|
||||
return wrapperspb.String(constants.Host), nil
|
||||
}
|
||||
|
||||
func (s *Service) IsPortFree(_ context.Context, port *wrapperspb.Int32Value) (*wrapperspb.BoolValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("IsPortFree")
|
||||
|
||||
return wrapperspb.Bool(ports.IsPortFree(int(port.Value))), nil
|
||||
}
|
||||
|
||||
func (s *Service) AvailableKeychains(_ context.Context, _ *emptypb.Empty) (*AvailableKeychainsResponse, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("AvailableKeychains")
|
||||
|
||||
return &AvailableKeychainsResponse{Keychains: s.bridge.GetHelpersNames()}, nil
|
||||
}
|
||||
|
||||
func (s *Service) SetCurrentKeychain(ctx context.Context, keychain *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.WithField("keychain", keychain.Value).Debug("SetCurrentKeyChain") // we do not check validity.
|
||||
|
||||
defer func() { _, _ = s.Restart(ctx, &emptypb.Empty{}) }()
|
||||
@ -770,6 +825,8 @@ func (s *Service) SetCurrentKeychain(ctx context.Context, keychain *wrapperspb.S
|
||||
}
|
||||
|
||||
func (s *Service) CurrentKeychain(_ context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
|
||||
s.log.Debug("CurrentKeychain")
|
||||
|
||||
helper, err := s.bridge.GetKeychainApp()
|
||||
@ -781,6 +838,20 @@ func (s *Service) CurrentKeychain(_ context.Context, _ *emptypb.Empty) (*wrapper
|
||||
return wrapperspb.String(helper), nil
|
||||
}
|
||||
|
||||
func (s *Service) TriggerRepair(_ context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
s.log.Debug("TriggerRepair")
|
||||
go func() {
|
||||
defer func() {
|
||||
async.HandlePanic(s.panicHandler)
|
||||
_ = s.SendEvent(NewRepairStartedEvent())
|
||||
}()
|
||||
|
||||
s.bridge.Repair()
|
||||
}()
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func base64Decode(in []byte) ([]byte, error) {
|
||||
out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
|
||||
|
||||
|
||||
@ -20,21 +20,25 @@ package grpc
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ProtonMail/gluon/async"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
func (s *Service) ReportBugClicked(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.bridge.ReportBugClicked()
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *Service) AutoconfigClicked(_ context.Context, client *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.bridge.AutoconfigUsed(client.Value)
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *Service) ExternalLinkClicked(_ context.Context, article *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.bridge.ExternalLinkClicked(article.Value)
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import (
|
||||
)
|
||||
|
||||
func (s *Service) GetUserList(_ context.Context, _ *emptypb.Empty) (*UserListResponse, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.Debug("GetUserList")
|
||||
|
||||
userIDs := s.bridge.GetUserIDs()
|
||||
@ -52,6 +53,7 @@ func (s *Service) GetUserList(_ context.Context, _ *emptypb.Empty) (*UserListRes
|
||||
}
|
||||
|
||||
func (s *Service) GetUser(_ context.Context, userID *wrapperspb.StringValue) (*User, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("userID", userID).Debug("GetUser")
|
||||
|
||||
user, err := s.bridge.GetUserInfo(userID.Value)
|
||||
@ -63,6 +65,7 @@ func (s *Service) GetUser(_ context.Context, userID *wrapperspb.StringValue) (*U
|
||||
}
|
||||
|
||||
func (s *Service) SetUserSplitMode(_ context.Context, splitMode *UserSplitModeRequest) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("UserID", splitMode.UserID).WithField("Active", splitMode.Active).Debug("SetUserSplitMode")
|
||||
|
||||
user, err := s.bridge.GetUserInfo(splitMode.UserID)
|
||||
@ -97,6 +100,7 @@ func (s *Service) SetUserSplitMode(_ context.Context, splitMode *UserSplitModeRe
|
||||
}
|
||||
|
||||
func (s *Service) SendBadEventUserFeedback(_ context.Context, feedback *UserBadEventFeedbackRequest) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
l := s.log.WithField("UserID", feedback.UserID).WithField("doResync", feedback.DoResync)
|
||||
l.Debug("SendBadEventUserFeedback")
|
||||
|
||||
@ -115,6 +119,7 @@ func (s *Service) SendBadEventUserFeedback(_ context.Context, feedback *UserBadE
|
||||
}
|
||||
|
||||
func (s *Service) LogoutUser(_ context.Context, userID *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("UserID", userID.Value).Debug("LogoutUser")
|
||||
|
||||
if _, err := s.bridge.GetUserInfo(userID.Value); err != nil {
|
||||
@ -133,6 +138,7 @@ func (s *Service) LogoutUser(_ context.Context, userID *wrapperspb.StringValue)
|
||||
}
|
||||
|
||||
func (s *Service) RemoveUser(_ context.Context, userID *wrapperspb.StringValue) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("UserID", userID.Value).Debug("RemoveUser")
|
||||
|
||||
go func() {
|
||||
@ -148,6 +154,7 @@ func (s *Service) RemoveUser(_ context.Context, userID *wrapperspb.StringValue)
|
||||
}
|
||||
|
||||
func (s *Service) ConfigureUserAppleMail(ctx context.Context, request *ConfigureAppleMailRequest) (*emptypb.Empty, error) {
|
||||
defer async.HandlePanic(s.panicHandler)
|
||||
s.log.WithField("UserID", request.UserID).WithField("Address", request.Address).Debug("ConfigureUserAppleMail")
|
||||
|
||||
sslWasEnabled := s.bridge.GetSMTPSSL()
|
||||
|
||||
@ -262,7 +262,8 @@
|
||||
"keywords": [
|
||||
"Outlook",
|
||||
"setup",
|
||||
"configuration"
|
||||
"configuration",
|
||||
"We encountered an error while adding account"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -421,5 +422,38 @@
|
||||
"Apple Mail",
|
||||
"macOS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"index": 37,
|
||||
"url": "https://proton.me/support/protonmail-bridge-clients-macos-new-outlook#may-17",
|
||||
"title": "Important notice regarding the New Outlook for Mac and issues you might face",
|
||||
"keywords": [
|
||||
"Receiving",
|
||||
"Sending",
|
||||
"Outlook",
|
||||
"Configuration",
|
||||
"Sync",
|
||||
"New Outlook"
|
||||
]
|
||||
},
|
||||
{
|
||||
"index": 38,
|
||||
"url": "https://proton.me/support/proton-mail-bridge-new-outlook-for-windows-set-up-guide",
|
||||
"title": "What is the Recovered Messages folder in Bridge (and your email client)?",
|
||||
"keywords": [
|
||||
"recovered messages",
|
||||
"recovered messages folder"
|
||||
]
|
||||
},
|
||||
{
|
||||
"index": 39,
|
||||
"url": "https://proton.me/support/proton-mail-bridge-new-outlook-for-windows-set-up-guide",
|
||||
"title": "Proton Mail Bridge New Outlook for Windows set up guide",
|
||||
"keywords": [
|
||||
"app password",
|
||||
"INVALIDCREDENTIALS",
|
||||
"TEMPORARILYUNAVAILABLE",
|
||||
"New Outlook"
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
@ -108,13 +108,13 @@ func (sm *Service) Init(ctx context.Context, group *async.Group, subscription ev
|
||||
})
|
||||
|
||||
if err := sm.serveIMAP(ctx); err != nil {
|
||||
sm.log.WithError(err).Error("Failed to start IMAP server")
|
||||
return err
|
||||
sm.log.WithError(err).Error("Failed to start IMAP server on bridge start")
|
||||
sm.imapListener = nil
|
||||
}
|
||||
|
||||
if err := sm.serveSMTP(ctx); err != nil {
|
||||
sm.log.WithError(err).Error("Failed to start SMTP server")
|
||||
return err
|
||||
sm.log.WithError(err).Error("Failed to start SMTP server on bridge start")
|
||||
sm.smtpListener = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -65,8 +65,10 @@ func TestHeartbeat_default_heartbeat(t *testing.T) {
|
||||
func TestHeartbeat_already_sent_heartbeat(t *testing.T) {
|
||||
withHeartbeat(t, 1143, 1025, "/tmp", "defaultKeychain", func(hb *telemetry.Heartbeat, mock *mocks.MockHeartbeatManager) {
|
||||
mock.EXPECT().IsTelemetryAvailable(context.Background()).Return(true)
|
||||
mock.EXPECT().GetLastHeartbeatSent().Return(time.Now().Truncate(24 * time.Hour))
|
||||
|
||||
mock.EXPECT().GetLastHeartbeatSent().DoAndReturn(func() time.Time {
|
||||
curTime := time.Now()
|
||||
return time.Date(curTime.Year(), curTime.Month(), curTime.Day(), 0, 0, 0, 0, curTime.Location())
|
||||
})
|
||||
hb.TrySending(context.Background())
|
||||
})
|
||||
}
|
||||
|
||||
43
internal/telemetry/repair.go
Normal file
43
internal/telemetry/repair.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package telemetry
|
||||
|
||||
type RepairData struct {
|
||||
MeasurementGroup string
|
||||
Event string
|
||||
Values map[string]string
|
||||
Dimensions map[string]string
|
||||
}
|
||||
|
||||
func NewRepairTriggerData() RepairData {
|
||||
return RepairData{
|
||||
MeasurementGroup: "bridge.any.repair",
|
||||
Event: "repair_trigger",
|
||||
Values: map[string]string{},
|
||||
Dimensions: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
func NewRepairDeferredTriggerData() RepairData {
|
||||
return RepairData{
|
||||
MeasurementGroup: "bridge.any.repair",
|
||||
Event: "repair_deferred_trigger",
|
||||
Values: map[string]string{},
|
||||
Dimensions: map[string]string{},
|
||||
}
|
||||
}
|
||||
65
internal/user/repair_telemetry.go
Normal file
65
internal/user/repair_telemetry.go
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/telemetry"
|
||||
)
|
||||
|
||||
func (user *User) SendRepairTrigger(ctx context.Context) {
|
||||
if !user.IsTelemetryEnabled(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
triggerData := telemetry.NewRepairTriggerData()
|
||||
data, err := json.Marshal(triggerData)
|
||||
if err != nil {
|
||||
user.log.WithError(err).Error("Failed to parse repair trigger data.")
|
||||
return
|
||||
}
|
||||
|
||||
if err := user.SendTelemetry(ctx, data); err != nil {
|
||||
user.log.WithError(err).Error("Failed to send repair trigger event.")
|
||||
return
|
||||
}
|
||||
|
||||
user.log.Info("Repair trigger event successfully sent.")
|
||||
}
|
||||
|
||||
func (user *User) SendRepairDeferredTrigger(ctx context.Context) {
|
||||
if !user.IsTelemetryEnabled(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
deferredTriggerData := telemetry.NewRepairDeferredTriggerData()
|
||||
data, err := json.Marshal(deferredTriggerData)
|
||||
if err != nil {
|
||||
user.log.WithError(err).Error("Failed to parse deferred repair trigger data.")
|
||||
return
|
||||
}
|
||||
|
||||
if err := user.SendTelemetry(ctx, data); err != nil {
|
||||
user.log.WithError(err).Error("Failed to send deferred repair trigger event.")
|
||||
return
|
||||
}
|
||||
|
||||
user.log.Info("Deferred repair trigger event successfully sent.")
|
||||
}
|
||||
@ -717,3 +717,28 @@ func (user *User) protonAddresses() []proton.Address {
|
||||
|
||||
return addresses
|
||||
}
|
||||
|
||||
func (user *User) VerifyResyncAndExecute() {
|
||||
user.log.Info("Checking whether logged in user should re-sync. UserID:", user.ID())
|
||||
if user.vault.GetShouldResync() {
|
||||
user.log.Info("User should re-sync, starting re-sync process. UserID:", user.ID())
|
||||
|
||||
if err := user.vault.SetShouldSync(false); err != nil {
|
||||
user.log.WithError(err).Error("Failed to disable re-sync flag in user vault. UserID:", user.ID())
|
||||
}
|
||||
|
||||
user.SendRepairDeferredTrigger(context.Background())
|
||||
if err := user.resyncIMAP(); err != nil {
|
||||
user.log.WithError(err).Error("Failed re-syncing IMAP for userID", user.ID())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (user *User) TriggerRepair() error {
|
||||
user.SendRepairTrigger(context.Background())
|
||||
return user.resyncIMAP()
|
||||
}
|
||||
|
||||
func (user *User) resyncIMAP() error {
|
||||
return user.imapService.Resync(context.Background())
|
||||
}
|
||||
|
||||
@ -18,11 +18,13 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/constants"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/updater"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/useragent"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -200,7 +202,14 @@ func (vault *Vault) SetTelemetryDisabled(telemetryDisabled bool) error {
|
||||
|
||||
// GetLastVersion returns the last version of the bridge that was run.
|
||||
func (vault *Vault) GetLastVersion() *semver.Version {
|
||||
return semver.MustParse(vault.getSafe().Settings.LastVersion)
|
||||
lastVersion := vault.getSafe().Settings.LastVersion
|
||||
version, err := semver.NewVersion(lastVersion)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error(fmt.Sprintf("Error encountered when trying to get last version from vault: %s", lastVersion))
|
||||
version, _ = semver.NewVersion(constants.Version)
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
// SetLastVersion sets the last version of the bridge that was run.
|
||||
|
||||
@ -40,6 +40,8 @@ type UserData struct {
|
||||
|
||||
// **WARNING**: This value can't be removed until we have vault migration support.
|
||||
UIDValidity map[string]imap.UID
|
||||
|
||||
ShouldResync bool // Whether user should re-sync on log-in (this is triggered by the `repair` button)
|
||||
}
|
||||
|
||||
type AddressMode int
|
||||
@ -88,5 +90,7 @@ func newDefaultUser(userID, username, primaryEmail, authUID, authRef string, key
|
||||
AuthUID: authUID,
|
||||
AuthRef: authRef,
|
||||
KeyPass: keyPass,
|
||||
|
||||
ShouldResync: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,3 +232,13 @@ func (user *User) Clear() error {
|
||||
func (user *User) Close() error {
|
||||
return user.vault.detachUser(user.userID)
|
||||
}
|
||||
|
||||
func (user *User) SetShouldSync(shouldResync bool) error {
|
||||
return user.vault.modUser(user.userID, func(data *UserData) {
|
||||
data.ShouldResync = shouldResync
|
||||
})
|
||||
}
|
||||
|
||||
func (user *User) GetShouldResync() bool {
|
||||
return user.vault.getUser(user.userID).ShouldResync
|
||||
}
|
||||
|
||||
@ -61,6 +61,7 @@ func TestUser_New(t *testing.T) {
|
||||
// Check the user's initial sync status.
|
||||
require.False(t, user.SyncStatus().HasLabels)
|
||||
require.False(t, user.SyncStatus().HasMessages)
|
||||
require.False(t, user.GetShouldResync())
|
||||
}
|
||||
|
||||
func TestUser_Clear(t *testing.T) {
|
||||
@ -239,3 +240,34 @@ func TestUser_ForEach(t *testing.T) {
|
||||
// The store should have no users again.
|
||||
require.Empty(t, s.GetUserIDs())
|
||||
}
|
||||
|
||||
func TestUser_ShouldResync(t *testing.T) {
|
||||
// Replace the token generator with a dummy one.
|
||||
vault.RandomToken = func(size int) ([]byte, error) {
|
||||
return []byte("token"), nil
|
||||
}
|
||||
|
||||
// Create a new test vault.
|
||||
s := newVault(t)
|
||||
|
||||
// There should be no users in the store.
|
||||
require.Empty(t, s.GetUserIDs())
|
||||
|
||||
// Create a new user.
|
||||
user, err := s.AddUser("userID", "username", "username@pm.me", "authUID", "authRef", []byte("keyPass"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// The user should be listed in the store.
|
||||
require.ElementsMatch(t, []string{"userID"}, s.GetUserIDs())
|
||||
|
||||
// The shouldResync field is supposed to be false for new users.
|
||||
require.False(t, user.GetShouldResync())
|
||||
|
||||
// Set it to true
|
||||
if err := user.SetShouldSync(true); err != nil {
|
||||
t.Fatalf("Failed to set should-sync: %v", err)
|
||||
}
|
||||
|
||||
// Check whether it matches the correct value
|
||||
require.True(t, user.GetShouldResync())
|
||||
}
|
||||
|
||||
@ -28,12 +28,8 @@ main(){
|
||||
jq -r '.finding | select( (.osv != null) and (.trace[0].function != null) ) | .osv ' < vulns.json > vulns_osv_ids.txt
|
||||
|
||||
ignore GO-2023-2328 "GODT-3124 RESTY race condition"
|
||||
ignore GO-2024-2598 "BRIDGE-16 Update Go to 1.21.9"
|
||||
ignore GO-2024-2599 "BRIDGE-16 Update Go to 1.21.9"
|
||||
ignore GO-2024-2600 "BRIDGE-16 Update Go to 1.21.9"
|
||||
ignore GO-2024-2609 "BRIDGE-16 Update Go to 1.21.9"
|
||||
ignore GO-2024-2610 "BRIDGE-16 Update Go to 1.21.9"
|
||||
ignore GO-2024-2687 "BRIDGE-16 Update Go to 1.21.9"
|
||||
ignore GO-2024-2887 "BRIDGE-95 net/http vulnerability"
|
||||
ignore GO-2024-2888 "BRIDGE-95 archive/zip vulnerability"
|
||||
|
||||
has_vulns
|
||||
|
||||
|
||||
Reference in New Issue
Block a user