mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82607efe1c | |||
| 961dc9435f | |||
| b574ccb6ea | |||
| 2569e83e51 | |||
| d9fdbb35bc | |||
| 5769fb9466 | |||
| a4020cebd4 | |||
| 7a8760e2ef | |||
| 9552e72ba8 | |||
| c692c21b87 | |||
| bb15efa711 | |||
| e94d3be12d | |||
| 66569f71a0 | |||
| 9bfa79455e | |||
| 67e802e3a0 | |||
| 8a5e2007f6 | |||
| 5b92945626 | |||
| 4a8a7ef093 | |||
| 2cfda14b1a | |||
| 312993e08e | |||
| b1110b04c9 | |||
| d2bc60d9cb | |||
| 1d8f6c75c8 | |||
| 06daaf8d9f | |||
| cb436fff63 | |||
| 921a44f1a3 | |||
| d35af6b686 | |||
| 4cb938c57f | |||
| 232e98d812 | |||
| 6fadbde4a6 | |||
| d2fbbc3e25 | |||
| 1c7c342e19 | |||
| 8e49c84a12 | |||
| 754d80d097 | |||
| 63e272e270 | |||
| 54859a34b2 | |||
| 9b1feed68b | |||
| c9b6cc162b | |||
| bf3c90b8e9 | |||
| 8d63fb2301 | |||
| 7953306cc8 | |||
| 37352d44d2 | |||
| 2a1aeb208d | |||
| 94fbe260e4 | |||
| 6d4937222e | |||
| e33bad7bf1 | |||
| 70fdc91aff | |||
| bde8e45b37 | |||
| 6cb2d944d0 | |||
| cf0f59afc0 | |||
| 65d8fbbf31 | |||
| d919c0accf | |||
| 0ca07066db | |||
| 7fa1948c21 | |||
| 413ab1fc1e | |||
| 45c2102ff7 | |||
| 97fc964467 | |||
| bfde96dc88 | |||
| fdb5c0cbee | |||
| 5b4c6870b5 | |||
| a433da8782 | |||
| 5df95566b7 | |||
| 164fb23653 | |||
| 374194c13b | |||
| 1cd35defe5 | |||
| 56aa497b9d | |||
| 773a230d14 | |||
| 76d257af21 | |||
| 856efec886 | |||
| 46fd1d5a76 | |||
| f565fc4f69 | |||
| 2895f42a64 | |||
| 5751166ebc | |||
| e63afd3910 | |||
| 9b1daa0373 | |||
| 89bb7b6389 | |||
| 31670ad9eb | |||
| fb32d652bc | |||
| 346988e604 | |||
| 43df20c25d | |||
| 25ebcffde3 | |||
| b8ae5be58c | |||
| 26a3385f4e | |||
| dc002959eb | |||
| 8703faf345 | |||
| 3ac59d6943 | |||
| 8f5bd37aee | |||
| 5c69af4418 | |||
| 416f696863 | |||
| 789c1cc816 | |||
| 58736dd254 | |||
| a057138880 | |||
| 76087f1749 | |||
| 83935f3a03 | |||
| b93c10ad47 | |||
| 3309137b80 | |||
| 88c4737ba4 | |||
| e5db9b1ccc | |||
| 6e2e622a2f | |||
| 3a66063938 | |||
| 120ddbbcbb | |||
| 39b31abef8 | |||
| ebeca394c7 | |||
| 2206cb3f12 | |||
| cfd07cf893 | |||
| 2e2648fcd5 | |||
| 3070912416 | |||
| 51722eb1a4 | |||
| 5950eff083 | |||
| 5c67cc2e76 | |||
| 01db488caa | |||
| 6cbef1d786 |
@ -16,8 +16,6 @@
|
||||
# along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
---
|
||||
image: gitlab.protontech.ch:4567/go/bridge-internal:test-go1.20
|
||||
|
||||
default:
|
||||
tags:
|
||||
- shared-small
|
||||
@ -35,6 +33,7 @@ stages:
|
||||
- build
|
||||
|
||||
include:
|
||||
- local: ci/setup.yml
|
||||
- local: ci/rules.yml
|
||||
- local: ci/env.yml
|
||||
- local: ci/test.yml
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
## Prerequisites
|
||||
* 64-bit OS:
|
||||
- the go-rfc5322 module cannot currently be compiled for 32-bit OSes
|
||||
* Go 1.20
|
||||
* Go 1.21.6
|
||||
* 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)
|
||||
|
||||
@ -132,7 +132,6 @@ Proton Mail Bridge includes the following 3rd party software:
|
||||
* [tools](https://golang.org/x/tools) available under [license](https://cs.opensource.google/go/x/tools/+/master:LICENSE)
|
||||
* [genproto](https://google.golang.org/genproto) available under [license](https://pkg.go.dev/google.golang.org/genproto?tab=licenses)
|
||||
* [yaml](https://gopkg.in/yaml.v3) available under [license](https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE)
|
||||
* [docker-credential-helpers](https://github.com/ProtonMail/docker-credential-helpers) available under [license](https://github.com/ProtonMail/docker-credential-helpers/blob/master/LICENSE)
|
||||
* [go-message](https://github.com/ProtonMail/go-message) available under [license](https://github.com/ProtonMail/go-message/blob/master/LICENSE)
|
||||
* [go-smtp](https://github.com/ProtonMail/go-smtp) available under [license](https://github.com/ProtonMail/go-smtp/blob/master/LICENSE)
|
||||
* [resty](https://github.com/LBeernaertProton/resty/v2) available under [license](https://github.com/LBeernaertProton/resty/v2/blob/master/LICENSE)
|
||||
|
||||
96
Changelog.md
96
Changelog.md
@ -3,6 +3,102 @@
|
||||
Changelog [format](http://keepachangelog.com/en/1.0.0/)
|
||||
|
||||
|
||||
## 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
|
||||
* GODT-3199: Add package log field.
|
||||
* GODT-3220: Add more test scenarios.
|
||||
|
||||
### Changed
|
||||
* GODT-3193: Preserve attachment encoding.
|
||||
* GODT-3214: Encrypt only with primary key.
|
||||
* GODT-2662: Use tart runner for darwin jobs.
|
||||
* GODT-1602: Test: run integration tests against black 🖤.
|
||||
* GODT-3257: Test: quad9 provider test not working on CI.
|
||||
|
||||
### Fixed
|
||||
* GODT-3290: Fix test failing because of leap day.
|
||||
|
||||
|
||||
## Ypsilon Bridge 3.9.1
|
||||
|
||||
### Fixed
|
||||
* GODT-3235: Update bridge update key.
|
||||
|
||||
|
||||
## Ypsilon Bridge 3.9.0
|
||||
|
||||
### Added
|
||||
* GODT-3230: Scripts for removing Bridge from device.
|
||||
* GODT-3195: Add OS info to the log.
|
||||
* GODT-3156: Add time zone info to the bridge log.
|
||||
* GODT-3162: Test: Add test scenarios for KB article suggestions.
|
||||
* Test: Add scenarios for checking messages sent from Web Client.
|
||||
* GODT-3162: Test: Add step definition for checking KB article suggestions.
|
||||
|
||||
### Changed
|
||||
* GODT-3160: Bump version Go 1.21.6.
|
||||
* GODT-3160: Load pipeline env from bridge internal.
|
||||
* GODT-3052: Test: Replace attachments and inline content in feature tests with the smallest valid versions.
|
||||
* GODT-3155: Customize log formatter for easier parsing.
|
||||
* GODT-3172: Detect missing keychain item.
|
||||
* GODT-3172: Do not list, just retrieve vault key.
|
||||
* Log the message received time when handling message creation event.
|
||||
* Set log as artefact for all integration test.
|
||||
* Get better logging arround keychain list initialisation.
|
||||
|
||||
### Fixed
|
||||
* GODT-3229: Escape reserved XML characters in Apple configuration profile.
|
||||
* GODT-3228: Get rid of fork of docker-credential-helpers.
|
||||
* GODT-3176: Assume inline if content id is present.
|
||||
* GODT-3160: Ignore non-called vulnerabilities.
|
||||
* GODT-3160: Updated external dependencies reported by govulncheck.
|
||||
* GODT-3203: Crash in chunkDivide.
|
||||
* Fix for SMTP connection mode toggle in bridge-gui-tester.
|
||||
* GODT-3183: Fix database indices.
|
||||
* GODT-3187: Fix numberOfDay computation when changing year and day.
|
||||
* GODT-3188: Happy new year.
|
||||
|
||||
|
||||
## Xikou Bridge 3.8.2
|
||||
|
||||
### Fixed
|
||||
* GODT-3235: Update bridge update key.
|
||||
|
||||
|
||||
## Xikou Bridge 3.8.1
|
||||
|
||||
### Added
|
||||
* GODT-3121: Suggest relevant KB articles in the in-app bug report form.
|
||||
* GODT-2001: Add govulncheck to scan for vulnerabilities.
|
||||
|
||||
### Changed
|
||||
* Keep nighlty-job log as artifact.
|
||||
* Test: Improve TestMetadata_JobCorrectlyFinishesAfterCancel.
|
||||
|
||||
### Fixed
|
||||
* GODT-3153: Do not take into account full address when hasing messages.
|
||||
|
||||
|
||||
## Xikou Bridge 3.8.0
|
||||
|
||||
### Added
|
||||
|
||||
29
Makefile
29
Makefile
@ -1,17 +1,18 @@
|
||||
export GO111MODULE=on
|
||||
export CGO_ENABLED=1
|
||||
|
||||
# By default, the target OS is the same as the host OS,
|
||||
# but this can be overridden by setting TARGET_OS to "windows"/"darwin"/"linux".
|
||||
GOOS:=$(shell go env GOOS)
|
||||
TARGET_CMD?=Desktop-Bridge
|
||||
TARGET_OS?=${GOOS}
|
||||
ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||
ROOT_DIR:=$(realpath .)
|
||||
|
||||
## Build
|
||||
.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.8.0+git
|
||||
BRIDGE_APP_VERSION?=3.11.0+git
|
||||
APP_VERSION:=${BRIDGE_APP_VERSION}
|
||||
APP_FULL_NAME:=Proton Mail Bridge
|
||||
APP_VENDOR:=Proton AG
|
||||
@ -19,8 +20,8 @@ SRC_ICO:=bridge.ico
|
||||
SRC_ICNS:=Bridge.icns
|
||||
SRC_SVG:=bridge.svg
|
||||
EXE_NAME:=proton-bridge
|
||||
REVISION:=$(shell ./utils/get_revision.sh)
|
||||
TAG:=$(shell ./utils/get_revision.sh tag)
|
||||
REVISION:=$(shell "${ROOT_DIR}/utils/get_revision.sh" rev)
|
||||
TAG:=$(shell "${ROOT_DIR}/utils/get_revision.sh" tag)
|
||||
BUILD_TIME:=$(shell date +%FT%T%z)
|
||||
MACOS_MIN_VERSION_ARM64=11.0
|
||||
MACOS_MIN_VERSION_AMD64=10.15
|
||||
@ -101,9 +102,9 @@ endif
|
||||
|
||||
ifeq "${GOOS}" "windows"
|
||||
go-build-finalize= \
|
||||
$(if $(4),powershell Copy-Item ${ROOT_DIR}/${RESOURCE_FILE} ${4} &&,) \
|
||||
$(if $(4),cp "${ROOT_DIR}/${RESOURCE_FILE}" ${4} &&,) \
|
||||
$(call go-build,$(1),$(2),$(3)) \
|
||||
$(if $(4), && powershell Remove-Item ${4} -Force,)
|
||||
$(if $(4), && rm -f ${4},)
|
||||
endif
|
||||
|
||||
${EXE_NAME}: gofiles ${RESOURCE_FILE}
|
||||
@ -117,7 +118,10 @@ versioner:
|
||||
go build ${BUILD_FLAGS} -o versioner utils/versioner/main.go
|
||||
|
||||
vault-editor:
|
||||
$(call go-build-finalize,"-tags=debug","vault-editor","./utils/vault-editor/main.go")
|
||||
$(call go-build-finalize,-tags=debug,"vault-editor","./utils/vault-editor/main.go")
|
||||
|
||||
bridge-rollout:
|
||||
$(call go-build-finalize,, "bridge-rollout","./utils/bridge-rollout/bridge-rollout.go")
|
||||
|
||||
hasher:
|
||||
go build -o hasher utils/hasher/main.go
|
||||
@ -164,7 +168,7 @@ ${EXE_TARGET}: check-build-essentials ${EXE_NAME}
|
||||
BRIDGE_BUILD_TIME=${BUILD_TIME} \
|
||||
BRIDGE_GUI_BUILD_CONFIG=Release \
|
||||
BRIDGE_BUILD_ENV=${BUILD_ENV} \
|
||||
BRIDGE_INSTALL_PATH=${ROOT_DIR}/${DEPLOY_DIR}/${GOOS} \
|
||||
BRIDGE_INSTALL_PATH="${ROOT_DIR}/${DEPLOY_DIR}/${GOOS}" \
|
||||
./build.sh install
|
||||
mv "${ROOT_DIR}/${BRIDGE_EXE}" "$(ROOT_DIR)/${EXE_TARGET}"
|
||||
|
||||
@ -185,7 +189,7 @@ ${RESOURCE_FILE}: ./dist/info.rc ./dist/${SRC_ICO} .FORCE
|
||||
|
||||
## Dev dependencies
|
||||
.PHONY: install-devel-tools install-linter install-go-mod-outdated install-git-hooks
|
||||
LINTVER:="v1.52.2"
|
||||
LINTVER:="v1.55.2"
|
||||
LINTSRC:="https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh"
|
||||
|
||||
install-dev-dependencies: install-devel-tools install-linter install-go-mod-outdated
|
||||
@ -328,13 +332,6 @@ lint-bug-report:
|
||||
lint-bug-report-preview:
|
||||
python3 utils/validate_bug_report_file.py --file "internal/frontend/bridge-gui/bridge-gui/qml/Resources/bug_report_flow.json" --preview
|
||||
|
||||
gobinsec: gobinsec-cache.yml build
|
||||
gobinsec -wait -cache -config utils/gobinsec_conf.yml ${EXE_TARGET} ${DEPLOY_DIR}/${TARGET_OS}/${LAUNCHER_EXE}
|
||||
|
||||
gobinsec-cache.yml:
|
||||
./utils/gobinsec_update.sh
|
||||
cp ./utils/gobinsec_update/gobinsec-cache-valid.yml ./gobinsec-cache.yml
|
||||
|
||||
updates: install-go-mod-outdated
|
||||
# Uncomment the "-ci" to fail the job if something can be updated.
|
||||
go list -u -m -json all | go-mod-outdated -update -direct #-ci
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Proton Mail Bridge and Import Export app
|
||||
Copyright (c) 2023 Proton AG
|
||||
Copyright (c) 2024 Proton AG
|
||||
|
||||
This repository holds the Proton Mail Bridge and the Proton Mail Import-Export applications.
|
||||
For a detailed build information see [BUILDS](./BUILDS.md).
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
---
|
||||
|
||||
.script-build:
|
||||
@ -7,9 +6,14 @@
|
||||
extends:
|
||||
- .rules-branch-and-MR-manual
|
||||
script:
|
||||
- which go && go version
|
||||
- which gcc && gcc --version
|
||||
- which qmake && qmake --version
|
||||
- git rev-parse --short=10 HEAD
|
||||
- make build
|
||||
- git diff && git diff-index --quiet HEAD
|
||||
- make vault-editor
|
||||
- make bridge-rollout
|
||||
artifacts:
|
||||
expire_in: 1 day
|
||||
when: always
|
||||
@ -17,7 +21,7 @@
|
||||
paths:
|
||||
- bridge_*.tgz
|
||||
- vault-editor
|
||||
|
||||
- bridge-rollout
|
||||
build-linux:
|
||||
extends:
|
||||
- .script-build
|
||||
@ -66,4 +70,3 @@ trigger-qa-installer:
|
||||
trigger:
|
||||
project: "jcuth/bridge-release"
|
||||
branch: master
|
||||
|
||||
|
||||
73
ci/env.yml
73
ci/env.yml
@ -2,46 +2,45 @@
|
||||
---
|
||||
|
||||
.env-windows:
|
||||
extends:
|
||||
- .image-windows-virt-build
|
||||
before_script:
|
||||
- export BRIDGE_SYNC_FORCE_MINIMUM_SPEC=1
|
||||
- export GOROOT=/c/Go1.20/
|
||||
- export PATH=$GOROOT/bin:$PATH
|
||||
- export GOARCH=amd64
|
||||
- export GOPATH=~/go1.20
|
||||
- export GO111MODULE=on
|
||||
- export PATH="${GOPATH}/bin:${PATH}"
|
||||
- export MSYSTEM=
|
||||
- export QT6DIR=/c/grrrQt/6.4.3/msvc2019_64
|
||||
- export PATH=$PATH:${QT6DIR}/bin
|
||||
- export PATH="/c/Program Files/Microsoft Visual Studio/2022/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin:$PATH"
|
||||
- $(git config --global -l | grep -o 'url.*gitlab.protontech.ch.*insteadof' | xargs -L 1 git config --global --unset &> /dev/null) || echo "nothing to remove"
|
||||
- git config --global url.https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}.insteadOf https://${CI_SERVER_HOST}
|
||||
- git config --global safe.directory '*'
|
||||
- git status --porcelain
|
||||
cache: {}
|
||||
tags:
|
||||
- windows-bridge
|
||||
- !reference [.before-script-windows-virt-build, before_script]
|
||||
- !reference [.before-script-git-config, before_script]
|
||||
- mkdir -p .cache/bin
|
||||
- export PATH=$(pwd)/.cache/bin:$PATH
|
||||
- export GOPATH="$CI_PROJECT_DIR/.cache"
|
||||
variables:
|
||||
GOARCH: amd64
|
||||
BRIDGE_SYNC_FORCE_MINIMUM_SPEC: 1
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${CI_PROJECT_DIR}/.cache
|
||||
cache:
|
||||
key: windows-vcpkg-go-0
|
||||
paths:
|
||||
- .cache
|
||||
when: 'always'
|
||||
|
||||
.env-darwin:
|
||||
extends:
|
||||
- .image-darwin-build
|
||||
before_script:
|
||||
- export BRIDGE_SYNC_FORCE_MINIMUM_SPEC=1
|
||||
- export PATH=/usr/local/bin:$PATH
|
||||
- export PATH=/usr/local/opt/git/bin:$PATH
|
||||
- export PATH=/usr/local/opt/make/libexec/gnubin:$PATH
|
||||
- export PATH=/usr/local/opt/gnu-sed/libexec/gnubin:$PATH
|
||||
- export GOROOT=~/local/opt/go@1.20
|
||||
- export PATH="${GOROOT}/bin:$PATH"
|
||||
- export GOPATH=~/go1.20
|
||||
- export PATH="${GOPATH}/bin:$PATH"
|
||||
- export QT6DIR=/opt/Qt/6.4.3/macos
|
||||
- export PATH="${QT6DIR}/bin:$PATH"
|
||||
- uname -a
|
||||
cache: {}
|
||||
tags:
|
||||
- macos-m1-bridge
|
||||
- !reference [.before-script-darwin-tart-build, before_script]
|
||||
- !reference [.before-script-git-config, before_script]
|
||||
- mkdir -p .cache/bin
|
||||
- export PATH=$(pwd)/.cache/bin:$PATH
|
||||
- export GOPATH="$CI_PROJECT_DIR/.cache"
|
||||
variables:
|
||||
BRIDGE_SYNC_FORCE_MINIMUM_SPEC: 1
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${CI_PROJECT_DIR}/.cache
|
||||
cache:
|
||||
key: darwin-go-and-vcpkg
|
||||
paths:
|
||||
- .cache
|
||||
when: 'always'
|
||||
|
||||
.env-linux-build:
|
||||
image: gitlab.protontech.ch:4567/go/bridge-internal:build-go1.20-qt6.4.3
|
||||
extends:
|
||||
- .image-linux-build
|
||||
variables:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${CI_PROJECT_DIR}/.cache
|
||||
cache:
|
||||
@ -50,13 +49,11 @@
|
||||
- .cache
|
||||
when: 'always'
|
||||
before_script:
|
||||
- mkdir -p .cache/bin
|
||||
- export BRIDGE_SYNC_FORCE_MINIMUM_SPEC=1
|
||||
- !reference [.before-script-git-config, before_script]
|
||||
- mkdir -p .cache/bin
|
||||
- export PATH=$(pwd)/.cache/bin:$PATH
|
||||
- export GOPATH="$CI_PROJECT_DIR/.cache"
|
||||
- export PATH=$PATH:$QT6DIR/bin
|
||||
- $(git config --global -l | grep -o 'url.*gitlab.protontech.ch.*insteadof' | xargs -L 1 git config --global --unset &> /dev/null) || echo "nothing to remove"
|
||||
- git config --global url.https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}.insteadOf https://${CI_SERVER_HOST}
|
||||
tags:
|
||||
- shared-large
|
||||
|
||||
|
||||
7
ci/setup.yml
Normal file
7
ci/setup.yml
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
|
||||
include:
|
||||
- project: 'go/bridge-internal'
|
||||
ref: 'master'
|
||||
file: 'ci/runners-setup.yml'
|
||||
|
||||
71
ci/test.yml
71
ci/test.yml
@ -4,15 +4,17 @@
|
||||
lint:
|
||||
stage: test
|
||||
extends:
|
||||
- .image-linux-test
|
||||
- .rules-branch-manual-br-tag-and-MR-and-devel-always
|
||||
script:
|
||||
- make lint
|
||||
tags:
|
||||
- shared-medium
|
||||
|
||||
bug-report-preview:
|
||||
lint-bug-report-preview:
|
||||
stage: test
|
||||
extends:
|
||||
- .image-linux-test
|
||||
- .rules-branch-and-MR-manual
|
||||
script:
|
||||
- make lint-bug-report-preview
|
||||
@ -24,20 +26,36 @@ bug-report-preview:
|
||||
extends:
|
||||
- .rules-branch-manual-MR-and-devel-always
|
||||
script:
|
||||
- which go && go version
|
||||
- which gcc && gcc --version
|
||||
- make test
|
||||
artifacts:
|
||||
paths:
|
||||
- coverage/**
|
||||
|
||||
|
||||
|
||||
test-linux:
|
||||
extends:
|
||||
- .image-linux-test
|
||||
- .script-test
|
||||
tags:
|
||||
- shared-large
|
||||
|
||||
test-windows:
|
||||
extends:
|
||||
- .env-windows
|
||||
- .script-test
|
||||
|
||||
test-darwin:
|
||||
extends:
|
||||
- .env-darwin
|
||||
- .script-test
|
||||
|
||||
fuzz-linux:
|
||||
stage: test
|
||||
extends:
|
||||
- .image-linux-test
|
||||
- .rules-branch-manual-MR-and-devel-always
|
||||
script:
|
||||
- make fuzz
|
||||
@ -55,14 +73,26 @@ test-integration:
|
||||
extends:
|
||||
- test-linux
|
||||
script:
|
||||
- make test-integration
|
||||
- make test-integration | tee -a integration-job.log
|
||||
after_script:
|
||||
- |
|
||||
grep "Error: " integration-job.log
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- integration-job.log
|
||||
|
||||
test-integration-race:
|
||||
extends:
|
||||
- test-integration
|
||||
- .rules-branch-and-MR-manual
|
||||
script:
|
||||
- make test-integration-race
|
||||
- make test-integration-race | tee -a integration-race-job.log
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- integration-race-job.log
|
||||
|
||||
|
||||
test-integration-nightly:
|
||||
extends:
|
||||
@ -71,21 +101,19 @@ test-integration-nightly:
|
||||
needs:
|
||||
- test-integration
|
||||
script:
|
||||
- make test-integration-nightly
|
||||
|
||||
test-windows:
|
||||
extends:
|
||||
- .env-windows
|
||||
- .script-test
|
||||
|
||||
test-darwin:
|
||||
extends:
|
||||
- .env-darwin
|
||||
- .script-test
|
||||
- make test-integration-nightly | tee -a nightly-job.log
|
||||
after_script:
|
||||
- |
|
||||
grep "Error: " nightly-job.log
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- nightly-job.log
|
||||
|
||||
test-coverage:
|
||||
stage: test
|
||||
extends:
|
||||
- .image-linux-test
|
||||
- .rules-branch-manual-scheduled-and-test-branch-always
|
||||
script:
|
||||
- ./utils/coverage.sh
|
||||
@ -107,3 +135,18 @@ test-coverage:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: coverage.xml
|
||||
|
||||
go-vuln-check:
|
||||
extends:
|
||||
- .image-linux-test
|
||||
- .rules-branch-manual-MR-and-devel-always
|
||||
stage: test
|
||||
tags:
|
||||
- shared-medium
|
||||
script:
|
||||
- ./utils/govulncheck.sh
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- vulns*
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -19,8 +19,15 @@ package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/constants"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/locations"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/logging"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/sentry"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/app"
|
||||
"github.com/bradenaw/juniper/xslices"
|
||||
)
|
||||
@ -43,5 +50,72 @@ import (
|
||||
*/
|
||||
|
||||
func main() {
|
||||
_ = app.New().Run(xslices.Filter(os.Args, func(arg string) bool { return !strings.Contains(arg, "-psn_") }))
|
||||
appErr := app.New().Run(xslices.Filter(os.Args, func(arg string) bool { return !strings.Contains(arg, "-psn_") }))
|
||||
if appErr != nil {
|
||||
_ = app.WithLocations(func(l *locations.Locations) error {
|
||||
logsPath, err := l.ProvideLogsPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the session ID if its specified
|
||||
var sessionID logging.SessionID
|
||||
if flagVal, found := getFlagValue(os.Args, app.FlagSessionID); found {
|
||||
sessionID = logging.SessionID(flagVal)
|
||||
} else {
|
||||
sessionID = logging.NewSessionID()
|
||||
}
|
||||
|
||||
closer, err := logging.Init(
|
||||
logsPath,
|
||||
sessionID,
|
||||
logging.BridgeShortAppName,
|
||||
logging.DefaultMaxLogFileSize,
|
||||
logging.DefaultPruningSize,
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = logging.Close(closer)
|
||||
}()
|
||||
|
||||
logrus.
|
||||
WithField("appName", constants.FullAppName).
|
||||
WithField("version", constants.Version).
|
||||
WithField("revision", constants.Revision).
|
||||
WithField("tag", constants.Tag).
|
||||
WithField("build", constants.BuildTime).
|
||||
WithField("runtime", runtime.GOOS).
|
||||
WithField("args", os.Args).
|
||||
WithField("SentryID", sentry.GetProtectedHostname()).WithError(appErr).Error("Failed to initialize bridge")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// getFlagValue - obtains the value of a specified tag
|
||||
// The flag can be of the following form `-flag value`, `--flag value`, `-flag=value` or `--flags=value`.
|
||||
func getFlagValue(argList []string, flag string) (string, bool) {
|
||||
eqPrefix1 := "-" + flag + "="
|
||||
eqPrefix2 := "--" + flag + "="
|
||||
|
||||
for i := 0; i < len(argList); i++ {
|
||||
arg := argList[i]
|
||||
if strings.HasPrefix(arg, eqPrefix1) {
|
||||
val := strings.TrimPrefix(arg, eqPrefix1)
|
||||
return val, len(val) > 0
|
||||
}
|
||||
if strings.HasPrefix(arg, eqPrefix2) {
|
||||
val := strings.TrimPrefix(arg, eqPrefix2)
|
||||
return val, len(val) > 0
|
||||
}
|
||||
if (arg == "-"+flag || arg == "--"+flag) && i+1 < len(argList) {
|
||||
return argList[i+1], true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
47
cmd/Desktop-Bridge/main_test.go
Normal file
47
cmd/Desktop-Bridge/main_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetFlagValue(t *testing.T) {
|
||||
tests := []struct {
|
||||
args []string
|
||||
flag string
|
||||
expected string
|
||||
}{
|
||||
{[]string{"session-id", ""}, "session-id", ""},
|
||||
{[]string{"-session-id", ""}, "session-id", ""},
|
||||
{[]string{"--session-id", ""}, "session-id", ""},
|
||||
{[]string{"session-id", "test"}, "session-id", ""},
|
||||
{[]string{"-session-id", "test"}, "session-id", "test"},
|
||||
{[]string{"--session-id", "test"}, "session-id", "test"},
|
||||
{[]string{"session-id=test"}, "session-id", ""},
|
||||
{[]string{"-session-id=test"}, "session-id", "test"},
|
||||
{[]string{"--session-id=test"}, "session-id", "test"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
val, _ := getFlagValue(tt.args, tt.flag)
|
||||
require.Equal(t, val, tt.expected)
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -40,6 +40,7 @@ import (
|
||||
"github.com/elastic/go-sysinfo/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
@ -53,9 +54,12 @@ const (
|
||||
FlagCLIShort = "c"
|
||||
FlagNonInteractive = "noninteractive"
|
||||
FlagNonInteractiveShort = "n"
|
||||
FlagLauncher = "--launcher"
|
||||
FlagWait = "--wait"
|
||||
FlagSessionID = "--session-id"
|
||||
FlagLauncher = "launcher"
|
||||
FlagWait = "wait"
|
||||
FlagSessionID = "session-id"
|
||||
HyphenatedFlagLauncher = "--" + FlagLauncher
|
||||
HyphenatedFlagWait = "--" + FlagWait
|
||||
HyphenatedFlagSessionID = "--" + FlagSessionID
|
||||
)
|
||||
|
||||
func main() { //nolint:funlen
|
||||
@ -151,7 +155,7 @@ func main() { //nolint:funlen
|
||||
}
|
||||
}
|
||||
|
||||
cmd := execabs.Command(exe, appendLauncherPath(launcher, append(args, FlagSessionID, string(sessionID)))...) //nolint:gosec
|
||||
cmd := execabs.Command(exe, appendLauncherPath(launcher, appendOrModifySessionID(args, string(sessionID)))...) //nolint:gosec
|
||||
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
@ -173,19 +177,14 @@ func main() { //nolint:funlen
|
||||
|
||||
// appendLauncherPath add launcher path if missing.
|
||||
func appendLauncherPath(path string, args []string) []string {
|
||||
if !sliceContains(args, FlagLauncher) {
|
||||
if !slices.Contains(args, HyphenatedFlagLauncher) {
|
||||
res := append([]string{}, args...)
|
||||
res = append(res, FlagLauncher, path)
|
||||
res = append(res, HyphenatedFlagLauncher, path)
|
||||
return res
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// sliceContains checks if a value is present in a list.
|
||||
func sliceContains[T comparable](list []T, s T) bool {
|
||||
return xslices.Any(list, func(arg T) bool { return arg == s })
|
||||
}
|
||||
|
||||
// inCLIMode detect if CLI mode is asked.
|
||||
func inCLIMode(args []string) bool {
|
||||
return hasFlag(args, FlagCLI) || hasFlag(args, FlagCLIShort) || hasFlag(args, FlagNonInteractive) || hasFlag(args, FlagNonInteractiveShort)
|
||||
@ -193,7 +192,12 @@ func inCLIMode(args []string) bool {
|
||||
|
||||
// hasFlag checks if a flag is present in a list.
|
||||
func hasFlag(args []string, flag string) bool {
|
||||
return xslices.Any(args, func(arg string) bool { return (arg == "-"+flag) || (arg == "--"+flag) })
|
||||
return flagIndex(args, flag) >= 0
|
||||
}
|
||||
|
||||
// flagIndex returns the position of the first occurrence of a flag int args, or -1 if the flag is not present.
|
||||
func flagIndex(args []string, flag string) int {
|
||||
return slices.IndexFunc(args, func(arg string) bool { return (arg == "-"+flag) || (arg == "--"+flag) })
|
||||
}
|
||||
|
||||
// findAndStrip check if a value is present in s list and remove all occurrences of the value from this list.
|
||||
@ -211,7 +215,7 @@ func findAndStripWait(args []string) ([]string, bool, []string) {
|
||||
hasFlag := false
|
||||
values := make([]string, 0)
|
||||
for k, v := range res {
|
||||
if v != FlagWait {
|
||||
if v != HyphenatedFlagWait {
|
||||
continue
|
||||
}
|
||||
if k+1 >= len(res) {
|
||||
@ -222,7 +226,7 @@ func findAndStripWait(args []string) ([]string, bool, []string) {
|
||||
}
|
||||
|
||||
if hasFlag {
|
||||
res, _ = findAndStrip(res, FlagWait)
|
||||
res, _ = findAndStrip(res, HyphenatedFlagWait)
|
||||
for _, v := range values {
|
||||
res, _ = findAndStrip(res, v)
|
||||
}
|
||||
@ -230,6 +234,23 @@ func findAndStripWait(args []string) ([]string, bool, []string) {
|
||||
return res, hasFlag, values
|
||||
}
|
||||
|
||||
// return args with the sessionID flag and value added or modified. The original slice is not modified.
|
||||
func appendOrModifySessionID(args []string, sessionID string) []string {
|
||||
index := flagIndex(args, FlagSessionID)
|
||||
if index < 0 {
|
||||
return append(args, HyphenatedFlagSessionID, sessionID)
|
||||
}
|
||||
|
||||
if index == len(args)-1 {
|
||||
return append(args, sessionID)
|
||||
}
|
||||
|
||||
res := slices.Clone(args)
|
||||
res[index+1] = sessionID
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func getPathToUpdatedExecutable(
|
||||
name string,
|
||||
ver *versioner.Versioner,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -20,61 +20,62 @@ package main
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bradenaw/juniper/xslices"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/logging"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSliceContains(t *testing.T) {
|
||||
assert.True(t, sliceContains([]string{"a", "b", "c"}, "a"))
|
||||
assert.True(t, sliceContains([]int{1, 2, 3}, 2))
|
||||
assert.False(t, sliceContains([]string{"a", "b", "c"}, "A"))
|
||||
assert.False(t, sliceContains([]int{1, 2, 3}, 4))
|
||||
assert.False(t, sliceContains([]string{}, "a"))
|
||||
assert.True(t, sliceContains([]string{"a", "a"}, "a"))
|
||||
}
|
||||
|
||||
func TestFindAndStrip(t *testing.T) {
|
||||
list := []string{"a", "b", "c", "c", "b", "c"}
|
||||
|
||||
result, found := findAndStrip(list, "a")
|
||||
assert.True(t, found)
|
||||
assert.True(t, xslices.Equal(result, []string{"b", "c", "c", "b", "c"}))
|
||||
assert.Equal(t, result, []string{"b", "c", "c", "b", "c"})
|
||||
|
||||
result, found = findAndStrip(list, "c")
|
||||
assert.True(t, found)
|
||||
assert.True(t, xslices.Equal(result, []string{"a", "b", "b"}))
|
||||
assert.Equal(t, result, []string{"a", "b", "b"})
|
||||
|
||||
result, found = findAndStrip([]string{"c", "c", "c"}, "c")
|
||||
assert.True(t, found)
|
||||
assert.True(t, xslices.Equal(result, []string{}))
|
||||
assert.Equal(t, result, []string{})
|
||||
|
||||
result, found = findAndStrip(list, "A")
|
||||
assert.False(t, found)
|
||||
assert.True(t, xslices.Equal(result, list))
|
||||
assert.Equal(t, result, list)
|
||||
|
||||
result, found = findAndStrip([]string{}, "a")
|
||||
assert.False(t, found)
|
||||
assert.True(t, xslices.Equal(result, []string{}))
|
||||
assert.Equal(t, result, []string{})
|
||||
}
|
||||
|
||||
func TestFindAndStripWait(t *testing.T) {
|
||||
result, found, values := findAndStripWait([]string{"a", "b", "c"})
|
||||
assert.False(t, found)
|
||||
assert.True(t, xslices.Equal(result, []string{"a", "b", "c"}))
|
||||
assert.True(t, xslices.Equal(values, []string{}))
|
||||
assert.Equal(t, result, []string{"a", "b", "c"})
|
||||
assert.Equal(t, values, []string{})
|
||||
|
||||
result, found, values = findAndStripWait([]string{"a", "--wait", "b"})
|
||||
assert.True(t, found)
|
||||
assert.True(t, xslices.Equal(result, []string{"a"}))
|
||||
assert.True(t, xslices.Equal(values, []string{"b"}))
|
||||
assert.Equal(t, result, []string{"a"})
|
||||
assert.Equal(t, values, []string{"b"})
|
||||
|
||||
result, found, values = findAndStripWait([]string{"a", "--wait", "b", "--wait", "c"})
|
||||
assert.True(t, found)
|
||||
assert.True(t, xslices.Equal(result, []string{"a"}))
|
||||
assert.True(t, xslices.Equal(values, []string{"b", "c"}))
|
||||
assert.Equal(t, result, []string{"a"})
|
||||
assert.Equal(t, values, []string{"b", "c"})
|
||||
|
||||
result, found, values = findAndStripWait([]string{"a", "--wait", "b", "--wait", "c", "--wait", "d"})
|
||||
assert.True(t, found)
|
||||
assert.True(t, xslices.Equal(result, []string{"a"}))
|
||||
assert.True(t, xslices.Equal(values, []string{"b", "c", "d"}))
|
||||
assert.Equal(t, result, []string{"a"})
|
||||
assert.Equal(t, values, []string{"b", "c", "d"})
|
||||
}
|
||||
|
||||
func TestAppendOrModifySessionID(t *testing.T) {
|
||||
sessionID := string(logging.NewSessionID())
|
||||
assert.Equal(t, appendOrModifySessionID(nil, sessionID), []string{"--session-id", sessionID})
|
||||
assert.Equal(t, appendOrModifySessionID([]string{}, sessionID), []string{"--session-id", sessionID})
|
||||
assert.Equal(t, appendOrModifySessionID([]string{"--cli"}, sessionID), []string{"--cli", "--session-id", sessionID})
|
||||
assert.Equal(t, appendOrModifySessionID([]string{"--cli", "--session-id"}, sessionID), []string{"--cli", "--session-id", sessionID})
|
||||
assert.Equal(t, appendOrModifySessionID([]string{"--cli", "--session-id"}, sessionID), []string{"--cli", "--session-id", sessionID})
|
||||
assert.Equal(t, appendOrModifySessionID([]string{"--session-id", "<oldID>", "--cli"}, sessionID), []string{"--session-id", sessionID, "--cli"})
|
||||
}
|
||||
|
||||
2
extern/vcpkg
vendored
2
extern/vcpkg
vendored
Submodule extern/vcpkg updated: d4d39d71b3...fba75d0906
27
go.mod
27
go.mod
@ -1,13 +1,13 @@
|
||||
module github.com/ProtonMail/proton-bridge/v3
|
||||
|
||||
go 1.20
|
||||
go 1.21
|
||||
|
||||
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.20231114153341-2ecbdd2739f7
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20240227105633-3734c7694bcd
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20231130083229-e8aa47d7a366
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240405124415-8f966ca60436
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.4-proton
|
||||
github.com/PuerkitoBio/goquery v1.8.1
|
||||
github.com/abiosoft/ishell v2.0.0+incompatible
|
||||
@ -15,7 +15,7 @@ require (
|
||||
github.com/bradenaw/juniper v0.12.0
|
||||
github.com/cucumber/godog v0.12.5
|
||||
github.com/cucumber/messages-go/v16 v16.0.1
|
||||
github.com/docker/docker-credential-helpers v0.6.3
|
||||
github.com/docker/docker-credential-helpers v0.8.1
|
||||
github.com/elastic/go-sysinfo v1.11.2-0.20231129083954-35e55cd2a542
|
||||
github.com/emersion/go-imap v1.2.1
|
||||
github.com/emersion/go-imap-id v0.0.0-20190926060100-f94a56b9ecde
|
||||
@ -39,16 +39,16 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/profile v1.7.0
|
||||
github.com/sirupsen/logrus v1.9.2
|
||||
github.com/stretchr/testify v1.8.3
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/urfave/cli/v2 v2.24.4
|
||||
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.13.0
|
||||
golang.org/x/text v0.13.0
|
||||
golang.org/x/sys v0.16.0
|
||||
golang.org/x/text v0.14.0
|
||||
google.golang.org/grpc v1.56.3
|
||||
google.golang.org/protobuf v1.30.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
howett.net/plist v1.0.0
|
||||
)
|
||||
|
||||
@ -66,7 +66,7 @@ require (
|
||||
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
|
||||
github.com/danieljoos/wincred v1.1.2 // indirect
|
||||
github.com/danieljoos/wincred v1.2.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/elastic/go-windows v1.0.1 // indirect
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 // indirect
|
||||
@ -100,7 +100,7 @@ require (
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
@ -111,18 +111,17 @@ 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.14.0 // indirect
|
||||
golang.org/x/crypto v0.18.0 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/sync v0.2.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/docker/docker-credential-helpers => github.com/ProtonMail/docker-credential-helpers v1.1.0
|
||||
github.com/emersion/go-message => github.com/ProtonMail/go-message v0.13.1-0.20230526094639-b62c999c85b7
|
||||
github.com/emersion/go-smtp => github.com/ProtonMail/go-smtp v0.0.0-20231109081432-2b3d50599865
|
||||
github.com/go-resty/resty/v2 => github.com/LBeernaertProton/resty/v2 v2.0.0-20231129100320-dddf8030d93a
|
||||
github.com/keybase/go-keychain => github.com/cuthix/go-keychain v0.0.0-20230517073537-fc1740a83768
|
||||
github.com/keybase/go-keychain => github.com/cuthix/go-keychain v0.0.0-20240103134243-0b6a41580b77
|
||||
)
|
||||
|
||||
62
go.sum
62
go.sum
@ -22,14 +22,13 @@ github.com/LBeernaertProton/resty/v2 v2.0.0-20231129100320-dddf8030d93a/go.mod h
|
||||
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
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/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk=
|
||||
github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20231114153341-2ecbdd2739f7 h1:w+VoSAq9FQvKMm3DlH1MIEZ1KGe7LJ+81EJFVwSV4VU=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20231114153341-2ecbdd2739f7/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo=
|
||||
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/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=
|
||||
@ -39,8 +38,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.20231130083229-e8aa47d7a366 h1:W9P5GdDnuGkB3tbzKnXmUrTjIs6zk/K+4lpPTWzsoRE=
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20231130083229-e8aa47d7a366/go.mod h1:t+hb0BfkmZ9fpvzVRpHC7limoowym6ln/j0XL9a8DDw=
|
||||
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-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=
|
||||
@ -107,20 +108,25 @@ github.com/cucumber/godog v0.12.5/go.mod h1:u6SD7IXC49dLpPN35kal0oYEjsXZWee4pW6T
|
||||
github.com/cucumber/messages-go/v16 v16.0.0/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g=
|
||||
github.com/cucumber/messages-go/v16 v16.0.1 h1:fvkpwsLgnIm0qugftrw2YwNlio+ABe2Iu94Ap8GMYIY=
|
||||
github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g=
|
||||
github.com/cuthix/go-keychain v0.0.0-20230517073537-fc1740a83768 h1:Jrcoxtrk4qpuzKIYPlEkjIK0M+bABs0oW2QzrOuwlzk=
|
||||
github.com/cuthix/go-keychain v0.0.0-20230517073537-fc1740a83768/go.mod h1:ZoZU1fnBy3mOLWr3Pg+Y2+nTKtu6ypDte2kZg9HvSwY=
|
||||
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
|
||||
github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
|
||||
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
|
||||
github.com/cuthix/go-keychain v0.0.0-20240103134243-0b6a41580b77 h1:sdB/yJMbubPQothFl6KYCOrMBRgy0pZbBXIWoJqSFLo=
|
||||
github.com/cuthix/go-keychain v0.0.0-20240103134243-0b6a41580b77/go.mod h1:ZoZU1fnBy3mOLWr3Pg+Y2+nTKtu6ypDte2kZg9HvSwY=
|
||||
github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs=
|
||||
github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
|
||||
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
|
||||
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/elastic/go-sysinfo v1.11.2-0.20231129083954-35e55cd2a542 h1:IFTm6NBbfSgZCaeEzorQhH4T7ZERl4j+1u7oXWzmJcM=
|
||||
github.com/elastic/go-sysinfo v1.11.2-0.20231129083954-35e55cd2a542/go.mod h1:GKqR8bbMK/1ITnez9NIsIfXQr25aLhRJa7AfT8HpBFQ=
|
||||
github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0=
|
||||
@ -157,6 +163,7 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@ -164,6 +171,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
@ -182,6 +190,7 @@ github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@ -283,9 +292,11 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
|
||||
@ -331,7 +342,9 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
|
||||
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
@ -341,6 +354,7 @@ github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNc
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@ -358,8 +372,8 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
|
||||
@ -367,6 +381,7 @@ github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@ -408,8 +423,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
@ -450,8 +466,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
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 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
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/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=
|
||||
@ -519,8 +536,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -546,7 +563,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -560,8 +576,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
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/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=
|
||||
@ -582,8 +599,9 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
@ -644,8 +662,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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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=
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -26,6 +26,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/ProtonMail/gluon/async"
|
||||
@ -43,6 +44,7 @@ import (
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/vault"
|
||||
"github.com/ProtonMail/proton-bridge/v3/pkg/keychain"
|
||||
"github.com/ProtonMail/proton-bridge/v3/pkg/restarter"
|
||||
"github.com/elastic/go-sysinfo"
|
||||
"github.com/pkg/profile"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
@ -81,7 +83,7 @@ const (
|
||||
flagNoWindow = "no-window"
|
||||
flagParentPID = "parent-pid"
|
||||
flagSoftwareRenderer = "software-renderer"
|
||||
flagSessionID = "session-id"
|
||||
FlagSessionID = "session-id"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -163,7 +165,7 @@ func New() *cli.App {
|
||||
Value: false,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flagSessionID,
|
||||
Name: FlagSessionID,
|
||||
Hidden: true,
|
||||
},
|
||||
}
|
||||
@ -236,7 +238,7 @@ func run(c *cli.Context) error {
|
||||
|
||||
return withSingleInstance(settings, locations.GetLockFile(), version, func() error {
|
||||
// Look for available keychains
|
||||
return WithKeychainList(func(keychains *keychain.List) error {
|
||||
return WithKeychainList(crashHandler, func(keychains *keychain.List) error {
|
||||
// Unlock the encrypted vault.
|
||||
return WithVault(locations, keychains, crashHandler, func(v *vault.Vault, insecure, corrupt bool) error {
|
||||
if !v.Migrated() {
|
||||
@ -344,7 +346,7 @@ func withLogging(c *cli.Context, crashHandler *crash.Handler, locations *locatio
|
||||
logrus.WithField("path", logsPath).Debug("Received logs path")
|
||||
|
||||
// Initialize logging.
|
||||
sessionID := logging.NewSessionIDFromString(c.String(flagSessionID))
|
||||
sessionID := logging.NewSessionIDFromString(c.String(FlagSessionID))
|
||||
var closer io.Closer
|
||||
if closer, err = logging.Init(
|
||||
logsPath,
|
||||
@ -371,6 +373,24 @@ func withLogging(c *cli.Context, crashHandler *crash.Handler, locations *locatio
|
||||
WithField("SentryID", sentry.GetProtectedHostname()).
|
||||
Info("Run app")
|
||||
|
||||
now := time.Now()
|
||||
logrus.
|
||||
WithField("timeZone", now.Format("MST")).
|
||||
WithField("offset", now.Format("-07:00:00")).
|
||||
Info("Time zone info")
|
||||
|
||||
host, err := sysinfo.Host()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("Could not retrieve operating system info")
|
||||
} else {
|
||||
osInfo := host.Info().OS
|
||||
logrus.
|
||||
WithField("name", osInfo.Name).
|
||||
WithField("version", osInfo.Version).
|
||||
WithField("build", osInfo.Build).
|
||||
Info("Operating system info")
|
||||
}
|
||||
|
||||
return fn(closer)
|
||||
}
|
||||
|
||||
@ -482,9 +502,10 @@ func withCookieJar(vault *vault.Vault, fn func(http.CookieJar) error) error {
|
||||
}
|
||||
|
||||
// WithKeychainList init the list of usable keychains.
|
||||
func WithKeychainList(fn func(*keychain.List) error) error {
|
||||
func WithKeychainList(panicHandler async.PanicHandler, fn func(*keychain.List) error) error {
|
||||
logrus.Debug("Creating keychain list")
|
||||
defer logrus.Debug("Keychain list stop")
|
||||
defer async.HandlePanic(panicHandler)
|
||||
return fn(keychain.NewList())
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -43,7 +43,7 @@ import (
|
||||
|
||||
// nolint:gosec
|
||||
func migrateKeychainHelper(locations *locations.Locations) error {
|
||||
logrus.Info("Migrating keychain helper")
|
||||
logrus.Trace("Checking if keychain helper needs to be migrated")
|
||||
|
||||
settings, err := locations.ProvideSettingsPath()
|
||||
if err != nil {
|
||||
@ -75,7 +75,11 @@ func migrateKeychainHelper(locations *locations.Locations) error {
|
||||
return fmt.Errorf("failed to unmarshal old prefs file: %w", err)
|
||||
}
|
||||
|
||||
return vault.SetHelper(settings, prefs.Helper)
|
||||
err = vault.SetHelper(settings, prefs.Helper)
|
||||
if err == nil {
|
||||
logrus.Info("Keychain helper has been migrated")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// nolint:gosec
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -104,14 +104,15 @@ func loadVaultKey(vaultDir string, keychains *keychain.List) ([]byte, error) {
|
||||
return nil, fmt.Errorf("could not create keychain: %w", err)
|
||||
}
|
||||
|
||||
has, err := vault.HasVaultKey(kc)
|
||||
key, err := vault.GetVaultKey(kc)
|
||||
if err != nil {
|
||||
if keychain.IsErrKeychainNoItem(err) {
|
||||
logrus.WithError(err).Warn("no vault key found, generating new")
|
||||
return vault.NewVaultKey(kc)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not check for vault key: %w", err)
|
||||
}
|
||||
|
||||
if has {
|
||||
return vault.GetVaultKey(kc)
|
||||
}
|
||||
|
||||
return vault.NewVaultKey(kc)
|
||||
return key, nil
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -40,7 +40,7 @@ func defaultAPIOptions(
|
||||
proton.WithAppVersion(constants.AppVersion(version.Original())),
|
||||
proton.WithCookieJar(cookieJar),
|
||||
proton.WithTransport(transport),
|
||||
proton.WithLogger(logrus.StandardLogger()),
|
||||
proton.WithLogger(logrus.WithField("pkg", "gpa/client")),
|
||||
proton.WithPanicHandler(panicHandler),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -132,6 +132,8 @@ type Bridge struct {
|
||||
syncService *syncservice.Service
|
||||
}
|
||||
|
||||
var logPkg = logrus.WithField("pkg", "bridge") //nolint:gochecknoglobals
|
||||
|
||||
// New creates a new bridge.
|
||||
func New(
|
||||
locator Locator, // the locator to provide paths to store data
|
||||
@ -322,7 +324,7 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
|
||||
// Handle connection up/down events.
|
||||
bridge.api.AddStatusObserver(func(status proton.Status) {
|
||||
logrus.Info("API status changed: ", status)
|
||||
logPkg.Info("API status changed: ", status)
|
||||
|
||||
switch {
|
||||
case status == proton.StatusUp:
|
||||
@ -337,7 +339,7 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
|
||||
// If any call returns a bad version code, we need to update.
|
||||
bridge.api.AddErrorHandler(proton.AppVersionBadCode, func() {
|
||||
logrus.Warn("App version is bad")
|
||||
logPkg.Warn("App version is bad")
|
||||
bridge.publish(events.UpdateForced{})
|
||||
})
|
||||
|
||||
@ -350,7 +352,7 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
// Log all manager API requests (client requests are logged separately).
|
||||
bridge.api.AddPostRequestHook(func(_ *resty.Client, r *resty.Response) error {
|
||||
if _, ok := proton.ClientIDFromContext(r.Request.Context()); !ok {
|
||||
logrus.Infof("[MANAGER] %v: %v %v", r.Status(), r.Request.Method, r.Request.URL)
|
||||
logrus.WithField("pkg", "gpa/manager").Infof("%v: %v %v", r.Status(), r.Request.Method, r.Request.URL)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -359,7 +361,7 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
// Publish a TLS issue event if a TLS issue is encountered.
|
||||
bridge.tasks.Once(func(ctx context.Context) {
|
||||
async.RangeContext(ctx, tlsReporter.GetTLSIssueCh(), func(struct{}) {
|
||||
logrus.Warn("TLS issue encountered")
|
||||
logPkg.Warn("TLS issue encountered")
|
||||
bridge.publish(events.TLSIssue{})
|
||||
})
|
||||
})
|
||||
@ -367,7 +369,7 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
// Publish a raise event if the focus service is called.
|
||||
bridge.tasks.Once(func(ctx context.Context) {
|
||||
async.RangeContext(ctx, bridge.focusService.GetRaiseCh(), func(struct{}) {
|
||||
logrus.Info("Focus service requested raise")
|
||||
logPkg.Info("Focus service requested raise")
|
||||
bridge.publish(events.Raise{})
|
||||
})
|
||||
})
|
||||
@ -375,7 +377,7 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
// Handle any IMAP events that are forwarded to the bridge from gluon.
|
||||
bridge.tasks.Once(func(ctx context.Context) {
|
||||
async.RangeContext(ctx, bridge.imapEventCh, func(event imapEvents.Event) {
|
||||
logrus.WithField("event", fmt.Sprintf("%T", event)).Debug("Received IMAP event")
|
||||
logPkg.WithField("event", fmt.Sprintf("%T", event)).Debug("Received IMAP event")
|
||||
bridge.handleIMAPEvent(event)
|
||||
})
|
||||
})
|
||||
@ -383,7 +385,7 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
// Attempt to load users from the vault when triggered.
|
||||
bridge.goLoad = bridge.tasks.Trigger(func(ctx context.Context) {
|
||||
if err := bridge.loadUsers(ctx); err != nil {
|
||||
logrus.WithError(err).Error("Failed to load users")
|
||||
logPkg.WithError(err).Error("Failed to load users")
|
||||
if netErr := new(proton.NetError); !errors.As(err, &netErr) {
|
||||
sentry.ReportError(bridge.reporter, "Failed to load users", err)
|
||||
}
|
||||
@ -396,7 +398,7 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error {
|
||||
|
||||
// Check for updates when triggered.
|
||||
bridge.goUpdate = bridge.tasks.PeriodicOrTrigger(constants.UpdateCheckInterval, 0, func(ctx context.Context) {
|
||||
logrus.Info("Checking for updates")
|
||||
logPkg.Info("Checking for updates")
|
||||
|
||||
version, err := bridge.updater.GetVersionInfo(ctx, bridge.api, bridge.vault.GetUpdateChannel())
|
||||
if err != nil {
|
||||
@ -434,7 +436,7 @@ func (bridge *Bridge) GetErrors() []error {
|
||||
}
|
||||
|
||||
func (bridge *Bridge) Close(ctx context.Context) {
|
||||
logrus.Info("Closing bridge")
|
||||
logPkg.Info("Closing bridge")
|
||||
|
||||
// Stop heart beat before closing users.
|
||||
bridge.heartbeat.stop()
|
||||
@ -448,7 +450,7 @@ func (bridge *Bridge) Close(ctx context.Context) {
|
||||
|
||||
// Close the servers
|
||||
if err := bridge.serverManager.CloseServers(ctx); err != nil {
|
||||
logrus.WithError(err).Error("Failed to close servers")
|
||||
logPkg.WithError(err).Error("Failed to close servers")
|
||||
}
|
||||
|
||||
bridge.syncService.Close()
|
||||
@ -474,12 +476,12 @@ func (bridge *Bridge) publish(event events.Event) {
|
||||
bridge.watchersLock.RLock()
|
||||
defer bridge.watchersLock.RUnlock()
|
||||
|
||||
logrus.WithField("event", event).Debug("Publishing event")
|
||||
logPkg.WithField("event", event).Debug("Publishing event")
|
||||
|
||||
for _, watcher := range bridge.watchers {
|
||||
if watcher.IsWatching(event) {
|
||||
if ok := watcher.Send(event); !ok {
|
||||
logrus.WithField("event", event).Warn("Failed to send event to watcher")
|
||||
logPkg.WithField("event", event).Warn("Failed to send event to watcher")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -512,13 +514,13 @@ func (bridge *Bridge) remWatcher(watcher *watcher.Watcher[events.Event]) {
|
||||
}
|
||||
|
||||
func (bridge *Bridge) onStatusUp(_ context.Context) {
|
||||
logrus.Info("Handling API status up")
|
||||
logPkg.Info("Handling API status up")
|
||||
|
||||
bridge.goLoad()
|
||||
}
|
||||
|
||||
func (bridge *Bridge) onStatusDown(ctx context.Context) {
|
||||
logrus.Info("Handling API status down")
|
||||
logPkg.Info("Handling API status down")
|
||||
|
||||
for backoff := time.Second; ; backoff = min(backoff*2, 30*time.Second) {
|
||||
select {
|
||||
@ -526,10 +528,10 @@ func (bridge *Bridge) onStatusDown(ctx context.Context) {
|
||||
return
|
||||
|
||||
case <-time.After(backoff):
|
||||
logrus.Info("Pinging API")
|
||||
logPkg.Info("Pinging API")
|
||||
|
||||
if err := bridge.api.Ping(ctx); err != nil {
|
||||
logrus.WithError(err).Warn("Ping failed, API is still unreachable")
|
||||
logPkg.WithError(err).Warn("Ping failed, API is still unreachable")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -184,20 +184,11 @@ func TestBridge_UserAgent_Persistence(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(b *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(b)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(b)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
currentUserAgent := b.GetCurrentUserAgent()
|
||||
require.Contains(t, currentUserAgent, useragent.DefaultUserAgent)
|
||||
|
||||
require.NoError(t, getErr(b.LoginFull(ctx, otherUser, otherPassword, nil, nil)))
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
defer func() { _ = imapClient.Logout() }()
|
||||
@ -235,21 +226,12 @@ func TestBridge_UserAgentFromUnknownClient(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(b *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(b)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(b)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
currentUserAgent := b.GetCurrentUserAgent()
|
||||
require.Contains(t, currentUserAgent, useragent.DefaultUserAgent)
|
||||
|
||||
userID, err := b.LoginFull(context.Background(), username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
defer func() { _ = imapClient.Logout() }()
|
||||
@ -274,21 +256,12 @@ func TestBridge_UserAgentFromSMTPClient(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(b *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(b)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(b)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
currentUserAgent := b.GetCurrentUserAgent()
|
||||
require.Contains(t, currentUserAgent, useragent.DefaultUserAgent)
|
||||
|
||||
userID, err := b.LoginFull(context.Background(), username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
client, err := smtp.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(b.GetSMTPPort())))
|
||||
require.NoError(t, err)
|
||||
defer client.Close() //nolint:errcheck
|
||||
@ -333,17 +306,8 @@ func TestBridge_UserAgentFromIMAPID(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(b *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(b)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(b)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
require.NoError(t, getErr(b.LoginFull(ctx, otherUser, otherPassword, nil, nil)))
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
defer func() { _ = imapClient.Logout() }()
|
||||
@ -715,21 +679,12 @@ func TestBridge_InitGluonDirectory(t *testing.T) {
|
||||
func TestBridge_LoginFailed(t *testing.T) {
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(bridge)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
failCh, done := chToType[events.Event, events.IMAPLoginFailed](bridge.GetEvents(events.IMAPLoginFailed{}))
|
||||
defer done()
|
||||
|
||||
_, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
imapClient, err := eventuallyDial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort())))
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -757,12 +712,6 @@ func TestBridge_ChangeCacheDirectory(t *testing.T) {
|
||||
configDir, err := b.GetGluonDataDir()
|
||||
require.NoError(t, err)
|
||||
|
||||
imapWaiter := waitForIMAPServerReady(b)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(b)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
// Login the user.
|
||||
syncCh, done := chToType[events.Event, events.SyncFinished](b.GetEvents(events.SyncFinished{}))
|
||||
defer done()
|
||||
@ -796,9 +745,6 @@ func TestBridge_ChangeCacheDirectory(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.True(t, info.State == bridge.Connected)
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass)))
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -34,7 +34,7 @@ import (
|
||||
// ConfigureAppleMail configures Apple Mail for the given userID and address.
|
||||
// If configuring Apple Mail for Catalina or newer, it ensures Bridge is using SSL.
|
||||
func (bridge *Bridge) ConfigureAppleMail(ctx context.Context, userID, address string) error {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
logPkg.WithFields(logrus.Fields{
|
||||
"userID": userID,
|
||||
"address": logging.Sensitive(address),
|
||||
}).Info("Configuring Apple Mail")
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -65,7 +65,11 @@ func (bridge *Bridge) CheckClientState(ctx context.Context, checkFlags bool, pro
|
||||
if progressCB != nil {
|
||||
progressCB(fmt.Sprintf("Checking state for user %v", usr.Name()))
|
||||
}
|
||||
log := logrus.WithField("user", usr.Name()).WithField("diag", "state-check")
|
||||
log := logrus.WithFields(logrus.Fields{
|
||||
"pkg": "bridge/debug",
|
||||
"user": usr.Name(),
|
||||
"diag": "state-check",
|
||||
})
|
||||
log.Debug("Retrieving all server metadata")
|
||||
meta, err := usr.GetDiagnosticMetadata(ctx)
|
||||
if err != nil {
|
||||
@ -280,7 +284,7 @@ func clientGetMessageIDs(client *goimapclient.Client, mailbox string) (map[strin
|
||||
|
||||
internalID, ok := header.GetChecked("X-Pm-Internal-Id")
|
||||
if !ok {
|
||||
logrus.Errorf("Message %v does not have internal id", internalID)
|
||||
logrus.WithField("pkg", "bridge/debug").Errorf("Message %v does not have internal id", internalID)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -64,9 +64,6 @@ func TestBridge_HandleDraftsSendFromOtherClient(t *testing.T) {
|
||||
|
||||
// The initial user should be fully synced.
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(b *bridge.Bridge, _ *bridge.Mocks) {
|
||||
waiter := waitForIMAPServerReady(b)
|
||||
defer waiter.Done()
|
||||
|
||||
syncCh, done := chToType[events.Event, events.SyncFinished](b.GetEvents(events.SyncFinished{}))
|
||||
defer done()
|
||||
|
||||
@ -74,7 +71,6 @@ func TestBridge_HandleDraftsSendFromOtherClient(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, userID, (<-syncCh).UserID)
|
||||
waiter.Wait()
|
||||
|
||||
info, err := b.GetUserInfo(userID)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -97,7 +97,7 @@ func (h *heartBeatState) start() {
|
||||
h.taskStarted = true
|
||||
|
||||
h.task.PeriodicOrTrigger(h.taskInterval, 0, func(ctx context.Context) {
|
||||
logrus.Debug("Checking for heartbeat")
|
||||
logrus.WithField("pkg", "bridge/heartbeat").Debug("Checking for heartbeat")
|
||||
|
||||
h.TrySending(ctx)
|
||||
})
|
||||
@ -135,7 +135,7 @@ func (bridge *Bridge) SendHeartbeat(ctx context.Context, heartbeat *telemetry.He
|
||||
if err := bridge.reporter.ReportMessageWithContext("Cannot parse heartbeat data.", reporter.Context{
|
||||
"error": err,
|
||||
}); err != nil {
|
||||
logrus.WithError(err).Error("Failed to parse heartbeat data.")
|
||||
logrus.WithField("pkg", "bridge/heartbeat").WithError(err).Error("Failed to parse heartbeat data.")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -35,10 +35,12 @@ func (bridge *Bridge) restartIMAP(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) {
|
||||
log := logrus.WithField("pkg", "bridge/event/imap")
|
||||
|
||||
switch event := event.(type) {
|
||||
case imapEvents.UserAdded:
|
||||
for labelID, count := range event.Counts {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"gluonID": event.UserID,
|
||||
"labelID": labelID,
|
||||
"count": count,
|
||||
@ -46,7 +48,7 @@ func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) {
|
||||
}
|
||||
|
||||
case imapEvents.IMAPID:
|
||||
logrus.WithFields(logrus.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"sessionID": event.SessionID,
|
||||
"name": event.IMAPID.Name,
|
||||
"version": event.IMAPID.Version,
|
||||
@ -57,7 +59,7 @@ func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) {
|
||||
}
|
||||
|
||||
case imapEvents.LoginFailed:
|
||||
logrus.WithFields(logrus.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"sessionID": event.SessionID,
|
||||
"username": event.Username,
|
||||
"pkg": "imap",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -46,17 +46,12 @@ func TestBridge_Send(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) {
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
senderUserID, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
recipientUserID, err := bridge.LoginFull(ctx, "recipient", password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
smtpWaiter.Wait()
|
||||
|
||||
senderInfo, err := bridge.GetUserInfo(senderUserID)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -409,9 +404,6 @@ SGVsbG8gd29ybGQK
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) {
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
senderUserID, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -431,8 +423,6 @@ SGVsbG8gd29ybGQK
|
||||
messageMultipartWithoutTextWithTextAttachment,
|
||||
}
|
||||
|
||||
smtpWaiter.Wait()
|
||||
|
||||
for _, m := range messages {
|
||||
// Dial the server.
|
||||
client, err := smtp.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetSMTPPort())))
|
||||
@ -617,9 +607,6 @@ Hello world
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) {
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
senderUserID, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -639,8 +626,6 @@ Hello world
|
||||
messageInlineImageFollowedByText,
|
||||
}
|
||||
|
||||
smtpWaiter.Wait()
|
||||
|
||||
for _, m := range messages {
|
||||
// Dial the server.
|
||||
client, err := smtp.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetSMTPPort())))
|
||||
@ -714,17 +699,12 @@ func TestBridge_SendAddressDisabled(t *testing.T) {
|
||||
require.NoError(t, s.ChangeAddressAllowSend(senderUserID, addrID, false))
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) {
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
senderUserID, err := bridge.LoginFull(ctx, "sender", password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = bridge.LoginFull(ctx, "recipient", password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
smtpWaiter.Wait()
|
||||
|
||||
recipientInfo, err := bridge.GetUserInfo(recipientUserID)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -750,7 +730,7 @@ func TestBridge_SendAddressDisabled(t *testing.T) {
|
||||
strings.NewReader("Subject: Test 1\r\n\r\nHello world!"),
|
||||
)
|
||||
|
||||
smtpErr := smtpservice.NewErrCanNotSendOnAddress(senderInfo.Addresses[0])
|
||||
smtpErr := smtpservice.NewErrCannotSendFromAddress(senderInfo.Addresses[0])
|
||||
require.Equal(t, fmt.Sprintf("Error: %v", smtpErr.Error()), err.Error())
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -36,9 +36,6 @@ import (
|
||||
func TestBridge_Report(t *testing.T) {
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(b *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(b)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
syncCh, done := chToType[events.Event, events.SyncFinished](b.GetEvents(events.SyncFinished{}))
|
||||
defer done()
|
||||
|
||||
@ -54,8 +51,6 @@ func TestBridge_Report(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.True(t, info.State == bridge.Connected)
|
||||
|
||||
imapWaiter.Wait()
|
||||
|
||||
// Dial the IMAP port.
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -20,6 +20,7 @@ package bridge_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/ProtonMail/go-proton-api"
|
||||
@ -27,57 +28,39 @@ import (
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/bridge"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/constants"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/events"
|
||||
"github.com/emersion/go-smtp"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestServerManager_NoLoadedUsersNoServers(t *testing.T) {
|
||||
func TestServerManager_ServersStartWithBridge(t *testing.T) {
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
_, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort()))
|
||||
require.Error(t, err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestServerManager_ServersStartAfterFirstConnectedUser(t *testing.T) {
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(bridge)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
_, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, imapClient.Logout())
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
smtpClient, err := smtp.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetSMTPPort())))
|
||||
require.NoError(t, err)
|
||||
smtpClient.Close() //nolint:errcheck
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestServerManager_ServersStopsAfterUserLogsOut(t *testing.T) {
|
||||
func TestServerManager_ServersKeepsRunningfterUserLogsOut(t *testing.T) {
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(bridge)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
userID, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
imapWaiterStopped := waitForIMAPServerStopped(bridge)
|
||||
defer imapWaiterStopped.Done()
|
||||
|
||||
require.NoError(t, bridge.LogoutUser(ctx, userID))
|
||||
|
||||
imapWaiterStopped.Wait()
|
||||
imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, imapClient.Logout())
|
||||
|
||||
smtpClient, err := smtp.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetSMTPPort())))
|
||||
require.NoError(t, err)
|
||||
smtpClient.Close() //nolint:errcheck
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -90,21 +73,12 @@ func TestServerManager_ServersDoNotStopWhenThereIsStillOneActiveUser(t *testing.
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(bridge)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
_, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
userIDOther, err := bridge.LoginFull(ctx, otherUser, otherPassword, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
evtCh, cancel := bridge.GetEvents(events.UserDeauth{})
|
||||
defer cancel()
|
||||
|
||||
@ -115,31 +89,10 @@ func TestServerManager_ServersDoNotStopWhenThereIsStillOneActiveUser(t *testing.
|
||||
imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, imapClient.Logout())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestServerManager_ServersStartIfAtLeastOneUserIsLoggedIn(t *testing.T) {
|
||||
otherPassword := []byte("bar")
|
||||
otherUser := "foo"
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
userIDOther, _, err := s.CreateUser(otherUser, otherPassword)
|
||||
require.NoError(t, err)
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
_, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
smtpClient, err := smtp.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetSMTPPort())))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = bridge.LoginFull(ctx, otherUser, otherPassword, nil, nil)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
require.NoError(t, s.RevokeUser(userIDOther))
|
||||
|
||||
withBridgeWaitForServers(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, imapClient.Logout())
|
||||
smtpClient.Close() //nolint:errcheck
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -162,8 +115,13 @@ func TestServerManager_NetworkLossStopsServers(t *testing.T) {
|
||||
_, err := bridge.LoginFull(ctx, username, password, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, imapClient.Logout())
|
||||
|
||||
smtpClient, err := smtp.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetSMTPPort())))
|
||||
require.NoError(t, err)
|
||||
smtpClient.Close() //nolint:errcheck
|
||||
|
||||
netCtl.Disable()
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -22,11 +22,11 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/kb"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/safe"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/services/userevents"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/updater"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/vault"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (bridge *Bridge) GetKeychainApp() (string, error) {
|
||||
@ -133,7 +133,7 @@ func (bridge *Bridge) SetGluonDir(ctx context.Context, newGluonDir string) error
|
||||
bridge.usersLock.RLock()
|
||||
|
||||
defer func() {
|
||||
logrus.Info("Restarting user event loops")
|
||||
logPkg.Info("Restarting user event loops")
|
||||
for _, u := range bridge.users {
|
||||
u.ResumeEventLoop()
|
||||
}
|
||||
@ -148,20 +148,20 @@ func (bridge *Bridge) SetGluonDir(ctx context.Context, newGluonDir string) error
|
||||
|
||||
waiters := make([]waiter, 0, len(bridge.users))
|
||||
|
||||
logrus.Info("Pausing user event loops for gluon dir change")
|
||||
logPkg.Info("Pausing user event loops for gluon dir change")
|
||||
for id, u := range bridge.users {
|
||||
waiters = append(waiters, waiter{w: u.PauseEventLoopWithWaiter(), id: id})
|
||||
}
|
||||
|
||||
logrus.Info("Waiting on user event loop completion")
|
||||
logPkg.Info("Waiting on user event loop completion")
|
||||
for _, waiter := range waiters {
|
||||
if err := waiter.w.WaitPollFinished(ctx); err != nil {
|
||||
logrus.WithError(err).Errorf("Failed to wait on event loop pause for user %v", waiter.id)
|
||||
logPkg.WithError(err).Errorf("Failed to wait on event loop pause for user %v", waiter.id)
|
||||
return fmt.Errorf("failed on event loop pause: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Info("Changing gluon directory")
|
||||
logPkg.Info("Changing gluon directory")
|
||||
return bridge.serverManager.SetGluonDir(ctx, newGluonDir)
|
||||
}
|
||||
|
||||
@ -310,6 +310,10 @@ func (bridge *Bridge) SetColorScheme(colorScheme string) error {
|
||||
return bridge.vault.SetColorScheme(colorScheme)
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetKnowledgeBaseSuggestions(userInput string) (kb.ArticleList, error) {
|
||||
return kb.GetSuggestions(userInput)
|
||||
}
|
||||
|
||||
// FactoryReset deletes all users, wipes the vault, and deletes all files.
|
||||
// Note: it does not clear the keychain. The only entry in the keychain is the vault password,
|
||||
// which we need at next startup to decrypt the vault.
|
||||
@ -325,13 +329,13 @@ func (bridge *Bridge) FactoryReset(ctx context.Context) {
|
||||
// Wipe the vault.
|
||||
gluonCacheDir, err := bridge.locator.ProvideGluonCachePath()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("Failed to provide gluon dir")
|
||||
logPkg.WithError(err).Error("Failed to provide gluon dir")
|
||||
} else if err := bridge.vault.Reset(gluonCacheDir); err != nil {
|
||||
logrus.WithError(err).Error("Failed to reset vault")
|
||||
logPkg.WithError(err).Error("Failed to reset vault")
|
||||
}
|
||||
|
||||
// Lastly, delete all files except the vault.
|
||||
if err := bridge.locator.Clear(bridge.vault.Path()); err != nil {
|
||||
logrus.WithError(err).Error("Failed to clear data paths")
|
||||
logPkg.WithError(err).Error("Failed to clear data paths")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -28,6 +28,7 @@ import (
|
||||
"github.com/ProtonMail/gluon/reporter"
|
||||
"github.com/ProtonMail/go-proton-api"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/events"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/hv"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/logging"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/safe"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/services/imapservice"
|
||||
@ -38,6 +39,8 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var logUser = logrus.WithField("pkg", "bridge/user") //nolint:gochecknoglobals
|
||||
|
||||
type UserState int
|
||||
|
||||
const (
|
||||
@ -121,23 +124,28 @@ func (bridge *Bridge) QueryUserInfo(query string) (UserInfo, error) {
|
||||
}
|
||||
|
||||
// LoginAuth begins the login process. It returns an authorized client that might need 2FA.
|
||||
func (bridge *Bridge) LoginAuth(ctx context.Context, username string, password []byte) (*proton.Client, proton.Auth, error) {
|
||||
logrus.WithField("username", logging.Sensitive(username)).Info("Authorizing user for login")
|
||||
func (bridge *Bridge) LoginAuth(ctx context.Context, username string, password []byte, hvDetails *proton.APIHVDetails) (*proton.Client, proton.Auth, error) {
|
||||
logUser.WithField("username", logging.Sensitive(username)).Info("Authorizing user for login")
|
||||
|
||||
if username == "crash@bandicoot" {
|
||||
panic("Your wish is my command.. I crash!")
|
||||
}
|
||||
|
||||
client, auth, err := bridge.api.NewClientWithLogin(ctx, username, password)
|
||||
client, auth, err := bridge.api.NewClientWithLoginWithHVToken(ctx, username, password, hvDetails)
|
||||
if err != nil {
|
||||
if hv.IsHvRequest(err) {
|
||||
logUser.WithFields(logrus.Fields{"username": logging.Sensitive(username),
|
||||
"loginError": err.Error()}).Info("Human Verification requested for login")
|
||||
return nil, proton.Auth{}, err
|
||||
}
|
||||
|
||||
return nil, proton.Auth{}, fmt.Errorf("failed to create new API client: %w", err)
|
||||
}
|
||||
|
||||
if ok := safe.RLockRet(func() bool { return mapHas(bridge.users, auth.UserID) }, bridge.usersLock); ok {
|
||||
logrus.WithField("userID", auth.UserID).Warn("User already logged in")
|
||||
logUser.WithField("userID", auth.UserID).Warn("User already logged in")
|
||||
|
||||
if err := client.AuthDelete(ctx); err != nil {
|
||||
logrus.WithError(err).Warn("Failed to delete auth")
|
||||
logUser.WithError(err).Warn("Failed to delete auth")
|
||||
}
|
||||
|
||||
return nil, proton.Auth{}, ErrUserAlreadyLoggedIn
|
||||
@ -152,12 +160,13 @@ func (bridge *Bridge) LoginUser(
|
||||
client *proton.Client,
|
||||
auth proton.Auth,
|
||||
keyPass []byte,
|
||||
hvDetails *proton.APIHVDetails,
|
||||
) (string, error) {
|
||||
logrus.WithField("userID", auth.UserID).Info("Logging in authorized user")
|
||||
logUser.WithField("userID", auth.UserID).Info("Logging in authorized user")
|
||||
|
||||
userID, err := try.CatchVal(
|
||||
func() (string, error) {
|
||||
return bridge.loginUser(ctx, client, auth.UID, auth.RefreshToken, keyPass)
|
||||
return bridge.loginUser(ctx, client, auth.UID, auth.RefreshToken, keyPass, hvDetails)
|
||||
},
|
||||
)
|
||||
|
||||
@ -165,7 +174,7 @@ func (bridge *Bridge) LoginUser(
|
||||
// Failure to unlock will allow retries, so we do not delete auth.
|
||||
if !errors.Is(err, ErrFailedToUnlock) {
|
||||
if deleteErr := client.AuthDelete(ctx); deleteErr != nil {
|
||||
logrus.WithError(deleteErr).Error("Failed to delete auth")
|
||||
logUser.WithError(deleteErr).Error("Failed to delete auth")
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("failed to login user: %w", err)
|
||||
@ -188,15 +197,16 @@ func (bridge *Bridge) LoginFull(
|
||||
getTOTP func() (string, error),
|
||||
getKeyPass func() ([]byte, error),
|
||||
) (string, error) {
|
||||
logrus.WithField("username", logging.Sensitive(username)).Info("Performing full user login")
|
||||
logUser.WithField("username", logging.Sensitive(username)).Info("Performing full user login")
|
||||
|
||||
client, auth, err := bridge.LoginAuth(ctx, username, password)
|
||||
// (atanas) the following may need to be modified once HV is merged (its used only for testing; and depends on whether we will test HV related logic)
|
||||
client, auth, err := bridge.LoginAuth(ctx, username, password, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to begin login process: %w", err)
|
||||
}
|
||||
|
||||
if auth.TwoFA.Enabled&proton.HasTOTP != 0 {
|
||||
logrus.WithField("userID", auth.UserID).Info("Requesting TOTP")
|
||||
logUser.WithField("userID", auth.UserID).Info("Requesting TOTP")
|
||||
|
||||
totp, err := getTOTP()
|
||||
if err != nil {
|
||||
@ -211,7 +221,7 @@ func (bridge *Bridge) LoginFull(
|
||||
var keyPass []byte
|
||||
|
||||
if auth.PasswordMode == proton.TwoPasswordMode {
|
||||
logrus.WithField("userID", auth.UserID).Info("Requesting mailbox password")
|
||||
logUser.WithField("userID", auth.UserID).Info("Requesting mailbox password")
|
||||
|
||||
userKeyPass, err := getKeyPass()
|
||||
if err != nil {
|
||||
@ -223,10 +233,10 @@ func (bridge *Bridge) LoginFull(
|
||||
keyPass = password
|
||||
}
|
||||
|
||||
userID, err := bridge.LoginUser(ctx, client, auth, keyPass)
|
||||
userID, err := bridge.LoginUser(ctx, client, auth, keyPass, nil)
|
||||
if err != nil {
|
||||
if deleteErr := client.AuthDelete(ctx); deleteErr != nil {
|
||||
logrus.WithError(err).Error("Failed to delete auth")
|
||||
logUser.WithError(err).Error("Failed to delete auth")
|
||||
}
|
||||
|
||||
return "", err
|
||||
@ -237,7 +247,7 @@ func (bridge *Bridge) LoginFull(
|
||||
|
||||
// LogoutUser logs out the given user.
|
||||
func (bridge *Bridge) LogoutUser(ctx context.Context, userID string) error {
|
||||
logrus.WithField("userID", userID).Info("Logging out user")
|
||||
logUser.WithField("userID", userID).Info("Logging out user")
|
||||
|
||||
return safe.LockRet(func() error {
|
||||
user, ok := bridge.users[userID]
|
||||
@ -257,7 +267,7 @@ func (bridge *Bridge) LogoutUser(ctx context.Context, userID string) error {
|
||||
|
||||
// DeleteUser deletes the given user.
|
||||
func (bridge *Bridge) DeleteUser(ctx context.Context, userID string) error {
|
||||
logrus.WithField("userID", userID).Info("Deleting user")
|
||||
logUser.WithField("userID", userID).Info("Deleting user")
|
||||
|
||||
syncConfigDir, err := bridge.locator.ProvideIMAPSyncConfigPath()
|
||||
if err != nil {
|
||||
@ -278,7 +288,7 @@ func (bridge *Bridge) DeleteUser(ctx context.Context, userID string) error {
|
||||
}
|
||||
|
||||
if err := bridge.vault.DeleteUser(userID); err != nil {
|
||||
logrus.WithError(err).Error("Failed to delete vault user")
|
||||
logUser.WithError(err).Error("Failed to delete vault user")
|
||||
}
|
||||
|
||||
bridge.publish(events.UserDeleted{
|
||||
@ -291,7 +301,7 @@ func (bridge *Bridge) DeleteUser(ctx context.Context, userID string) error {
|
||||
|
||||
// SetAddressMode sets the address mode for the given user.
|
||||
func (bridge *Bridge) SetAddressMode(ctx context.Context, userID string, mode vault.AddressMode) error {
|
||||
logrus.WithField("userID", userID).WithField("mode", mode).Info("Setting address mode")
|
||||
logUser.WithField("userID", userID).WithField("mode", mode).Info("Setting address mode")
|
||||
|
||||
return safe.RLockRet(func() error {
|
||||
user, ok := bridge.users[userID]
|
||||
@ -327,7 +337,7 @@ func (bridge *Bridge) SetAddressMode(ctx context.Context, userID string, mode va
|
||||
|
||||
// SendBadEventUserFeedback passes the feedback to the given user.
|
||||
func (bridge *Bridge) SendBadEventUserFeedback(_ context.Context, userID string, doResync bool) error {
|
||||
logrus.WithField("userID", userID).WithField("doResync", doResync).Info("Passing bad event feedback to user")
|
||||
logUser.WithField("userID", userID).WithField("doResync", doResync).Info("Passing bad event feedback to user")
|
||||
|
||||
return safe.RLockRet(func() error {
|
||||
ctx := context.Background()
|
||||
@ -338,7 +348,7 @@ func (bridge *Bridge) SendBadEventUserFeedback(_ context.Context, userID string,
|
||||
"Failed to handle event: feedback failed: no such user",
|
||||
reporter.Context{"user_id": userID},
|
||||
); rerr != nil {
|
||||
logrus.WithError(rerr).Error("Failed to report feedback failure")
|
||||
logUser.WithError(rerr).Error("Failed to report feedback failure")
|
||||
}
|
||||
|
||||
return ErrNoSuchUser
|
||||
@ -349,7 +359,7 @@ func (bridge *Bridge) SendBadEventUserFeedback(_ context.Context, userID string,
|
||||
"Failed to handle event: feedback resync",
|
||||
reporter.Context{"user_id": userID},
|
||||
); rerr != nil {
|
||||
logrus.WithError(rerr).Error("Failed to report feedback failure")
|
||||
logUser.WithError(rerr).Error("Failed to report feedback failure")
|
||||
}
|
||||
|
||||
return user.BadEventFeedbackResync(ctx)
|
||||
@ -359,7 +369,7 @@ func (bridge *Bridge) SendBadEventUserFeedback(_ context.Context, userID string,
|
||||
"Failed to handle event: feedback logout",
|
||||
reporter.Context{"user_id": userID},
|
||||
); rerr != nil {
|
||||
logrus.WithError(rerr).Error("Failed to report feedback failure")
|
||||
logUser.WithError(rerr).Error("Failed to report feedback failure")
|
||||
}
|
||||
|
||||
bridge.logoutUser(ctx, user, true, false, false)
|
||||
@ -372,8 +382,8 @@ func (bridge *Bridge) SendBadEventUserFeedback(_ context.Context, userID string,
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
func (bridge *Bridge) loginUser(ctx context.Context, client *proton.Client, authUID, authRef string, keyPass []byte) (string, error) {
|
||||
apiUser, err := client.GetUser(ctx)
|
||||
func (bridge *Bridge) loginUser(ctx context.Context, client *proton.Client, authUID, authRef string, keyPass []byte, hvDetails *proton.APIHVDetails) (string, error) {
|
||||
apiUser, err := client.GetUserWithHV(ctx, hvDetails)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get API user: %w", err)
|
||||
}
|
||||
@ -403,11 +413,11 @@ func (bridge *Bridge) loginUser(ctx context.Context, client *proton.Client, auth
|
||||
|
||||
// loadUsers tries to load each user in the vault that isn't already loaded.
|
||||
func (bridge *Bridge) loadUsers(ctx context.Context) error {
|
||||
logrus.WithField("count", len(bridge.vault.GetUserIDs())).Info("Loading users")
|
||||
defer logrus.Info("Finished loading users")
|
||||
logUser.WithField("count", len(bridge.vault.GetUserIDs())).Info("Loading users")
|
||||
defer logUser.Info("Finished loading users")
|
||||
|
||||
return bridge.vault.ForUser(runtime.NumCPU(), func(user *vault.User) error {
|
||||
log := logrus.WithField("userID", user.UserID())
|
||||
log := logUser.WithField("userID", user.UserID())
|
||||
|
||||
if user.AuthUID() == "" {
|
||||
log.Info("User is not connected (skipping)")
|
||||
@ -451,7 +461,7 @@ func (bridge *Bridge) loadUser(ctx context.Context, user *vault.User) error {
|
||||
if apiErr := new(proton.APIError); errors.As(err, &apiErr) && (apiErr.Code == proton.AuthRefreshTokenInvalid) {
|
||||
// The session cannot be refreshed, we sign out the user by clearing his auth secrets.
|
||||
if err := user.Clear(); err != nil {
|
||||
logrus.WithError(err).Warn("Failed to clear user secrets")
|
||||
logUser.WithError(err).Warn("Failed to clear user secrets")
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,24 +506,24 @@ func (bridge *Bridge) addUser(
|
||||
|
||||
if err := bridge.addUserWithVault(ctx, client, apiUser, vaultUser, isNew); err != nil {
|
||||
if _, ok := err.(*resty.ResponseError); ok || isLogin {
|
||||
logrus.WithError(err).Error("Failed to add user, clearing its secrets from vault")
|
||||
logUser.WithError(err).Error("Failed to add user, clearing its secrets from vault")
|
||||
|
||||
if err := vaultUser.Clear(); err != nil {
|
||||
logrus.WithError(err).Error("Failed to clear user secrets")
|
||||
logUser.WithError(err).Error("Failed to clear user secrets")
|
||||
}
|
||||
} else {
|
||||
logrus.WithError(err).Error("Failed to add user")
|
||||
logUser.WithError(err).Error("Failed to add user")
|
||||
}
|
||||
|
||||
if err := vaultUser.Close(); err != nil {
|
||||
logrus.WithError(err).Error("Failed to close vault user")
|
||||
logUser.WithError(err).Error("Failed to close vault user")
|
||||
}
|
||||
|
||||
if isNew {
|
||||
logrus.Warn("Deleting newly added vault user")
|
||||
logUser.Warn("Deleting newly added vault user")
|
||||
|
||||
if err := bridge.vault.DeleteUser(apiUser.ID); err != nil {
|
||||
logrus.WithError(err).Error("Failed to delete vault user")
|
||||
logUser.WithError(err).Error("Failed to delete vault user")
|
||||
}
|
||||
}
|
||||
|
||||
@ -567,7 +577,7 @@ func (bridge *Bridge) addUserWithVault(
|
||||
// For example, if the user's addresses change, we need to update them in gluon.
|
||||
bridge.tasks.Once(func(ctx context.Context) {
|
||||
async.RangeContext(ctx, user.GetEventCh(), func(event events.Event) {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
logUser.WithFields(logrus.Fields{
|
||||
"userID": apiUser.ID,
|
||||
"event": event,
|
||||
}).Debug("Received user event")
|
||||
@ -618,14 +628,14 @@ func (bridge *Bridge) logoutUser(ctx context.Context, user *user.User, withAPI,
|
||||
user.SendConfigStatusAbort(ctx, withTelemetry)
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
logUser.WithFields(logrus.Fields{
|
||||
"userID": user.ID(),
|
||||
"withAPI": withAPI,
|
||||
"withData": withData,
|
||||
}).Debug("Logging out user")
|
||||
|
||||
if err := user.Logout(ctx, withAPI); err != nil {
|
||||
logrus.WithError(err).Error("Failed to logout user")
|
||||
logUser.WithError(err).Error("Failed to logout user")
|
||||
}
|
||||
|
||||
bridge.heartbeat.SetNbAccount(len(bridge.users))
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -139,9 +139,6 @@ func test_badMessage_badEvent(userFeedback func(t *testing.T, ctx context.Contex
|
||||
})
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
userLoginAndSync(ctx, t, bridge, "user", password)
|
||||
|
||||
var messageIDs []string
|
||||
@ -177,8 +174,6 @@ func test_badMessage_badEvent(userFeedback func(t *testing.T, ctx context.Contex
|
||||
|
||||
userFeedback(t, ctx, bridge, badUserID)
|
||||
|
||||
smtpWaiter.Wait()
|
||||
|
||||
userContinueEventProcess(ctx, t, s, bridge)
|
||||
})
|
||||
})
|
||||
@ -197,9 +192,6 @@ func TestBridge_User_BadMessage_NoBadEvent(t *testing.T) {
|
||||
})
|
||||
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
userLoginAndSync(ctx, t, bridge, "user", password)
|
||||
|
||||
var messageIDs []string
|
||||
@ -223,7 +215,6 @@ func TestBridge_User_BadMessage_NoBadEvent(t *testing.T) {
|
||||
require.NoError(t, c.DeleteMessage(ctx, messageIDs...))
|
||||
})
|
||||
|
||||
smtpWaiter.Wait()
|
||||
userContinueEventProcess(ctx, t, s, bridge)
|
||||
})
|
||||
})
|
||||
@ -776,20 +767,11 @@ func TestBridge_User_CreateDisabledAddress(t *testing.T) {
|
||||
func TestBridge_User_HandleParentLabelRename(t *testing.T) {
|
||||
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
|
||||
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
|
||||
imapWaiter := waitForIMAPServerReady(bridge)
|
||||
defer imapWaiter.Done()
|
||||
|
||||
smtpWaiter := waitForSMTPServerReady(bridge)
|
||||
defer smtpWaiter.Done()
|
||||
|
||||
require.NoError(t, getErr(bridge.LoginFull(ctx, username, password, nil, nil)))
|
||||
|
||||
info, err := bridge.QueryUserInfo(username)
|
||||
require.NoError(t, err)
|
||||
|
||||
imapWaiter.Wait()
|
||||
smtpWaiter.Wait()
|
||||
|
||||
cli, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, cli.Login(info.Addresses[0], string(info.BridgePass)))
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -58,7 +58,7 @@ func (bridge *Bridge) handleUserBadEvent(ctx context.Context, user *user.User, e
|
||||
"error": event.Error,
|
||||
"error_type": internal.ErrCauseType(event.Error),
|
||||
}); rerr != nil {
|
||||
logrus.WithError(rerr).Error("Failed to report failed event handling")
|
||||
logrus.WithField("pkg", "bridge/event").WithError(rerr).Error("Failed to report failed event handling")
|
||||
}
|
||||
|
||||
user.OnBadEvent(ctx)
|
||||
@ -70,6 +70,6 @@ func (bridge *Bridge) handleUncategorizedErrorEvent(event events.UncategorizedEv
|
||||
"error_type": internal.ErrCauseType(event.Error),
|
||||
"error": event.Error,
|
||||
}); rerr != nil {
|
||||
logrus.WithError(rerr).Error("Failed to report failed event handling")
|
||||
logrus.WithField("pkg", "bridge/event").WithError(rerr).Error("Failed to report failed event handling")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -21,6 +21,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/useragent"
|
||||
@ -70,24 +71,24 @@ func prepareMobileConfig(
|
||||
password []byte,
|
||||
) *mobileconfig.Config {
|
||||
return &mobileconfig.Config{
|
||||
DisplayName: username,
|
||||
EmailAddress: addresses,
|
||||
AccountName: displayName,
|
||||
AccountDescription: username,
|
||||
Identifier: "protonmail " + username + strconv.FormatInt(time.Now().Unix(), 10),
|
||||
DisplayName: escapeXMLString(username),
|
||||
EmailAddress: escapeXMLString(addresses),
|
||||
AccountName: escapeXMLString(displayName),
|
||||
AccountDescription: escapeXMLString(username),
|
||||
Identifier: escapeXMLString("protonmail " + username + strconv.FormatInt(time.Now().Unix(), 10)),
|
||||
IMAP: &mobileconfig.IMAP{
|
||||
Hostname: hostname,
|
||||
Hostname: escapeXMLString(hostname),
|
||||
Port: imapPort,
|
||||
TLS: imapSSL,
|
||||
Username: username,
|
||||
Password: string(password),
|
||||
Username: escapeXMLString(username),
|
||||
Password: escapeXMLString(string(password)),
|
||||
},
|
||||
SMTP: &mobileconfig.SMTP{
|
||||
Hostname: hostname,
|
||||
Hostname: escapeXMLString(hostname),
|
||||
Port: smtpPort,
|
||||
TLS: smtpSSL,
|
||||
Username: username,
|
||||
Password: string(password),
|
||||
Username: escapeXMLString(username),
|
||||
Password: escapeXMLString(string(password)),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -121,3 +122,13 @@ func saveConfigTemporarily(mc *mobileconfig.Config) (fname string, err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// escapeXMLString replace all occurrences of the 5 characters `&`, `<`, `>`, `"` and `'` by their respective escaped version as per the XML spec.
|
||||
// https://www.w3.org/TR/xml/#syntax
|
||||
func escapeXMLString(input string) string {
|
||||
result := strings.ReplaceAll(input, `&`, `&`)
|
||||
result = strings.ReplaceAll(result, `<`, `<`)
|
||||
result = strings.ReplaceAll(result, `>`, `>`)
|
||||
result = strings.ReplaceAll(result, `"`, `"`)
|
||||
return strings.ReplaceAll(result, `'`, `'`)
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
// 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
|
||||
@ -15,26 +15,24 @@
|
||||
// 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 tests
|
||||
//go:build darwin
|
||||
|
||||
package clientconfig
|
||||
|
||||
import (
|
||||
"time"
|
||||
"testing"
|
||||
|
||||
"github.com/ProtonMail/go-proton-api/server/backend"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/certs"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/user"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Use the fast key generation for tests.
|
||||
backend.GenerateKey = backend.FastGenerateKey
|
||||
|
||||
// Use the fast cert generation for tests.
|
||||
certs.GenerateCert = FastGenerateCert
|
||||
|
||||
// Set the event period to 1 second for more responsive tests.
|
||||
user.EventPeriod = time.Second
|
||||
|
||||
// Don't use jitter during tests.
|
||||
user.EventJitter = 0
|
||||
func TestEscapeXMLString(t *testing.T) {
|
||||
require.Equal(t, escapeXMLString(`abc&&''""<<>>def`), `abc&&''""<<>>def`)
|
||||
}
|
||||
|
||||
// This test requires human interaction (user configuration profile installation prompt). It is for debugging purpose and is disabled by default.
|
||||
func _TestInstallCert(t *testing.T) { //nolint:unused
|
||||
require.NoError(
|
||||
t,
|
||||
(&AppleMail{}).Configure(`127.0.0.1`, 1143, 1025, true, false, `user&>>`, `<<abc&&'"def>>`, `user&a`, []byte(`ir8R9vhdNXyB7isWzhyEkQ`)),
|
||||
)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -135,7 +135,7 @@ func (status *ConfigurationStatus) ApplyProgress() error {
|
||||
return status.Save()
|
||||
}
|
||||
|
||||
func (status *ConfigurationStatus) RecordLinkClicked(link uint) error {
|
||||
func (status *ConfigurationStatus) RecordLinkClicked(link uint64) error {
|
||||
status.DataLock.Lock()
|
||||
defer status.DataLock.Unlock()
|
||||
|
||||
@ -198,11 +198,11 @@ func (data *ConfigurationStatusData) init() {
|
||||
data.DataV1.FailureDetails = ""
|
||||
}
|
||||
|
||||
func (data *ConfigurationStatusData) setClickedLink(pos uint) {
|
||||
func (data *ConfigurationStatusData) setClickedLink(pos uint64) {
|
||||
data.DataV1.ClickedLink |= 1 << pos
|
||||
}
|
||||
|
||||
func (data *ConfigurationStatusData) hasLinkClicked(pos uint) bool {
|
||||
func (data *ConfigurationStatusData) hasLinkClicked(pos uint64) bool {
|
||||
val := data.DataV1.ClickedLink & (1 << pos)
|
||||
return val > 0
|
||||
}
|
||||
@ -211,7 +211,7 @@ func (data *ConfigurationStatusData) clickedLinkToString() string {
|
||||
var str = ""
|
||||
var first = true
|
||||
for i := 0; i < 64; i++ {
|
||||
if data.hasLinkClicked(uint(i)) {
|
||||
if data.hasLinkClicked(uint64(i)) {
|
||||
if !first {
|
||||
str += ","
|
||||
} else {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -52,10 +52,7 @@ func numberOfDay(now, prev time.Time) int {
|
||||
return 1
|
||||
}
|
||||
if now.Year() > prev.Year() {
|
||||
if now.YearDay() > prev.YearDay() {
|
||||
return 365 + (now.YearDay() - prev.YearDay())
|
||||
}
|
||||
return (prev.YearDay() + now.YearDay()) - 365
|
||||
return (365 * (now.Year() - prev.Year())) + now.YearDay() - prev.YearDay()
|
||||
} else if now.YearDay() > prev.YearDay() {
|
||||
return now.YearDay() - prev.YearDay()
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
@ -69,3 +69,32 @@ func TestConfigurationProgress_fed(t *testing.T) {
|
||||
require.Equal(t, 5, req.Values.NbDay)
|
||||
require.Equal(t, 2, req.Values.NbDaySinceLast)
|
||||
}
|
||||
|
||||
func TestConfigurationProgress_fed_year_change(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
file := filepath.Join(dir, "dummy.json")
|
||||
var data = configstatus.ConfigurationStatusData{
|
||||
Metadata: configstatus.Metadata{Version: "1.0.0"},
|
||||
DataV1: configstatus.DataV1{
|
||||
PendingSince: time.Now().AddDate(-1, 0, -5),
|
||||
LastProgress: time.Now().AddDate(0, 0, -2),
|
||||
Autoconf: "Mr TBird",
|
||||
ClickedLink: 42,
|
||||
ReportSent: false,
|
||||
ReportClick: true,
|
||||
FailureDetails: "Not an error",
|
||||
},
|
||||
}
|
||||
require.NoError(t, dumpConfigStatusInFile(&data, file))
|
||||
|
||||
config, err := configstatus.LoadConfigurationStatus(file)
|
||||
require.NoError(t, err)
|
||||
|
||||
var builder = configstatus.ConfigProgressBuilder{}
|
||||
req := builder.New(config)
|
||||
|
||||
require.Equal(t, "bridge.any.configuration", req.MeasurementGroup)
|
||||
require.Equal(t, "bridge_config_progress", req.Event)
|
||||
require.True(t, (req.Values.NbDay == 370) || (req.Values.NbDay == 371)) // leap year is accounted for in the simplest manner.
|
||||
require.Equal(t, 2, req.Values.NbDaySinceLast)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
@ -29,27 +29,34 @@ type TLSDialer interface {
|
||||
DialTLSContext(ctx context.Context, network, address string) (conn net.Conn, err error)
|
||||
}
|
||||
|
||||
func SetBasicTransportTimeouts(t *http.Transport) {
|
||||
t.MaxIdleConns = 100
|
||||
t.MaxIdleConnsPerHost = 100
|
||||
t.IdleConnTimeout = 5 * time.Minute
|
||||
|
||||
t.ExpectContinueTimeout = 500 * time.Millisecond
|
||||
|
||||
// GODT-126: this was initially 10s but logs from users showed a significant number
|
||||
// were hitting this timeout, possibly due to flaky wifi taking >10s to reconnect.
|
||||
// Bumping to 30s for now to avoid this problem.
|
||||
t.ResponseHeaderTimeout = 30 * time.Second
|
||||
|
||||
// If we allow up to 30 seconds for response headers, it is reasonable to allow up
|
||||
// to 30 seconds for the TLS handshake to take place.
|
||||
t.TLSHandshakeTimeout = 30 * time.Second
|
||||
}
|
||||
|
||||
// CreateTransportWithDialer creates an http.Transport that uses the given dialer to make TLS connections.
|
||||
func CreateTransportWithDialer(dialer TLSDialer) *http.Transport {
|
||||
return &http.Transport{
|
||||
t := &http.Transport{
|
||||
DialTLSContext: dialer.DialTLSContext,
|
||||
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 100,
|
||||
IdleConnTimeout: 5 * time.Minute,
|
||||
|
||||
ExpectContinueTimeout: 500 * time.Millisecond,
|
||||
|
||||
// GODT-126: this was initially 10s but logs from users showed a significant number
|
||||
// were hitting this timeout, possibly due to flaky wifi taking >10s to reconnect.
|
||||
// Bumping to 30s for now to avoid this problem.
|
||||
ResponseHeaderTimeout: 30 * time.Second,
|
||||
|
||||
// If we allow up to 30 seconds for response headers, it is reasonable to allow up
|
||||
// to 30 seconds for the TLS handshake to take place.
|
||||
TLSHandshakeTimeout: 30 * time.Second,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
|
||||
SetBasicTransportTimeouts(t)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// BasicTLSDialer implements TLSDialer.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023 Proton AG
|
||||
// Copyright (c) 2024 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.Bridge.
|
||||
//
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user