forked from Silverfish/proton-bridge
Compare commits
130 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba712516ff | |||
| 865ac44037 | |||
| 7d41062ae9 | |||
| f3c69faf8b | |||
| e353dc554d | |||
| 415d08b411 | |||
| 62499a5630 | |||
| d6d7ea592e | |||
| 5033e9718c | |||
| 16f9dc43cb | |||
| b8f27cc7d2 | |||
| 6b10da524c | |||
| 51eb2c42cd | |||
| c94d839fbb | |||
| de586e5f12 | |||
| c32a106898 | |||
| 5b20b6a3d0 | |||
| 3b07121f08 | |||
| a53bc4b027 | |||
| 478345e277 | |||
| 0ed78f1ccb | |||
| 6671dd38ea | |||
| 2d5ea669a5 | |||
| c7eb7234a2 | |||
| 73d1fe2f65 | |||
| cf75ea739f | |||
| c920c53243 | |||
| 63379001e3 | |||
| aa8cc3fc4b | |||
| 61e4ca5814 | |||
| 8e0693ab03 | |||
| a3d2df9d38 | |||
| f9f4ce996d | |||
| fc69b9aabb | |||
| f7ed3abcfe | |||
| c2ffae3799 | |||
| 437b7a4cfe | |||
| df601ecbbd | |||
| e9c05c5a6b | |||
| 22f427d522 | |||
| d356f306d9 | |||
| e717b69139 | |||
| 1dbd37d05b | |||
| 7dad6cc9a4 | |||
| 0332a3f873 | |||
| 20a0404efb | |||
| 29b7530ddf | |||
| 27e7d7967d | |||
| d40fbda2ab | |||
| 3bb9146d9f | |||
| f0d05aeb79 | |||
| ad6b84d4e0 | |||
| 38031b2fb9 | |||
| b74dba884f | |||
| 7276c23b2b | |||
| f0b1ab55a2 | |||
| f851f4d5c2 | |||
| f2d568d92f | |||
| a0dc764bb9 | |||
| 55beb9227f | |||
| 6ed97a0347 | |||
| 7ce3529f5d | |||
| ed9edb3620 | |||
| f30269865d | |||
| d7c5ace8e4 | |||
| b82e2ca176 | |||
| 5af3e930ec | |||
| 72cd641c72 | |||
| 4a2ac813d3 | |||
| 961742fa53 | |||
| 9984165798 | |||
| 551f5c3c18 | |||
| 41f2ffa4ec | |||
| 778b17c44e | |||
| 5d51cc1739 | |||
| a7270102af | |||
| ca5c45b1c5 | |||
| 31920a4468 | |||
| 2e52b8db87 | |||
| 2899e7bb15 | |||
| 41e15db442 | |||
| b5b477a3ce | |||
| 07b7fa7364 | |||
| 5637ca2529 | |||
| a93a8e7be9 | |||
| db7ead3901 | |||
| 42ced6694e | |||
| af0c5e6bae | |||
| cf6ed81a00 | |||
| 8c9d5c54fc | |||
| 36ec9b07e0 | |||
| d9847ddd6a | |||
| e1747357bc | |||
| 77e352a101 | |||
| b41c4d2fa6 | |||
| b6ad1fe490 | |||
| bc21bb1d8d | |||
| 8ea610c625 | |||
| 10da4f284c | |||
| e49d2e1be7 | |||
| b259de238e | |||
| ea821b1bd8 | |||
| 94347d95df | |||
| ef051d5ed6 | |||
| e40e8e3e75 | |||
| 9d0368de97 | |||
| c5699700b3 | |||
| 1141ea27e2 | |||
| ecc1c34b16 | |||
| 3601adcae6 | |||
| d11cf57879 | |||
| 2c8feff97a | |||
| b7adccf651 | |||
| 726c8918ab | |||
| 29af8e7178 | |||
| 18257f0302 | |||
| aeceb7d593 | |||
| 85c06809d2 | |||
| f65e050588 | |||
| e0d07d67a0 | |||
| 0a9748a15d | |||
| 6bd0739013 | |||
| 5cb893fc1b | |||
| f5624c9932 | |||
| 2b1daa60bb | |||
| ffb18adfd0 | |||
| 649195cc2b | |||
| b0ce46ca8a | |||
| 6435f7b09a | |||
| 59075f2e26 |
33
.gitignore
vendored
33
.gitignore
vendored
@ -6,9 +6,6 @@
|
|||||||
.*.sw?
|
.*.sw?
|
||||||
*~
|
*~
|
||||||
|
|
||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
|
||||||
vendor
|
|
||||||
|
|
||||||
# Test files
|
# Test files
|
||||||
godog.test
|
godog.test
|
||||||
debug.test
|
debug.test
|
||||||
@ -17,17 +14,12 @@ coverage.html
|
|||||||
# Run files
|
# Run files
|
||||||
mem.pprof
|
mem.pprof
|
||||||
|
|
||||||
# Auto generated frontend
|
# Auto generated
|
||||||
internal/frontend/qml/BridgeUI/*.qmlc
|
|
||||||
internal/frontend/qml/ImportExportUI/*.qmlc
|
|
||||||
internal/frontend/qml/ProtonUI/*.qmlc
|
|
||||||
internal/frontend/qml/ProtonUI/fontawesome.ttf
|
|
||||||
internal/frontend/qml/ProtonUI/images
|
|
||||||
internal/frontend/qml/ImportExportUI/images
|
|
||||||
frontend/qml/*.qmlc
|
|
||||||
|
|
||||||
# Credits files (generated).
|
|
||||||
internal/**/credits.go
|
internal/**/credits.go
|
||||||
|
vendor
|
||||||
|
vendor-cache
|
||||||
|
/main.go
|
||||||
|
|
||||||
|
|
||||||
# Build files
|
# Build files
|
||||||
/launcher-*
|
/launcher-*
|
||||||
@ -37,18 +29,3 @@ internal/**/credits.go
|
|||||||
/hasher
|
/hasher
|
||||||
cmd/Desktop-Bridge/deploy
|
cmd/Desktop-Bridge/deploy
|
||||||
cmd/Import-Export/deploy
|
cmd/Import-Export/deploy
|
||||||
internal/frontend/qt*/moc.cpp
|
|
||||||
internal/frontend/qt*/moc.go
|
|
||||||
internal/frontend/qt*/moc.h
|
|
||||||
internal/frontend/qt*/moc_cgo_*.go
|
|
||||||
internal/frontend/qt*/moc_moc.h
|
|
||||||
internal/frontend/qt*/rcc.cpp
|
|
||||||
internal/frontend/qt*/rcc.qrc
|
|
||||||
internal/frontend/qt*/rcc_cgo_*.go
|
|
||||||
|
|
||||||
internal/frontend/rcc.cpp
|
|
||||||
internal/frontend/rcc.qrc
|
|
||||||
internal/frontend/rcc_cgo_*.go
|
|
||||||
vendor-cache/
|
|
||||||
|
|
||||||
/main.go
|
|
||||||
|
|||||||
@ -43,12 +43,16 @@ lint:
|
|||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
- branches
|
- branches
|
||||||
|
before_script:
|
||||||
|
- mkdir -p .cache/bin
|
||||||
|
- export PATH=$(pwd)/.cache/bin:$PATH
|
||||||
|
- export GOPATH="$CI_PROJECT_DIR/.cache"
|
||||||
script:
|
script:
|
||||||
- env GOMAXPROCS=$(( ${CI_TAG_CPU} / 2 )) make lint
|
- env GOMAXPROCS=$(( ${CI_TAG_CPU} / 2 )) make lint
|
||||||
tags:
|
tags:
|
||||||
- medium
|
- medium
|
||||||
|
|
||||||
test:
|
test-linux:
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
- branches
|
- branches
|
||||||
@ -65,6 +69,14 @@ test:
|
|||||||
tags:
|
tags:
|
||||||
- medium
|
- medium
|
||||||
|
|
||||||
|
test-windows:
|
||||||
|
extends: .build-windows-base
|
||||||
|
stage: test
|
||||||
|
only:
|
||||||
|
- branches
|
||||||
|
script:
|
||||||
|
- make test
|
||||||
|
|
||||||
test-integration:
|
test-integration:
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
@ -81,10 +93,26 @@ dependency-updates:
|
|||||||
|
|
||||||
# Stage: BUILD
|
# Stage: BUILD
|
||||||
|
|
||||||
|
build-qml:
|
||||||
|
tags:
|
||||||
|
- small
|
||||||
|
only:
|
||||||
|
- branches
|
||||||
|
stage: build
|
||||||
|
artifacts:
|
||||||
|
name: "bridge-qml-$CI_COMMIT_SHORT_SHA"
|
||||||
|
expire_in: 1 day
|
||||||
|
paths:
|
||||||
|
- bridge_qml.tgz
|
||||||
|
script:
|
||||||
|
- cd internal/frontend/qml
|
||||||
|
- tar -cvzf ../../../bridge_qml.tgz ./*
|
||||||
|
|
||||||
|
|
||||||
.build-base:
|
.build-base:
|
||||||
stage: build
|
stage: build
|
||||||
only:
|
only:
|
||||||
- branches
|
- manual
|
||||||
before_script:
|
before_script:
|
||||||
- mkdir -p .cache/bin
|
- mkdir -p .cache/bin
|
||||||
- export PATH=$(pwd)/.cache/bin:$PATH
|
- export PATH=$(pwd)/.cache/bin:$PATH
|
||||||
@ -111,6 +139,7 @@ build-linux-qa:
|
|||||||
extends: .build-base
|
extends: .build-base
|
||||||
only:
|
only:
|
||||||
- web
|
- web
|
||||||
|
- branches
|
||||||
script:
|
script:
|
||||||
- BUILD_TAGS="build_qa" make build
|
- BUILD_TAGS="build_qa" make build
|
||||||
artifacts:
|
artifacts:
|
||||||
@ -118,31 +147,10 @@ build-linux-qa:
|
|||||||
paths:
|
paths:
|
||||||
- bridge_*.tgz
|
- bridge_*.tgz
|
||||||
|
|
||||||
build-ie-linux:
|
|
||||||
extends: .build-base
|
|
||||||
script:
|
|
||||||
- make build-ie
|
|
||||||
artifacts:
|
|
||||||
name: "ie-linux-$CI_COMMIT_SHORT_SHA"
|
|
||||||
paths:
|
|
||||||
- ie_*.tgz
|
|
||||||
|
|
||||||
build-ie-linux-qa:
|
|
||||||
extends: .build-base
|
|
||||||
only:
|
|
||||||
- web
|
|
||||||
script:
|
|
||||||
- BUILD_TAGS="build_qa" make build-ie
|
|
||||||
artifacts:
|
|
||||||
name: "ie-linux-qa-$CI_COMMIT_SHORT_SHA"
|
|
||||||
paths:
|
|
||||||
- ie_*.tgz
|
|
||||||
|
|
||||||
.build-darwin-base:
|
.build-darwin-base:
|
||||||
extends: .build-base
|
extends: .build-base
|
||||||
before_script:
|
before_script:
|
||||||
- eval $(ssh-agent -s)
|
|
||||||
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
|
|
||||||
- export PATH=/usr/local/bin:$PATH
|
- export PATH=/usr/local/bin:$PATH
|
||||||
- export PATH=/usr/local/opt/git/bin:$PATH
|
- export PATH=/usr/local/opt/git/bin:$PATH
|
||||||
- export PATH=/usr/local/opt/make/libexec/gnubin:$PATH
|
- export PATH=/usr/local/opt/make/libexec/gnubin:$PATH
|
||||||
@ -166,6 +174,7 @@ build-darwin-qa:
|
|||||||
extends: .build-darwin-base
|
extends: .build-darwin-base
|
||||||
only:
|
only:
|
||||||
- web
|
- web
|
||||||
|
- branches
|
||||||
script:
|
script:
|
||||||
- BUILD_TAGS="build_qa" make build
|
- BUILD_TAGS="build_qa" make build
|
||||||
artifacts:
|
artifacts:
|
||||||
@ -173,25 +182,39 @@ build-darwin-qa:
|
|||||||
paths:
|
paths:
|
||||||
- bridge_*.tgz
|
- bridge_*.tgz
|
||||||
|
|
||||||
build-ie-darwin:
|
|
||||||
extends: .build-darwin-base
|
|
||||||
script:
|
|
||||||
- make build-ie
|
|
||||||
artifacts:
|
|
||||||
name: "ie-darwin-$CI_COMMIT_SHORT_SHA"
|
|
||||||
paths:
|
|
||||||
- ie_*.tgz
|
|
||||||
|
|
||||||
build-ie-darwin-qa:
|
.build-windows-base:
|
||||||
extends: .build-darwin-base
|
extends: .build-base
|
||||||
|
before_script:
|
||||||
|
- export GOROOT=/c/Go
|
||||||
|
- export PATH=$GOROOT/bin:$PATH
|
||||||
|
- export GOARCH=amd64
|
||||||
|
- export GOPATH=~/go
|
||||||
|
- export GO111MODULE=on
|
||||||
|
- export PATH=$GOPATH/bin:$PATH
|
||||||
|
- export MSYSTEM=
|
||||||
|
- export PATH=$PATH:/c/grrrQt/5.13.2/mingw73_64/bin
|
||||||
|
tags:
|
||||||
|
- windows-bridge
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
extends: .build-windows-base
|
||||||
|
artifacts:
|
||||||
|
name: "bridge-windows-$CI_COMMIT_SHORT_SHA"
|
||||||
|
paths:
|
||||||
|
- bridge_*.tgz
|
||||||
|
|
||||||
|
build-windows-qa:
|
||||||
|
extends: .build-windows-base
|
||||||
only:
|
only:
|
||||||
- web
|
- web
|
||||||
|
- branches
|
||||||
script:
|
script:
|
||||||
- BUILD_TAGS="build_qa" make build-ie
|
- BUILD_TAGS="build_qa" make build
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "ie-darwin-qa-$CI_COMMIT_SHORT_SHA"
|
name: "bridge-windows-qa-$CI_COMMIT_SHORT_SHA"
|
||||||
paths:
|
paths:
|
||||||
- ie_*.tgz
|
- bridge_*.tgz
|
||||||
|
|
||||||
# Stage: MIRROR
|
# Stage: MIRROR
|
||||||
|
|
||||||
|
|||||||
0
.gitmodules
vendored
0
.gitmodules
vendored
@ -1,8 +1,6 @@
|
|||||||
---
|
---
|
||||||
run:
|
run:
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
build-tags:
|
|
||||||
- nogui
|
|
||||||
skip-dirs:
|
skip-dirs:
|
||||||
- pkg/mime
|
- pkg/mime
|
||||||
|
|
||||||
@ -58,7 +56,6 @@ linters:
|
|||||||
- godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false]
|
- godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false]
|
||||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
|
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
|
||||||
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports [fast: true, auto-fix: true]
|
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports [fast: true, auto-fix: true]
|
||||||
- golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes [fast: true, auto-fix: false]
|
|
||||||
- gosec # Inspects source code for security problems [fast: true, auto-fix: false]
|
- gosec # Inspects source code for security problems [fast: true, auto-fix: false]
|
||||||
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
|
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
|
||||||
- nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
|
- nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
# Building ProtonMail Bridge and Import-Export app
|
# Building Proton Mail Bridge and Import-Export app
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
* 64-bit OS (the go-rfc5322 module cannot currently be compiled for 32-bit OSes)
|
* 64-bit AMD OS:
|
||||||
|
- the go-rfc5322 module cannot currently be compiled for 32-bit OSes
|
||||||
|
- the Apple M1 builds are not supported yet due to dependencies
|
||||||
* Go 1.13
|
* Go 1.13
|
||||||
* Bash with basic build utils: make, gcc, sed, find, grep, ...
|
* 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/)
|
* For Windows it is recommended to use MinGW 64bit shell from [MSYS2](https://www.msys2.org/)
|
||||||
|
|||||||
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
By making a contribution to this project:
|
By making a contribution to this project:
|
||||||
|
|
||||||
1. I assign any and all copyright related to the contribution to
|
1. I assign any and all copyright related to the contribution to Proton AG;
|
||||||
Proton Technologies AG;
|
|
||||||
2. I certify that the contribution was created in whole by me;
|
2. I certify that the contribution was created in whole by me;
|
||||||
3. I understand and agree that this project and the contribution are public
|
3. I understand and agree that this project and the contribution are public
|
||||||
and that a record of the contribution (including all personal information I
|
and that a record of the contribution (including all personal information I
|
||||||
|
|||||||
131
COPYING_NOTES.md
131
COPYING_NOTES.md
@ -1,72 +1,93 @@
|
|||||||
# Copying
|
# Copying
|
||||||
Copyright (c) 2020 Proton Technologies AG
|
Copyright (c) 2022 Proton AG
|
||||||
|
|
||||||
ProtonMail Bridge is free software: you can redistribute it and/or modify it
|
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
|
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
|
Software Foundation, either version 3 of the License, or (at your option) any
|
||||||
later version.
|
later version.
|
||||||
|
|
||||||
ProtonMail Bridge is distributed in the hope that it will be useful, but WITHOUT ANY
|
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
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
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
|
You should have received a copy of the GNU General Public License along with
|
||||||
ProtonMail Bridge. If not, see https://www.gnu.org/licenses.
|
Proton Mail Bridge. If not, see https://www.gnu.org/licenses.
|
||||||
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
ProtonMail Bridge app includes the following libraries from Proton Technologies AG:
|
Proton Mail Bridge includes the following 3rd party software:
|
||||||
|
|
||||||
* [GopenPGP library](https://gopenpgp.org/) | The [MIT License](https://github.com/ProtonMail/gopenpgp/blob/master/LICENSE).
|
|
||||||
|
|
||||||
ProtonMail Bridge includes the following 3rd party software:
|
|
||||||
|
|
||||||
* [The Go Project libraries](https://golang.org/project/) | Available under [BSD license](https://golang.org/LICENSE)
|
* [The Go Project libraries](https://golang.org/project/) | Available under [BSD license](https://golang.org/LICENSE)
|
||||||
* [Qt Go binding](https://github.com/therecipe/qt) | Available under [LGPLv3 license](https://github.com/therecipe/qt/blob/master/LICENSE)
|
|
||||||
* [Qt](https://www.qt.io/) | Available under [multiple licences](https://www.qt.io/licensing)
|
* [Qt](https://www.qt.io/) | Available under [multiple licences](https://www.qt.io/licensing)
|
||||||
* [Font Awesome 4.7.0](https://fontawesome.com/v4.7.0/) | Available under [multiple licenses](https://fontawesome.com/v4.7.0/license/)
|
|
||||||
|
|
||||||
* [notificator](https://github.com/0xAX/notificator) | Available under [license](https://github.com/0xAX/notificator/blob/master/LICENSE)
|
<!-- START AUTOGEN -->
|
||||||
* [ishell](https://github.com/abiosoft/ishell) | Available under [license](https://github.com/abiosoft/ishell/blob/master/LICENSE)
|
* [docker-credential-helpers](https://github.com/docker/docker-credential-helpers) available under [license](https://github.com/docker/docker-credential-helpers/blob/master/LICENSE)
|
||||||
* [readline](https://github.com/abiosoft/readline) | Available under [license](https://github.com/abiosoft/readline/blob/master/LICENSE)
|
* [go-imap](https://github.com/emersion/go-imap) available under [license](https://github.com/emersion/go-imap/blob/master/LICENSE)
|
||||||
* [singleinstance](https://github.com/allan-simon/go-singleinstance) | Available under [license](https://github.com/allan-simon/go-singleinstance/blob/master/LICENSE)
|
* [bcrypt](https://github.com/jameskeane/bcrypt) available under [license](https://github.com/jameskeane/bcrypt/blob/master/LICENSE)
|
||||||
* [cascadia](https://github.com/andybalholm/cascadia) | Available under [license](https://github.com/andybalholm/cascadia/blob/master/LICENSE)
|
* [notificator](https://github.com/0xAX/notificator) available under [license](https://github.com/0xAX/notificator/blob/master/LICENSE)
|
||||||
* [gocertifi](https://github.com/certifi/gocertifi) | Available under [license](https://github.com/certifi/gocertifi/blob/master/LICENSE)
|
* [semver](https://github.com/Masterminds/semver/v3) available under [license](https://github.com/Masterminds/semver/v3/blob/master/LICENSE)
|
||||||
* [logex](https://github.com/chzyer/logex) | Available under [license](https://github.com/chzyer/logex/blob/master/LICENSE)
|
* [go-autostart](https://github.com/ProtonMail/go-autostart) available under [license](https://github.com/ProtonMail/go-autostart/blob/master/LICENSE)
|
||||||
* [test](https://github.com/chzyer/test) | Available under [license](https://github.com/chzyer/test/blob/master/LICENSE)
|
* [go-crypto](https://github.com/ProtonMail/go-crypto) available under [license](https://github.com/ProtonMail/go-crypto/blob/master/LICENSE)
|
||||||
* [godog](https://github.com/cucumber/godog) | Available under [license](https://github.com/cucumber/godog/blob/master/LICENSE)
|
* [go-imap-id](https://github.com/ProtonMail/go-imap-id) available under [license](https://github.com/ProtonMail/go-imap-id/blob/master/LICENSE)
|
||||||
* [wincred](https://github.com/danieljoos/wincred) | Available under [license](https://github.com/danieljoos/wincred/blob/master/LICENSE)
|
* [go-rfc5322](https://github.com/ProtonMail/go-rfc5322) available under [license](https://github.com/ProtonMail/go-rfc5322/blob/master/LICENSE)
|
||||||
* [credential-helpers](https://github.com/docker/docker-credential-helpers) | Available under [license](https://github.com/docker/docker-credential-helpers/blob/master/LICENSE)
|
* [go-srp](https://github.com/ProtonMail/go-srp) available under [license](https://github.com/ProtonMail/go-srp/blob/master/LICENSE)
|
||||||
* [imap](https://github.com/emersion/go-imap) | Available under [license](https://github.com/emersion/go-imap/blob/master/LICENSE)
|
* [go-vcard](https://github.com/ProtonMail/go-vcard) available under [license](https://github.com/ProtonMail/go-vcard/blob/master/LICENSE)
|
||||||
* [imap-appendlimit](https://github.com/emersion/go-imap-appendlimit) | Available under [license](https://github.com/emersion/go-imap-appendlimit/blob/master/LICENSE)
|
* [gopenpgp](https://github.com/ProtonMail/gopenpgp/v2) available under [license](https://github.com/ProtonMail/gopenpgp/v2/blob/master/LICENSE)
|
||||||
* [imap-idle](https://github.com/emersion/go-imap-idle) | Available under [license](https://github.com/emersion/go-imap-idle/blob/master/LICENSE)
|
* [goquery](https://github.com/PuerkitoBio/goquery) available under [license](https://github.com/PuerkitoBio/goquery/blob/master/LICENSE)
|
||||||
* [imap-quota](https://github.com/emersion/go-imap-quota) | Available under [license](https://github.com/emersion/go-imap-quota/blob/master/LICENSE)
|
* [ishell](https://github.com/abiosoft/ishell) available under [license](https://github.com/abiosoft/ishell/blob/master/LICENSE)
|
||||||
* [sasl](https://github.com/emersion/go-sasl) | Available under [license](https://github.com/emersion/go-sasl/blob/master/LICENSE)
|
* [readline](https://github.com/abiosoft/readline) available under [license](https://github.com/abiosoft/readline/blob/master/LICENSE)
|
||||||
* [smtp](https://github.com/emersion/go-smtp) | Available under [license](https://github.com/emersion/go-smtp/blob/master/LICENSE)
|
* [go-singleinstance](https://github.com/allan-simon/go-singleinstance) available under [license](https://github.com/allan-simon/go-singleinstance/blob/master/LICENSE)
|
||||||
* [textwrapper](https://github.com/emersion/go-textwrapper) | Available under [license](https://github.com/emersion/go-textwrapper/blob/master/LICENSE)
|
* [logex](https://github.com/chzyer/logex) available under [license](https://github.com/chzyer/logex/blob/master/LICENSE)
|
||||||
* [vcard](https://github.com/emersion/go-vcard) | Available under [license](https://github.com/emersion/go-vcard/blob/master/LICENSE)
|
* [test](https://github.com/chzyer/test) available under [license](https://github.com/chzyer/test/blob/master/LICENSE)
|
||||||
* [color](https://github.com/fatih/color) | Available under [license](https://github.com/fatih/color/blob/master/LICENSE.md)
|
* [godog](https://github.com/cucumber/godog) available under [license](https://github.com/cucumber/godog/blob/master/LICENSE)
|
||||||
* [shlex](https://github.com/flynn-archive/go-shlex) | Available under [license](https://github.com/flynn-archive/go-shlex/blob/master/COPYING)
|
* [messages-go](https://github.com/cucumber/messages-go/v16) available under [license](https://github.com/cucumber/messages-go/v16/blob/master/LICENSE)
|
||||||
* [raven](https://github.com/getsentry/raven-go) | Available under [license](https://github.com/getsentry/raven-go/blob/master/LICENSE)
|
* [go-sysinfo](https://github.com/elastic/go-sysinfo) available under [license](https://github.com/elastic/go-sysinfo/blob/master/LICENSE)
|
||||||
* [resty](https://github.com/go-resty/resty) | Available under [license](https://github.com/go-resty/resty/blob/master/LICENSE)
|
* [go-windows](https://github.com/elastic/go-windows) available under [license](https://github.com/elastic/go-windows/blob/master/LICENSE)
|
||||||
* [mock](https://github.com/golang/mock) | Available under [license](https://github.com/golang/mock/blob/master/LICENSE)
|
* [go-imap-appendlimit](https://github.com/emersion/go-imap-appendlimit) available under [license](https://github.com/emersion/go-imap-appendlimit/blob/master/LICENSE)
|
||||||
* [cmp](https://github.com/google/go-cmp) | Available under [license](https://github.com/google/go-cmp/blob/master/LICENSE)
|
* [go-imap-move](https://github.com/emersion/go-imap-move) available under [license](https://github.com/emersion/go-imap-move/blob/master/LICENSE)
|
||||||
* [gopherjs](https://github.com/gopherjs/gopherjs) | Available under [license](https://github.com/gopherjs/gopherjs/blob/master/LICENSE)
|
* [go-imap-quota](https://github.com/emersion/go-imap-quota) available under [license](https://github.com/emersion/go-imap-quota/blob/master/LICENSE)
|
||||||
* [multierror](https://github.com/hashicorp/go-multierror) | Available under [license](https://github.com/hashicorp/go-multierror/blob/master/LICENSE)
|
* [go-imap-unselect](https://github.com/emersion/go-imap-unselect) available under [license](https://github.com/emersion/go-imap-unselect/blob/master/LICENSE)
|
||||||
* [bcrypt](https://github.com/jameskeane/bcrypt) | Available under [license](https://github.com/jameskeane/bcrypt/blob/master/LICENSE)
|
* [go-message](https://github.com/emersion/go-message) available under [license](https://github.com/emersion/go-message/blob/master/LICENSE)
|
||||||
* [html2text](https://github.com/jaytaylor/html2text) | Available under [license](https://github.com/jaytaylor/html2text/blob/master/LICENSE)
|
* [go-sasl](https://github.com/emersion/go-sasl) available under [license](https://github.com/emersion/go-sasl/blob/master/LICENSE)
|
||||||
* [enmime](https://github.com/jhillyerd/enmime) | Available under [license](https://github.com/jhillyerd/enmime/blob/master/LICENSE)
|
* [go-smtp](https://github.com/emersion/go-smtp) available under [license](https://github.com/emersion/go-smtp/blob/master/LICENSE)
|
||||||
* [osext](https://github.com/kardianos/osext) | Available under [license](https://github.com/kardianos/osext/blob/master/LICENSE)
|
* [go-textwrapper](https://github.com/emersion/go-textwrapper) available under [license](https://github.com/emersion/go-textwrapper/blob/master/LICENSE)
|
||||||
* [keychain](https://github.com/keybase/go-keychain) | Available under [license](https://github.com/keybase/go-keychain/blob/master/LICENSE)
|
* [go-vcard](https://github.com/emersion/go-vcard) available under [license](https://github.com/emersion/go-vcard/blob/master/LICENSE)
|
||||||
* [aurora](https://github.com/logrusorgru/aurora) | Available under [license](https://github.com/logrusorgru/aurora/blob/master/LICENSE)
|
* [color](https://github.com/fatih/color) available under [license](https://github.com/fatih/color/blob/master/LICENSE)
|
||||||
* [dns](https://github.com/miekg/dns) | Available under [license](https://github.com/miekg/dns/blob/master/LICENSE)
|
* [go-shlex](https://github.com/flynn-archive/go-shlex) available under [license](https://github.com/flynn-archive/go-shlex/blob/master/LICENSE)
|
||||||
* [uuid](https://github.com/myesui/uuid) | Available under [license](https://github.com/myesui/uuid/blob/master/LICENSE)
|
* [sentry-go](https://github.com/getsentry/sentry-go) available under [license](https://github.com/getsentry/sentry-go/blob/master/LICENSE)
|
||||||
* [jsondiff](https://github.com/nsf/jsondiff) | Available under [license](https://github.com/nsf/jsondiff/blob/master/LICENSE)
|
* [resty](https://github.com/go-resty/resty/v2) available under [license](https://github.com/go-resty/resty/v2/blob/master/LICENSE)
|
||||||
* [logrus](https://github.com/sirupsen/logrus) | Available under [license](https://github.com/sirupsen/logrus/blob/master/LICENSE)
|
* [dbus](https://github.com/godbus/dbus) available under [license](https://github.com/godbus/dbus/blob/master/LICENSE)
|
||||||
* [golang](https://github.com/skratchdot/open-golang) | Available under [license](https://github.com/skratchdot/open-golang/blob/master/LICENSE)
|
* [mock](https://github.com/golang/mock) available under [license](https://github.com/golang/mock/blob/master/LICENSE)
|
||||||
* [testify](https://github.com/stretchr/testify) | Available under [license](https://github.com/stretchr/testify/blob/master/LICENSE)
|
* [go-cmp](https://github.com/google/go-cmp) available under [license](https://github.com/google/go-cmp/blob/master/LICENSE)
|
||||||
* [uuid](https://github.com/twinj/uuid) | Available under [license](https://github.com/twinj/uuid/blob/master/LICENSE)
|
* [uuid](https://github.com/google/uuid) available under [license](https://github.com/google/uuid/blob/master/LICENSE)
|
||||||
* [cli](https://github.com/urfave/cli) | Available under [license](https://github.com/urfave/cli/blob/master/LICENSE)
|
* [go-multierror](https://github.com/hashicorp/go-multierror) available under [license](https://github.com/hashicorp/go-multierror/blob/master/LICENSE)
|
||||||
|
* [html2text](https://github.com/jaytaylor/html2text) available under [license](https://github.com/jaytaylor/html2text/blob/master/LICENSE)
|
||||||
* [BBolt](https://pkg.go.dev/go.etcd.io/bbolt/?tab=doc) | Available under [license](https://pkg.go.dev/go.etcd.io/bbolt?tab=licenses#LICENSE)
|
* [go-keychain](https://github.com/keybase/go-keychain) available under [license](https://github.com/keybase/go-keychain/blob/master/LICENSE)
|
||||||
* [testify.v1](https://gopkg.in/stretchr/testify.v1) | Available under [license](https://github.com/stretchr/testify/blob/master/LICENSE)
|
* [text](https://github.com/kr/text) available under [license](https://github.com/kr/text/blob/master/LICENSE)
|
||||||
|
* [aurora](https://github.com/logrusorgru/aurora) available under [license](https://github.com/logrusorgru/aurora/blob/master/LICENSE)
|
||||||
|
* [go-runewidth](https://github.com/mattn/go-runewidth) available under [license](https://github.com/mattn/go-runewidth/blob/master/LICENSE)
|
||||||
|
* [dns](https://github.com/miekg/dns) available under [license](https://github.com/miekg/dns/blob/master/LICENSE)
|
||||||
|
* [pretty](https://github.com/niemeyer/pretty) available under [license](https://github.com/niemeyer/pretty/blob/master/LICENSE)
|
||||||
|
* [jsondiff](https://github.com/nsf/jsondiff) available under [license](https://github.com/nsf/jsondiff/blob/master/LICENSE)
|
||||||
|
* [tablewriter](https://github.com/olekukonko/tablewriter) available under [license](https://github.com/olekukonko/tablewriter/blob/master/LICENSE)
|
||||||
|
* [errors](https://github.com/pkg/errors) available under [license](https://github.com/pkg/errors/blob/master/LICENSE)
|
||||||
|
* [procfs](https://github.com/prometheus/procfs) available under [license](https://github.com/prometheus/procfs/blob/master/LICENSE)
|
||||||
|
* [du](https://github.com/ricochet2200/go-disk-usage/du) available under [license](https://github.com/ricochet2200/go-disk-usage/du/blob/master/LICENSE)
|
||||||
|
* [logrus](https://github.com/sirupsen/logrus) available under [license](https://github.com/sirupsen/logrus/blob/master/LICENSE)
|
||||||
|
* [bom](https://github.com/ssor/bom) available under [license](https://github.com/ssor/bom/blob/master/LICENSE)
|
||||||
|
* [testify](https://github.com/stretchr/testify) available under [license](https://github.com/stretchr/testify/blob/master/LICENSE)
|
||||||
|
* [qt](https://github.com/therecipe/qt) available under [license](https://github.com/therecipe/qt/blob/master/LICENSE)
|
||||||
|
* [cli](https://github.com/urfave/cli/v2) available under [license](https://github.com/urfave/cli/v2/blob/master/LICENSE)
|
||||||
|
* [msgpack](https://github.com/vmihailenco/msgpack/v5) available under [license](https://github.com/vmihailenco/msgpack/v5/blob/master/LICENSE)
|
||||||
|
* [bbolt](https://go.etcd.io/bbolt) available under [license](https://github.com/etcd-io/bbolt/blob/master/LICENSE)
|
||||||
|
* [crypto](https://golang.org/x/crypto) available under [license](https://cs.opensource.google/go/x/crypto/+/master:LICENSE)
|
||||||
|
* [net](https://golang.org/x/net) available under [license](https://cs.opensource.google/go/x/net/+/master:LICENSE)
|
||||||
|
* [sys](https://golang.org/x/sys) available under [license](https://cs.opensource.google/go/x/sys/+/master:LICENSE)
|
||||||
|
* [text](https://golang.org/x/text) available under [license](https://cs.opensource.google/go/x/text/+/master:LICENSE)
|
||||||
|
* [plist](https://howett.net/plist) available under [license](https://github.com/DHowett/go-plist/blob/main/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-imap](https://github.com/ProtonMail/go-imap) available under [license](https://github.com/ProtonMail/go-imap/blob/master/LICENSE)
|
||||||
|
* [go-message](https://github.com/ProtonMail/go-message) available under [license](https://github.com/ProtonMail/go-message/blob/master/LICENSE)
|
||||||
|
* [bcrypt](https://github.com/ProtonMail/bcrypt) available under [license](https://github.com/ProtonMail/bcrypt/blob/master/LICENSE)
|
||||||
|
* [go-keychain](https://github.com/cuthix/go-keychain) available under [license](https://github.com/cuthix/go-keychain/blob/master/LICENSE)
|
||||||
|
<!-- END AUTOGEN -->
|
||||||
|
|||||||
175
Changelog.md
175
Changelog.md
@ -1,7 +1,179 @@
|
|||||||
# ProtonMail Bridge and Import-Export app Changelog
|
# Proton Mail Bridge and Import-Export app Changelog
|
||||||
|
|
||||||
Changelog [format](http://keepachangelog.com/en/1.0.0/)
|
Changelog [format](http://keepachangelog.com/en/1.0.0/)
|
||||||
|
|
||||||
|
## [Bridge 2.2.0] Millau
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Rebranding:
|
||||||
|
* GODT-1508: Splash screen for rebranding.
|
||||||
|
* GODT-1542: Update login screen for rebranding.
|
||||||
|
* GODT-1260: Renaming.
|
||||||
|
* GODT-1502: Rebranding: color and radius.
|
||||||
|
* GODT-1549: Add notification when address list changes.
|
||||||
|
* GODT-1560: Dependecy licenses update and link.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* GODT-1543: Using one buffered event for off and on connection.
|
||||||
|
* GODT-1550: Update dependencies.
|
||||||
|
* GODT-1545 GODT-1521: Change wording and enable release notes link.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* GODT-1534: Reset address when leaving split mode.
|
||||||
|
|
||||||
|
|
||||||
|
## [Bridge 2.1.3] London
|
||||||
|
|
||||||
|
### Added
|
||||||
|
GODT-1525: Add keybase/go-keychain/secretservice as new keychain helper.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
GODT-1527: Change bug report description.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
GODT-1537: Manual in-app update mechanism.
|
||||||
|
|
||||||
|
|
||||||
|
## [Bridge 2.1.2] London
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* GODT-1522: Rebuild macOS keychain notification.
|
||||||
|
* GODT-1437 Add new proxy provider (Quad9 with port).
|
||||||
|
* GODT-1516: Return notification on missing keychain.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* GODT-1451: Do not check for gnome keyring to allow other implementations of secret-service API. Thanks to @remgodow.
|
||||||
|
* GODT-1516 GODT-1451: KeepassXC is crashing on start. We need to block it until it's fixed.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* GODT-1524: Logout issues with macOS.
|
||||||
|
* GODT-1503 GODT-1492: Improve email validation and username in bug report.
|
||||||
|
* GODT-1507: Enable autostart after Qt setup.
|
||||||
|
* GODT-1515: Do not crash when bridge users got disconnected.
|
||||||
|
|
||||||
|
|
||||||
|
## [Bridge 2.1.1] London
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* GODT-1376: Add first userID to sentry scope.
|
||||||
|
* GODT-1375: Add host architecture to sentry reports.
|
||||||
|
* GODT-1364: Add windows CI machine for tests, and build.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* GODT-1499: Remove message from DB once it is not on server any more.
|
||||||
|
|
||||||
|
|
||||||
|
## [Bridge 2.1.0] London
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* GODT-1482: Comment or mitigate panics, unlock cache when needed.
|
||||||
|
* GODT-1481: Always turn off non-encrypted recipient report.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* GODT-1494: Update GopenPGP to 2.4.1.
|
||||||
|
* GODT-1490: Update go sentry and openpgp.
|
||||||
|
* GODT-1474: Optimising live integration tests.
|
||||||
|
* GODT-1483: Correct scope in sentry report.
|
||||||
|
* GODT-1477: Change CoD wording.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* GODT-1478: Add GUI settings for keychain selection.
|
||||||
|
* Other: Change copyright year.
|
||||||
|
* GODT-1329: Dark mode, with autodetect.
|
||||||
|
|
||||||
|
|
||||||
|
## [Bridge 2.0.1] Kwai
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* GODT-1468: Fix main windows status and add background context without retry.
|
||||||
|
|
||||||
|
|
||||||
|
## [Bridge 2.0.0] Kwai
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* GODT-22: New GUI style and improved UX:
|
||||||
|
* GODT-1168 GODT-1169 Qml artifacts for preview.
|
||||||
|
* GODT-1177: Remove Import-Export from repo.
|
||||||
|
* GODT-1167 GODT-1179 Make run-qml-preview.
|
||||||
|
* GODT-1051: Add factory reset to bridge object.
|
||||||
|
* GODT-1179 GODT-658: Components and login flows.
|
||||||
|
* GODT-1051: Factory reset button.
|
||||||
|
* GODT-1158: Adding cache on disk signals.
|
||||||
|
* GODT-1298: Signal GUI is ready and rise window.
|
||||||
|
* Other: Reactive show on startup.
|
||||||
|
* GODT-1319: Set sourceSize everywhere for images.
|
||||||
|
* GODT-1317 Use large png for systray and mark it as mask.
|
||||||
|
* GODT-1346: GODT-1340 GODT-1315 QML changes.
|
||||||
|
* GODT-1365: Create ComboBox component.
|
||||||
|
* GODT-1338: GODT-1343 Help view buttons.
|
||||||
|
* GODT-1340: Not crashing, user list updating in main thread.
|
||||||
|
* GODT-1345: Adding panic handlers.
|
||||||
|
* GODT-1271: Fix Status margings.
|
||||||
|
* GODT-1320: Add loading property to each action within a notification.
|
||||||
|
* GODT-1210: Add "free user" banner.
|
||||||
|
* GODT-1314: Limit description field length within 150/800 bounds.
|
||||||
|
* GODT-1250: Fix Port settings wording.
|
||||||
|
* GODT-1369: Fix link render and wording in Help view.
|
||||||
|
* GODT-1358: Fix wording.
|
||||||
|
* GODT-1272: Fix status view layout.
|
||||||
|
* GODT-1336: Fix showing window on startup.
|
||||||
|
* GODT-175: Add option to attach logs for bug reports.
|
||||||
|
* GODT-1272: Ultimate fix for MacOS transparency.
|
||||||
|
* GODT-1384: Fix SettingsView scroll.
|
||||||
|
* GODT-1385: Fix port setting.
|
||||||
|
* GODT-1378: varia GUI fixes.
|
||||||
|
* GODT-1390: Fix autostart toggle.
|
||||||
|
* GODT-1251: Fix change SMTP settings.
|
||||||
|
* GODT-1389: Fix buttons and banner layout.
|
||||||
|
* GODT-1316: Set default TextArea and TextField behavior.
|
||||||
|
* GODT-1244: Refactor switching stable-early and factory reset.
|
||||||
|
* GODT-1351: Cache and update of space bytes in user object.
|
||||||
|
* GODT-1351: Fix used size update from mail operations.
|
||||||
|
* GODT-1411: refactor SettingView content to fill height.
|
||||||
|
* GODT-1327: Reset cache path to default when disabling.
|
||||||
|
* GODT-1412: Refactor paths and links.
|
||||||
|
* GODT-1226: Fix status window position.
|
||||||
|
* GODT-1366: Simple lookup of index and select current user.
|
||||||
|
* GODT-1325: Add "already logged in" notification.
|
||||||
|
* GODT-1391: Fix link colors across GUI.
|
||||||
|
* GODT-1391: Fix color for avatar text.
|
||||||
|
* GODT-1442: Fix "Sign In" button.
|
||||||
|
* GODT-1428: Fix welcome illustration by using PNG.
|
||||||
|
* GODT-1455 Adding links to setup guide.
|
||||||
|
* GODT-1456: Make text selectable and clickable.
|
||||||
|
* GODT-1459: Wording.
|
||||||
|
* GODT-1460 GODT-1462: Adding delete account dialog and fixing status view brief and icon.
|
||||||
|
* GODT-1458: Splash screen and wording.
|
||||||
|
* GODT-1158: Caching encrypted full body messages on disk:
|
||||||
|
* GODT-1433: Do not save message to cache if it's a draft.
|
||||||
|
* GODT-1431 Do not cache message during new message event when CoD is off.
|
||||||
|
* GODT-1381 Treat readonly folder as failure for cache on disk.
|
||||||
|
* GODT-1431 Prevent watcher when not using disk on cache.
|
||||||
|
* GODT-1381: Use in-memory cache in case local cache is unavailable.
|
||||||
|
* GODT-1356 GODT-1302: Cache on disk concurency and API retries.
|
||||||
|
* GODT-1332 Added tests for cache move functions.
|
||||||
|
* GODT-1332: moved cache related functions to separate file.
|
||||||
|
* GODT-1332 moving cache does not work on Windows.
|
||||||
|
* GODT-1367: use waitgroup instead of channel in pool/pchan.
|
||||||
|
* GODT-1367: Use sync.Once to only close pool jobs once.
|
||||||
|
* GODT-1349: Change cache-related settings when enabling/disabling/moving cache.
|
||||||
|
* GODT-1350: stop cacher/worker properly when logging out user.
|
||||||
|
* GODT-1158: Store full messages bodies on disk.
|
||||||
|
* GODT-1433 Adding first integration test for drafts.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* GODT-1438: Turn off SW OpenGL on windows and add debug info about graphic renderer.
|
||||||
|
* GODT-1425: Factory reset enables launch on startup.
|
||||||
|
* GODT-1433 Message.Type is deprecated, use Flags instead.
|
||||||
|
* GODT-1388: Refactor Alternative routing.
|
||||||
|
|
||||||
|
|
||||||
|
## [Bridge 1.8.12] James
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* GODT-1432: Check if keys are active before unlocking.
|
||||||
|
|
||||||
|
|
||||||
## [Bridge 1.8.11] James
|
## [Bridge 1.8.11] James
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
@ -20,6 +192,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/)
|
|||||||
* GODT-1410: Remove event ID from sentry report description.
|
* GODT-1410: Remove event ID from sentry report description.
|
||||||
* GODT-1395: CI should fail on go.sum changed.
|
* GODT-1395: CI should fail on go.sum changed.
|
||||||
|
|
||||||
|
|
||||||
## [Bridge 1.8.10] James
|
## [Bridge 1.8.10] James
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
88
Makefile
88
Makefile
@ -7,29 +7,16 @@ TARGET_CMD?=Desktop-Bridge
|
|||||||
TARGET_OS?=${GOOS}
|
TARGET_OS?=${GOOS}
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
.PHONY: build build-ie build-nogui build-ie-nogui build-launcher build-launcher-ie versioner hasher
|
.PHONY: build build-nogui build-launcher versioner hasher
|
||||||
|
|
||||||
# Keep version hardcoded so app build works also without Git repository.
|
# Keep version hardcoded so app build works also without Git repository.
|
||||||
BRIDGE_APP_VERSION?=1.8.11+git
|
BRIDGE_APP_VERSION?=2.2.0+git
|
||||||
IE_APP_VERSION?=1.3.3+git
|
|
||||||
APP_VERSION:=${BRIDGE_APP_VERSION}
|
APP_VERSION:=${BRIDGE_APP_VERSION}
|
||||||
SRC_ICO:=logo.ico
|
SRC_ICO:=logo.ico
|
||||||
SRC_ICNS:=Bridge.icns
|
SRC_ICNS:=Bridge.icns
|
||||||
SRC_SVG:=logo.svg
|
SRC_SVG:=logo.svg
|
||||||
TGT_ICNS:=Bridge.icns
|
|
||||||
EXE_NAME:=proton-bridge
|
EXE_NAME:=proton-bridge
|
||||||
CONFIGNAME:=bridge
|
CONFIGNAME:=bridge
|
||||||
WINDRES_DEFINE:=BUILD_BRIDGE
|
|
||||||
ifeq "${TARGET_CMD}" "Import-Export"
|
|
||||||
APP_VERSION:=${IE_APP_VERSION}
|
|
||||||
SRC_ICO:=ie.ico
|
|
||||||
SRC_ICNS:=ie.icns
|
|
||||||
SRC_SVG:=ie.svg
|
|
||||||
TGT_ICNS:=ImportExport.icns
|
|
||||||
EXE_NAME:=proton-ie
|
|
||||||
CONFIGNAME:=importExport
|
|
||||||
WINDRES_DEFINE:=BUILD_IE
|
|
||||||
endif
|
|
||||||
REVISION:=$(shell git rev-parse --short=10 HEAD)
|
REVISION:=$(shell git rev-parse --short=10 HEAD)
|
||||||
BUILD_TIME:=$(shell date +%FT%T%z)
|
BUILD_TIME:=$(shell date +%FT%T%z)
|
||||||
|
|
||||||
@ -41,7 +28,6 @@ ifneq "${BUILD_LDFLAGS}" ""
|
|||||||
GO_LDFLAGS+=${BUILD_LDFLAGS}
|
GO_LDFLAGS+=${BUILD_LDFLAGS}
|
||||||
endif
|
endif
|
||||||
GO_LDFLAGS_LAUNCHER:=${GO_LDFLAGS}
|
GO_LDFLAGS_LAUNCHER:=${GO_LDFLAGS}
|
||||||
GO_LDFLAGS_LAUNCHER+=$(addprefix -X main.,ConfigName=${CONFIGNAME} ExeName=proton-${APP})
|
|
||||||
ifeq "${TARGET_OS}" "windows"
|
ifeq "${TARGET_OS}" "windows"
|
||||||
GO_LDFLAGS_LAUNCHER+=-H=windowsgui
|
GO_LDFLAGS_LAUNCHER+=-H=windowsgui
|
||||||
endif
|
endif
|
||||||
@ -70,9 +56,6 @@ EXE_TARGET:=${DEPLOY_DIR}/${TARGET_OS}/${EXE}
|
|||||||
EXE_QT_TARGET:=${DEPLOY_DIR}/${TARGET_OS}/${EXE_QT}
|
EXE_QT_TARGET:=${DEPLOY_DIR}/${TARGET_OS}/${EXE_QT}
|
||||||
|
|
||||||
TGZ_TARGET:=bridge_${TARGET_OS}_${REVISION}.tgz
|
TGZ_TARGET:=bridge_${TARGET_OS}_${REVISION}.tgz
|
||||||
ifeq "${TARGET_CMD}" "Import-Export"
|
|
||||||
TGZ_TARGET:=ie_${TARGET_OS}_${REVISION}.tgz
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifdef QT_API
|
ifdef QT_API
|
||||||
VENDOR_TARGET:=prepare-vendor update-qt-docs
|
VENDOR_TARGET:=prepare-vendor update-qt-docs
|
||||||
@ -82,15 +65,9 @@ endif
|
|||||||
|
|
||||||
build: ${TGZ_TARGET}
|
build: ${TGZ_TARGET}
|
||||||
|
|
||||||
build-ie:
|
|
||||||
TARGET_CMD=Import-Export $(MAKE) build
|
|
||||||
|
|
||||||
build-nogui: gofiles
|
build-nogui: gofiles
|
||||||
go build ${BUILD_FLAGS} -o ${EXE_NAME} cmd/${TARGET_CMD}/main.go
|
go build ${BUILD_FLAGS} -o ${EXE_NAME} cmd/${TARGET_CMD}/main.go
|
||||||
|
|
||||||
build-ie-nogui:
|
|
||||||
TARGET_CMD=Import-Export $(MAKE) build-nogui
|
|
||||||
|
|
||||||
ifeq "${GOOS}" "windows"
|
ifeq "${GOOS}" "windows"
|
||||||
PRERESOURCECMD:=cp ./resource.syso ./cmd/launcher/resource.syso
|
PRERESOURCECMD:=cp ./resource.syso ./cmd/launcher/resource.syso
|
||||||
POSTRESOURCECMD:=rm -f ./cmd/launcher/resource.syso
|
POSTRESOURCECMD:=rm -f ./cmd/launcher/resource.syso
|
||||||
@ -100,9 +77,6 @@ build-launcher: ${RESOURCE_FILE}
|
|||||||
go build ${BUILD_FLAGS_LAUNCHER} -o launcher-${EXE} ./cmd/launcher/
|
go build ${BUILD_FLAGS_LAUNCHER} -o launcher-${EXE} ./cmd/launcher/
|
||||||
${POSTRESOURCECMD}
|
${POSTRESOURCECMD}
|
||||||
|
|
||||||
build-launcher-ie:
|
|
||||||
TARGET_CMD=Import-Export $(MAKE) build-launcher
|
|
||||||
|
|
||||||
versioner:
|
versioner:
|
||||||
go build ${BUILD_FLAGS} -o versioner utils/versioner/main.go
|
go build ${BUILD_FLAGS} -o versioner utils/versioner/main.go
|
||||||
|
|
||||||
@ -111,10 +85,10 @@ hasher:
|
|||||||
|
|
||||||
${TGZ_TARGET}: ${DEPLOY_DIR}/${TARGET_OS}
|
${TGZ_TARGET}: ${DEPLOY_DIR}/${TARGET_OS}
|
||||||
rm -f $@
|
rm -f $@
|
||||||
cd ${DEPLOY_DIR}/${TARGET_OS} && tar czf ../../../../$@ .
|
cd ${DEPLOY_DIR}/${TARGET_OS} && tar -czvf ../../../../$@ .
|
||||||
|
|
||||||
${DEPLOY_DIR}/linux: ${EXE_TARGET}
|
${DEPLOY_DIR}/linux: ${EXE_TARGET}
|
||||||
cp -pf ./internal/frontend/share/icons/${SRC_SVG} ${DEPLOY_DIR}/linux/logo.svg
|
cp -pf ./internal/frontend/share/${SRC_SVG} ${DEPLOY_DIR}/linux/logo.svg
|
||||||
cp -pf ./LICENSE ${DEPLOY_DIR}/linux/
|
cp -pf ./LICENSE ${DEPLOY_DIR}/linux/
|
||||||
cp -pf ./Changelog.md ${DEPLOY_DIR}/linux/
|
cp -pf ./Changelog.md ${DEPLOY_DIR}/linux/
|
||||||
cp -pf ./dist/${EXE_NAME}.desktop ${DEPLOY_DIR}/linux/
|
cp -pf ./dist/${EXE_NAME}.desktop ${DEPLOY_DIR}/linux/
|
||||||
@ -124,7 +98,7 @@ ${DEPLOY_DIR}/darwin: ${EXE_TARGET}
|
|||||||
mv ${EXE_TARGET}/Contents/MacOS/{${DIRNAME},${EXE_NAME}}; \
|
mv ${EXE_TARGET}/Contents/MacOS/{${DIRNAME},${EXE_NAME}}; \
|
||||||
perl -i -pe"s/>${DIRNAME}/>${EXE_NAME}/g" ${EXE_TARGET}/Contents/Info.plist; \
|
perl -i -pe"s/>${DIRNAME}/>${EXE_NAME}/g" ${EXE_TARGET}/Contents/Info.plist; \
|
||||||
fi
|
fi
|
||||||
cp ./internal/frontend/share/icons/${SRC_ICNS} ${DARWINAPP_CONTENTS}/Resources/${TGT_ICNS}
|
cp ./internal/frontend/share/${SRC_ICNS} ${DARWINAPP_CONTENTS}/Resources/${SRC_ICNS}
|
||||||
cp LICENSE ${DARWINAPP_CONTENTS}/Resources/
|
cp LICENSE ${DARWINAPP_CONTENTS}/Resources/
|
||||||
rm -rf "${DARWINAPP_CONTENTS}/Frameworks/QtWebEngine.framework"
|
rm -rf "${DARWINAPP_CONTENTS}/Frameworks/QtWebEngine.framework"
|
||||||
rm -rf "${DARWINAPP_CONTENTS}/Frameworks/QtWebView.framework"
|
rm -rf "${DARWINAPP_CONTENTS}/Frameworks/QtWebView.framework"
|
||||||
@ -132,7 +106,7 @@ ${DEPLOY_DIR}/darwin: ${EXE_TARGET}
|
|||||||
./utils/remove_non_relative_links_darwin.sh "${EXE_TARGET}${EXE_BINARY_DARWIN}"
|
./utils/remove_non_relative_links_darwin.sh "${EXE_TARGET}${EXE_BINARY_DARWIN}"
|
||||||
|
|
||||||
${DEPLOY_DIR}/windows: ${EXE_TARGET}
|
${DEPLOY_DIR}/windows: ${EXE_TARGET}
|
||||||
cp ./internal/frontend/share/icons/${SRC_ICO} ${DEPLOY_DIR}/windows/logo.ico
|
cp ./internal/frontend/share/${SRC_ICO} ${DEPLOY_DIR}/windows/logo.ico
|
||||||
cp LICENSE ${DEPLOY_DIR}/windows/
|
cp LICENSE ${DEPLOY_DIR}/windows/
|
||||||
|
|
||||||
QT_BUILD_TARGET:=build desktop
|
QT_BUILD_TARGET:=build desktop
|
||||||
@ -153,9 +127,9 @@ ${EXE_TARGET}: check-has-go gofiles ${RESOURCE_FILE} ${VENDOR_TARGET}
|
|||||||
|
|
||||||
WINDRES_YEAR:=$(shell date +%Y)
|
WINDRES_YEAR:=$(shell date +%Y)
|
||||||
APP_VERSION_COMMA:=$(shell echo "${APP_VERSION}" | sed -e 's/[^0-9,.]*//g' -e 's/\./,/g')
|
APP_VERSION_COMMA:=$(shell echo "${APP_VERSION}" | sed -e 's/[^0-9,.]*//g' -e 's/\./,/g')
|
||||||
resource.syso: ./internal/frontend/share/info.rc ./internal/frontend/share/icons/${SRC_ICO} .FORCE
|
resource.syso: ./internal/frontend/share/info.rc ./internal/frontend/share/${SRC_ICO} .FORCE
|
||||||
rm -f ./*.syso
|
rm -f ./*.syso
|
||||||
windres --target=pe-x86-64 -I ./internal/frontend/share/icons/ -D ${WINDRES_DEFINE} -D ICO_FILE=${SRC_ICO} -D EXE_NAME="${EXE_NAME}" -D FILE_VERSION="${APP_VERSION}" -D ORIGINAL_FILE_NAME="${EXE}" -D PRODUCT_VERSION="${APP_VERSION}" -D FILE_VERSION_COMMA=${APP_VERSION_COMMA} -D YEAR=${WINDRES_YEAR} -o $@ $<
|
windres --target=pe-x86-64 -I ./internal/frontend/share/ -D ICO_FILE=${SRC_ICO} -D EXE_NAME="${EXE_NAME}" -D FILE_VERSION="${APP_VERSION}" -D ORIGINAL_FILE_NAME="${EXE}" -D PRODUCT_VERSION="${APP_VERSION}" -D FILE_VERSION_COMMA=${APP_VERSION_COMMA} -D YEAR=${WINDRES_YEAR} -o $@ $<
|
||||||
|
|
||||||
## Rules for therecipe/qt
|
## Rules for therecipe/qt
|
||||||
.PHONY: prepare-vendor update-vendor update-qt-docs
|
.PHONY: prepare-vendor update-vendor update-qt-docs
|
||||||
@ -230,16 +204,13 @@ test: gofiles
|
|||||||
./internal/cookies/... \
|
./internal/cookies/... \
|
||||||
./internal/crash/... \
|
./internal/crash/... \
|
||||||
./internal/events/... \
|
./internal/events/... \
|
||||||
./internal/frontend/autoconfig/... \
|
|
||||||
./internal/frontend/cli/... \
|
./internal/frontend/cli/... \
|
||||||
./internal/imap/... \
|
./internal/imap/... \
|
||||||
./internal/importexport/... \
|
|
||||||
./internal/locations/... \
|
./internal/locations/... \
|
||||||
./internal/logging/... \
|
./internal/logging/... \
|
||||||
./internal/metrics/... \
|
./internal/metrics/... \
|
||||||
./internal/smtp/... \
|
./internal/smtp/... \
|
||||||
./internal/store/... \
|
./internal/store/... \
|
||||||
./internal/transfer/... \
|
|
||||||
./internal/updater/... \
|
./internal/updater/... \
|
||||||
./internal/users/... \
|
./internal/users/... \
|
||||||
./internal/versioner/... \
|
./internal/versioner/... \
|
||||||
@ -259,17 +230,19 @@ integration-test-bridge:
|
|||||||
mocks:
|
mocks:
|
||||||
mockgen --package mocks github.com/ProtonMail/proton-bridge/internal/users Locator,PanicHandler,CredentialsStorer,StoreMaker > internal/users/mocks/mocks.go
|
mockgen --package mocks github.com/ProtonMail/proton-bridge/internal/users Locator,PanicHandler,CredentialsStorer,StoreMaker > internal/users/mocks/mocks.go
|
||||||
mockgen --package mocks github.com/ProtonMail/proton-bridge/pkg/listener Listener > internal/users/mocks/listener_mocks.go
|
mockgen --package mocks github.com/ProtonMail/proton-bridge/pkg/listener Listener > internal/users/mocks/listener_mocks.go
|
||||||
mockgen --package mocks github.com/ProtonMail/proton-bridge/internal/transfer PanicHandler,IMAPClientProvider > internal/transfer/mocks/mocks.go
|
mockgen --package mocks github.com/ProtonMail/proton-bridge/internal/store PanicHandler,BridgeUser,ChangeNotifier,Storer > internal/store/mocks/mocks.go
|
||||||
mockgen --package mocks github.com/ProtonMail/proton-bridge/internal/store PanicHandler,BridgeUser,ChangeNotifier > internal/store/mocks/mocks.go
|
|
||||||
mockgen --package mocks github.com/ProtonMail/proton-bridge/pkg/listener Listener > internal/store/mocks/utils_mocks.go
|
mockgen --package mocks github.com/ProtonMail/proton-bridge/pkg/listener Listener > internal/store/mocks/utils_mocks.go
|
||||||
mockgen --package mocks github.com/ProtonMail/proton-bridge/pkg/pmapi Client,Manager > pkg/pmapi/mocks/mocks.go
|
mockgen --package mocks github.com/ProtonMail/proton-bridge/pkg/pmapi Client,Manager > pkg/pmapi/mocks/mocks.go
|
||||||
mockgen --package mocks github.com/ProtonMail/proton-bridge/pkg/message Fetcher > pkg/message/mocks/mocks.go
|
mockgen --package mocks github.com/ProtonMail/proton-bridge/pkg/message Fetcher > pkg/message/mocks/mocks.go
|
||||||
|
|
||||||
lint: gofiles lint-golang lint-license lint-changelog
|
lint: gofiles lint-golang lint-license lint-dependencies lint-changelog
|
||||||
|
|
||||||
lint-license:
|
lint-license:
|
||||||
./utils/missing_license.sh check
|
./utils/missing_license.sh check
|
||||||
|
|
||||||
|
lint-dependencies:
|
||||||
|
./utils/dependency_license.sh check
|
||||||
|
|
||||||
lint-changelog:
|
lint-changelog:
|
||||||
./utils/changelog_linter.sh Changelog.md
|
./utils/changelog_linter.sh Changelog.md
|
||||||
|
|
||||||
@ -285,7 +258,7 @@ updates: install-go-mod-outdated
|
|||||||
doc:
|
doc:
|
||||||
godoc -http=:6060
|
godoc -http=:6060
|
||||||
|
|
||||||
release-notes: release-notes/bridge_stable.html release-notes/bridge_early.html release-notes/ie_stable.html release-notes/ie_early.html
|
release-notes: release-notes/bridge_stable.html release-notes/bridge_early.html
|
||||||
|
|
||||||
release-notes/%.html: release-notes/%.md
|
release-notes/%.html: release-notes/%.md
|
||||||
./utils/release_notes.sh $^
|
./utils/release_notes.sh $^
|
||||||
@ -293,26 +266,22 @@ release-notes/%.html: release-notes/%.md
|
|||||||
.PHONY: gofiles
|
.PHONY: gofiles
|
||||||
# Following files are for the whole app so it makes sense to have them in bridge package.
|
# Following files are for the whole app so it makes sense to have them in bridge package.
|
||||||
# (Options like cmd or internal were considered and bridge package is the best place for them.)
|
# (Options like cmd or internal were considered and bridge package is the best place for them.)
|
||||||
gofiles: ./internal/bridge/credits.go ./internal/importexport/credits.go
|
gofiles: ./internal/bridge/credits.go
|
||||||
./internal/bridge/credits.go: ./utils/credits.sh go.mod
|
./internal/bridge/credits.go: ./utils/credits.sh go.mod
|
||||||
cd ./utils/ && ./credits.sh bridge
|
cd ./utils/ && ./credits.sh bridge
|
||||||
./internal/importexport/credits.go: ./utils/credits.sh go.mod
|
|
||||||
cd ./utils/ && ./credits.sh importexport
|
|
||||||
|
|
||||||
|
|
||||||
## Run and debug
|
## Run and debug
|
||||||
.PHONY: run run-qt run-qt-cli run-nogui run-nogui-cli run-debug run-qml-preview run-ie-qml-preview run-ie run-ie-qt run-ie-qt-cli run-ie-nogui run-ie-nogui-cli clean-vendor clean-frontend-qt clean-frontend-qt-ie clean-frontend-qt-common clean
|
.PHONY: run run-qt run-qt-cli run-nogui run-nogui-cli run-debug run-qml-preview clean-vendor clean-frontend-qt clean-frontend-qt-common clean
|
||||||
|
|
||||||
LOG?=debug
|
LOG?=debug
|
||||||
LOG_IMAP?=client # client/server/all, or empty to turn it off
|
LOG_IMAP?=client # client/server/all, or empty to turn it off
|
||||||
LOG_SMTP?=--log-smtp # empty to turn it off
|
LOG_SMTP?=--log-smtp # empty to turn it off
|
||||||
RUN_FLAGS?=-m -l=${LOG} --log-imap=${LOG_IMAP} ${LOG_SMTP}
|
RUN_FLAGS?=-m -l=${LOG} --log-imap=${LOG_IMAP} ${LOG_SMTP}
|
||||||
RUN_FLAGS_IE?=-m -l=${LOG}
|
|
||||||
|
|
||||||
run: run-nogui-cli
|
run: run-nogui-cli
|
||||||
|
|
||||||
run-qt: ${EXE_TARGET}
|
run-qt: ${EXE_TARGET}
|
||||||
PROTONMAIL_ENV=dev ./$< ${RUN_FLAGS} | tee last.log
|
PROTONMAIL_ENV=dev ./$< ${RUN_FLAGS} 2>&1 | tee last.log
|
||||||
run-qt-cli: ${EXE_TARGET}
|
run-qt-cli: ${EXE_TARGET}
|
||||||
PROTONMAIL_ENV=dev ./$< ${RUN_FLAGS} -c
|
PROTONMAIL_ENV=dev ./$< ${RUN_FLAGS} -c
|
||||||
|
|
||||||
@ -322,28 +291,17 @@ run-nogui-cli: clean-vendor gofiles
|
|||||||
PROTONMAIL_ENV=dev go run ${BUILD_FLAGS} cmd/${TARGET_CMD}/main.go ${RUN_FLAGS} -c
|
PROTONMAIL_ENV=dev go run ${BUILD_FLAGS} cmd/${TARGET_CMD}/main.go ${RUN_FLAGS} -c
|
||||||
|
|
||||||
run-debug:
|
run-debug:
|
||||||
PROTONMAIL_ENV=dev dlv debug --build-flags "${BUILD_FLAGS}" cmd/${TARGET_CMD}/main.go -- ${RUN_FLAGS}
|
PROTONMAIL_ENV=dev dlv debug --build-flags "${BUILD_FLAGS}" cmd/${TARGET_CMD}/main.go -- ${RUN_FLAGS} --noninteractive
|
||||||
|
|
||||||
run-qml-preview:
|
run-qml-preview:
|
||||||
$(MAKE) -C internal/frontend/qt -f Makefile.local qmlpreview
|
find internal/frontend/qml/ -iname '*qmlc' | xargs rm -f
|
||||||
run-ie-qml-preview:
|
bridge_preview internal/frontend/qml/Bridge_test.qml
|
||||||
$(MAKE) -C internal/frontend/qt-ie -f Makefile.local qmlpreview
|
|
||||||
|
|
||||||
run-ie:
|
|
||||||
TARGET_CMD=Import-Export RUN_FLAGS="${RUN_FLAGS_IE}" $(MAKE) run
|
|
||||||
run-ie-qt:
|
|
||||||
TARGET_CMD=Import-Export RUN_FLAGS="${RUN_FLAGS_IE}" $(MAKE) run-qt
|
|
||||||
run-ie-nogui:
|
|
||||||
TARGET_CMD=Import-Export RUN_FLAGS="${RUN_FLAGS_IE}" $(MAKE) run-nogui
|
|
||||||
|
|
||||||
clean-frontend-qt:
|
clean-frontend-qt:
|
||||||
$(MAKE) -C internal/frontend/qt -f Makefile.local clean
|
$(MAKE) -C internal/frontend -f Makefile.local clean
|
||||||
clean-frontend-qt-ie:
|
|
||||||
$(MAKE) -C internal/frontend/qt-ie -f Makefile.local clean
|
|
||||||
clean-frontend-qt-common:
|
|
||||||
$(MAKE) -C internal/frontend/qt-common -f Makefile.local clean
|
|
||||||
|
|
||||||
clean-vendor: clean-frontend-qt clean-frontend-qt-ie clean-frontend-qt-common
|
clean-vendor: clean-frontend-qt clean-frontend-qt-common
|
||||||
rm -rf ./vendor
|
rm -rf ./vendor
|
||||||
|
|
||||||
clean: clean-vendor
|
clean: clean-vendor
|
||||||
|
|||||||
35
README.md
35
README.md
@ -1,22 +1,22 @@
|
|||||||
# ProtonMail Bridge and Import Export app
|
# Proton Mail Bridge and Import Export app
|
||||||
Copyright (c) 2020 Proton Technologies AG
|
Copyright (c) 2022 Proton AG
|
||||||
|
|
||||||
This repository holds the ProtonMail Bridge and the ProtonMail Import-Export applications.
|
This repository holds the Proton Mail Bridge and the Proton Mail Import-Export applications.
|
||||||
For a detailed build information see [BUILDS](./BUILDS.md).
|
For a detailed build information see [BUILDS](./BUILDS.md).
|
||||||
The license can be found in [LICENSE](./LICENSE) file, for more licensing information see [COPYING_NOTES](./COPYING_NOTES.md).
|
The license can be found in [LICENSE](./LICENSE) file, for more licensing information see [COPYING_NOTES](./COPYING_NOTES.md).
|
||||||
For contribution policy see [CONTRIBUTING](./CONTRIBUTING.md).
|
For contribution policy see [CONTRIBUTING](./CONTRIBUTING.md).
|
||||||
|
|
||||||
|
|
||||||
## Description Bridge
|
## Description Bridge
|
||||||
ProtonMail Bridge for e-mail clients.
|
Proton Mail Bridge for e-mail clients.
|
||||||
|
|
||||||
When launched, Bridge will initialize local IMAP/SMTP servers and render
|
When launched, Bridge will initialize local IMAP/SMTP servers and render
|
||||||
its GUI.
|
its GUI.
|
||||||
|
|
||||||
To configure an e-mail client, firstly log in using your ProtonMail credentials.
|
To configure an e-mail client, firstly log in using your Proton Mail credentials.
|
||||||
Open your e-mail client and add a new account using the settings which are
|
Open your e-mail client and add a new account using the settings which are
|
||||||
located in the Bridge GUI. The client will only be able to sync with
|
located in the Bridge GUI. The client will only be able to sync with
|
||||||
your ProtonMail account when the Bridge is running, thus the option
|
your Proton Mail account when the Bridge is running, thus the option
|
||||||
to start Bridge on startup is enabled by default.
|
to start Bridge on startup is enabled by default.
|
||||||
|
|
||||||
When the main window is closed, Bridge will continue to run in the
|
When the main window is closed, Bridge will continue to run in the
|
||||||
@ -25,9 +25,9 @@ background.
|
|||||||
More details [on the public website](https://protonmail.com/bridge).
|
More details [on the public website](https://protonmail.com/bridge).
|
||||||
|
|
||||||
## Description Import-Export app
|
## Description Import-Export app
|
||||||
ProtonMail Import-Export app for importing and exporting messages.
|
Proton Mail Import-Export app for importing and exporting messages.
|
||||||
|
|
||||||
To transfer messages, firstly log in using your ProtonMail credentials.
|
To transfer messages, firstly log in using your Proton Mail credentials.
|
||||||
For import, expand your account, and pick the address to which to import
|
For import, expand your account, and pick the address to which to import
|
||||||
messages from IMAP server or local EML or MBOX files. For export, pick
|
messages from IMAP server or local EML or MBOX files. For export, pick
|
||||||
the whole account or only a specific address. Then, in both cases,
|
the whole account or only a specific address. Then, in both cases,
|
||||||
@ -37,10 +37,12 @@ check the results.
|
|||||||
|
|
||||||
More details [on the public website](https://protonmail.com/import-export).
|
More details [on the public website](https://protonmail.com/import-export).
|
||||||
|
|
||||||
## Launchers
|
The Import-Export app is developed in separate branch `master-ie`.
|
||||||
Launchers are binaries used to run the ProtonMail Bridge or Import-Export apps.
|
|
||||||
|
|
||||||
Official distributions of the ProtonMail Bridge and Import-Export apps contain
|
## Launchers
|
||||||
|
Launchers are binaries used to run the Proton Mail Bridge or Import-Export apps.
|
||||||
|
|
||||||
|
Official distributions of the Proton Mail Bridge and Import-Export apps contain
|
||||||
both a launcher and the app itself. The launcher is installed in a protected
|
both a launcher and the app itself. The launcher is installed in a protected
|
||||||
area of the system (i.e. an area accessible only with admin privileges) and is
|
area of the system (i.e. an area accessible only with admin privileges) and is
|
||||||
used to run the app. The launcher ensures that nobody tampered with the app's
|
used to run the app. The launcher ensures that nobody tampered with the app's
|
||||||
@ -50,11 +52,13 @@ feature enables the app to securely update itself automatically without asking
|
|||||||
the user for a password.
|
the user for a password.
|
||||||
|
|
||||||
## Keychain
|
## Keychain
|
||||||
You need to have a keychain in order to run the ProtonMail Bridge. On Mac or
|
You need to have a keychain in order to run the Proton Mail Bridge. On Mac or
|
||||||
Windows, Bridge uses native credential managers. On Linux, use
|
Windows, Bridge uses native credential managers. On Linux, use `secret-service` freedesktop.org API
|
||||||
[Gnome keyring](https://wiki.gnome.org/Projects/GnomeKeyring/)
|
(e.g. [Gnome keyring](https://wiki.gnome.org/Projects/GnomeKeyring/))
|
||||||
or
|
or
|
||||||
[pass](https://www.passwordstore.org/).
|
[pass](https://www.passwordstore.org/). We are working on allowing other secret
|
||||||
|
services (e.g. KeepassXC), but for now only gnome-keyring is usable without
|
||||||
|
major problems.
|
||||||
|
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
@ -69,7 +73,6 @@ or
|
|||||||
|
|
||||||
### Integration testing
|
### Integration testing
|
||||||
- `TEST_ENV`: set which env to use (fake or live)
|
- `TEST_ENV`: set which env to use (fake or live)
|
||||||
- `TEST_APP`: set which app to test (bridge or ie)
|
|
||||||
- `TEST_ACCOUNTS`: set JSON file with configured accounts
|
- `TEST_ACCOUNTS`: set JSON file with configured accounts
|
||||||
- `TAGS`: set build tags for tests
|
- `TAGS`: set build tags for tests
|
||||||
- `FEATURES`: set feature dir, file or scenario to test
|
- `FEATURES`: set feature dir, file or scenario to test
|
||||||
|
|||||||
1
TODO.md
Normal file
1
TODO.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
- when cache is full, we need to stop the watcher? don't want to keep downloading messages and throwing them away when we try to cache them.
|
||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
appName = "ProtonMail Bridge"
|
appName = "Proton Mail Bridge"
|
||||||
appUsage = "ProtonMail IMAP and SMTP Bridge"
|
appUsage = "Proton Mail IMAP and SMTP Bridge"
|
||||||
configName = "bridge"
|
configName = "bridge"
|
||||||
updateURLName = "bridge"
|
updateURLName = "bridge"
|
||||||
keychainName = "bridge"
|
keychainName = "bridge"
|
||||||
|
|||||||
@ -1,57 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/app/base"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/app/ie"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
appName = "ProtonMail Import-Export app"
|
|
||||||
appUsage = "Import and export messages to/from your ProtonMail account"
|
|
||||||
configName = "importExport"
|
|
||||||
updateURLName = "ie"
|
|
||||||
keychainName = "import-export-app"
|
|
||||||
cacheVersion = "c11"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
base, err := base.New(
|
|
||||||
appName,
|
|
||||||
appUsage,
|
|
||||||
configName,
|
|
||||||
updateURLName,
|
|
||||||
keychainName,
|
|
||||||
cacheVersion,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
logrus.WithError(err).Fatal("Failed to create app base")
|
|
||||||
}
|
|
||||||
// Other instance already running.
|
|
||||||
if base == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ie.New(base).Run(os.Args); err != nil {
|
|
||||||
logrus.WithError(err).Fatal("IE exited with error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@ -38,25 +38,24 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const appName = "ProtonMail Launcher"
|
const (
|
||||||
|
appName = "Proton Mail Launcher"
|
||||||
var (
|
configName = "bridge"
|
||||||
ConfigName = "" // nolint[gochecknoglobals]
|
exeName = "proton-bridge"
|
||||||
ExeName = "" // nolint[gochecknoglobals]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() { // nolint[funlen]
|
func main() { //nolint:funlen
|
||||||
reporter := sentry.NewReporter(appName, constants.Version, useragent.New())
|
reporter := sentry.NewReporter(appName, constants.Version, useragent.New())
|
||||||
|
|
||||||
crashHandler := crash.NewHandler(reporter.ReportException)
|
crashHandler := crash.NewHandler(reporter.ReportException)
|
||||||
defer crashHandler.HandlePanic()
|
defer crashHandler.HandlePanic()
|
||||||
|
|
||||||
locationsProvider, err := locations.NewDefaultProvider(filepath.Join(constants.VendorName, ConfigName))
|
locationsProvider, err := locations.NewDefaultProvider(filepath.Join(constants.VendorName, configName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatal("Failed to get locations provider")
|
logrus.WithError(err).Fatal("Failed to get locations provider")
|
||||||
}
|
}
|
||||||
|
|
||||||
locations := locations.New(locationsProvider, ConfigName)
|
locations := locations.New(locationsProvider, configName)
|
||||||
|
|
||||||
logsPath, err := locations.ProvideLogsPath()
|
logsPath, err := locations.ProvideLogsPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -87,9 +86,9 @@ func main() { // nolint[funlen]
|
|||||||
|
|
||||||
versioner := versioner.New(updatesPath)
|
versioner := versioner.New(updatesPath)
|
||||||
|
|
||||||
exe, err := getPathToUpdatedExecutable(ExeName, versioner, kr, reporter)
|
exe, err := getPathToUpdatedExecutable(exeName, versioner, kr, reporter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if exe, err = getFallbackExecutable(ExeName, versioner); err != nil {
|
if exe, err = getFallbackExecutable(exeName, versioner); err != nil {
|
||||||
logrus.WithError(err).Fatal("Failed to find any launchable executable")
|
logrus.WithError(err).Fatal("Failed to find any launchable executable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,7 +98,7 @@ func main() { // nolint[funlen]
|
|||||||
logrus.WithError(err).Fatal("Failed to determine path to launcher")
|
logrus.WithError(err).Fatal("Failed to determine path to launcher")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(exe, appendLauncherPath(launcher, os.Args[1:])...) // nolint[gosec]
|
cmd := exec.Command(exe, appendLauncherPath(launcher, os.Args[1:])...) //nolint:gosec
|
||||||
|
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
|
|||||||
4
dist/proton-bridge.desktop
vendored
4
dist/proton-bridge.desktop
vendored
@ -1,8 +1,8 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Version=1.1
|
Version=1.1
|
||||||
Name=ProtonMail Bridge
|
Name=Proton Mail Bridge
|
||||||
GenericName=ProtonMail Bridge for Linux
|
GenericName=Proton Mail Bridge for Linux
|
||||||
Comment=The Bridge is an application that runs on your computer in the background and seamlessly encrypts and decrypts your mail as it enters and leaves your computer.
|
Comment=The Bridge is an application that runs on your computer in the background and seamlessly encrypts and decrypts your mail as it enters and leaves your computer.
|
||||||
Icon=protonmail-bridge
|
Icon=protonmail-bridge
|
||||||
Exec=protonmail-bridge
|
Exec=protonmail-bridge
|
||||||
|
|||||||
11
dist/proton-ie.desktop
vendored
11
dist/proton-ie.desktop
vendored
@ -1,11 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Type=Application
|
|
||||||
Version=1.1
|
|
||||||
Name=ProtonMail Import-Export app
|
|
||||||
GenericName=ProtonMail Import-Export app for Linux
|
|
||||||
Comment=The Import-Export app helps you to migrate your emails from local files or remote IMAP servers to ProtonMail or simply export emails to local folder.
|
|
||||||
Icon=protonmail-import-export-app
|
|
||||||
Exec=protonmail-import-export-app
|
|
||||||
Terminal=false
|
|
||||||
Categories=Office;Email;Network
|
|
||||||
StartupWMClass=protonmail-import-export-app
|
|
||||||
@ -51,7 +51,7 @@ PMAPI directly.
|
|||||||
graph TD
|
graph TD
|
||||||
|
|
||||||
C["Client (e.g. Thunderbird)"]
|
C["Client (e.g. Thunderbird)"]
|
||||||
PM[ProtonMail Server]
|
PM[Proton Mail Server]
|
||||||
|
|
||||||
subgraph "Bridge app"
|
subgraph "Bridge app"
|
||||||
subgraph "Bridge core"
|
subgraph "Bridge core"
|
||||||
|
|||||||
@ -1,135 +0,0 @@
|
|||||||
# Import-Export app
|
|
||||||
|
|
||||||
## Main blocks
|
|
||||||
|
|
||||||
This is basic overview of the main Import-Export blocks.
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph LR
|
|
||||||
S[ProtonMail server]
|
|
||||||
U[User]
|
|
||||||
|
|
||||||
subgraph "Import-Export app"
|
|
||||||
Users
|
|
||||||
Frontend["Qt / CLI"]
|
|
||||||
ImportExport
|
|
||||||
Transfer
|
|
||||||
|
|
||||||
Frontend --> ImportExport
|
|
||||||
Frontend --> Transfer
|
|
||||||
ImportExport --> Users
|
|
||||||
ImportExport --> Transfer
|
|
||||||
end
|
|
||||||
|
|
||||||
EML --> Transfer
|
|
||||||
MBOX --> Transfer
|
|
||||||
IMAP --> Transfer
|
|
||||||
S --> Transfer
|
|
||||||
|
|
||||||
Transfer --> EML
|
|
||||||
Transfer --> MBOX
|
|
||||||
Transfer --> S
|
|
||||||
|
|
||||||
U --> Frontend
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code structure
|
|
||||||
|
|
||||||
More detailed graph of main types used in Import-Export app and connection between them.
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
PM[ProtonMail Server]
|
|
||||||
EML[EML]
|
|
||||||
MBOX[MBOX]
|
|
||||||
IMAP[IMAP]
|
|
||||||
|
|
||||||
subgraph "Import-Export app"
|
|
||||||
subgraph "pkg users"
|
|
||||||
subgraph "pkg credentials"
|
|
||||||
CredStore[Store]
|
|
||||||
Creds[Credentials]
|
|
||||||
|
|
||||||
CredStore --> Creds
|
|
||||||
end
|
|
||||||
|
|
||||||
US[Users]
|
|
||||||
U[User]
|
|
||||||
|
|
||||||
US --> U
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph "pkg frontend"
|
|
||||||
CLI
|
|
||||||
Qt
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph "pkg importExport"
|
|
||||||
IE[ImportExport]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph "pkg transfer"
|
|
||||||
Transfer
|
|
||||||
Rules
|
|
||||||
Progress
|
|
||||||
|
|
||||||
Provider
|
|
||||||
LocalProvider
|
|
||||||
EMLProvider
|
|
||||||
MBOXProvider
|
|
||||||
IMAPProvider
|
|
||||||
PMAPIProvider
|
|
||||||
|
|
||||||
Mailbox
|
|
||||||
Message
|
|
||||||
|
|
||||||
Transfer --> |source|Provider
|
|
||||||
Transfer --> |target|Provider
|
|
||||||
Transfer --> Rules
|
|
||||||
Transfer --> Progress
|
|
||||||
|
|
||||||
Provider --> LocalProvider
|
|
||||||
Provider --> EMLProvider
|
|
||||||
Provider --> MBOXProvider
|
|
||||||
Provider --> IMAPProvider
|
|
||||||
Provider --> PMAPIProvider
|
|
||||||
|
|
||||||
LocalProvider --> EMLProvider
|
|
||||||
LocalProvider --> MBOXProvider
|
|
||||||
|
|
||||||
Provider --> Mailbox
|
|
||||||
Provider --> Message
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph PMAPI
|
|
||||||
APIM[ClientManager]
|
|
||||||
APIC[Client]
|
|
||||||
|
|
||||||
APIM --> APIC
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
CLI --> IE
|
|
||||||
CLI --> Transfer
|
|
||||||
CLI --> Progress
|
|
||||||
Qt --> IE
|
|
||||||
Qt --> Transfer
|
|
||||||
Qt --> Progress
|
|
||||||
|
|
||||||
U --> CredStore
|
|
||||||
U --> Creds
|
|
||||||
|
|
||||||
US --> APIM
|
|
||||||
U --> APIM
|
|
||||||
|
|
||||||
PMAPIProvider --> APIM
|
|
||||||
EMLProvider --> EML
|
|
||||||
MBOXProvider --> MBOX
|
|
||||||
IMAPProvider --> IMAP
|
|
||||||
|
|
||||||
IE --> US
|
|
||||||
IE --> Transfer
|
|
||||||
|
|
||||||
APIC --> PM
|
|
||||||
```
|
|
||||||
@ -1,14 +1,9 @@
|
|||||||
# Documentation
|
# Bridge Documentation
|
||||||
|
|
||||||
Documentation pages in order to read for a novice:
|
Documentation pages in order to read for a novice:
|
||||||
|
|
||||||
## Bridge
|
|
||||||
|
|
||||||
* [Bridge code](bridge.md)
|
* [Bridge code](bridge.md)
|
||||||
* [Internal Bridge database](database.md)
|
* [Internal Bridge database](database.md)
|
||||||
* [Communication between Bridge, Client and Server](communication.md)
|
* [Communication between Bridge, Client and Server](communication.md)
|
||||||
* [Encryption](encryption.md)
|
* [Encryption](encryption.md)
|
||||||
|
|
||||||
## Import-Export app
|
|
||||||
|
|
||||||
* [Import-Export code](importexport.md)
|
|
||||||
|
|||||||
103
doc/updates.md
Normal file
103
doc/updates.md
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# Update mechanism of Bridge
|
||||||
|
|
||||||
|
There are mulitple options how to change version of application:
|
||||||
|
* Automatic in-app update
|
||||||
|
* Manual in-app update
|
||||||
|
* Manual install
|
||||||
|
|
||||||
|
In-app update ends with restarting bridge into new version. Automatic in-app
|
||||||
|
update is downloading, verifying and installing the new version immediatelly
|
||||||
|
without user confirmation. For manual in-app update user needs to confirm first.
|
||||||
|
Update is done from special update file published on website.
|
||||||
|
|
||||||
|
The manual installation requires user to download, verify and install manually
|
||||||
|
using installer for given OS.
|
||||||
|
|
||||||
|
The bridge is installed and executed differently for given OS:
|
||||||
|
|
||||||
|
* Windows and Linux apps are using launcher mechanism:
|
||||||
|
* There is system protected installation path which is created on first
|
||||||
|
install. It contains bridge exe and launcher exe. When users starts
|
||||||
|
bridge the launcher is executed first. It will check update path compare
|
||||||
|
version with installed one. The newer version then is then executed.
|
||||||
|
* Update mechanism means to replace files in update folder which is located
|
||||||
|
in user space.
|
||||||
|
|
||||||
|
* macOS app does not use launcher
|
||||||
|
* No launcher, only one executable
|
||||||
|
* In-App udpate replaces the bridge files in installation path directly
|
||||||
|
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph Frontend
|
||||||
|
U[User requests<br>version check]
|
||||||
|
ManIns((Notify user about<br>manual install<br>is needed))
|
||||||
|
R((Notify user<br>about restart))
|
||||||
|
ManUp((Notify user about<br>manual update))
|
||||||
|
NF((Notify user about<br>force update))
|
||||||
|
|
||||||
|
ManUp -->|Install| InstFront[Install]
|
||||||
|
InstFront -->|Ok| R
|
||||||
|
InstFront -->|Error| ManIns
|
||||||
|
|
||||||
|
U --> CheckFront[Check online]
|
||||||
|
CheckFront -->|Ok| IAFront{Is new version<br>and applicable?}
|
||||||
|
CheckFront -->|Error| ManIns
|
||||||
|
|
||||||
|
IAFront -->|No| Latest((Notify user<br>has latest version))
|
||||||
|
IAFront -->|Yes| CanInstall{Can update?}
|
||||||
|
CanInstall -->|No| ManIns
|
||||||
|
CanInstall -->|Yes| NotifOrInstall{Is automatic<br>update enabled?}
|
||||||
|
NotifOrInstall -->|Manual| ManUp
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
subgraph Backend
|
||||||
|
W[Wait for next check]
|
||||||
|
|
||||||
|
W --> Check[Check online]
|
||||||
|
|
||||||
|
Check --> NV{Has new<br>version?}
|
||||||
|
Check -->|Error| W
|
||||||
|
NV -->|No new version| W
|
||||||
|
IA{Is install<br>applicable?}
|
||||||
|
NV -->|New version<br>available| IA
|
||||||
|
IA -->|Local rollout<br>not enough| W
|
||||||
|
IA -->|Yes| AU{Is automatic\nupdate enabled?}
|
||||||
|
|
||||||
|
AU -->|Yes| CanUp{Can update?}
|
||||||
|
CanUp -->|No| ManIns
|
||||||
|
|
||||||
|
CanUp -->|Yes| Ins[Install]
|
||||||
|
Ins -->|Error| ManIns
|
||||||
|
Ins -->|Ok| R
|
||||||
|
|
||||||
|
AU -->|No| ManUp
|
||||||
|
ManUp -->|Ignore| W
|
||||||
|
|
||||||
|
|
||||||
|
F[Force update]
|
||||||
|
F --> NF
|
||||||
|
end
|
||||||
|
|
||||||
|
ManIns --> Web[Open web page]
|
||||||
|
NF --> Web
|
||||||
|
ManUp --> Web
|
||||||
|
R --> Re[Restart]
|
||||||
|
NF --> Q[Quit bridge]
|
||||||
|
NotifOrInstall -->|Automatic| W
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The non-trivial is to combine the update with setting change:
|
||||||
|
* turn off/on automatic in-app updates
|
||||||
|
* change from stable to beta or back
|
||||||
|
|
||||||
|
_TODO fill flow chart details_
|
||||||
|
|
||||||
|
|
||||||
|
We are not support downgrade functionality. Only some circumstances can lead to
|
||||||
|
downgrading the app version.
|
||||||
|
|
||||||
|
_TODO fill flow chart details_
|
||||||
29
go.mod
29
go.mod
@ -14,12 +14,12 @@ require (
|
|||||||
github.com/0xAX/notificator v0.0.0-20191016112426-3962a5ea8da1
|
github.com/0xAX/notificator v0.0.0-20191016112426-3962a5ea8da1
|
||||||
github.com/Masterminds/semver/v3 v3.1.0
|
github.com/Masterminds/semver/v3 v3.1.0
|
||||||
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a
|
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c
|
github.com/ProtonMail/go-crypto v0.0.0-20211221144345-a4f6767435ab
|
||||||
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde
|
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde
|
||||||
github.com/ProtonMail/go-rfc5322 v0.8.0
|
github.com/ProtonMail/go-rfc5322 v0.8.0
|
||||||
github.com/ProtonMail/go-srp v0.0.1
|
github.com/ProtonMail/go-srp v0.0.1
|
||||||
github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5
|
github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.2.2
|
github.com/ProtonMail/gopenpgp/v2 v2.4.1
|
||||||
github.com/PuerkitoBio/goquery v1.5.1
|
github.com/PuerkitoBio/goquery v1.5.1
|
||||||
github.com/abiosoft/ishell v2.0.0+incompatible
|
github.com/abiosoft/ishell v2.0.0+incompatible
|
||||||
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect
|
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect
|
||||||
@ -28,11 +28,12 @@ require (
|
|||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
|
||||||
github.com/cucumber/godog v0.12.1
|
github.com/cucumber/godog v0.12.1
|
||||||
github.com/cucumber/messages-go/v16 v16.0.1
|
github.com/cucumber/messages-go/v16 v16.0.1
|
||||||
|
github.com/elastic/go-sysinfo v1.7.1
|
||||||
|
github.com/elastic/go-windows v1.0.1 // indirect
|
||||||
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a
|
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a
|
||||||
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342
|
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342
|
||||||
github.com/emersion/go-imap-quota v0.0.0-20210203125329-619074823f3c
|
github.com/emersion/go-imap-quota v0.0.0-20210203125329-619074823f3c
|
||||||
github.com/emersion/go-imap-unselect v0.0.0-20171113212723-b985794e5f26
|
github.com/emersion/go-imap-unselect v0.0.0-20171113212723-b985794e5f26
|
||||||
github.com/emersion/go-mbox v1.0.2
|
|
||||||
github.com/emersion/go-message v0.12.1-0.20201221184100-40c3f864532b
|
github.com/emersion/go-message v0.12.1-0.20201221184100-40c3f864532b
|
||||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
|
||||||
github.com/emersion/go-smtp v0.14.0
|
github.com/emersion/go-smtp v0.14.0
|
||||||
@ -40,23 +41,26 @@ require (
|
|||||||
github.com/emersion/go-vcard v0.0.0-20190105225839-8856043f13c5 // indirect
|
github.com/emersion/go-vcard v0.0.0-20190105225839-8856043f13c5 // indirect
|
||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.9.0
|
||||||
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||||
github.com/getsentry/sentry-go v0.8.0
|
github.com/getsentry/sentry-go v0.12.0
|
||||||
github.com/go-resty/resty/v2 v2.6.0
|
github.com/go-resty/resty/v2 v2.6.0
|
||||||
|
github.com/godbus/dbus v4.1.0+incompatible
|
||||||
github.com/golang/mock v1.4.4
|
github.com/golang/mock v1.4.4
|
||||||
github.com/google/go-cmp v0.5.1
|
github.com/google/go-cmp v0.5.5
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect
|
|
||||||
github.com/hashicorp/go-multierror v1.1.0
|
github.com/hashicorp/go-multierror v1.1.0
|
||||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
|
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
|
||||||
github.com/keybase/go-keychain v0.0.0-20200502122510-cda31fe0c86d
|
github.com/keybase/go-keychain v0.0.0
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
github.com/miekg/dns v1.1.41
|
github.com/miekg/dns v1.1.41
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce
|
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce
|
||||||
github.com/olekukonko/tablewriter v0.0.4 // indirect
|
github.com/olekukonko/tablewriter v0.0.4 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/prometheus/procfs v0.7.3 // indirect
|
||||||
|
github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285
|
||||||
github.com/sirupsen/logrus v1.7.0
|
github.com/sirupsen/logrus v1.7.0
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/therecipe/qt v0.0.0-20200701200531-7f61353ee73e
|
github.com/therecipe/qt v0.0.0-20200701200531-7f61353ee73e
|
||||||
@ -65,9 +69,11 @@ require (
|
|||||||
github.com/urfave/cli/v2 v2.2.0
|
github.com/urfave/cli/v2 v2.2.0
|
||||||
github.com/vmihailenco/msgpack/v5 v5.1.3
|
github.com/vmihailenco/msgpack/v5 v5.1.3
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.6
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
|
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
|
||||||
golang.org/x/text v0.3.5-0.20201125200606-c27b9fd57aec
|
golang.org/x/sys v0.0.0-20220111092808-5a964db01320
|
||||||
|
golang.org/x/text v0.3.7
|
||||||
|
howett.net/plist v1.0.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
@ -75,4 +81,5 @@ replace (
|
|||||||
github.com/emersion/go-imap => github.com/ProtonMail/go-imap v0.0.0-20201228133358-4db68cea0cac
|
github.com/emersion/go-imap => github.com/ProtonMail/go-imap v0.0.0-20201228133358-4db68cea0cac
|
||||||
github.com/emersion/go-message => github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753
|
github.com/emersion/go-message => github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753
|
||||||
github.com/jameskeane/bcrypt => github.com/ProtonMail/bcrypt v0.0.0-20210511135022-227b4adcab57
|
github.com/jameskeane/bcrypt => github.com/ProtonMail/bcrypt v0.0.0-20210511135022-227b4adcab57
|
||||||
|
github.com/keybase/go-keychain => github.com/cuthix/go-keychain v0.0.0-20220405075754-31e7cee908fe
|
||||||
)
|
)
|
||||||
|
|||||||
98
go.sum
98
go.sum
@ -29,9 +29,8 @@ github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756
|
|||||||
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a h1:fXK2KsfnkBV9Nh+9SKzHchYjuE9s0vI20JG1mbtEAcc=
|
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a h1:fXK2KsfnkBV9Nh+9SKzHchYjuE9s0vI20JG1mbtEAcc=
|
||||||
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4=
|
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
github.com/ProtonMail/go-crypto v0.0.0-20211221144345-a4f6767435ab h1:5FiL/TCaiKCss/BLMIACDxxadYrx767l9kh0qYX+sLQ=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c h1:FP7mMdsXy0ybzar1sJeIcZtaJka0U/ZmLTW4wRpolYk=
|
github.com/ProtonMail/go-crypto v0.0.0-20211221144345-a4f6767435ab/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20210707164159-52430bf6b52c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
|
||||||
github.com/ProtonMail/go-imap v0.0.0-20201228133358-4db68cea0cac h1:2xU3QncAiS/W3UlWZTkbNKW5WkLzk6Egl1T0xX+sbjs=
|
github.com/ProtonMail/go-imap v0.0.0-20201228133358-4db68cea0cac h1:2xU3QncAiS/W3UlWZTkbNKW5WkLzk6Egl1T0xX+sbjs=
|
||||||
github.com/ProtonMail/go-imap v0.0.0-20201228133358-4db68cea0cac/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU=
|
github.com/ProtonMail/go-imap v0.0.0-20201228133358-4db68cea0cac/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU=
|
||||||
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde h1:5koQozTDELymYOyFbQ/VSubexAEXzDR8qGM5mO8GRdw=
|
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde h1:5koQozTDELymYOyFbQ/VSubexAEXzDR8qGM5mO8GRdw=
|
||||||
@ -42,14 +41,12 @@ github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a h1:W6RrgN/sTxg1
|
|||||||
github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
|
github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
|
||||||
github.com/ProtonMail/go-rfc5322 v0.8.0 h1:7emrf75n3CDIduQflx7aT1nJa5h/kGsiFKUYX/+IAkU=
|
github.com/ProtonMail/go-rfc5322 v0.8.0 h1:7emrf75n3CDIduQflx7aT1nJa5h/kGsiFKUYX/+IAkU=
|
||||||
github.com/ProtonMail/go-rfc5322 v0.8.0/go.mod h1:BwpTbkJxkMGkc+pC84AXZnwuWOisEULBpfPIyIKS/Us=
|
github.com/ProtonMail/go-rfc5322 v0.8.0/go.mod h1:BwpTbkJxkMGkc+pC84AXZnwuWOisEULBpfPIyIKS/Us=
|
||||||
github.com/ProtonMail/go-srp v0.0.0-20210910093455-a843a0b9adff h1:eiue56XAPSkOpsy5Fwnyz4+Vd7i2cN5D4orc++Irt1g=
|
|
||||||
github.com/ProtonMail/go-srp v0.0.0-20210910093455-a843a0b9adff/go.mod h1:Uvv5cqSGCs8MTZ8sbKiCkBnaB6/OA3eq2mc77tl2VVA=
|
|
||||||
github.com/ProtonMail/go-srp v0.0.1 h1:J0O9Zb5XTC6iDrB7feH41cu+TUEB+l7uHctXIK6oS2o=
|
github.com/ProtonMail/go-srp v0.0.1 h1:J0O9Zb5XTC6iDrB7feH41cu+TUEB+l7uHctXIK6oS2o=
|
||||||
github.com/ProtonMail/go-srp v0.0.1/go.mod h1:Uvv5cqSGCs8MTZ8sbKiCkBnaB6/OA3eq2mc77tl2VVA=
|
github.com/ProtonMail/go-srp v0.0.1/go.mod h1:Uvv5cqSGCs8MTZ8sbKiCkBnaB6/OA3eq2mc77tl2VVA=
|
||||||
github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5 h1:Uga1DHFN4GUxuDQr0F71tpi8I9HqPIlZodZAI1lR6VQ=
|
github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5 h1:Uga1DHFN4GUxuDQr0F71tpi8I9HqPIlZodZAI1lR6VQ=
|
||||||
github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5/go.mod h1:oeP9CMN+ajWp5jKp1kue5daJNwMMxLF+ujPaUIoJWlA=
|
github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5/go.mod h1:oeP9CMN+ajWp5jKp1kue5daJNwMMxLF+ujPaUIoJWlA=
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.2.2 h1:u2m7xt+CZWj88qK1UUNBoXeJCFJwJCZ/Ff4ymGoxEXs=
|
github.com/ProtonMail/gopenpgp/v2 v2.4.1 h1:b3El0zabaKi73u4sRnb3hOOUczuKuYpN8wnp7wRsZSc=
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.2.2/go.mod h1:ajUlBGvxMH1UBZnaYO3d1FSVzjiC6kK9XlZYGiDCvpM=
|
github.com/ProtonMail/gopenpgp/v2 v2.4.1/go.mod h1:RFjoVjfhV8f78tjz/fLrp/OXkugL3QmWsiJq/fsQYA4=
|
||||||
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
|
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
|
||||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||||
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
|
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
|
||||||
@ -105,6 +102,8 @@ github.com/cucumber/godog v0.12.1/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.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 h1:fvkpwsLgnIm0qugftrw2YwNlio+ABe2Iu94Ap8GMYIY=
|
||||||
github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g=
|
github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g=
|
||||||
|
github.com/cuthix/go-keychain v0.0.0-20220405075754-31e7cee908fe h1:KRj3wdvA9yE92prNmOjS7x5DOqoyjxqdE30qnrmTasc=
|
||||||
|
github.com/cuthix/go-keychain v0.0.0-20220405075754-31e7cee908fe/go.mod h1:ZoZU1fnBy3mOLWr3Pg+Y2+nTKtu6ypDte2kZg9HvSwY=
|
||||||
github.com/danieljoos/wincred v1.1.0 h1:3RNcEpBg4IhIChZdFRSdlQt1QjCp1sMAPIrOnm7Yf8g=
|
github.com/danieljoos/wincred v1.1.0 h1:3RNcEpBg4IhIChZdFRSdlQt1QjCp1sMAPIrOnm7Yf8g=
|
||||||
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
|
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -116,6 +115,11 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn
|
|||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||||
|
github.com/elastic/go-sysinfo v1.7.1 h1:Wx4DSARcKLllpKT2TnFVdSUJOsybqMYCNQZq1/wO+s0=
|
||||||
|
github.com/elastic/go-sysinfo v1.7.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0=
|
||||||
|
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
|
||||||
|
github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0=
|
||||||
|
github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
|
||||||
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a h1:bMdSPm6sssuOFpIaveu3XGAijMS3Tq2S3EqFZmZxidc=
|
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a h1:bMdSPm6sssuOFpIaveu3XGAijMS3Tq2S3EqFZmZxidc=
|
||||||
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a/go.mod h1:ikgISoP7pRAolqsVP64yMteJa2FIpS6ju88eBT6K1yQ=
|
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a/go.mod h1:ikgISoP7pRAolqsVP64yMteJa2FIpS6ju88eBT6K1yQ=
|
||||||
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 h1:5p1t3e1PomYgLWwEwhwEU5kVBwcyAcVrOpexv8AeZx0=
|
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 h1:5p1t3e1PomYgLWwEwhwEU5kVBwcyAcVrOpexv8AeZx0=
|
||||||
@ -124,8 +128,6 @@ github.com/emersion/go-imap-quota v0.0.0-20210203125329-619074823f3c h1:khcEdu1y
|
|||||||
github.com/emersion/go-imap-quota v0.0.0-20210203125329-619074823f3c/go.mod h1:iApyhIQBiU4XFyr+3kdJyyGqle82TbQyuP2o+OZHrV0=
|
github.com/emersion/go-imap-quota v0.0.0-20210203125329-619074823f3c/go.mod h1:iApyhIQBiU4XFyr+3kdJyyGqle82TbQyuP2o+OZHrV0=
|
||||||
github.com/emersion/go-imap-unselect v0.0.0-20171113212723-b985794e5f26 h1:FiSb8+XBQQSkcX3ubr+1tAtlRJBYaFmRZqOAweZ9Wy8=
|
github.com/emersion/go-imap-unselect v0.0.0-20171113212723-b985794e5f26 h1:FiSb8+XBQQSkcX3ubr+1tAtlRJBYaFmRZqOAweZ9Wy8=
|
||||||
github.com/emersion/go-imap-unselect v0.0.0-20171113212723-b985794e5f26/go.mod h1:+gnnZx3Mg3MnCzZrv0eZdp5puxXQUgGT/6N6L7ShKfM=
|
github.com/emersion/go-imap-unselect v0.0.0-20171113212723-b985794e5f26/go.mod h1:+gnnZx3Mg3MnCzZrv0eZdp5puxXQUgGT/6N6L7ShKfM=
|
||||||
github.com/emersion/go-mbox v1.0.2 h1:tE/rT+lEugK9y0myEymCCHnwlZN04hlXPrbKkxRBA5I=
|
|
||||||
github.com/emersion/go-mbox v1.0.2/go.mod h1:Yp9IVuuOYLEuMv4yjgDHvhb5mHOcYH6x92Oas3QqEZI=
|
|
||||||
github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k=
|
github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k=
|
||||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
||||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||||
@ -145,8 +147,8 @@ github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BMXYYRWT
|
|||||||
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M=
|
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
|
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
|
||||||
github.com/getsentry/sentry-go v0.8.0 h1:F52cjBVLuiTfdW6p4JFuxlt3pOjKfWYT/aka7cdJ7v0=
|
github.com/getsentry/sentry-go v0.12.0 h1:era7g0re5iY13bHSdN/xMkyV+5zZppjRVQhZrXCaEIk=
|
||||||
github.com/getsentry/sentry-go v0.8.0/go.mod h1:kELm/9iCblqUYh+ZRML7PNdCvEuw24wBvJPYyi86cws=
|
github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||||
@ -164,10 +166,13 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
|||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||||
|
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
|
||||||
|
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
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.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
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=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
@ -183,9 +188,9 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
|
|||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
@ -197,9 +202,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e h1:XWcjeEtTFTOVA9Fs1w7n2XBftk5ib4oZrhzWk0B+3eA=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
@ -247,6 +251,9 @@ github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0Gqw
|
|||||||
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
||||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 h1:g0fAGBisHaEQ0TRq1iBvemFRf+8AEWEmBESSiWB3Vsc=
|
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 h1:g0fAGBisHaEQ0TRq1iBvemFRf+8AEWEmBESSiWB3Vsc=
|
||||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||||
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
||||||
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
@ -262,6 +269,8 @@ github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7
|
|||||||
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
|
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
|
||||||
github.com/keybase/go-keychain v0.0.0-20200502122510-cda31fe0c86d h1:gVjhBCfVGl32RIBooOANzfw+0UqX8HU+yPlMv8vypcg=
|
github.com/keybase/go-keychain v0.0.0-20200502122510-cda31fe0c86d h1:gVjhBCfVGl32RIBooOANzfw+0UqX8HU+yPlMv8vypcg=
|
||||||
github.com/keybase/go-keychain v0.0.0-20200502122510-cda31fe0c86d/go.mod h1:W6EbaYmb4RldPn0N3gvVHjY1wmU59kbymhW9NATWhwY=
|
github.com/keybase/go-keychain v0.0.0-20200502122510-cda31fe0c86d/go.mod h1:W6EbaYmb4RldPn0N3gvVHjY1wmU59kbymhW9NATWhwY=
|
||||||
|
github.com/keybase/go-keychain v0.0.0-20211119201326-e02f34051621 h1:aMQ7pA4f06yOVXSulygyGvy4xA94fyzjUGs0iqQdMOI=
|
||||||
|
github.com/keybase/go-keychain v0.0.0-20211119201326-e02f34051621/go.mod h1:enrU/ug069Om7vWxuFE6nikLI2BZNwevMiGSo43Kt5w=
|
||||||
github.com/keybase/go.dbus v0.0.0-20200324223359-a94be52c0b03/go.mod h1:a8clEhrrGV/d76/f9r2I41BwANMihfZYV9C223vaxqE=
|
github.com/keybase/go.dbus v0.0.0-20200324223359-a94be52c0b03/go.mod h1:a8clEhrrGV/d76/f9r2I41BwANMihfZYV9C223vaxqE=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
@ -278,7 +287,7 @@ 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.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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
|
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
|
||||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
@ -286,14 +295,18 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
|
|||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
||||||
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
@ -349,8 +362,13 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
|
|||||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
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-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||||
|
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
|
github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285 h1:d54EL9l+XteliUfUCGsEwwuk65dmmxX85VXF+9T6+50=
|
||||||
|
github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285/go.mod h1:fxIDly1xtudczrZeOOlfaUvd2OPb2qZAPuWdU2BsBTk=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||||
@ -369,8 +387,6 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
@ -418,6 +434,7 @@ github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKn
|
|||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.1.3 h1:FwC9KPjyW8OqTUqMt6rQw9y50vA2cTLXPKCcBCRbQgg=
|
github.com/vmihailenco/msgpack/v5 v5.1.3 h1:FwC9KPjyW8OqTUqMt6rQw9y50vA2cTLXPKCcBCRbQgg=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.1.3/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI=
|
github.com/vmihailenco/msgpack/v5 v5.1.3/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI=
|
||||||
@ -451,8 +468,11 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
|
||||||
|
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -497,8 +517,12 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/net v0.0.0-20211008194852-3b03d305991f h1:1scJEYZBaF48BaG6tYbtxmLcXqwYGSfGcMoStTqkkIw=
|
||||||
|
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||||
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -508,6 +532,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -531,22 +556,39 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
|
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
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-20210927094055-39ccf1dd6fa6/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-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
|
||||||
|
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5-0.20201125200606-c27b9fd57aec h1:A1qYjneJuzBZZ2gIB8rd6zrfq6l7SoEMJ8EsSilNK/U=
|
|
||||||
golang.org/x/text v0.3.5-0.20201125200606-c27b9fd57aec/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5-0.20201125200606-c27b9fd57aec/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
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.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@ -610,6 +652,7 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|||||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@ -623,4 +666,7 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
||||||
|
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||||
|
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package api provides HTTP API of the Bridge.
|
// Package api provides HTTP API of the Bridge.
|
||||||
//
|
//
|
||||||
@ -34,7 +34,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
log = logrus.WithField("pkg", "api") //nolint[gochecknoglobals]
|
log = logrus.WithField("pkg", "api") //nolint:gochecknoglobals
|
||||||
)
|
)
|
||||||
|
|
||||||
type apiServer struct {
|
type apiServer struct {
|
||||||
@ -44,7 +44,7 @@ type apiServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewAPIServer returns prepared API server struct.
|
// NewAPIServer returns prepared API server struct.
|
||||||
func NewAPIServer(settings *settings.Settings, eventListener listener.Listener) *apiServer { //nolint[golint]
|
func NewAPIServer(settings *settings.Settings, eventListener listener.Listener) *apiServer { //nolint:revive
|
||||||
return &apiServer{
|
return &apiServer{
|
||||||
host: bridge.Host,
|
host: bridge.Host,
|
||||||
settings: settings,
|
settings: settings,
|
||||||
@ -68,7 +68,7 @@ func (api *apiServer) ListenAndServe() {
|
|||||||
api.eventListener.Emit(events.ErrorEvent, "API failed: "+err.Error())
|
api.eventListener.Emit(events.ErrorEvent, "API failed: "+err.Error())
|
||||||
log.Error("API failed: ", err)
|
log.Error("API failed: ", err)
|
||||||
}
|
}
|
||||||
defer server.Close() //nolint[errcheck]
|
defer server.Close() //nolint:errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *apiServer) getAddress() string {
|
func (api *apiServer) getAddress() string {
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package api
|
package api
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package api
|
package api
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ func CheckOtherInstanceAndFocus(port int) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close() //nolint[errcheck]
|
defer resp.Body.Close() //nolint:errcheck
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
log.Error("Focus error: ", resp.StatusCode)
|
log.Error("Focus error: ", resp.StatusCode)
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package base
|
package base
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package base implements a common application base currently shared by bridge and IE.
|
// Package base implements a common application base currently shared by bridge and IE.
|
||||||
// The base includes the following:
|
// The base includes the following:
|
||||||
@ -73,7 +73,8 @@ const (
|
|||||||
FlagCLI = "cli"
|
FlagCLI = "cli"
|
||||||
flagCLIShort = "c"
|
flagCLIShort = "c"
|
||||||
flagRestart = "restart"
|
flagRestart = "restart"
|
||||||
flagLauncher = "launcher"
|
FlagLauncher = "launcher"
|
||||||
|
FlagNoWindow = "no-window"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Base struct {
|
type Base struct {
|
||||||
@ -101,7 +102,7 @@ type Base struct {
|
|||||||
teardown []func() error // actions to perform when app is exiting
|
teardown []func() error // actions to perform when app is exiting
|
||||||
}
|
}
|
||||||
|
|
||||||
func New( // nolint[funlen]
|
func New( //nolint:funlen
|
||||||
appName,
|
appName,
|
||||||
appUsage,
|
appUsage,
|
||||||
configName,
|
configName,
|
||||||
@ -158,6 +159,10 @@ func New( // nolint[funlen]
|
|||||||
return nil, api.CheckOtherInstanceAndFocus(settingsObj.GetInt(settings.APIPortKey))
|
return nil, api.CheckOtherInstanceAndFocus(settingsObj.GetInt(settings.APIPortKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := migrateRebranding(settingsObj, keychainName); err != nil {
|
||||||
|
logrus.WithError(err).Warn("Rebranding migration failed")
|
||||||
|
}
|
||||||
|
|
||||||
cachePath, err := locations.ProvideCachePath()
|
cachePath, err := locations.ProvideCachePath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -188,9 +193,11 @@ func New( // nolint[funlen]
|
|||||||
|
|
||||||
cm := pmapi.New(cfg)
|
cm := pmapi.New(cfg)
|
||||||
|
|
||||||
|
sentryReporter.SetClientFromManager(cm)
|
||||||
|
|
||||||
cm.AddConnectionObserver(pmapi.NewConnectionObserver(
|
cm.AddConnectionObserver(pmapi.NewConnectionObserver(
|
||||||
func() { listener.Emit(events.InternetOffEvent, "") },
|
func() { listener.Emit(events.InternetConnChangedEvent, events.InternetOff) },
|
||||||
func() { listener.Emit(events.InternetOnEvent, "") },
|
func() { listener.Emit(events.InternetConnChangedEvent, events.InternetOn) },
|
||||||
))
|
))
|
||||||
|
|
||||||
jar, err := cookies.NewCookieJar(settingsObj)
|
jar, err := cookies.NewCookieJar(settingsObj)
|
||||||
@ -233,9 +240,9 @@ func New( // nolint[funlen]
|
|||||||
}
|
}
|
||||||
|
|
||||||
autostart := &autostart.App{
|
autostart := &autostart.App{
|
||||||
Name: appName,
|
Name: startupNameForRebranding(appName),
|
||||||
DisplayName: appName,
|
DisplayName: appName,
|
||||||
Exec: []string{exe},
|
Exec: []string{exe, "--" + FlagNoWindow},
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Base{
|
return &Base{
|
||||||
@ -264,13 +271,13 @@ func New( // nolint[funlen]
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Base) NewApp(action func(*Base, *cli.Context) error) *cli.App {
|
func (b *Base) NewApp(mainLoop func(*Base, *cli.Context) error) *cli.App {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
|
|
||||||
app.Name = b.Name
|
app.Name = b.Name
|
||||||
app.Usage = b.usage
|
app.Usage = b.usage
|
||||||
app.Version = constants.Version
|
app.Version = constants.Version
|
||||||
app.Action = b.run(action)
|
app.Action = b.wrapMainLoop(mainLoop)
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: flagCPUProfile,
|
Name: flagCPUProfile,
|
||||||
@ -292,13 +299,17 @@ func (b *Base) NewApp(action func(*Base, *cli.Context) error) *cli.App {
|
|||||||
Aliases: []string{flagCLIShort},
|
Aliases: []string{flagCLIShort},
|
||||||
Usage: "Use command line interface",
|
Usage: "Use command line interface",
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: FlagNoWindow,
|
||||||
|
Usage: "Don't show window after start",
|
||||||
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: flagRestart,
|
Name: flagRestart,
|
||||||
Usage: "The number of times the application has already restarted",
|
Usage: "The number of times the application has already restarted",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: flagLauncher,
|
Name: FlagLauncher,
|
||||||
Usage: "The launcher to use to restart the application",
|
Usage: "The launcher to use to restart the application",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
},
|
},
|
||||||
@ -317,15 +328,18 @@ func (b *Base) AddTeardownAction(fn func() error) {
|
|||||||
b.teardown = append(b.teardown, fn)
|
b.teardown = append(b.teardown, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Base) run(appMainLoop func(*Base, *cli.Context) error) cli.ActionFunc { // nolint[funlen]
|
func (b *Base) wrapMainLoop(appMainLoop func(*Base, *cli.Context) error) cli.ActionFunc { //nolint:funlen
|
||||||
return func(c *cli.Context) error {
|
return func(c *cli.Context) error {
|
||||||
defer b.CrashHandler.HandlePanic()
|
defer b.CrashHandler.HandlePanic()
|
||||||
defer func() { _ = b.Lock.Close() }()
|
defer func() { _ = b.Lock.Close() }()
|
||||||
|
|
||||||
// If launcher was used to start the app, use that for restart/autostart.
|
// If launcher was used to start the app, use that for restart
|
||||||
if launcher := c.String(flagLauncher); launcher != "" {
|
// and autostart.
|
||||||
b.Autostart.Exec = []string{launcher}
|
if launcher := c.String(FlagLauncher); launcher != "" {
|
||||||
b.command = launcher
|
b.command = launcher
|
||||||
|
// Bridge supports no-window option which we should use
|
||||||
|
// for autostart.
|
||||||
|
b.Autostart.Exec = []string{launcher, "--" + FlagNoWindow}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Bool(flagCPUProfile) {
|
if c.Bool(flagCPUProfile) {
|
||||||
@ -350,10 +364,13 @@ func (b *Base) run(appMainLoop func(*Base, *cli.Context) error) cli.ActionFunc {
|
|||||||
Info("Run app")
|
Info("Run app")
|
||||||
|
|
||||||
b.CrashHandler.AddRecoveryAction(func(interface{}) error {
|
b.CrashHandler.AddRecoveryAction(func(interface{}) error {
|
||||||
|
sentry.Flush(2 * time.Second)
|
||||||
|
|
||||||
if c.Int(flagRestart) > maxAllowedRestarts {
|
if c.Int(flagRestart) > maxAllowedRestarts {
|
||||||
logrus.
|
logrus.
|
||||||
WithField("restart", c.Int("restart")).
|
WithField("restart", c.Int("restart")).
|
||||||
Warn("Not restarting, already restarted too many times")
|
Warn("Not restarting, already restarted too many times")
|
||||||
|
os.Exit(1)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package base
|
package base
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ func migrateFiles(configName string) error {
|
|||||||
if err := migrateCacheFromBoth15xAnd16x(locations, userCacheDir); err != nil {
|
if err := migrateCacheFromBoth15xAnd16x(locations, userCacheDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := migrateUpdatesFrom16x(configName, locations); err != nil { //nolint[revive] It is more clear to structure this way
|
if err := migrateUpdatesFrom16x(configName, locations); err != nil { //nolint:revive It is more clear to structure this way
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
197
internal/app/base/migration_rebranding.go
Normal file
197
internal/app/base/migration_rebranding.go
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
// Copyright (c) 2022 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 base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
||||||
|
"github.com/ProtonMail/proton-bridge/pkg/keychain"
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const darwin = "darwin"
|
||||||
|
|
||||||
|
func migrateRebranding(settingsObj *settings.Settings, keychainName string) (result error) {
|
||||||
|
if err := migrateStartupBeforeRebranding(); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastUsedVersion := settingsObj.Get(settings.LastVersionKey)
|
||||||
|
|
||||||
|
// Skipping migration: it is first bridge start or cache was cleared.
|
||||||
|
if lastUsedVersion == "" {
|
||||||
|
settingsObj.SetBool(settings.RebrandingMigrationKey, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skipping rest of migration: already done
|
||||||
|
if settingsObj.GetBool(settings.RebrandingMigrationKey) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows", "linux":
|
||||||
|
// GODT-1260 we would need admin rights to changes desktop files
|
||||||
|
// and start menu items.
|
||||||
|
settingsObj.SetBool(settings.RebrandingMigrationKey, true)
|
||||||
|
case darwin:
|
||||||
|
if shouldContinue, err := isMacBeforeRebranding(); !shouldContinue || err != nil {
|
||||||
|
if err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := migrateMacKeychainBeforeRebranding(settingsObj, keychainName); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsObj.SetBool(settings.RebrandingMigrationKey, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// migrateMacKeychainBeforeRebranding deals with write access restriction to
|
||||||
|
// mac keychain passwords which are caused by application renaming. The old
|
||||||
|
// passwords are copied under new name in order to have write access afer
|
||||||
|
// renaming.
|
||||||
|
func migrateMacKeychainBeforeRebranding(settingsObj *settings.Settings, keychainName string) error {
|
||||||
|
l := logrus.WithField("pkg", "app/base/migration")
|
||||||
|
l.Warn("Migrating mac keychain")
|
||||||
|
|
||||||
|
helperConstructor, ok := keychain.Helpers["macos-keychain"]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("cannot find macos-keychain helper")
|
||||||
|
}
|
||||||
|
|
||||||
|
oldKC, err := helperConstructor("ProtonMailBridgeService")
|
||||||
|
if err != nil {
|
||||||
|
l.WithError(err).Error("Keychain constructor failed")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
idByURL, err := oldKC.List()
|
||||||
|
if err != nil {
|
||||||
|
l.WithError(err).Error("List old keychain failed")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newKC, err := keychain.NewKeychain(settingsObj, keychainName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for url, id := range idByURL {
|
||||||
|
li := l.WithField("id", id).WithField("url", url)
|
||||||
|
userID, secret, err := oldKC.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
li.WithField("userID", userID).
|
||||||
|
WithField("err", err).
|
||||||
|
Error("Faild to get old item")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, _, err := newKC.Get(userID); err == nil {
|
||||||
|
li.Warn("Skipping migration, item already exists.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := newKC.Put(userID, secret); err != nil {
|
||||||
|
li.WithError(err).Error("Failed to migrate user")
|
||||||
|
}
|
||||||
|
|
||||||
|
li.Info("Item migrated")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// migrateStartupBeforeRebranding removes old startup links. The creation of new links is
|
||||||
|
// handled by bridge initialisation.
|
||||||
|
func migrateStartupBeforeRebranding() error {
|
||||||
|
path, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
path = filepath.Join(path, `AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\ProtonMail Bridge.lnk`)
|
||||||
|
case "linux":
|
||||||
|
path = filepath.Join(path, `.config/autostart/ProtonMail Bridge.desktop`)
|
||||||
|
case darwin:
|
||||||
|
path = filepath.Join(path, `Library/LaunchAgents/ProtonMail Bridge.plist`)
|
||||||
|
default:
|
||||||
|
return errors.New("unknown GOOS")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField("pkg", "app/base/migration").Warn("Migrating autostartup links")
|
||||||
|
return os.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// startupNameForRebranding returns the name for autostart launcher based on
|
||||||
|
// type of rebranded instance i.e. update or manual.
|
||||||
|
//
|
||||||
|
// This only affects darwin when udpate re-writes the old startup and then
|
||||||
|
// manual installed it would not run proper exe. Therefore we return "old" name
|
||||||
|
// for updates and "new" name for manual which would be properly migrated.
|
||||||
|
//
|
||||||
|
// For orther (linux and windows) the link is always pointing to launcher which
|
||||||
|
// path didn't changed.
|
||||||
|
func startupNameForRebranding(origin string) string {
|
||||||
|
if runtime.GOOS == darwin {
|
||||||
|
if path, err := os.Executable(); err == nil && strings.Contains(path, "ProtonMail Bridge") {
|
||||||
|
return "ProtonMail Bridge"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to solve for other OS. See comment above.
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
|
||||||
|
// isBeforeRebranding decide if last used version was older than 2.2.0. If
|
||||||
|
// cannot decide it returns false with error.
|
||||||
|
func isMacBeforeRebranding() (bool, error) {
|
||||||
|
// previous version | update | do mac migration |
|
||||||
|
// | first | false |
|
||||||
|
// cleared-cache | manual | false |
|
||||||
|
// cleared-cache | in-app | false |
|
||||||
|
// old | in-app | false |
|
||||||
|
// old in-app | in-app | false |
|
||||||
|
// old | manual | true |
|
||||||
|
// old in-app | manual | true |
|
||||||
|
// manual | in-app | false |
|
||||||
|
|
||||||
|
// Skip if it was in-app update and not manual
|
||||||
|
if path, err := os.Executable(); err != nil || strings.Contains(path, "ProtonMail Bridge") {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package base
|
package base
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package base
|
package base
|
||||||
|
|
||||||
@ -33,6 +33,7 @@ func (b *Base) restartApp(crash bool) error {
|
|||||||
|
|
||||||
if crash {
|
if crash {
|
||||||
args = incrementRestartFlag(os.Args)[1:]
|
args = incrementRestartFlag(os.Args)[1:]
|
||||||
|
defer func() { os.Exit(1) }()
|
||||||
} else {
|
} else {
|
||||||
args = os.Args[1:]
|
args = os.Args[1:]
|
||||||
}
|
}
|
||||||
@ -42,7 +43,7 @@ func (b *Base) restartApp(crash bool) error {
|
|||||||
WithField("args", args).
|
WithField("args", args).
|
||||||
Warn("Restarting")
|
Warn("Restarting")
|
||||||
|
|
||||||
return exec.Command(b.command, args...).Start() // nolint[gosec]
|
return exec.Command(b.command, args...).Start() //nolint:gosec
|
||||||
}
|
}
|
||||||
|
|
||||||
// incrementRestartFlag increments the value of the restart flag.
|
// incrementRestartFlag increments the value of the restart flag.
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package base
|
package base
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package bridge implements the bridge CLI application.
|
// Package bridge implements the bridge CLI application.
|
||||||
package bridge
|
package bridge
|
||||||
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/api"
|
"github.com/ProtonMail/proton-bridge/internal/api"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/app/base"
|
"github.com/ProtonMail/proton-bridge/internal/app/base"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/bridge"
|
pkgBridge "github.com/ProtonMail/proton-bridge/internal/bridge"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
||||||
pkgTLS "github.com/ProtonMail/proton-bridge/internal/config/tls"
|
pkgTLS "github.com/ProtonMail/proton-bridge/internal/config/tls"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/constants"
|
"github.com/ProtonMail/proton-bridge/internal/constants"
|
||||||
@ -32,7 +32,10 @@ import (
|
|||||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/imap"
|
"github.com/ProtonMail/proton-bridge/internal/imap"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/smtp"
|
"github.com/ProtonMail/proton-bridge/internal/smtp"
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/store"
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/store/cache"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/updater"
|
"github.com/ProtonMail/proton-bridge/internal/updater"
|
||||||
|
"github.com/ProtonMail/proton-bridge/pkg/message"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
@ -41,12 +44,15 @@ import (
|
|||||||
const (
|
const (
|
||||||
flagLogIMAP = "log-imap"
|
flagLogIMAP = "log-imap"
|
||||||
flagLogSMTP = "log-smtp"
|
flagLogSMTP = "log-smtp"
|
||||||
flagNoWindow = "no-window"
|
|
||||||
flagNonInteractive = "noninteractive"
|
flagNonInteractive = "noninteractive"
|
||||||
|
|
||||||
|
// Memory cache was estimated by empirical usage in past and it was set to 100MB.
|
||||||
|
// NOTE: This value must not be less than maximal size of one email (~30MB).
|
||||||
|
inMemoryCacheLimnit = 100 * (1 << 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(base *base.Base) *cli.App {
|
func New(base *base.Base) *cli.App {
|
||||||
app := base.NewApp(run)
|
app := base.NewApp(mailLoop)
|
||||||
|
|
||||||
app.Flags = append(app.Flags, []cli.Flag{
|
app.Flags = append(app.Flags, []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@ -55,9 +61,6 @@ func New(base *base.Base) *cli.App {
|
|||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: flagLogSMTP,
|
Name: flagLogSMTP,
|
||||||
Usage: "Enable logging of SMTP communications (may contain decrypted data!)"},
|
Usage: "Enable logging of SMTP communications (may contain decrypted data!)"},
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: flagNoWindow,
|
|
||||||
Usage: "Don't show window after start"},
|
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: flagNonInteractive,
|
Name: flagNonInteractive,
|
||||||
Usage: "Start Bridge entirely noninteractively"},
|
Usage: "Start Bridge entirely noninteractively"},
|
||||||
@ -66,15 +69,47 @@ func New(base *base.Base) *cli.App {
|
|||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
|
func mailLoop(b *base.Base, c *cli.Context) error { //nolint:funlen
|
||||||
tlsConfig, err := loadTLSConfig(b)
|
tlsConfig, err := loadTLSConfig(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatal("Failed to load TLS config")
|
return err
|
||||||
}
|
}
|
||||||
bridge := bridge.New(b.Locations, b.Cache, b.Settings, b.SentryReporter, b.CrashHandler, b.Listener, b.CM, b.Creds, b.Updater, b.Versioner)
|
|
||||||
imapBackend := imap.NewIMAPBackend(b.CrashHandler, b.Listener, b.Cache, bridge)
|
// GODT-1481: Always turn off reporting of unencrypted recipient in v2.
|
||||||
|
b.Settings.SetBool(settings.ReportOutgoingNoEncKey, false)
|
||||||
|
|
||||||
|
cache, cacheErr := loadMessageCache(b)
|
||||||
|
if cacheErr != nil {
|
||||||
|
logrus.WithError(cacheErr).Error("Could not load local cache.")
|
||||||
|
}
|
||||||
|
|
||||||
|
builder := message.NewBuilder(
|
||||||
|
b.Settings.GetInt(settings.FetchWorkers),
|
||||||
|
b.Settings.GetInt(settings.AttachmentWorkers),
|
||||||
|
)
|
||||||
|
|
||||||
|
bridge := pkgBridge.New(
|
||||||
|
b.Locations,
|
||||||
|
b.Cache,
|
||||||
|
b.Settings,
|
||||||
|
b.SentryReporter,
|
||||||
|
b.CrashHandler,
|
||||||
|
b.Listener,
|
||||||
|
cache,
|
||||||
|
builder,
|
||||||
|
b.CM,
|
||||||
|
b.Creds,
|
||||||
|
b.Updater,
|
||||||
|
b.Versioner,
|
||||||
|
b.Autostart,
|
||||||
|
)
|
||||||
|
imapBackend := imap.NewIMAPBackend(b.CrashHandler, b.Listener, b.Cache, b.Settings, bridge)
|
||||||
smtpBackend := smtp.NewSMTPBackend(b.CrashHandler, b.Listener, b.Settings, bridge)
|
smtpBackend := smtp.NewSMTPBackend(b.CrashHandler, b.Listener, b.Settings, bridge)
|
||||||
|
|
||||||
|
if cacheErr != nil {
|
||||||
|
bridge.AddError(pkgBridge.ErrLocalCacheUnavailable)
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer b.CrashHandler.HandlePanic()
|
defer b.CrashHandler.HandlePanic()
|
||||||
api.NewAPIServer(b.Settings, b.Listener).ListenAndServe()
|
api.NewAPIServer(b.Settings, b.Listener).ListenAndServe()
|
||||||
@ -100,9 +135,6 @@ func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
|
|||||||
smtpPort, useSSL, tlsConfig, smtpBackend, b.Listener).ListenAndServe()
|
smtpPort, useSSL, tlsConfig, smtpBackend, b.Listener).ListenAndServe()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Bridge supports no-window option which we should use for autostart.
|
|
||||||
b.Autostart.Exec = append(b.Autostart.Exec, "--"+flagNoWindow)
|
|
||||||
|
|
||||||
// We want to remove old versions if the app exits successfully.
|
// We want to remove old versions if the app exits successfully.
|
||||||
b.AddTeardownAction(b.Versioner.RemoveOldVersions)
|
b.AddTeardownAction(b.Versioner.RemoveOldVersions)
|
||||||
|
|
||||||
@ -125,7 +157,7 @@ func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
|
|||||||
constants.BuildVersion,
|
constants.BuildVersion,
|
||||||
b.Name,
|
b.Name,
|
||||||
frontendMode,
|
frontendMode,
|
||||||
!c.Bool(flagNoWindow),
|
!c.Bool(base.FlagNoWindow),
|
||||||
b.CrashHandler,
|
b.CrashHandler,
|
||||||
b.Locations,
|
b.Locations,
|
||||||
b.Settings,
|
b.Settings,
|
||||||
@ -134,7 +166,6 @@ func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
|
|||||||
b.UserAgent,
|
b.UserAgent,
|
||||||
bridge,
|
bridge,
|
||||||
smtpBackend,
|
smtpBackend,
|
||||||
b.Autostart,
|
|
||||||
b,
|
b,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -233,3 +264,51 @@ func checkAndHandleUpdate(u types.Updater, f frontend.Frontend, autoUpdate bool)
|
|||||||
|
|
||||||
f.NotifySilentUpdateInstalled()
|
f.NotifySilentUpdateInstalled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadMessageCache loads local cache in case it is enabled in settings and available.
|
||||||
|
// In any other case it is returning in-memory cache. Could also return an error in case
|
||||||
|
// local cache is enabled but unavailable (in-memory cache will be returned nevertheless).
|
||||||
|
func loadMessageCache(b *base.Base) (cache.Cache, error) {
|
||||||
|
if !b.Settings.GetBool(settings.CacheEnabledKey) {
|
||||||
|
return cache.NewInMemoryCache(inMemoryCacheLimnit), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var compressor cache.Compressor
|
||||||
|
|
||||||
|
// NOTE(GODT-1158): Changing compression is not an option currently
|
||||||
|
// available for user but, if user changes compression setting we have
|
||||||
|
// to nuke the cache.
|
||||||
|
if b.Settings.GetBool(settings.CacheCompressionKey) {
|
||||||
|
compressor = &cache.GZipCompressor{}
|
||||||
|
} else {
|
||||||
|
compressor = &cache.NoopCompressor{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var path string
|
||||||
|
|
||||||
|
if customPath := b.Settings.Get(settings.CacheLocationKey); customPath != "" {
|
||||||
|
path = customPath
|
||||||
|
} else {
|
||||||
|
path = b.Cache.GetDefaultMessageCacheDir()
|
||||||
|
// Store path so it will allways persist if default location
|
||||||
|
// will be changed in new version.
|
||||||
|
b.Settings.Set(settings.CacheLocationKey, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// To prevent memory peaks we set maximal write concurency for store
|
||||||
|
// build jobs.
|
||||||
|
store.SetBuildAndCacheJobLimit(b.Settings.GetInt(settings.CacheConcurrencyWrite))
|
||||||
|
|
||||||
|
messageCache, err := cache.NewOnDiskCache(path, compressor, cache.Options{
|
||||||
|
MinFreeAbs: uint64(b.Settings.GetInt(settings.CacheMinFreeAbsKey)),
|
||||||
|
MinFreeRat: b.Settings.GetFloat64(settings.CacheMinFreeRatKey),
|
||||||
|
ConcurrentRead: b.Settings.GetInt(settings.CacheConcurrencyRead),
|
||||||
|
ConcurrentWrite: b.Settings.GetInt(settings.CacheConcurrencyWrite),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return cache.NewInMemoryCache(inMemoryCacheLimnit), err
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageCache, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -1,110 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Package ie implements the ie CLI application.
|
|
||||||
package ie
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/api"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/app/base"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/constants"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/frontend"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/importexport"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func New(b *base.Base) *cli.App {
|
|
||||||
return b.NewApp(run)
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(b *base.Base, c *cli.Context) error {
|
|
||||||
ie := importexport.New(b.Locations, b.Cache, b.CrashHandler, b.Listener, b.CM, b.Creds)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer b.CrashHandler.HandlePanic()
|
|
||||||
api.NewAPIServer(b.Settings, b.Listener).ListenAndServe()
|
|
||||||
}()
|
|
||||||
|
|
||||||
var frontendMode string
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case c.Bool(base.FlagCLI):
|
|
||||||
frontendMode = "cli"
|
|
||||||
default:
|
|
||||||
frontendMode = "qt"
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want to remove old versions if the app exits successfully.
|
|
||||||
b.AddTeardownAction(b.Versioner.RemoveOldVersions)
|
|
||||||
|
|
||||||
// We want cookies to be saved to disk so they are loaded the next time.
|
|
||||||
b.AddTeardownAction(b.CookieJar.PersistCookies)
|
|
||||||
|
|
||||||
f := frontend.NewImportExport(
|
|
||||||
constants.Version,
|
|
||||||
constants.BuildVersion,
|
|
||||||
b.Name,
|
|
||||||
frontendMode,
|
|
||||||
b.CrashHandler,
|
|
||||||
b.Locations,
|
|
||||||
b.Settings,
|
|
||||||
b.Listener,
|
|
||||||
b.Updater,
|
|
||||||
ie,
|
|
||||||
b,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Watch for updates routine
|
|
||||||
go func() {
|
|
||||||
ticker := time.NewTicker(time.Hour)
|
|
||||||
|
|
||||||
for {
|
|
||||||
checkAndHandleUpdate(b.Updater, f, b.Settings.GetBool(settings.AutoUpdateKey))
|
|
||||||
<-ticker.C
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return f.Loop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAndHandleUpdate(u types.Updater, f frontend.Frontend, autoUpdate bool) { //nolint[unparam]
|
|
||||||
log := logrus.WithField("pkg", "app/ie")
|
|
||||||
version, err := u.Check()
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("An error occurred while checking for updates")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f.WaitUntilFrontendIsReady()
|
|
||||||
|
|
||||||
// Update links in UI
|
|
||||||
f.SetVersion(version)
|
|
||||||
|
|
||||||
if !u.IsUpdateApplicable(version) {
|
|
||||||
log.Info("No need to update")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithField("version", version.Version).Info("An update is available")
|
|
||||||
|
|
||||||
f.NotifyManualUpdate(version, u.CanInstall(version))
|
|
||||||
}
|
|
||||||
38
internal/bridge/autostart.go
Normal file
38
internal/bridge/autostart.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) 2022 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 bridge provides core functionality of Bridge app.
|
||||||
|
package bridge
|
||||||
|
|
||||||
|
import "github.com/ProtonMail/proton-bridge/internal/config/settings"
|
||||||
|
|
||||||
|
// IsAutostartEnabled checks if link file exits.
|
||||||
|
func (b *Bridge) IsAutostartEnabled() bool {
|
||||||
|
return b.autostart.IsEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableAutostart creates link and sets the preferences.
|
||||||
|
func (b *Bridge) EnableAutostart() error {
|
||||||
|
b.settings.SetBool(settings.AutostartKey, true)
|
||||||
|
return b.autostart.Enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableAutostart removes link and sets the preferences.
|
||||||
|
func (b *Bridge) DisableAutostart() error {
|
||||||
|
b.settings.SetBool(settings.AutostartKey, false)
|
||||||
|
return b.autostart.Disable()
|
||||||
|
}
|
||||||
@ -1,44 +1,48 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package bridge provides core functionality of Bridge app.
|
// Package bridge provides core functionality of Bridge app.
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver/v3"
|
||||||
|
"github.com/ProtonMail/go-autostart"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/constants"
|
"github.com/ProtonMail/proton-bridge/internal/constants"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/metrics"
|
"github.com/ProtonMail/proton-bridge/internal/metrics"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/sentry"
|
"github.com/ProtonMail/proton-bridge/internal/sentry"
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/store/cache"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/updater"
|
"github.com/ProtonMail/proton-bridge/internal/updater"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/users"
|
"github.com/ProtonMail/proton-bridge/internal/users"
|
||||||
|
"github.com/ProtonMail/proton-bridge/pkg/message"
|
||||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||||
logrus "github.com/sirupsen/logrus"
|
logrus "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var log = logrus.WithField("pkg", "bridge") //nolint:gochecknoglobals
|
||||||
log = logrus.WithField("pkg", "bridge") //nolint[gochecknoglobals]
|
|
||||||
)
|
var ErrLocalCacheUnavailable = errors.New("local cache is unavailable")
|
||||||
|
|
||||||
type Bridge struct {
|
type Bridge struct {
|
||||||
*users.Users
|
*users.Users
|
||||||
@ -48,46 +52,69 @@ type Bridge struct {
|
|||||||
clientManager pmapi.Manager
|
clientManager pmapi.Manager
|
||||||
updater Updater
|
updater Updater
|
||||||
versioner Versioner
|
versioner Versioner
|
||||||
|
cacheProvider CacheProvider
|
||||||
|
autostart *autostart.App
|
||||||
|
// Bridge's global errors list.
|
||||||
|
errors []error
|
||||||
|
|
||||||
|
isFirstStart bool
|
||||||
|
lastVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
locations Locator,
|
locations Locator,
|
||||||
cache Cacher,
|
cacheProvider CacheProvider,
|
||||||
s SettingsProvider,
|
setting SettingsProvider,
|
||||||
sentryReporter *sentry.Reporter,
|
sentryReporter *sentry.Reporter,
|
||||||
panicHandler users.PanicHandler,
|
panicHandler users.PanicHandler,
|
||||||
eventListener listener.Listener,
|
eventListener listener.Listener,
|
||||||
|
cache cache.Cache,
|
||||||
|
builder *message.Builder,
|
||||||
clientManager pmapi.Manager,
|
clientManager pmapi.Manager,
|
||||||
credStorer users.CredentialsStorer,
|
credStorer users.CredentialsStorer,
|
||||||
updater Updater,
|
updater Updater,
|
||||||
versioner Versioner,
|
versioner Versioner,
|
||||||
|
autostart *autostart.App,
|
||||||
) *Bridge {
|
) *Bridge {
|
||||||
// Allow DoH before starting the app if the user has previously set this setting.
|
// Allow DoH before starting the app if the user has previously set this setting.
|
||||||
// This allows us to start even if protonmail is blocked.
|
// This allows us to start even if protonmail is blocked.
|
||||||
if s.GetBool(settings.AllowProxyKey) {
|
if setting.GetBool(settings.AllowProxyKey) {
|
||||||
clientManager.AllowProxy()
|
clientManager.AllowProxy()
|
||||||
}
|
}
|
||||||
|
|
||||||
storeFactory := newStoreFactory(cache, sentryReporter, panicHandler, eventListener)
|
u := users.New(
|
||||||
u := users.New(locations, panicHandler, eventListener, clientManager, credStorer, storeFactory, true)
|
locations,
|
||||||
b := &Bridge{
|
panicHandler,
|
||||||
Users: u,
|
eventListener,
|
||||||
|
clientManager,
|
||||||
|
credStorer,
|
||||||
|
newStoreFactory(cacheProvider, sentryReporter, panicHandler, eventListener, cache, builder),
|
||||||
|
)
|
||||||
|
|
||||||
|
b := &Bridge{
|
||||||
|
Users: u,
|
||||||
locations: locations,
|
locations: locations,
|
||||||
settings: s,
|
settings: setting,
|
||||||
clientManager: clientManager,
|
clientManager: clientManager,
|
||||||
updater: updater,
|
updater: updater,
|
||||||
versioner: versioner,
|
versioner: versioner,
|
||||||
|
cacheProvider: cacheProvider,
|
||||||
|
autostart: autostart,
|
||||||
|
isFirstStart: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.GetBool(settings.FirstStartKey) {
|
if setting.GetBool(settings.FirstStartKey) {
|
||||||
|
b.isFirstStart = true
|
||||||
if err := b.SendMetric(metrics.New(metrics.Setup, metrics.FirstStart, metrics.Label(constants.Version))); err != nil {
|
if err := b.SendMetric(metrics.New(metrics.Setup, metrics.FirstStart, metrics.Label(constants.Version))); err != nil {
|
||||||
logrus.WithError(err).Error("Failed to send metric")
|
logrus.WithError(err).Error("Failed to send metric")
|
||||||
}
|
}
|
||||||
|
setting.SetBool(settings.FirstStartKey, false)
|
||||||
s.SetBool(settings.FirstStartKey, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep in bridge and update in settings the last used version.
|
||||||
|
b.lastVersion = b.settings.Get(settings.LastVersionKey)
|
||||||
|
b.settings.Set(settings.LastVersionKey, constants.Version)
|
||||||
|
|
||||||
go b.heartbeat()
|
go b.heartbeat()
|
||||||
|
|
||||||
return b
|
return b
|
||||||
@ -117,55 +144,60 @@ func (b *Bridge) heartbeat() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReportBug reports a new bug from the user.
|
|
||||||
func (b *Bridge) ReportBug(osType, osVersion, description, accountName, address, emailClient string) error {
|
|
||||||
return b.clientManager.ReportBug(context.Background(), pmapi.ReportBugReq{
|
|
||||||
OS: osType,
|
|
||||||
OSVersion: osVersion,
|
|
||||||
Browser: emailClient,
|
|
||||||
Title: "[Bridge] Bug",
|
|
||||||
Description: description,
|
|
||||||
Username: accountName,
|
|
||||||
Email: address,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUpdateChannel returns currently set update channel.
|
// GetUpdateChannel returns currently set update channel.
|
||||||
func (b *Bridge) GetUpdateChannel() updater.UpdateChannel {
|
func (b *Bridge) GetUpdateChannel() updater.UpdateChannel {
|
||||||
return updater.UpdateChannel(b.settings.Get(settings.UpdateChannelKey))
|
return updater.UpdateChannel(b.settings.Get(settings.UpdateChannelKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUpdateChannel switches update channel.
|
// SetUpdateChannel switches update channel.
|
||||||
// Downgrading to previous version (by switching from early to stable, for example)
|
func (b *Bridge) SetUpdateChannel(channel updater.UpdateChannel) {
|
||||||
// requires clearing all data including update files due to possibility of
|
|
||||||
// inconsistency between versions and absence of backwards migration scripts.
|
|
||||||
func (b *Bridge) SetUpdateChannel(channel updater.UpdateChannel) (needRestart bool, err error) {
|
|
||||||
b.settings.Set(settings.UpdateChannelKey, string(channel))
|
b.settings.Set(settings.UpdateChannelKey, string(channel))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) resetToLatestStable() error {
|
||||||
version, err := b.updater.Check()
|
version, err := b.updater.Check()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
// If we can not check for updates - just remove all local updates and reset to base installer version.
|
||||||
|
// Not using `b.locations.ClearUpdates()` because `versioner.RemoveOtherVersions` can also handle
|
||||||
|
// case when it is needed to remove currently running verion.
|
||||||
|
if err := b.versioner.RemoveOtherVersions(semver.MustParse("0.0.0")); err != nil {
|
||||||
|
log.WithError(err).Error("Failed to clear updates while downgrading channel")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to deal right away only with downgrade - that action needs to
|
// If current version is same as upstream stable version - do nothing.
|
||||||
// clear data and updates, and install bridge right away. But regular
|
if version.Version.Equal(semver.MustParse(constants.Version)) {
|
||||||
// upgrade can be leaved out for periodic check.
|
return nil
|
||||||
if !b.updater.IsDowngrade(version) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := b.Users.ClearData(); err != nil {
|
|
||||||
log.WithError(err).Error("Failed to clear data while downgrading channel")
|
|
||||||
}
|
|
||||||
if err := b.locations.ClearUpdates(); err != nil {
|
|
||||||
log.WithError(err).Error("Failed to clear updates while downgrading channel")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.updater.InstallUpdate(version); err != nil {
|
if err := b.updater.InstallUpdate(version); err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, b.versioner.RemoveOtherVersions(version.Version)
|
return b.versioner.RemoveOtherVersions(version.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FactoryReset will remove all local cache and settings.
|
||||||
|
// It will also downgrade to latest stable version if user is on early version.
|
||||||
|
func (b *Bridge) FactoryReset() {
|
||||||
|
wasEarly := b.GetUpdateChannel() == updater.EarlyChannel
|
||||||
|
|
||||||
|
b.settings.Set(settings.UpdateChannelKey, string(updater.StableChannel))
|
||||||
|
|
||||||
|
if wasEarly {
|
||||||
|
if err := b.resetToLatestStable(); err != nil {
|
||||||
|
log.WithError(err).Error("Failed to reset to latest stable version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.Users.ClearData(); err != nil {
|
||||||
|
log.WithError(err).Error("Failed to remove bridge data")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.Users.ClearUsers(); err != nil {
|
||||||
|
log.WithError(err).Error("Failed to remove bridge users")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKeychainApp returns current keychain helper.
|
// GetKeychainApp returns current keychain helper.
|
||||||
@ -177,3 +209,96 @@ func (b *Bridge) GetKeychainApp() string {
|
|||||||
func (b *Bridge) SetKeychainApp(helper string) {
|
func (b *Bridge) SetKeychainApp(helper string) {
|
||||||
b.settings.Set(settings.PreferredKeychainKey, helper)
|
b.settings.Set(settings.PreferredKeychainKey, helper)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) EnableCache() error {
|
||||||
|
if err := b.Users.EnableCache(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.settings.SetBool(settings.CacheEnabledKey, true)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) DisableCache() error {
|
||||||
|
if err := b.Users.DisableCache(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.settings.SetBool(settings.CacheEnabledKey, false)
|
||||||
|
// Reset back to the default location when disabling.
|
||||||
|
b.settings.Set(settings.CacheLocationKey, b.cacheProvider.GetDefaultMessageCacheDir())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) MigrateCache(from, to string) error {
|
||||||
|
if err := b.Users.MigrateCache(from, to); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.settings.Set(settings.CacheLocationKey, to)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProxyAllowed instructs the app whether to use DoH to access an API proxy if necessary.
|
||||||
|
// It also needs to work before the app is initialised (because we may need to use the proxy at startup).
|
||||||
|
func (b *Bridge) SetProxyAllowed(proxyAllowed bool) {
|
||||||
|
b.settings.SetBool(settings.AllowProxyKey, proxyAllowed)
|
||||||
|
if proxyAllowed {
|
||||||
|
b.clientManager.AllowProxy()
|
||||||
|
} else {
|
||||||
|
b.clientManager.DisallowProxy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProxyAllowed returns whether use of DoH is enabled to access an API proxy if necessary.
|
||||||
|
func (b *Bridge) GetProxyAllowed() bool {
|
||||||
|
return b.settings.GetBool(settings.AllowProxyKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddError add an error to a global error list if it does not contain it yet. Adding nil is noop.
|
||||||
|
func (b *Bridge) AddError(err error) {
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if b.HasError(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b.errors = append(b.errors, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelError removes an error from global error list.
|
||||||
|
func (b *Bridge) DelError(err error) {
|
||||||
|
for idx, val := range b.errors {
|
||||||
|
if val == err {
|
||||||
|
b.errors = append(b.errors[:idx], b.errors[idx+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasError returnes true if global error list contains an err.
|
||||||
|
func (b *Bridge) HasError(err error) bool {
|
||||||
|
for _, val := range b.errors {
|
||||||
|
if val == err {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLastVersion returns the version which was used in previous execution of
|
||||||
|
// Bridge.
|
||||||
|
func (b *Bridge) GetLastVersion() string {
|
||||||
|
return b.lastVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFirstStart returns true when Bridge is running for first time or after
|
||||||
|
// factory reset.
|
||||||
|
func (b *Bridge) IsFirstStart() bool {
|
||||||
|
return b.isFirstStart
|
||||||
|
}
|
||||||
|
|||||||
205
internal/bridge/bug_report.go
Normal file
205
internal/bridge/bug_report.go
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
// Copyright (c) 2022 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 bridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/logging"
|
||||||
|
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
const MaxAttachmentSize = 7 * 1024 * 1024 // 7 MB total limit
|
||||||
|
const MaxCompressedFilesCount = 6
|
||||||
|
|
||||||
|
var ErrSizeTooLarge = errors.New("file is too big")
|
||||||
|
|
||||||
|
// ReportBug reports a new bug from the user.
|
||||||
|
func (b *Bridge) ReportBug(osType, osVersion, description, accountName, address, emailClient string, attachLogs bool) error {
|
||||||
|
if user, err := b.GetUser(address); err == nil {
|
||||||
|
accountName = user.Username()
|
||||||
|
} else if users := b.GetUsers(); len(users) > 0 {
|
||||||
|
accountName = users[0].Username()
|
||||||
|
}
|
||||||
|
|
||||||
|
report := pmapi.ReportBugReq{
|
||||||
|
OS: osType,
|
||||||
|
OSVersion: osVersion,
|
||||||
|
Browser: emailClient,
|
||||||
|
Title: "[Bridge] Bug",
|
||||||
|
Description: description,
|
||||||
|
Username: accountName,
|
||||||
|
Email: address,
|
||||||
|
}
|
||||||
|
|
||||||
|
if attachLogs {
|
||||||
|
logs, err := b.getMatchingLogs(
|
||||||
|
func(filename string) bool {
|
||||||
|
return logging.MatchLogName(filename) && !logging.MatchStackTraceName(filename)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Can't get log files list")
|
||||||
|
}
|
||||||
|
crashes, err := b.getMatchingLogs(
|
||||||
|
func(filename string) bool {
|
||||||
|
return logging.MatchLogName(filename) && logging.MatchStackTraceName(filename)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Can't get crash files list")
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchFiles []string
|
||||||
|
|
||||||
|
matchFiles = append(matchFiles, logs[max(0, len(logs)-(MaxCompressedFilesCount/2)):]...)
|
||||||
|
matchFiles = append(matchFiles, crashes[max(0, len(crashes)-(MaxCompressedFilesCount/2)):]...)
|
||||||
|
|
||||||
|
archive, err := zipFiles(matchFiles)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Can't zip logs and crashes")
|
||||||
|
}
|
||||||
|
|
||||||
|
if archive != nil {
|
||||||
|
report.AddAttachment("logs.zip", "application/zip", archive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.clientManager.ReportBug(context.Background(), report)
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) getMatchingLogs(filenameMatchFunc func(string) bool) (filenames []string, err error) {
|
||||||
|
logsPath, err := b.locations.ProvideLogsPath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(logsPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchFiles []string
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
if filenameMatchFunc(file.Name()) {
|
||||||
|
matchFiles = append(matchFiles, filepath.Join(logsPath, file.Name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(matchFiles) // Sorted by timestamp: oldest first.
|
||||||
|
|
||||||
|
return matchFiles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LimitedBuffer struct {
|
||||||
|
capacity int
|
||||||
|
buf *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLimitedBuffer(capacity int) *LimitedBuffer {
|
||||||
|
return &LimitedBuffer{
|
||||||
|
capacity: capacity,
|
||||||
|
buf: bytes.NewBuffer(make([]byte, 0, capacity)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LimitedBuffer) Write(p []byte) (n int, err error) {
|
||||||
|
if len(p)+b.buf.Len() > b.capacity {
|
||||||
|
return 0, ErrSizeTooLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.buf.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LimitedBuffer) Read(p []byte) (n int, err error) {
|
||||||
|
return b.buf.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func zipFiles(filenames []string) (io.Reader, error) {
|
||||||
|
if len(filenames) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := NewLimitedBuffer(MaxAttachmentSize)
|
||||||
|
|
||||||
|
w := zip.NewWriter(buf)
|
||||||
|
defer w.Close() //nolint:errcheck
|
||||||
|
|
||||||
|
for _, file := range filenames {
|
||||||
|
err := addFileToZip(file, w)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFileToZip(filename string, writer *zip.Writer) error {
|
||||||
|
fileReader, err := os.Open(filepath.Clean(filename))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fileReader.Close() //nolint:errcheck,gosec
|
||||||
|
|
||||||
|
fileInfo, err := fileReader.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := zip.FileInfoHeader(fileInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header.Method = zip.Deflate
|
||||||
|
header.Name = filepath.Base(filename)
|
||||||
|
|
||||||
|
fileWriter, err := writer.CreateHeader(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(fileWriter, fileReader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fileReader.Close()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Code generated by ./release-notes.sh at 'Fri Jan 22 11:01:06 AM CET 2021'. DO NOT EDIT.
|
// Code generated by ./release-notes.sh at 'Fri Jan 22 11:01:06 AM CET 2021'. DO NOT EDIT.
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
@ -23,47 +23,65 @@ import (
|
|||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/sentry"
|
"github.com/ProtonMail/proton-bridge/internal/sentry"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/store"
|
"github.com/ProtonMail/proton-bridge/internal/store"
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/store/cache"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/users"
|
"github.com/ProtonMail/proton-bridge/internal/users"
|
||||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||||
|
"github.com/ProtonMail/proton-bridge/pkg/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
type storeFactory struct {
|
type storeFactory struct {
|
||||||
cache Cacher
|
cacheProvider CacheProvider
|
||||||
sentryReporter *sentry.Reporter
|
sentryReporter *sentry.Reporter
|
||||||
panicHandler users.PanicHandler
|
panicHandler users.PanicHandler
|
||||||
eventListener listener.Listener
|
eventListener listener.Listener
|
||||||
storeCache *store.Cache
|
events *store.Events
|
||||||
|
cache cache.Cache
|
||||||
|
builder *message.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStoreFactory(
|
func newStoreFactory(
|
||||||
cache Cacher,
|
cacheProvider CacheProvider,
|
||||||
sentryReporter *sentry.Reporter,
|
sentryReporter *sentry.Reporter,
|
||||||
panicHandler users.PanicHandler,
|
panicHandler users.PanicHandler,
|
||||||
eventListener listener.Listener,
|
eventListener listener.Listener,
|
||||||
|
cache cache.Cache,
|
||||||
|
builder *message.Builder,
|
||||||
) *storeFactory {
|
) *storeFactory {
|
||||||
return &storeFactory{
|
return &storeFactory{
|
||||||
cache: cache,
|
cacheProvider: cacheProvider,
|
||||||
sentryReporter: sentryReporter,
|
sentryReporter: sentryReporter,
|
||||||
panicHandler: panicHandler,
|
panicHandler: panicHandler,
|
||||||
eventListener: eventListener,
|
eventListener: eventListener,
|
||||||
storeCache: store.NewCache(cache.GetIMAPCachePath()),
|
events: store.NewEvents(cacheProvider.GetIMAPCachePath()),
|
||||||
|
cache: cache,
|
||||||
|
builder: builder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates new store for given user.
|
// New creates new store for given user.
|
||||||
func (f *storeFactory) New(user store.BridgeUser) (*store.Store, error) {
|
func (f *storeFactory) New(user store.BridgeUser) (*store.Store, error) {
|
||||||
storePath := getUserStorePath(f.cache.GetDBDir(), user.ID())
|
return store.New(
|
||||||
return store.New(f.sentryReporter, f.panicHandler, user, f.eventListener, storePath, f.storeCache)
|
f.sentryReporter,
|
||||||
|
f.panicHandler,
|
||||||
|
user,
|
||||||
|
f.eventListener,
|
||||||
|
f.cache,
|
||||||
|
f.builder,
|
||||||
|
getUserStorePath(f.cacheProvider.GetDBDir(), user.ID()),
|
||||||
|
f.events,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes all store files for given user.
|
// Remove removes all store files for given user.
|
||||||
func (f *storeFactory) Remove(userID string) error {
|
func (f *storeFactory) Remove(userID string) error {
|
||||||
storePath := getUserStorePath(f.cache.GetDBDir(), userID)
|
return store.RemoveStore(
|
||||||
return store.RemoveStore(f.storeCache, storePath, userID)
|
f.events,
|
||||||
|
getUserStorePath(f.cacheProvider.GetDBDir(), userID),
|
||||||
|
userID,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getUserStorePath returns the file path of the store database for the given userID.
|
// getUserStorePath returns the file path of the store database for the given userID.
|
||||||
func getUserStorePath(storeDir string, userID string) (path string) {
|
func getUserStorePath(storeDir string, userID string) (path string) {
|
||||||
fileName := fmt.Sprintf("mailbox-%v.db", userID)
|
return filepath.Join(storeDir, fmt.Sprintf("mailbox-%v.db", userID))
|
||||||
return filepath.Join(storeDir, fileName)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
@ -26,11 +26,13 @@ import (
|
|||||||
type Locator interface {
|
type Locator interface {
|
||||||
Clear() error
|
Clear() error
|
||||||
ClearUpdates() error
|
ClearUpdates() error
|
||||||
|
ProvideLogsPath() (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Cacher interface {
|
type CacheProvider interface {
|
||||||
GetIMAPCachePath() string
|
GetIMAPCachePath() string
|
||||||
GetDBDir() string
|
GetDBDir() string
|
||||||
|
GetDefaultMessageCacheDir() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingsProvider interface {
|
type SettingsProvider interface {
|
||||||
@ -38,6 +40,7 @@ type SettingsProvider interface {
|
|||||||
Set(key string, value string)
|
Set(key string, value string)
|
||||||
GetBool(key string) bool
|
GetBool(key string) bool
|
||||||
SetBool(key string, val bool)
|
SetBool(key string, val bool)
|
||||||
|
GetInt(key string) int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Updater interface {
|
type Updater interface {
|
||||||
|
|||||||
15
internal/config/cache/cache.go
vendored
15
internal/config/cache/cache.go
vendored
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package cache provides access to contents inside a cache directory.
|
// Package cache provides access to contents inside a cache directory.
|
||||||
package cache
|
package cache
|
||||||
@ -45,6 +45,11 @@ func (c *Cache) GetDBDir() string {
|
|||||||
return c.getCurrentCacheDir()
|
return c.getCurrentCacheDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDefaultMessageCacheDir returns folder for cached messages files.
|
||||||
|
func (c *Cache) GetDefaultMessageCacheDir() string {
|
||||||
|
return filepath.Join(c.getCurrentCacheDir(), "messages")
|
||||||
|
}
|
||||||
|
|
||||||
// GetIMAPCachePath returns path to file with IMAP status.
|
// GetIMAPCachePath returns path to file with IMAP status.
|
||||||
func (c *Cache) GetIMAPCachePath() string {
|
func (c *Cache) GetIMAPCachePath() string {
|
||||||
return filepath.Join(c.getCurrentCacheDir(), "user_info.json")
|
return filepath.Join(c.getCurrentCacheDir(), "user_info.json")
|
||||||
|
|||||||
10
internal/config/cache/cache_test.go
vendored
10
internal/config/cache/cache_test.go
vendored
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cache
|
package cache
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package settings
|
package settings
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ func (p *keyValueStore) load() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close() //nolint[errcheck]
|
defer f.Close() //nolint:errcheck,gosec
|
||||||
|
|
||||||
return json.NewDecoder(f).Decode(&p.cache)
|
return json.NewDecoder(f).Decode(&p.cache)
|
||||||
}
|
}
|
||||||
@ -100,18 +100,28 @@ func (p *keyValueStore) GetBool(key string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *keyValueStore) GetInt(key string) int {
|
func (p *keyValueStore) GetInt(key string) int {
|
||||||
|
if p.Get(key) == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
value, err := strconv.Atoi(p.Get(key))
|
value, err := strconv.Atoi(p.Get(key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Error("Cannot parse int")
|
logrus.WithError(err).Error("Cannot parse int")
|
||||||
}
|
}
|
||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *keyValueStore) GetFloat64(key string) float64 {
|
func (p *keyValueStore) GetFloat64(key string) float64 {
|
||||||
|
if p.Get(key) == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
value, err := strconv.ParseFloat(p.Get(key), 64)
|
value, err := strconv.ParseFloat(p.Get(key), 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Error("Cannot parse float64")
|
logrus.WithError(err).Error("Cannot parse float64")
|
||||||
}
|
}
|
||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package settings
|
package settings
|
||||||
|
|
||||||
@ -25,81 +25,118 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testPrefFilePath = "/tmp/pref.json"
|
|
||||||
|
|
||||||
func TestLoadNoKeyValueStore(t *testing.T) {
|
func TestLoadNoKeyValueStore(t *testing.T) {
|
||||||
pref := newTestEmptyKeyValueStore(t)
|
r := require.New(t)
|
||||||
require.Equal(t, "", pref.Get("key"))
|
pref, clean := newTestEmptyKeyValueStore(r)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
|
r.Equal("", pref.Get("key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadBadKeyValueStore(t *testing.T) {
|
func TestLoadBadKeyValueStore(t *testing.T) {
|
||||||
require.NoError(t, ioutil.WriteFile(testPrefFilePath, []byte("{\"key\":\"value"), 0700))
|
r := require.New(t)
|
||||||
pref := newKeyValueStore(testPrefFilePath)
|
path, clean := newTmpFile(r)
|
||||||
require.Equal(t, "", pref.Get("key"))
|
defer clean()
|
||||||
|
|
||||||
|
r.NoError(ioutil.WriteFile(path, []byte("{\"key\":\"MISSING_QUOTES"), 0700))
|
||||||
|
pref := newKeyValueStore(path)
|
||||||
|
r.Equal("", pref.Get("key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyValueStoreGet(t *testing.T) {
|
func TestKeyValueStor(t *testing.T) {
|
||||||
pref := newTestKeyValueStore(t)
|
r := require.New(t)
|
||||||
require.Equal(t, "value", pref.Get("str"))
|
pref, clean := newTestKeyValueStore(r)
|
||||||
require.Equal(t, "42", pref.Get("int"))
|
defer clean()
|
||||||
require.Equal(t, "true", pref.Get("bool"))
|
|
||||||
require.Equal(t, "t", pref.Get("falseBool"))
|
r.Equal("value", pref.Get("str"))
|
||||||
|
r.Equal("42", pref.Get("int"))
|
||||||
|
r.Equal("true", pref.Get("bool"))
|
||||||
|
r.Equal("t", pref.Get("falseBool"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyValueStoreGetInt(t *testing.T) {
|
func TestKeyValueStoreGetInt(t *testing.T) {
|
||||||
pref := newTestKeyValueStore(t)
|
r := require.New(t)
|
||||||
require.Equal(t, 0, pref.GetInt("str"))
|
pref, clean := newTestKeyValueStore(r)
|
||||||
require.Equal(t, 42, pref.GetInt("int"))
|
defer clean()
|
||||||
require.Equal(t, 0, pref.GetInt("bool"))
|
|
||||||
require.Equal(t, 0, pref.GetInt("falseBool"))
|
r.Equal(0, pref.GetInt("str"))
|
||||||
|
r.Equal(42, pref.GetInt("int"))
|
||||||
|
r.Equal(0, pref.GetInt("bool"))
|
||||||
|
r.Equal(0, pref.GetInt("falseBool"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyValueStoreGetBool(t *testing.T) {
|
func TestKeyValueStoreGetBool(t *testing.T) {
|
||||||
pref := newTestKeyValueStore(t)
|
r := require.New(t)
|
||||||
require.Equal(t, false, pref.GetBool("str"))
|
pref, clean := newTestKeyValueStore(r)
|
||||||
require.Equal(t, false, pref.GetBool("int"))
|
defer clean()
|
||||||
require.Equal(t, true, pref.GetBool("bool"))
|
|
||||||
require.Equal(t, false, pref.GetBool("falseBool"))
|
r.Equal(false, pref.GetBool("str"))
|
||||||
|
r.Equal(false, pref.GetBool("int"))
|
||||||
|
r.Equal(true, pref.GetBool("bool"))
|
||||||
|
r.Equal(false, pref.GetBool("falseBool"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyValueStoreSetDefault(t *testing.T) {
|
func TestKeyValueStoreSetDefault(t *testing.T) {
|
||||||
pref := newTestEmptyKeyValueStore(t)
|
r := require.New(t)
|
||||||
|
pref, clean := newTestEmptyKeyValueStore(r)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
pref.setDefault("key", "value")
|
pref.setDefault("key", "value")
|
||||||
pref.setDefault("key", "othervalue")
|
pref.setDefault("key", "othervalue")
|
||||||
require.Equal(t, "value", pref.Get("key"))
|
r.Equal("value", pref.Get("key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyValueStoreSet(t *testing.T) {
|
func TestKeyValueStoreSet(t *testing.T) {
|
||||||
pref := newTestEmptyKeyValueStore(t)
|
r := require.New(t)
|
||||||
|
pref, clean := newTestEmptyKeyValueStore(r)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
pref.Set("str", "value")
|
pref.Set("str", "value")
|
||||||
checkSavedKeyValueStore(t, "{\n\t\"str\": \"value\"\n}")
|
checkSavedKeyValueStore(r, pref.path, "{\n\t\"str\": \"value\"\n}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyValueStoreSetInt(t *testing.T) {
|
func TestKeyValueStoreSetInt(t *testing.T) {
|
||||||
pref := newTestEmptyKeyValueStore(t)
|
r := require.New(t)
|
||||||
|
pref, clean := newTestEmptyKeyValueStore(r)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
pref.SetInt("int", 42)
|
pref.SetInt("int", 42)
|
||||||
checkSavedKeyValueStore(t, "{\n\t\"int\": \"42\"\n}")
|
checkSavedKeyValueStore(r, pref.path, "{\n\t\"int\": \"42\"\n}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyValueStoreSetBool(t *testing.T) {
|
func TestKeyValueStoreSetBool(t *testing.T) {
|
||||||
pref := newTestEmptyKeyValueStore(t)
|
r := require.New(t)
|
||||||
|
pref, clean := newTestEmptyKeyValueStore(r)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
pref.SetBool("trueBool", true)
|
pref.SetBool("trueBool", true)
|
||||||
pref.SetBool("falseBool", false)
|
pref.SetBool("falseBool", false)
|
||||||
checkSavedKeyValueStore(t, "{\n\t\"falseBool\": \"false\",\n\t\"trueBool\": \"true\"\n}")
|
checkSavedKeyValueStore(r, pref.path, "{\n\t\"falseBool\": \"false\",\n\t\"trueBool\": \"true\"\n}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestEmptyKeyValueStore(t *testing.T) *keyValueStore {
|
func newTmpFile(r *require.Assertions) (path string, clean func()) {
|
||||||
require.NoError(t, os.RemoveAll(testPrefFilePath))
|
tmpfile, err := ioutil.TempFile("", "pref.*.json")
|
||||||
return newKeyValueStore(testPrefFilePath)
|
r.NoError(err)
|
||||||
|
defer r.NoError(tmpfile.Close())
|
||||||
|
|
||||||
|
return tmpfile.Name(), func() {
|
||||||
|
r.NoError(os.Remove(tmpfile.Name()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestKeyValueStore(t *testing.T) *keyValueStore {
|
func newTestEmptyKeyValueStore(r *require.Assertions) (*keyValueStore, func()) {
|
||||||
require.NoError(t, ioutil.WriteFile(testPrefFilePath, []byte("{\"str\":\"value\",\"int\":\"42\",\"bool\":\"true\",\"falseBool\":\"t\"}"), 0700))
|
path, clean := newTmpFile(r)
|
||||||
return newKeyValueStore(testPrefFilePath)
|
return newKeyValueStore(path), clean
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSavedKeyValueStore(t *testing.T, expected string) {
|
func newTestKeyValueStore(r *require.Assertions) (*keyValueStore, func()) {
|
||||||
data, err := ioutil.ReadFile(testPrefFilePath)
|
path, clean := newTmpFile(r)
|
||||||
require.NoError(t, err)
|
r.NoError(ioutil.WriteFile(path, []byte("{\"str\":\"value\",\"int\":\"42\",\"bool\":\"true\",\"falseBool\":\"t\"}"), 0700))
|
||||||
require.Equal(t, expected, string(data))
|
return newKeyValueStore(path), clean
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkSavedKeyValueStore(r *require.Assertions, path, expected string) {
|
||||||
|
data, err := ioutil.ReadFile(path)
|
||||||
|
r.NoError(err)
|
||||||
|
r.Equal(expected, string(data))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package settings provides access to persistent user settings.
|
// Package settings provides access to persistent user settings.
|
||||||
package settings
|
package settings
|
||||||
@ -43,6 +43,18 @@ const (
|
|||||||
UpdateChannelKey = "update_channel"
|
UpdateChannelKey = "update_channel"
|
||||||
RolloutKey = "rollout"
|
RolloutKey = "rollout"
|
||||||
PreferredKeychainKey = "preferred_keychain"
|
PreferredKeychainKey = "preferred_keychain"
|
||||||
|
CacheEnabledKey = "cache_enabled"
|
||||||
|
CacheCompressionKey = "cache_compression"
|
||||||
|
CacheLocationKey = "cache_location"
|
||||||
|
CacheMinFreeAbsKey = "cache_min_free_abs"
|
||||||
|
CacheMinFreeRatKey = "cache_min_free_rat"
|
||||||
|
CacheConcurrencyRead = "cache_concurrent_read"
|
||||||
|
CacheConcurrencyWrite = "cache_concurrent_write"
|
||||||
|
IMAPWorkers = "imap_workers"
|
||||||
|
FetchWorkers = "fetch_workers"
|
||||||
|
AttachmentWorkers = "attachment_workers"
|
||||||
|
ColorScheme = "color_scheme"
|
||||||
|
RebrandingMigrationKey = "rebranding_migrated"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
@ -78,8 +90,19 @@ func (s *Settings) setDefaultValues() {
|
|||||||
s.setDefault(ReportOutgoingNoEncKey, "false")
|
s.setDefault(ReportOutgoingNoEncKey, "false")
|
||||||
s.setDefault(LastVersionKey, "")
|
s.setDefault(LastVersionKey, "")
|
||||||
s.setDefault(UpdateChannelKey, "")
|
s.setDefault(UpdateChannelKey, "")
|
||||||
s.setDefault(RolloutKey, fmt.Sprintf("%v", rand.Float64())) //nolint[gosec] G404 It is OK to use weak random number generator here
|
s.setDefault(RolloutKey, fmt.Sprintf("%v", rand.Float64())) //nolint:gosec // G404 It is OK to use weak random number generator here
|
||||||
s.setDefault(PreferredKeychainKey, "")
|
s.setDefault(PreferredKeychainKey, "")
|
||||||
|
s.setDefault(CacheEnabledKey, "true")
|
||||||
|
s.setDefault(CacheCompressionKey, "true")
|
||||||
|
s.setDefault(CacheLocationKey, "")
|
||||||
|
s.setDefault(CacheMinFreeAbsKey, "250000000")
|
||||||
|
s.setDefault(CacheMinFreeRatKey, "")
|
||||||
|
s.setDefault(CacheConcurrencyRead, "16")
|
||||||
|
s.setDefault(CacheConcurrencyWrite, "16")
|
||||||
|
s.setDefault(IMAPWorkers, "16")
|
||||||
|
s.setDefault(FetchWorkers, "16")
|
||||||
|
s.setDefault(AttachmentWorkers, "16")
|
||||||
|
s.setDefault(ColorScheme, "")
|
||||||
|
|
||||||
s.setDefault(APIPortKey, DefaultAPIPort)
|
s.setDefault(APIPortKey, DefaultAPIPort)
|
||||||
s.setDefault(IMAPPortKey, DefaultIMAPPort)
|
s.setDefault(IMAPPortKey, DefaultIMAPPort)
|
||||||
|
|||||||
@ -1,26 +1,26 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package tls
|
package tls
|
||||||
|
|
||||||
import "os/exec"
|
import "os/exec"
|
||||||
|
|
||||||
func addTrustedCert(certPath string) error {
|
func addTrustedCert(certPath string) error {
|
||||||
return exec.Command( // nolint[gosec]
|
return exec.Command( //nolint:gosec
|
||||||
"/usr/bin/security",
|
"/usr/bin/security",
|
||||||
"execute-with-privileges",
|
"execute-with-privileges",
|
||||||
"/usr/bin/security",
|
"/usr/bin/security",
|
||||||
@ -34,7 +34,7 @@ func addTrustedCert(certPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeTrustedCert(certPath string) error {
|
func removeTrustedCert(certPath string) error {
|
||||||
return exec.Command( // nolint[gosec]
|
return exec.Command( //nolint:gosec
|
||||||
"/usr/bin/security",
|
"/usr/bin/security",
|
||||||
"execute-with-privileges",
|
"execute-with-privileges",
|
||||||
"/usr/bin/security",
|
"/usr/bin/security",
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package tls
|
package tls
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package tls
|
package tls
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package tls
|
package tls
|
||||||
|
|
||||||
@ -55,8 +55,8 @@ func NewTLSTemplate() (*x509.Certificate, error) {
|
|||||||
SerialNumber: serialNumber,
|
SerialNumber: serialNumber,
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
Country: []string{"CH"},
|
Country: []string{"CH"},
|
||||||
Organization: []string{"Proton Technologies AG"},
|
Organization: []string{"Proton AG"},
|
||||||
OrganizationalUnit: []string{"ProtonMail"},
|
OrganizationalUnit: []string{"Proton Mail"},
|
||||||
CommonName: "127.0.0.1",
|
CommonName: "127.0.0.1",
|
||||||
},
|
},
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||||
@ -110,7 +110,7 @@ func (t *TLS) GenerateCerts(template *x509.Certificate) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer certOut.Close() // nolint[errcheck]
|
defer certOut.Close() //nolint:errcheck,gosec
|
||||||
|
|
||||||
if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
|
if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -120,7 +120,7 @@ func (t *TLS) GenerateCerts(template *x509.Certificate) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer keyOut.Close() // nolint[errcheck]
|
defer keyOut.Close() //nolint:errcheck,gosec
|
||||||
|
|
||||||
return pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
return pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ func (t *TLS) GetConfig() (*tls.Config, error) {
|
|||||||
caCertPool := x509.NewCertPool()
|
caCertPool := x509.NewCertPool()
|
||||||
caCertPool.AddCert(c.Leaf)
|
caCertPool.AddCert(c.Leaf)
|
||||||
|
|
||||||
// nolint[gosec]: We need to support older TLS versions for AppleMail and Outlook.
|
//nolint:gosec // We need to support older TLS versions for AppleMail and Outlook
|
||||||
return &tls.Config{
|
return &tls.Config{
|
||||||
Certificates: []tls.Certificate{c},
|
Certificates: []tls.Certificate{c},
|
||||||
ServerName: "127.0.0.1",
|
ServerName: "127.0.0.1",
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package tls
|
package tls
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package useragent
|
package useragent
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package useragent
|
package useragent
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package useragent
|
package useragent
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package useragent
|
package useragent
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.Bridge.
|
// This file is part of Proton Mail Bridge.Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package constants contains variables that are set via ldflags during build.
|
// Package constants contains variables that are set via ldflags during build.
|
||||||
package constants
|
package constants
|
||||||
@ -22,7 +22,7 @@ import "fmt"
|
|||||||
|
|
||||||
const VendorName = "protonmail"
|
const VendorName = "protonmail"
|
||||||
|
|
||||||
// nolint[gochecknoglobals]
|
//nolint:gochecknoglobals
|
||||||
var (
|
var (
|
||||||
// Version of the build.
|
// Version of the build.
|
||||||
Version = ""
|
Version = ""
|
||||||
|
|||||||
@ -1,28 +1,29 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//go:build !build_qa
|
||||||
// +build !build_qa
|
// +build !build_qa
|
||||||
|
|
||||||
package constants
|
package constants
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// nolint[gochecknoglobals]
|
//nolint:gochecknoglobals
|
||||||
var (
|
var (
|
||||||
// UpdateCheckInterval defines how often we check for new version
|
// UpdateCheckInterval defines how often we check for new version.
|
||||||
UpdateCheckInterval = time.Hour //nolint[gochecknoglobals]
|
UpdateCheckInterval = time.Hour //nolint:gochecknoglobals
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,27 +1,28 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//go:build build_qa
|
||||||
// +build build_qa
|
// +build build_qa
|
||||||
|
|
||||||
package constants
|
package constants
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// nolint[gochecknoglobals]
|
//nolint:gochecknoglobals
|
||||||
var (
|
var (
|
||||||
// UpdateCheckInterval defines how often we check for new version
|
// UpdateCheckInterval defines how often we check for new version
|
||||||
UpdateCheckInterval = time.Duration(5 * time.Minute)
|
UpdateCheckInterval = time.Duration(5 * time.Minute)
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package cookies implements a persistent cookie jar which satisfies the http.CookieJar interface.
|
// Package cookies implements a persistent cookie jar which satisfies the http.CookieJar interface.
|
||||||
package cookies
|
package cookies
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cookies
|
package cookies
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package crash
|
package crash
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package crash implements a crash handler with configurable recovery actions.
|
// Package crash implements a crash handler with configurable recovery actions.
|
||||||
package crash
|
package crash
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package crash
|
package crash
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package events provides names of events used by the event listener in bridge.
|
// Package events provides names of events used by the event listener in bridge.
|
||||||
package events
|
package events
|
||||||
@ -34,13 +34,15 @@ const (
|
|||||||
AddressChangedLogoutEvent = "addressChangedLogout"
|
AddressChangedLogoutEvent = "addressChangedLogout"
|
||||||
UserRefreshEvent = "userRefresh"
|
UserRefreshEvent = "userRefresh"
|
||||||
RestartBridgeEvent = "restartBridge"
|
RestartBridgeEvent = "restartBridge"
|
||||||
InternetOffEvent = "internetOff"
|
InternetConnChangedEvent = "internetChanged"
|
||||||
InternetOnEvent = "internetOn"
|
InternetOff = "internetOff"
|
||||||
|
InternetOn = "internetOn"
|
||||||
SecondInstanceEvent = "secondInstance"
|
SecondInstanceEvent = "secondInstance"
|
||||||
OutgoingNoEncEvent = "outgoingNoEncryption"
|
OutgoingNoEncEvent = "outgoingNoEncryption"
|
||||||
NoActiveKeyForRecipientEvent = "noActiveKeyForRecipient"
|
NoActiveKeyForRecipientEvent = "noActiveKeyForRecipient"
|
||||||
UpgradeApplicationEvent = "upgradeApplication"
|
UpgradeApplicationEvent = "upgradeApplication"
|
||||||
TLSCertIssue = "tlsCertPinningIssue"
|
TLSCertIssue = "tlsCertPinningIssue"
|
||||||
|
UserChangeDone = "QMLUserChangedDone"
|
||||||
|
|
||||||
// LogoutEventTimeout is the minimum time to permit between logout events being sent.
|
// LogoutEventTimeout is the minimum time to permit between logout events being sent.
|
||||||
LogoutEventTimeout = 3 * time.Minute
|
LogoutEventTimeout = 3 * time.Minute
|
||||||
@ -51,7 +53,9 @@ func SetupEvents(listener listener.Listener) {
|
|||||||
listener.SetLimit(LogoutEvent, LogoutEventTimeout)
|
listener.SetLimit(LogoutEvent, LogoutEventTimeout)
|
||||||
listener.SetBuffer(ErrorEvent)
|
listener.SetBuffer(ErrorEvent)
|
||||||
listener.SetBuffer(CredentialsErrorEvent)
|
listener.SetBuffer(CredentialsErrorEvent)
|
||||||
listener.SetBuffer(InternetOffEvent)
|
listener.SetBuffer(InternetConnChangedEvent)
|
||||||
listener.SetBuffer(UpgradeApplicationEvent)
|
listener.SetBuffer(UpgradeApplicationEvent)
|
||||||
listener.SetBuffer(TLSCertIssue)
|
listener.SetBuffer(TLSCertIssue)
|
||||||
|
listener.SetBuffer(UserRefreshEvent)
|
||||||
|
listener.Book(UserChangeDone)
|
||||||
}
|
}
|
||||||
|
|||||||
11
internal/frontend/.gitignore
vendored
Normal file
11
internal/frontend/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Auto generated
|
||||||
|
moc.cpp
|
||||||
|
moc.go
|
||||||
|
moc.h
|
||||||
|
moc_cgo_*.go
|
||||||
|
moc_moc.h
|
||||||
|
rcc.cpp
|
||||||
|
rcc.qrc
|
||||||
|
rcc_cgo_*.go
|
||||||
|
*.qmlc
|
||||||
|
|
||||||
14
internal/frontend/Makefile.local
Normal file
14
internal/frontend/Makefile.local
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FILES=$(shell find . -iname 'rcc.qrc')
|
||||||
|
FILES+=$(shell find . -iname 'rcc.cpp')
|
||||||
|
FILES+=$(shell find . -iname 'rcc_cgo*.go')
|
||||||
|
|
||||||
|
FILES+=$(shell find . -iname 'moc.go')
|
||||||
|
FILES+=$(shell find . -iname 'moc.cpp')
|
||||||
|
FILES+=$(shell find . -iname 'moc.h')
|
||||||
|
FILES+=$(shell find . -iname 'moc_cgo*.go')
|
||||||
|
|
||||||
|
FILES+=$(shell find ./qml -iname '*.qmlc')
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f ${FILES}
|
||||||
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Package autoconfig provides automatic config of IMAP and SMTP.
|
|
||||||
// For now only for Apple Mail.
|
|
||||||
package autoconfig
|
|
||||||
|
|
||||||
import "github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
|
||||||
|
|
||||||
type AutoConfig interface {
|
|
||||||
Name() string
|
|
||||||
Configure(imapPort int, smtpPort int, imapSSl, smtpSSL bool, user types.User, addressIndex int) error
|
|
||||||
}
|
|
||||||
|
|
||||||
var available []AutoConfig //nolint[gochecknoglobals]
|
|
||||||
|
|
||||||
func Available() []AutoConfig {
|
|
||||||
return available
|
|
||||||
}
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package cliie
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
|
||||||
"github.com/abiosoft/ishell"
|
|
||||||
)
|
|
||||||
|
|
||||||
// completeUsernames is a helper to complete usernames as the user types.
|
|
||||||
func (f *frontendCLI) completeUsernames(args []string) (usernames []string) {
|
|
||||||
if len(args) > 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
arg := ""
|
|
||||||
if len(args) == 1 {
|
|
||||||
arg = args[0]
|
|
||||||
}
|
|
||||||
for _, user := range f.ie.GetUsers() {
|
|
||||||
if strings.HasPrefix(strings.ToLower(user.Username()), strings.ToLower(arg)) {
|
|
||||||
usernames = append(usernames, user.Username())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// noAccountWrapper is a decorator for functions which need any account to be properly functional.
|
|
||||||
func (f *frontendCLI) noAccountWrapper(callback func(*ishell.Context)) func(*ishell.Context) {
|
|
||||||
return func(c *ishell.Context) {
|
|
||||||
users := f.ie.GetUsers()
|
|
||||||
if len(users) == 0 {
|
|
||||||
f.Println("No active accounts. Please add account to continue.")
|
|
||||||
} else {
|
|
||||||
callback(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) askUserByIndexOrName(c *ishell.Context) types.User {
|
|
||||||
user := f.getUserByIndexOrName("")
|
|
||||||
if user != nil {
|
|
||||||
return user
|
|
||||||
}
|
|
||||||
|
|
||||||
numberOfAccounts := len(f.ie.GetUsers())
|
|
||||||
indexRange := fmt.Sprintf("number between 0 and %d", numberOfAccounts-1)
|
|
||||||
if len(c.Args) == 0 {
|
|
||||||
f.Printf("Please choose %s or username.\n", indexRange)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
arg := c.Args[0]
|
|
||||||
user = f.getUserByIndexOrName(arg)
|
|
||||||
if user == nil {
|
|
||||||
f.Printf("Wrong input '%s'. Choose %s or username.\n", bold(arg), indexRange)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return user
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) getUserByIndexOrName(arg string) types.User {
|
|
||||||
users := f.ie.GetUsers()
|
|
||||||
numberOfAccounts := len(users)
|
|
||||||
if numberOfAccounts == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if numberOfAccounts == 1 {
|
|
||||||
return users[0]
|
|
||||||
}
|
|
||||||
if index, err := strconv.Atoi(arg); err == nil {
|
|
||||||
if index < 0 || index >= numberOfAccounts {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return users[index]
|
|
||||||
}
|
|
||||||
for _, user := range users {
|
|
||||||
if user.Username() == arg {
|
|
||||||
return user
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@ -1,154 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package cliie
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/abiosoft/ishell"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f *frontendCLI) listAccounts(c *ishell.Context) {
|
|
||||||
spacing := "%-2d: %-20s (%-15s, %-15s)\n"
|
|
||||||
f.Printf(bold(strings.ReplaceAll(spacing, "d", "s")), "#", "account", "status", "address mode")
|
|
||||||
for idx, user := range f.ie.GetUsers() {
|
|
||||||
connected := "disconnected"
|
|
||||||
if user.IsConnected() {
|
|
||||||
connected = "connected"
|
|
||||||
}
|
|
||||||
mode := "split"
|
|
||||||
if user.IsCombinedAddressMode() {
|
|
||||||
mode = "combined"
|
|
||||||
}
|
|
||||||
f.Printf(spacing, idx, user.Username(), connected, mode)
|
|
||||||
}
|
|
||||||
f.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) loginAccount(c *ishell.Context) { // nolint[funlen]
|
|
||||||
f.ShowPrompt(false)
|
|
||||||
defer f.ShowPrompt(true)
|
|
||||||
|
|
||||||
loginName := ""
|
|
||||||
if len(c.Args) > 0 {
|
|
||||||
user := f.getUserByIndexOrName(c.Args[0])
|
|
||||||
if user != nil {
|
|
||||||
loginName = user.GetPrimaryAddress()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if loginName == "" {
|
|
||||||
loginName = f.readStringInAttempts("Username", c.ReadLine, isNotEmpty)
|
|
||||||
if loginName == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
f.Println("Username:", loginName)
|
|
||||||
}
|
|
||||||
|
|
||||||
password := f.readStringInAttempts("Password", c.ReadPassword, isNotEmpty)
|
|
||||||
if password == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Println("Authenticating ... ")
|
|
||||||
client, auth, err := f.ie.Login(loginName, []byte(password))
|
|
||||||
if err != nil {
|
|
||||||
f.processAPIError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if auth.HasTwoFactor() {
|
|
||||||
twoFactor := f.readStringInAttempts("Two factor code", c.ReadLine, isNotEmpty)
|
|
||||||
if twoFactor == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = client.Auth2FA(context.Background(), twoFactor)
|
|
||||||
if err != nil {
|
|
||||||
f.processAPIError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mailboxPassword := password
|
|
||||||
if auth.HasMailboxPassword() {
|
|
||||||
mailboxPassword = f.readStringInAttempts("Mailbox password", c.ReadPassword, isNotEmpty)
|
|
||||||
}
|
|
||||||
if mailboxPassword == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Println("Adding account ...")
|
|
||||||
user, err := f.ie.FinishLogin(client, auth, []byte(mailboxPassword))
|
|
||||||
if err != nil {
|
|
||||||
log.WithField("username", loginName).WithError(err).Error("Login was unsuccessful")
|
|
||||||
f.Println("Adding account was unsuccessful:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Printf("Account %s was added successfully.\n", bold(user.Username()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) logoutAccount(c *ishell.Context) {
|
|
||||||
f.ShowPrompt(false)
|
|
||||||
defer f.ShowPrompt(true)
|
|
||||||
|
|
||||||
user := f.askUserByIndexOrName(c)
|
|
||||||
if user == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if f.yesNoQuestion("Are you sure you want to logout account " + bold(user.Username())) {
|
|
||||||
if err := user.Logout(); err != nil {
|
|
||||||
f.printAndLogError("Logging out failed: ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) deleteAccount(c *ishell.Context) {
|
|
||||||
f.ShowPrompt(false)
|
|
||||||
defer f.ShowPrompt(true)
|
|
||||||
|
|
||||||
user := f.askUserByIndexOrName(c)
|
|
||||||
if user == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if f.yesNoQuestion("Are you sure you want to " + bold("remove account "+user.Username())) {
|
|
||||||
clearCache := f.yesNoQuestion("Do you want to remove cache for this account")
|
|
||||||
if err := f.ie.DeleteUser(user.ID(), clearCache); err != nil {
|
|
||||||
f.printAndLogError("Cannot delete account: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) deleteAccounts(c *ishell.Context) {
|
|
||||||
f.ShowPrompt(false)
|
|
||||||
defer f.ShowPrompt(true)
|
|
||||||
|
|
||||||
if !f.yesNoQuestion("Do you really want remove all accounts") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, user := range f.ie.GetUsers() {
|
|
||||||
if err := f.ie.DeleteUser(user.ID(), false); err != nil {
|
|
||||||
f.printAndLogError("Cannot delete account ", user.Username(), ": ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.Println("Keychain cleared")
|
|
||||||
}
|
|
||||||
@ -1,224 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Package cliie provides CLI interface of the Import-Export app.
|
|
||||||
package cliie
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/events"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/locations"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/updater"
|
|
||||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
|
||||||
|
|
||||||
"github.com/abiosoft/ishell"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
log = logrus.WithField("pkg", "frontend/cli-ie") //nolint[gochecknoglobals]
|
|
||||||
)
|
|
||||||
|
|
||||||
type frontendCLI struct {
|
|
||||||
*ishell.Shell
|
|
||||||
|
|
||||||
locations *locations.Locations
|
|
||||||
eventListener listener.Listener
|
|
||||||
updater types.Updater
|
|
||||||
ie types.ImportExporter
|
|
||||||
|
|
||||||
restarter types.Restarter
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new CLI frontend configured with the given options.
|
|
||||||
func New( //nolint[funlen]
|
|
||||||
panicHandler types.PanicHandler,
|
|
||||||
|
|
||||||
locations *locations.Locations,
|
|
||||||
eventListener listener.Listener,
|
|
||||||
updater types.Updater,
|
|
||||||
ie types.ImportExporter,
|
|
||||||
restarter types.Restarter,
|
|
||||||
) *frontendCLI { //nolint[golint]
|
|
||||||
fe := &frontendCLI{
|
|
||||||
Shell: ishell.New(),
|
|
||||||
|
|
||||||
locations: locations,
|
|
||||||
eventListener: eventListener,
|
|
||||||
updater: updater,
|
|
||||||
ie: ie,
|
|
||||||
|
|
||||||
restarter: restarter,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear commands.
|
|
||||||
clearCmd := &ishell.Cmd{Name: "clear",
|
|
||||||
Help: "remove stored accounts and preferences. (alias: cl)",
|
|
||||||
Aliases: []string{"cl"},
|
|
||||||
}
|
|
||||||
clearCmd.AddCmd(&ishell.Cmd{Name: "accounts",
|
|
||||||
Help: "remove all accounts from keychain. (aliases: a, k, keychain)",
|
|
||||||
Aliases: []string{"a", "k", "keychain"},
|
|
||||||
Func: fe.deleteAccounts,
|
|
||||||
})
|
|
||||||
fe.AddCmd(clearCmd)
|
|
||||||
|
|
||||||
// Check commands.
|
|
||||||
checkCmd := &ishell.Cmd{Name: "check", Help: "check internet connection or new version."}
|
|
||||||
checkCmd.AddCmd(&ishell.Cmd{Name: "updates",
|
|
||||||
Help: "check for Import-Export updates. (aliases: u, v, version)",
|
|
||||||
Aliases: []string{"u", "version", "v"},
|
|
||||||
Func: fe.checkUpdates,
|
|
||||||
})
|
|
||||||
fe.AddCmd(checkCmd)
|
|
||||||
|
|
||||||
// Print info commands.
|
|
||||||
fe.AddCmd(&ishell.Cmd{Name: "log-dir",
|
|
||||||
Help: "print path to directory with logs. (aliases: log, logs)",
|
|
||||||
Aliases: []string{"log", "logs"},
|
|
||||||
Func: fe.printLogDir,
|
|
||||||
})
|
|
||||||
fe.AddCmd(&ishell.Cmd{Name: "manual",
|
|
||||||
Help: "print URL with instructions. (alias: man)",
|
|
||||||
Aliases: []string{"man"},
|
|
||||||
Func: fe.printManual,
|
|
||||||
})
|
|
||||||
fe.AddCmd(&ishell.Cmd{Name: "credits",
|
|
||||||
Help: "print used resources.",
|
|
||||||
Func: fe.printCredits,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Account commands.
|
|
||||||
fe.AddCmd(&ishell.Cmd{Name: "list",
|
|
||||||
Help: "print the list of accounts. (aliases: l, ls)",
|
|
||||||
Func: fe.noAccountWrapper(fe.listAccounts),
|
|
||||||
Aliases: []string{"l", "ls"},
|
|
||||||
})
|
|
||||||
fe.AddCmd(&ishell.Cmd{Name: "login",
|
|
||||||
Help: "login procedure to add or connect account. Optionally use index or account as parameter. (aliases: a, add, con, connect)",
|
|
||||||
Func: fe.loginAccount,
|
|
||||||
Aliases: []string{"add", "a", "con", "connect"},
|
|
||||||
Completer: fe.completeUsernames,
|
|
||||||
})
|
|
||||||
fe.AddCmd(&ishell.Cmd{Name: "logout",
|
|
||||||
Help: "disconnect the account. Use index or account name as parameter. (aliases: d, disconnect)",
|
|
||||||
Func: fe.noAccountWrapper(fe.logoutAccount),
|
|
||||||
Aliases: []string{"d", "disconnect"},
|
|
||||||
Completer: fe.completeUsernames,
|
|
||||||
})
|
|
||||||
fe.AddCmd(&ishell.Cmd{Name: "delete",
|
|
||||||
Help: "remove the account from keychain. Use index or account name as parameter. (aliases: del, rm, remove)",
|
|
||||||
Func: fe.noAccountWrapper(fe.deleteAccount),
|
|
||||||
Aliases: []string{"del", "rm", "remove"},
|
|
||||||
Completer: fe.completeUsernames,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Import-Export commands.
|
|
||||||
importCmd := &ishell.Cmd{Name: "import",
|
|
||||||
Help: "import messages. (alias: imp)",
|
|
||||||
Aliases: []string{"imp"},
|
|
||||||
}
|
|
||||||
importCmd.AddCmd(&ishell.Cmd{Name: "local",
|
|
||||||
Help: "import local messages. (aliases: loc)",
|
|
||||||
Func: fe.noAccountWrapper(fe.importLocalMessages),
|
|
||||||
Aliases: []string{"loc"},
|
|
||||||
})
|
|
||||||
importCmd.AddCmd(&ishell.Cmd{Name: "remote",
|
|
||||||
Help: "import remote messages. (aliases: rem)",
|
|
||||||
Func: fe.noAccountWrapper(fe.importRemoteMessages),
|
|
||||||
Aliases: []string{"rem"},
|
|
||||||
})
|
|
||||||
fe.AddCmd(importCmd)
|
|
||||||
|
|
||||||
exportCmd := &ishell.Cmd{Name: "export",
|
|
||||||
Help: "export messages. (alias: exp)",
|
|
||||||
Aliases: []string{"exp"},
|
|
||||||
}
|
|
||||||
exportCmd.AddCmd(&ishell.Cmd{Name: "eml",
|
|
||||||
Help: "export messages to eml files.",
|
|
||||||
Func: fe.noAccountWrapper(fe.exportMessagesToEML),
|
|
||||||
})
|
|
||||||
exportCmd.AddCmd(&ishell.Cmd{Name: "mbox",
|
|
||||||
Help: "export messages to mbox files.",
|
|
||||||
Func: fe.noAccountWrapper(fe.exportMessagesToMBOX),
|
|
||||||
})
|
|
||||||
fe.AddCmd(exportCmd)
|
|
||||||
|
|
||||||
// System commands.
|
|
||||||
fe.AddCmd(&ishell.Cmd{Name: "restart",
|
|
||||||
Help: "restart the Import-Export app.",
|
|
||||||
Func: fe.restart,
|
|
||||||
})
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer panicHandler.HandlePanic()
|
|
||||||
fe.watchEvents()
|
|
||||||
}()
|
|
||||||
return fe
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) watchEvents() {
|
|
||||||
errorCh := f.eventListener.ProvideChannel(events.ErrorEvent)
|
|
||||||
credentialsErrorCh := f.eventListener.ProvideChannel(events.CredentialsErrorEvent)
|
|
||||||
internetOffCh := f.eventListener.ProvideChannel(events.InternetOffEvent)
|
|
||||||
internetOnCh := f.eventListener.ProvideChannel(events.InternetOnEvent)
|
|
||||||
addressChangedLogoutCh := f.eventListener.ProvideChannel(events.AddressChangedLogoutEvent)
|
|
||||||
logoutCh := f.eventListener.ProvideChannel(events.LogoutEvent)
|
|
||||||
certIssue := f.eventListener.ProvideChannel(events.TLSCertIssue)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case errorDetails := <-errorCh:
|
|
||||||
f.Println("Import-Export failed:", errorDetails)
|
|
||||||
case <-credentialsErrorCh:
|
|
||||||
f.notifyCredentialsError()
|
|
||||||
case <-internetOffCh:
|
|
||||||
f.notifyInternetOff()
|
|
||||||
case <-internetOnCh:
|
|
||||||
f.notifyInternetOn()
|
|
||||||
case address := <-addressChangedLogoutCh:
|
|
||||||
f.notifyLogout(address)
|
|
||||||
case userID := <-logoutCh:
|
|
||||||
user, err := f.ie.GetUser(userID)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f.notifyLogout(user.Username())
|
|
||||||
case <-certIssue:
|
|
||||||
f.notifyCertIssue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop starts the frontend loop with an interactive shell.
|
|
||||||
func (f *frontendCLI) Loop() error {
|
|
||||||
f.Print(`
|
|
||||||
Welcome to ProtonMail Import-Export app interactive shell
|
|
||||||
|
|
||||||
WARNING: The CLI is an experimental feature and does not yet cover all functionality.
|
|
||||||
`)
|
|
||||||
f.Run()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) NotifyManualUpdate(update updater.VersionInfo, canInstall bool) {
|
|
||||||
// NOTE: Save the update somewhere so that it can be installed when user chooses "install now".
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) WaitUntilFrontendIsReady() {}
|
|
||||||
func (f *frontendCLI) SetVersion(version updater.VersionInfo) {}
|
|
||||||
func (f *frontendCLI) NotifySilentUpdateInstalled() {}
|
|
||||||
func (f *frontendCLI) NotifySilentUpdateError(err error) {}
|
|
||||||
@ -1,232 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package cliie
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/transfer"
|
|
||||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
|
||||||
"github.com/abiosoft/ishell"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f *frontendCLI) importLocalMessages(c *ishell.Context) {
|
|
||||||
f.ShowPrompt(false)
|
|
||||||
defer f.ShowPrompt(true)
|
|
||||||
|
|
||||||
user, path := f.getUserAndPath(c, false)
|
|
||||||
if user == nil || path == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := f.ie.GetLocalImporter(user.Username(), user.GetPrimaryAddress(), path)
|
|
||||||
f.transfer(t, err, false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) importRemoteMessages(c *ishell.Context) {
|
|
||||||
f.ShowPrompt(false)
|
|
||||||
defer f.ShowPrompt(true)
|
|
||||||
|
|
||||||
user := f.askUserByIndexOrName(c)
|
|
||||||
if user == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
username := f.readStringInAttempts("IMAP username", c.ReadLine, isNotEmpty)
|
|
||||||
if username == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
password := f.readStringInAttempts("IMAP password", c.ReadPassword, isNotEmpty)
|
|
||||||
if password == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
host := f.readStringInAttempts("IMAP host", c.ReadLine, isNotEmpty)
|
|
||||||
if host == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
port := f.readStringInAttempts("IMAP port", c.ReadLine, isNotEmpty)
|
|
||||||
if port == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := f.ie.GetRemoteImporter(user.Username(), user.GetPrimaryAddress(), username, password, host, port)
|
|
||||||
f.transfer(t, err, false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) exportMessagesToEML(c *ishell.Context) {
|
|
||||||
f.ShowPrompt(false)
|
|
||||||
defer f.ShowPrompt(true)
|
|
||||||
|
|
||||||
user, path := f.getUserAndPath(c, true)
|
|
||||||
if user == nil || path == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := f.ie.GetEMLExporter(user.Username(), user.GetPrimaryAddress(), path)
|
|
||||||
f.transfer(t, err, true, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) exportMessagesToMBOX(c *ishell.Context) {
|
|
||||||
f.ShowPrompt(false)
|
|
||||||
defer f.ShowPrompt(true)
|
|
||||||
|
|
||||||
user, path := f.getUserAndPath(c, true)
|
|
||||||
if user == nil || path == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := f.ie.GetMBOXExporter(user.Username(), user.GetPrimaryAddress(), path)
|
|
||||||
f.transfer(t, err, true, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) getUserAndPath(c *ishell.Context, createPath bool) (types.User, string) {
|
|
||||||
user := f.askUserByIndexOrName(c)
|
|
||||||
if user == nil {
|
|
||||||
return nil, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
path := f.readStringInAttempts("Path of EML and MBOX files", c.ReadLine, isNotEmpty)
|
|
||||||
if path == "" {
|
|
||||||
return nil, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if createPath {
|
|
||||||
_ = os.Mkdir(path, os.ModePerm)
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, path
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) transfer(t *transfer.Transfer, err error, askSkipEncrypted bool, askGlobalMailbox bool) {
|
|
||||||
if err != nil {
|
|
||||||
f.printAndLogError("Failed to init transferrer: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if askSkipEncrypted {
|
|
||||||
skipEncryptedMessages := f.yesNoQuestion("Skip encrypted messages")
|
|
||||||
t.SetSkipEncryptedMessages(skipEncryptedMessages)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !f.setTransferRules(t) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if askGlobalMailbox {
|
|
||||||
if err := f.setTransferGlobalMailbox(t); err != nil {
|
|
||||||
f.printAndLogError("Failed to create global mailbox: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
progress := t.Start()
|
|
||||||
for range progress.GetUpdateChannel() {
|
|
||||||
f.printTransferProgress(progress)
|
|
||||||
}
|
|
||||||
f.printTransferResult(progress)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) setTransferGlobalMailbox(t *transfer.Transfer) error {
|
|
||||||
labelName := fmt.Sprintf("Imported %s", time.Now().Format("Jan-02-2006 15:04"))
|
|
||||||
|
|
||||||
useGlobalLabel := f.yesNoQuestion("Use global label " + labelName)
|
|
||||||
if !useGlobalLabel {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
globalMailbox, err := t.CreateTargetMailbox(transfer.Mailbox{
|
|
||||||
Name: labelName,
|
|
||||||
Color: pmapi.LabelColors[0],
|
|
||||||
IsExclusive: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
t.SetGlobalMailbox(&globalMailbox)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) setTransferRules(t *transfer.Transfer) bool {
|
|
||||||
f.Println("Rules:")
|
|
||||||
for _, rule := range t.GetRules() {
|
|
||||||
if !rule.Active {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
targets := strings.Join(rule.TargetMailboxNames(), ", ")
|
|
||||||
if rule.HasTimeLimit() {
|
|
||||||
f.Printf(" %-30s → %s (%s - %s)\n", rule.SourceMailbox.Name, targets, rule.FromDate(), rule.ToDate())
|
|
||||||
} else {
|
|
||||||
f.Printf(" %-30s → %s\n", rule.SourceMailbox.Name, targets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.yesNoQuestion("Proceed")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) printTransferProgress(progress *transfer.Progress) {
|
|
||||||
counts := progress.GetCounts()
|
|
||||||
if counts.Total != 0 {
|
|
||||||
f.Println(fmt.Sprintf(
|
|
||||||
"Progress update: %d (%d / %d) / %d, skipped: %d, failed: %d",
|
|
||||||
counts.Imported,
|
|
||||||
counts.Exported,
|
|
||||||
counts.Added,
|
|
||||||
counts.Total,
|
|
||||||
counts.Skipped,
|
|
||||||
counts.Failed,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
if progress.IsPaused() {
|
|
||||||
f.Printf("Transfer is paused bacause %s", progress.PauseReason())
|
|
||||||
if !f.yesNoQuestion("Continue (y) or stop (n)") {
|
|
||||||
progress.Stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) printTransferResult(progress *transfer.Progress) {
|
|
||||||
err := progress.GetFatalError()
|
|
||||||
if err != nil {
|
|
||||||
f.Println("Transfer failed: " + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
statuses := progress.GetFailedMessages()
|
|
||||||
if len(statuses) == 0 {
|
|
||||||
f.Println("Transfer finished!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Println("Transfer finished with errors:")
|
|
||||||
for _, messageStatus := range statuses {
|
|
||||||
f.Printf(
|
|
||||||
" %-17s | %-30s | %-30s\n %s: %s\n",
|
|
||||||
messageStatus.Time.Format("Jan 02 2006 15:04"),
|
|
||||||
messageStatus.From,
|
|
||||||
messageStatus.Subject,
|
|
||||||
messageStatus.SourceID,
|
|
||||||
messageStatus.GetErrorMessage(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package cliie
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/abiosoft/ishell"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f *frontendCLI) restart(c *ishell.Context) {
|
|
||||||
if f.yesNoQuestion("Are you sure you want to restart the Import-Export app") {
|
|
||||||
f.Println("Restarting the Import-Export app...")
|
|
||||||
f.restarter.SetToRestart()
|
|
||||||
f.Stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) printLogDir(c *ishell.Context) {
|
|
||||||
if path, err := f.locations.ProvideLogsPath(); err != nil {
|
|
||||||
f.Println("Failed to determine location of log files")
|
|
||||||
} else {
|
|
||||||
f.Println("Log files are stored in\n\n ", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) printManual(c *ishell.Context) {
|
|
||||||
f.Println("More instructions about the Import-Export app can be found at\n\n https://protonmail.com/support/categories/import-export/")
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package cliie
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/importexport"
|
|
||||||
"github.com/abiosoft/ishell"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f *frontendCLI) checkUpdates(c *ishell.Context) {
|
|
||||||
f.Println("Your version is up to date.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) printCredits(c *ishell.Context) {
|
|
||||||
for _, pkg := range strings.Split(importexport.Credits, ";") {
|
|
||||||
f.Println(pkg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package cliie
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
|
||||||
"github.com/fatih/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxInputRepeat = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
bold = color.New(color.Bold).SprintFunc() //nolint[gochecknoglobals]
|
|
||||||
)
|
|
||||||
|
|
||||||
func isNotEmpty(val string) bool {
|
|
||||||
return val != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) yesNoQuestion(question string) bool {
|
|
||||||
f.Print(question, "? yes/"+bold("no")+": ")
|
|
||||||
yes := "yes"
|
|
||||||
answer := strings.ToLower(f.ReadLine())
|
|
||||||
for i := 0; i < len(answer); i++ {
|
|
||||||
if i >= len(yes) || answer[i] != yes[i] {
|
|
||||||
return false // Everything else is false.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(answer) > 0 // Empty is false.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) readStringInAttempts(title string, readFunc func() string, isOK func(string) bool) (value string) {
|
|
||||||
f.Printf("%s: ", title)
|
|
||||||
value = readFunc()
|
|
||||||
title = strings.ToLower(string(title[0])) + title[1:]
|
|
||||||
for i := 0; !isOK(value); i++ {
|
|
||||||
if i >= maxInputRepeat {
|
|
||||||
f.Println("Too many attempts")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
f.Printf("Please fill %s: ", title)
|
|
||||||
value = readFunc()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) printAndLogError(args ...interface{}) {
|
|
||||||
log.Error(args...)
|
|
||||||
f.Println(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) processAPIError(err error) {
|
|
||||||
log.Warn("API error: ", err)
|
|
||||||
switch err {
|
|
||||||
case pmapi.ErrNoConnection:
|
|
||||||
f.notifyInternetOff()
|
|
||||||
case pmapi.ErrUpgradeApplication:
|
|
||||||
f.notifyNeedUpgrade()
|
|
||||||
default:
|
|
||||||
f.Println("Server error:", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) notifyInternetOff() {
|
|
||||||
f.Println("Internet connection is not available.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) notifyInternetOn() {
|
|
||||||
f.Println("Internet connection is available again.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) notifyLogout(address string) {
|
|
||||||
f.Printf("Account %s is disconnected. Login to continue using this account with email client.", address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) notifyNeedUpgrade() {
|
|
||||||
version, err := f.updater.Check()
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Error("Failed to notify need upgrade")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f.Println("Please download and install the newest version of application from", version.LandingPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) notifyCredentialsError() { // nolint[unused]
|
|
||||||
// Print in 80-column width.
|
|
||||||
f.Println("ProtonMail Import-Export app is not able to detect a supported password manager")
|
|
||||||
f.Println("(pass, gnome-keyring). Please install and set up a supported password manager")
|
|
||||||
f.Println("and restart the application.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *frontendCLI) notifyCertIssue() {
|
|
||||||
// Print in 80-column width.
|
|
||||||
f.Println(`Connection security error: Your network connection to Proton services may
|
|
||||||
be insecure.
|
|
||||||
|
|
||||||
Description:
|
|
||||||
ProtonMail Import-Export was not able to establish a secure connection to Proton
|
|
||||||
servers due to a TLS certificate error. This means your connection may
|
|
||||||
potentially be insecure and susceptible to monitoring by third parties.
|
|
||||||
|
|
||||||
Recommendation:
|
|
||||||
* If you trust your network operator, you can continue to use ProtonMail
|
|
||||||
as usual.
|
|
||||||
* If you don't trust your network operator, reconnect to ProtonMail over a VPN
|
|
||||||
(such as ProtonVPN) which encrypts your Internet connection, or use
|
|
||||||
a different network to access ProtonMail.
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ func (f *frontendCLI) showAccountAddressInfo(user types.User, address string) {
|
|||||||
f.Println("")
|
f.Println("")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *frontendCLI) loginAccount(c *ishell.Context) { // nolint[funlen]
|
func (f *frontendCLI) loginAccount(c *ishell.Context) { //nolint:funlen
|
||||||
f.ShowPrompt(false)
|
f.ShowPrompt(false)
|
||||||
defer f.ShowPrompt(true)
|
defer f.ShowPrompt(true)
|
||||||
|
|
||||||
@ -192,14 +192,34 @@ func (f *frontendCLI) deleteAccounts(c *ishell.Context) {
|
|||||||
if !f.yesNoQuestion("Do you really want remove all accounts") {
|
if !f.yesNoQuestion("Do you really want remove all accounts") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, user := range f.bridge.GetUsers() {
|
for _, user := range f.bridge.GetUsers() {
|
||||||
if err := f.bridge.DeleteUser(user.ID(), false); err != nil {
|
if err := f.bridge.DeleteUser(user.ID(), false); err != nil {
|
||||||
f.printAndLogError("Cannot delete account ", user.Username(), ": ", err)
|
f.printAndLogError("Cannot delete account ", user.Username(), ": ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Println("Keychain cleared")
|
c.Println("Keychain cleared")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *frontendCLI) deleteEverything(c *ishell.Context) {
|
||||||
|
f.ShowPrompt(false)
|
||||||
|
defer f.ShowPrompt(true)
|
||||||
|
|
||||||
|
if !f.yesNoQuestion("Do you really want remove everything") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.bridge.FactoryReset()
|
||||||
|
|
||||||
|
c.Println("Everything cleared")
|
||||||
|
|
||||||
|
// Clearing data removes everything (db, preferences, ...) so everything has to be stopped and started again.
|
||||||
|
f.restarter.SetToRestart()
|
||||||
|
|
||||||
|
f.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
func (f *frontendCLI) changeMode(c *ishell.Context) {
|
func (f *frontendCLI) changeMode(c *ishell.Context) {
|
||||||
user := f.askUserByIndexOrName(c)
|
user := f.askUserByIndexOrName(c)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package cli provides CLI interface of the Bridge.
|
// Package cli provides CLI interface of the Bridge.
|
||||||
package cli
|
package cli
|
||||||
@ -31,7 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
log = logrus.WithField("pkg", "frontend/cli") //nolint[gochecknoglobals]
|
log = logrus.WithField("pkg", "frontend/cli") //nolint:gochecknoglobals
|
||||||
)
|
)
|
||||||
|
|
||||||
type frontendCLI struct {
|
type frontendCLI struct {
|
||||||
@ -47,7 +47,7 @@ type frontendCLI struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new CLI frontend configured with the given options.
|
// New returns a new CLI frontend configured with the given options.
|
||||||
func New( //nolint[funlen]
|
func New( //nolint:funlen
|
||||||
panicHandler types.PanicHandler,
|
panicHandler types.PanicHandler,
|
||||||
|
|
||||||
locations *locations.Locations,
|
locations *locations.Locations,
|
||||||
@ -56,7 +56,7 @@ func New( //nolint[funlen]
|
|||||||
updater types.Updater,
|
updater types.Updater,
|
||||||
bridge types.Bridger,
|
bridge types.Bridger,
|
||||||
restarter types.Restarter,
|
restarter types.Restarter,
|
||||||
) *frontendCLI { //nolint[golint]
|
) *frontendCLI { //nolint:revive
|
||||||
fe := &frontendCLI{
|
fe := &frontendCLI{
|
||||||
Shell: ishell.New(),
|
Shell: ishell.New(),
|
||||||
|
|
||||||
@ -84,6 +84,11 @@ func New( //nolint[funlen]
|
|||||||
Aliases: []string{"a", "k", "keychain"},
|
Aliases: []string{"a", "k", "keychain"},
|
||||||
Func: fe.deleteAccounts,
|
Func: fe.deleteAccounts,
|
||||||
})
|
})
|
||||||
|
clearCmd.AddCmd(&ishell.Cmd{Name: "everything",
|
||||||
|
Help: "remove everything",
|
||||||
|
Aliases: []string{"a", "k", "keychain"},
|
||||||
|
Func: fe.deleteEverything,
|
||||||
|
})
|
||||||
fe.AddCmd(clearCmd)
|
fe.AddCmd(clearCmd)
|
||||||
|
|
||||||
// Change commands.
|
// Change commands.
|
||||||
@ -123,6 +128,24 @@ func New( //nolint[funlen]
|
|||||||
})
|
})
|
||||||
fe.AddCmd(dohCmd)
|
fe.AddCmd(dohCmd)
|
||||||
|
|
||||||
|
// Cache-On-Disk commands.
|
||||||
|
codCmd := &ishell.Cmd{Name: "local-cache",
|
||||||
|
Help: "manage the local encrypted message cache",
|
||||||
|
}
|
||||||
|
codCmd.AddCmd(&ishell.Cmd{Name: "enable",
|
||||||
|
Help: "enable the local cache",
|
||||||
|
Func: fe.enableCacheOnDisk,
|
||||||
|
})
|
||||||
|
codCmd.AddCmd(&ishell.Cmd{Name: "disable",
|
||||||
|
Help: "disable the local cache",
|
||||||
|
Func: fe.disableCacheOnDisk,
|
||||||
|
})
|
||||||
|
codCmd.AddCmd(&ishell.Cmd{Name: "change-location",
|
||||||
|
Help: "change the location of the local cache",
|
||||||
|
Func: fe.setCacheOnDiskLocation,
|
||||||
|
})
|
||||||
|
fe.AddCmd(codCmd)
|
||||||
|
|
||||||
// Updates commands.
|
// Updates commands.
|
||||||
updatesCmd := &ishell.Cmd{Name: "updates",
|
updatesCmd := &ishell.Cmd{Name: "updates",
|
||||||
Help: "manage bridge updates",
|
Help: "manage bridge updates",
|
||||||
@ -221,8 +244,7 @@ func New( //nolint[funlen]
|
|||||||
func (f *frontendCLI) watchEvents() {
|
func (f *frontendCLI) watchEvents() {
|
||||||
errorCh := f.eventListener.ProvideChannel(events.ErrorEvent)
|
errorCh := f.eventListener.ProvideChannel(events.ErrorEvent)
|
||||||
credentialsErrorCh := f.eventListener.ProvideChannel(events.CredentialsErrorEvent)
|
credentialsErrorCh := f.eventListener.ProvideChannel(events.CredentialsErrorEvent)
|
||||||
internetOffCh := f.eventListener.ProvideChannel(events.InternetOffEvent)
|
internetConnChangedCh := f.eventListener.ProvideChannel(events.InternetConnChangedEvent)
|
||||||
internetOnCh := f.eventListener.ProvideChannel(events.InternetOnEvent)
|
|
||||||
addressChangedCh := f.eventListener.ProvideChannel(events.AddressChangedEvent)
|
addressChangedCh := f.eventListener.ProvideChannel(events.AddressChangedEvent)
|
||||||
addressChangedLogoutCh := f.eventListener.ProvideChannel(events.AddressChangedLogoutEvent)
|
addressChangedLogoutCh := f.eventListener.ProvideChannel(events.AddressChangedLogoutEvent)
|
||||||
logoutCh := f.eventListener.ProvideChannel(events.LogoutEvent)
|
logoutCh := f.eventListener.ProvideChannel(events.LogoutEvent)
|
||||||
@ -233,10 +255,13 @@ func (f *frontendCLI) watchEvents() {
|
|||||||
f.Println("Bridge failed:", errorDetails)
|
f.Println("Bridge failed:", errorDetails)
|
||||||
case <-credentialsErrorCh:
|
case <-credentialsErrorCh:
|
||||||
f.notifyCredentialsError()
|
f.notifyCredentialsError()
|
||||||
case <-internetOffCh:
|
case stat := <-internetConnChangedCh:
|
||||||
f.notifyInternetOff()
|
if stat == events.InternetOff {
|
||||||
case <-internetOnCh:
|
f.notifyInternetOff()
|
||||||
f.notifyInternetOn()
|
}
|
||||||
|
if stat == events.InternetOn {
|
||||||
|
f.notifyInternetOn()
|
||||||
|
}
|
||||||
case address := <-addressChangedCh:
|
case address := <-addressChangedCh:
|
||||||
f.Printf("Address changed for %s. You may need to reconfigure your email client.", address)
|
f.Printf("Address changed for %s. You may need to reconfigure your email client.", address)
|
||||||
case address := <-addressChangedLogoutCh:
|
case address := <-addressChangedLogoutCh:
|
||||||
@ -256,7 +281,7 @@ func (f *frontendCLI) watchEvents() {
|
|||||||
// Loop starts the frontend loop with an interactive shell.
|
// Loop starts the frontend loop with an interactive shell.
|
||||||
func (f *frontendCLI) Loop() error {
|
func (f *frontendCLI) Loop() error {
|
||||||
f.Print(`
|
f.Print(`
|
||||||
Welcome to ProtonMail Bridge interactive shell
|
Welcome to Proton Mail Bridge interactive shell
|
||||||
___....___
|
___....___
|
||||||
^^ __..-:'':__:..:__:'':-..__
|
^^ __..-:'':__:..:__:'':-..__
|
||||||
_.-:__:.-:'': : : :'':-.:__:-._
|
_.-:__:.-:'': : : :'':-.:__:-._
|
||||||
|
|||||||
@ -1,24 +1,25 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
currentPort = "" //nolint[gochecknoglobals]
|
currentPort = "" //nolint:gochecknoglobals
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f *frontendCLI) restart(c *ishell.Context) {
|
func (f *frontendCLI) restart(c *ishell.Context) {
|
||||||
@ -58,14 +59,17 @@ func (f *frontendCLI) deleteCache(c *ishell.Context) {
|
|||||||
if !f.yesNoQuestion("Do you really want to remove all stored preferences") {
|
if !f.yesNoQuestion("Do you really want to remove all stored preferences") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := f.bridge.ClearData(); err != nil {
|
if err := f.bridge.ClearData(); err != nil {
|
||||||
f.printAndLogError("Cache clear failed: ", err.Error())
|
f.printAndLogError("Cache clear failed: ", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Println("Cached cleared, restarting bridge")
|
f.Println("Cached cleared, restarting bridge")
|
||||||
// Clearing data removes everything (db, preferences, ...)
|
|
||||||
// so everything has to be stopped and started again.
|
// Clearing data removes everything (db, preferences, ...) so everything has to be stopped and started again.
|
||||||
f.restarter.SetToRestart()
|
f.restarter.SetToRestart()
|
||||||
|
|
||||||
f.Stop()
|
f.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +129,7 @@ func (f *frontendCLI) changePort(c *ishell.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *frontendCLI) allowProxy(c *ishell.Context) {
|
func (f *frontendCLI) allowProxy(c *ishell.Context) {
|
||||||
if f.settings.GetBool(settings.AllowProxyKey) {
|
if f.bridge.GetProxyAllowed() {
|
||||||
f.Println("Bridge is already set to use alternative routing to connect to Proton if it is being blocked.")
|
f.Println("Bridge is already set to use alternative routing to connect to Proton if it is being blocked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -133,13 +137,12 @@ func (f *frontendCLI) allowProxy(c *ishell.Context) {
|
|||||||
f.Println("Bridge is currently set to NOT use alternative routing to connect to Proton if it is being blocked.")
|
f.Println("Bridge is currently set to NOT use alternative routing to connect to Proton if it is being blocked.")
|
||||||
|
|
||||||
if f.yesNoQuestion("Are you sure you want to allow bridge to do this") {
|
if f.yesNoQuestion("Are you sure you want to allow bridge to do this") {
|
||||||
f.settings.SetBool(settings.AllowProxyKey, true)
|
f.bridge.SetProxyAllowed(true)
|
||||||
f.bridge.AllowProxy()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *frontendCLI) disallowProxy(c *ishell.Context) {
|
func (f *frontendCLI) disallowProxy(c *ishell.Context) {
|
||||||
if !f.settings.GetBool(settings.AllowProxyKey) {
|
if !f.bridge.GetProxyAllowed() {
|
||||||
f.Println("Bridge is already set to NOT use alternative routing to connect to Proton if it is being blocked.")
|
f.Println("Bridge is already set to NOT use alternative routing to connect to Proton if it is being blocked.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -147,8 +150,62 @@ func (f *frontendCLI) disallowProxy(c *ishell.Context) {
|
|||||||
f.Println("Bridge is currently set to use alternative routing to connect to Proton if it is being blocked.")
|
f.Println("Bridge is currently set to use alternative routing to connect to Proton if it is being blocked.")
|
||||||
|
|
||||||
if f.yesNoQuestion("Are you sure you want to stop bridge from doing this") {
|
if f.yesNoQuestion("Are you sure you want to stop bridge from doing this") {
|
||||||
f.settings.SetBool(settings.AllowProxyKey, false)
|
f.bridge.SetProxyAllowed(false)
|
||||||
f.bridge.DisallowProxy()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *frontendCLI) enableCacheOnDisk(c *ishell.Context) {
|
||||||
|
if f.settings.GetBool(settings.CacheEnabledKey) {
|
||||||
|
f.Println("The local cache is already enabled.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.yesNoQuestion("Are you sure you want to enable the local cache") {
|
||||||
|
if err := f.bridge.EnableCache(); err != nil {
|
||||||
|
f.Println("The local cache could not be enabled.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.restarter.SetToRestart()
|
||||||
|
f.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *frontendCLI) disableCacheOnDisk(c *ishell.Context) {
|
||||||
|
if !f.settings.GetBool(settings.CacheEnabledKey) {
|
||||||
|
f.Println("The local cache is already disabled.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.yesNoQuestion("Are you sure you want to disable the local cache") {
|
||||||
|
if err := f.bridge.DisableCache(); err != nil {
|
||||||
|
f.Println("The local cache could not be disabled.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.restarter.SetToRestart()
|
||||||
|
f.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *frontendCLI) setCacheOnDiskLocation(c *ishell.Context) {
|
||||||
|
if !f.settings.GetBool(settings.CacheEnabledKey) {
|
||||||
|
f.Println("The local cache must be enabled.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if location := f.settings.Get(settings.CacheLocationKey); location != "" {
|
||||||
|
f.Println("The current local cache location is:", location)
|
||||||
|
}
|
||||||
|
|
||||||
|
if location := f.readStringInAttempts("Enter a new location for the cache", c.ReadLine, f.isCacheLocationUsable); location != "" {
|
||||||
|
if err := f.bridge.MigrateCache(f.settings.Get(settings.CacheLocationKey), location); err != nil {
|
||||||
|
f.Println("The local cache location could not be changed.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.restarter.SetToRestart()
|
||||||
|
f.Stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,3 +225,13 @@ func (f *frontendCLI) isPortFree(port string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(GODT-1158): Check free space in location.
|
||||||
|
func (f *frontendCLI) isCacheLocationUsable(location string) bool {
|
||||||
|
stat, err := os.Stat(location)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return stat.IsDir()
|
||||||
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
@ -81,13 +81,7 @@ func (f *frontendCLI) selectEarlyChannel(c *ishell.Context) {
|
|||||||
f.Println("Bridge is currently on the stable update channel.")
|
f.Println("Bridge is currently on the stable update channel.")
|
||||||
|
|
||||||
if f.yesNoQuestion("Are you sure you want to switch to the early-access update channel") {
|
if f.yesNoQuestion("Are you sure you want to switch to the early-access update channel") {
|
||||||
needRestart, err := f.bridge.SetUpdateChannel(updater.EarlyChannel)
|
f.bridge.SetUpdateChannel(updater.EarlyChannel)
|
||||||
if err != nil {
|
|
||||||
f.Println("There was a problem switching update channel.")
|
|
||||||
}
|
|
||||||
if needRestart {
|
|
||||||
f.restarter.SetToRestart()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,12 +95,6 @@ func (f *frontendCLI) selectStableChannel(c *ishell.Context) {
|
|||||||
f.Println("Switching to the stable channel may reset all data!")
|
f.Println("Switching to the stable channel may reset all data!")
|
||||||
|
|
||||||
if f.yesNoQuestion("Are you sure you want to switch to the stable update channel") {
|
if f.yesNoQuestion("Are you sure you want to switch to the stable update channel") {
|
||||||
needRestart, err := f.bridge.SetUpdateChannel(updater.StableChannel)
|
f.bridge.SetUpdateChannel(updater.StableChannel)
|
||||||
if err != nil {
|
|
||||||
f.Println("There was a problem switching update channel.")
|
|
||||||
}
|
|
||||||
if needRestart {
|
|
||||||
f.restarter.SetToRestart()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bold = color.New(color.Bold).SprintFunc() //nolint[gochecknoglobals]
|
bold = color.New(color.Bold).SprintFunc() //nolint:gochecknoglobals
|
||||||
)
|
)
|
||||||
|
|
||||||
func isNotEmpty(val string) bool {
|
func isNotEmpty(val string) bool {
|
||||||
@ -101,10 +101,10 @@ func (f *frontendCLI) notifyNeedUpgrade() {
|
|||||||
f.Println("Please download and install the newest version of application from", version.LandingPage)
|
f.Println("Please download and install the newest version of application from", version.LandingPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *frontendCLI) notifyCredentialsError() { // nolint[unused]
|
func (f *frontendCLI) notifyCredentialsError() {
|
||||||
// Print in 80-column width.
|
// Print in 80-column width.
|
||||||
f.Println("ProtonMail Bridge is not able to detect a supported password manager")
|
f.Println("Proton Mail Bridge is not able to detect a supported password manager")
|
||||||
f.Println("(pass, gnome-keyring). Please install and set up a supported password manager")
|
f.Println("(secret-service or pass). Please install and set up a supported password manager")
|
||||||
f.Println("and restart the application.")
|
f.Println("and restart the application.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,15 +114,15 @@ func (f *frontendCLI) notifyCertIssue() {
|
|||||||
be insecure.
|
be insecure.
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
ProtonMail Bridge was not able to establish a secure connection to Proton
|
Proton Mail Bridge was not able to establish a secure connection to Proton
|
||||||
servers due to a TLS certificate error. This means your connection may
|
servers due to a TLS certificate error. This means your connection may
|
||||||
potentially be insecure and susceptible to monitoring by third parties.
|
potentially be insecure and susceptible to monitoring by third parties.
|
||||||
|
|
||||||
Recommendation:
|
Recommendation:
|
||||||
* If you trust your network operator, you can continue to use ProtonMail
|
* If you trust your network operator, you can continue to use Proton Mail
|
||||||
as usual.
|
as usual.
|
||||||
* If you don't trust your network operator, reconnect to ProtonMail over a VPN
|
* If you don't trust your network operator, reconnect to Proton Mail over a VPN
|
||||||
(such as ProtonVPN) which encrypts your Internet connection, or use
|
(such as ProtonVPN) which encrypts your Internet connection, or use
|
||||||
a different network to access ProtonMail.
|
a different network to access Proton Mail.
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|||||||
76
internal/frontend/clientconfig/config.go
Normal file
76
internal/frontend/clientconfig/config.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// Copyright (c) 2022 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 clientconfig provides automatic config of IMAP and SMTP.
|
||||||
|
// For now only for Apple Mail.
|
||||||
|
package clientconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/config/useragent"
|
||||||
|
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AutoConfig interface {
|
||||||
|
Name() string
|
||||||
|
Configure(imapPort int, smtpPort int, imapSSl, smtpSSL bool, user types.User, address string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
available = map[string]AutoConfig{} //nolint:gochecknoglobals
|
||||||
|
ErrNotAvailable = errors.New("configuration not available")
|
||||||
|
)
|
||||||
|
|
||||||
|
const AppleMailClient = "Apple Mail"
|
||||||
|
|
||||||
|
func ConfigureAppleMail(user types.User, address string, s *settings.Settings) (needRestart bool, err error) {
|
||||||
|
return configure(AppleMailClient, user, address, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func configure(configName string, user types.User, address string, s *settings.Settings) (needRestart bool, err error) {
|
||||||
|
log := logrus.WithField("pkg", "client_config").WithField("client", configName)
|
||||||
|
|
||||||
|
config, ok := available[configName]
|
||||||
|
if !ok {
|
||||||
|
return false, ErrNotAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
imapPort := s.GetInt(settings.IMAPPortKey)
|
||||||
|
imapSSL := false
|
||||||
|
smtpPort := s.GetInt(settings.SMTPPortKey)
|
||||||
|
smtpSSL := s.GetBool(settings.SMTPSSLKey)
|
||||||
|
|
||||||
|
if address == "" {
|
||||||
|
address = user.GetPrimaryAddress()
|
||||||
|
}
|
||||||
|
|
||||||
|
if configName == AppleMailClient {
|
||||||
|
// If configuring apple mail for Catalina or newer, users should use SSL.
|
||||||
|
needRestart = false
|
||||||
|
if !smtpSSL && useragent.IsCatalinaOrNewer() {
|
||||||
|
smtpSSL = true
|
||||||
|
s.SetBool(settings.SMTPSSLKey, true)
|
||||||
|
log.Warn("Detected Catalina or newer with bad SMTP SSL settings, now using SSL, bridge needs to restart")
|
||||||
|
needRestart = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return needRestart, config.Configure(imapPort, smtpPort, imapSSL, smtpSSL, user, address)
|
||||||
|
}
|
||||||
@ -1,23 +1,24 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//go:build darwin
|
||||||
// +build darwin
|
// +build darwin
|
||||||
|
|
||||||
package autoconfig
|
package clientconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -38,18 +39,16 @@ const (
|
|||||||
bigSurPreferncesPane = "/System/Library/PreferencePanes/Profiles.prefPane"
|
bigSurPreferncesPane = "/System/Library/PreferencePanes/Profiles.prefPane"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() { //nolint[gochecknoinit]
|
func init() { //nolint:gochecknoinit
|
||||||
available = append(available, &appleMail{})
|
available[AppleMailClient] = &appleMail{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type appleMail struct{}
|
type appleMail struct{}
|
||||||
|
|
||||||
func (c *appleMail) Name() string {
|
func (c *appleMail) Name() string { return AppleMailClient }
|
||||||
return "Apple Mail"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *appleMail) Configure(imapPort, smtpPort int, imapSSL, smtpSSL bool, user types.User, addressIndex int) error {
|
func (c *appleMail) Configure(imapPort, smtpPort int, imapSSL, smtpSSL bool, user types.User, address string) error {
|
||||||
mc := prepareMobileConfig(imapPort, smtpPort, imapSSL, smtpSSL, user, addressIndex)
|
mc := prepareMobileConfig(imapPort, smtpPort, imapSSL, smtpSSL, user, address)
|
||||||
|
|
||||||
confPath, err := saveConfigTemporarily(mc)
|
confPath, err := saveConfigTemporarily(mc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -57,27 +56,19 @@ func (c *appleMail) Configure(imapPort, smtpPort int, imapSSL, smtpSSL bool, use
|
|||||||
}
|
}
|
||||||
|
|
||||||
if useragent.IsBigSurOrNewer() {
|
if useragent.IsBigSurOrNewer() {
|
||||||
return exec.Command("open", bigSurPreferncesPane, confPath).Run() //nolint[gosec] G204: open command is safe, mobileconfig is generated by us
|
return exec.Command("open", bigSurPreferncesPane, confPath).Run() //nolint:gosec G204: open command is safe, mobileconfig is generated by us
|
||||||
}
|
}
|
||||||
|
|
||||||
return exec.Command("open", confPath).Run() //nolint[gosec] G204: open command is safe, mobileconfig is generated by us
|
return exec.Command("open", confPath).Run() //nolint:gosec G204: open command is safe, mobileconfig is generated by us
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareMobileConfig(imapPort, smtpPort int, imapSSL, smtpSSL bool, user types.User, addressIndex int) *mobileconfig.Config {
|
func prepareMobileConfig(imapPort, smtpPort int, imapSSL, smtpSSL bool, user types.User, address string) *mobileconfig.Config {
|
||||||
var addresses string
|
displayName := address
|
||||||
var displayName string
|
addresses := address
|
||||||
|
|
||||||
if user.IsCombinedAddressMode() {
|
if user.IsCombinedAddressMode() {
|
||||||
displayName = user.GetPrimaryAddress()
|
displayName = user.GetPrimaryAddress()
|
||||||
addresses = strings.Join(user.GetAddresses(), ",")
|
addresses = strings.Join(user.GetAddresses(), ",")
|
||||||
} else {
|
|
||||||
for idx, address := range user.GetAddresses() {
|
|
||||||
if idx == addressIndex {
|
|
||||||
displayName = address
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addresses = displayName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
@ -109,10 +100,10 @@ func saveConfigTemporarily(mc *mobileconfig.Config) (fname string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the temporary file is deleted.
|
// Make sure the temporary file is deleted.
|
||||||
go (func() {
|
go func() {
|
||||||
<-time.After(10 * time.Minute)
|
<-time.After(10 * time.Minute)
|
||||||
_ = os.RemoveAll(dir)
|
_ = os.RemoveAll(dir)
|
||||||
})()
|
}()
|
||||||
|
|
||||||
// Make sure the file is only readable for the current user.
|
// Make sure the file is only readable for the current user.
|
||||||
fname = filepath.Clean(filepath.Join(dir, "protonmail.mobileconfig"))
|
fname = filepath.Clean(filepath.Join(dir, "protonmail.mobileconfig"))
|
||||||
@ -1,45 +1,35 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
// Copyright (c) 2022 Proton AG
|
||||||
//
|
//
|
||||||
// This file is part of ProtonMail Bridge.
|
// This file is part of Proton Mail Bridge.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package frontend provides all interfaces of the Bridge.
|
// Package frontend provides all interfaces of the Bridge.
|
||||||
package frontend
|
package frontend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ProtonMail/go-autostart"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/bridge"
|
"github.com/ProtonMail/proton-bridge/internal/bridge"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
"github.com/ProtonMail/proton-bridge/internal/config/settings"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/config/useragent"
|
"github.com/ProtonMail/proton-bridge/internal/config/useragent"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/frontend/cli"
|
"github.com/ProtonMail/proton-bridge/internal/frontend/cli"
|
||||||
cliie "github.com/ProtonMail/proton-bridge/internal/frontend/cli-ie"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/frontend/qt"
|
"github.com/ProtonMail/proton-bridge/internal/frontend/qt"
|
||||||
qtie "github.com/ProtonMail/proton-bridge/internal/frontend/qt-ie"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/importexport"
|
|
||||||
"github.com/ProtonMail/proton-bridge/internal/locations"
|
"github.com/ProtonMail/proton-bridge/internal/locations"
|
||||||
"github.com/ProtonMail/proton-bridge/internal/updater"
|
"github.com/ProtonMail/proton-bridge/internal/updater"
|
||||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
log = logrus.WithField("pkg", "frontend") // nolint[unused]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Frontend is an interface to be implemented by each frontend type (cli, gui, html).
|
|
||||||
type Frontend interface {
|
type Frontend interface {
|
||||||
Loop() error
|
Loop() error
|
||||||
NotifyManualUpdate(update updater.VersionInfo, canInstall bool)
|
NotifyManualUpdate(update updater.VersionInfo, canInstall bool)
|
||||||
@ -64,58 +54,11 @@ func New(
|
|||||||
userAgent *useragent.UserAgent,
|
userAgent *useragent.UserAgent,
|
||||||
bridge *bridge.Bridge,
|
bridge *bridge.Bridge,
|
||||||
noEncConfirmator types.NoEncConfirmator,
|
noEncConfirmator types.NoEncConfirmator,
|
||||||
autostart *autostart.App,
|
|
||||||
restarter types.Restarter,
|
restarter types.Restarter,
|
||||||
) Frontend {
|
) Frontend {
|
||||||
bridgeWrap := types.NewBridgeWrap(bridge)
|
bridgeWrap := types.NewBridgeWrap(bridge)
|
||||||
return newBridgeFrontend(
|
|
||||||
version,
|
|
||||||
buildVersion,
|
|
||||||
programName,
|
|
||||||
frontendType,
|
|
||||||
showWindowOnStart,
|
|
||||||
panicHandler,
|
|
||||||
locations,
|
|
||||||
settings,
|
|
||||||
eventListener,
|
|
||||||
updater,
|
|
||||||
userAgent,
|
|
||||||
bridgeWrap,
|
|
||||||
noEncConfirmator,
|
|
||||||
autostart,
|
|
||||||
restarter,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBridgeFrontend(
|
|
||||||
version,
|
|
||||||
buildVersion,
|
|
||||||
programName,
|
|
||||||
frontendType string,
|
|
||||||
showWindowOnStart bool,
|
|
||||||
panicHandler types.PanicHandler,
|
|
||||||
locations *locations.Locations,
|
|
||||||
settings *settings.Settings,
|
|
||||||
eventListener listener.Listener,
|
|
||||||
updater types.Updater,
|
|
||||||
userAgent *useragent.UserAgent,
|
|
||||||
bridge types.Bridger,
|
|
||||||
noEncConfirmator types.NoEncConfirmator,
|
|
||||||
autostart *autostart.App,
|
|
||||||
restarter types.Restarter,
|
|
||||||
) Frontend {
|
|
||||||
switch frontendType {
|
switch frontendType {
|
||||||
case "cli":
|
case "qt":
|
||||||
return cli.New(
|
|
||||||
panicHandler,
|
|
||||||
locations,
|
|
||||||
settings,
|
|
||||||
eventListener,
|
|
||||||
updater,
|
|
||||||
bridge,
|
|
||||||
restarter,
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
return qt.New(
|
return qt.New(
|
||||||
version,
|
version,
|
||||||
buildVersion,
|
buildVersion,
|
||||||
@ -127,79 +70,21 @@ func newBridgeFrontend(
|
|||||||
eventListener,
|
eventListener,
|
||||||
updater,
|
updater,
|
||||||
userAgent,
|
userAgent,
|
||||||
bridge,
|
bridgeWrap,
|
||||||
noEncConfirmator,
|
noEncConfirmator,
|
||||||
autostart,
|
|
||||||
restarter,
|
restarter,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewImportExport returns initialized frontend based on `frontendType`, which can be `cli` or `qt`.
|
|
||||||
func NewImportExport(
|
|
||||||
version,
|
|
||||||
buildVersion,
|
|
||||||
programName,
|
|
||||||
frontendType string,
|
|
||||||
panicHandler types.PanicHandler,
|
|
||||||
locations *locations.Locations,
|
|
||||||
settings *settings.Settings,
|
|
||||||
eventListener listener.Listener,
|
|
||||||
updater types.Updater,
|
|
||||||
ie *importexport.ImportExport,
|
|
||||||
restarter types.Restarter,
|
|
||||||
) Frontend {
|
|
||||||
ieWrap := types.NewImportExportWrap(ie)
|
|
||||||
return newIEFrontend(
|
|
||||||
version,
|
|
||||||
buildVersion,
|
|
||||||
programName,
|
|
||||||
frontendType,
|
|
||||||
panicHandler,
|
|
||||||
locations,
|
|
||||||
settings,
|
|
||||||
eventListener,
|
|
||||||
updater,
|
|
||||||
ieWrap,
|
|
||||||
restarter,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newIEFrontend(
|
|
||||||
version,
|
|
||||||
buildVersion,
|
|
||||||
programName,
|
|
||||||
frontendType string,
|
|
||||||
panicHandler types.PanicHandler,
|
|
||||||
locations *locations.Locations,
|
|
||||||
settings *settings.Settings,
|
|
||||||
eventListener listener.Listener,
|
|
||||||
updater types.Updater,
|
|
||||||
ie types.ImportExporter,
|
|
||||||
restarter types.Restarter,
|
|
||||||
) Frontend {
|
|
||||||
switch frontendType {
|
|
||||||
case "cli":
|
case "cli":
|
||||||
return cliie.New(
|
return cli.New(
|
||||||
panicHandler,
|
|
||||||
locations,
|
|
||||||
eventListener,
|
|
||||||
updater,
|
|
||||||
ie,
|
|
||||||
restarter,
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
return qtie.New(
|
|
||||||
version,
|
|
||||||
buildVersion,
|
|
||||||
programName,
|
|
||||||
panicHandler,
|
panicHandler,
|
||||||
locations,
|
locations,
|
||||||
settings,
|
settings,
|
||||||
eventListener,
|
eventListener,
|
||||||
updater,
|
updater,
|
||||||
ie,
|
bridgeWrap,
|
||||||
restarter,
|
restarter,
|
||||||
)
|
)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
190
internal/frontend/qml/AccountDelegate.qml
Normal file
190
internal/frontend/qml/AccountDelegate.qml
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
// Copyright (c) 2022 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/>.
|
||||||
|
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
|
||||||
|
import Proton 4.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property ColorScheme colorScheme
|
||||||
|
property var user
|
||||||
|
|
||||||
|
property var _spacing: 12 * ProtonStyle.px
|
||||||
|
|
||||||
|
property color usedSpaceColor : {
|
||||||
|
if (!root.enabled) return root.colorScheme.text_weak
|
||||||
|
if (root.type == AccountDelegate.SmallView) return root.colorScheme.text_weak
|
||||||
|
if (root.usedFraction < .50) return root.colorScheme.signal_success
|
||||||
|
if (root.usedFraction < .75) return root.colorScheme.signal_warning
|
||||||
|
return root.colorScheme.signal_danger
|
||||||
|
}
|
||||||
|
property real usedFraction: root.user ? reasonableFracion(root.user.usedBytes, root.user.totalBytes) : 0
|
||||||
|
property string totalSpace: root.spaceWithUnits(root.user ? root.reasonableBytes(root.user.totalBytes) : 0)
|
||||||
|
property string usedSpace: root.spaceWithUnits(root.user ? root.reasonableBytes(root.user.usedBytes) : 0)
|
||||||
|
|
||||||
|
function reasonableFracion(used, total){
|
||||||
|
var usedSafe = root.reasonableBytes(used)
|
||||||
|
var totalSafe = root.reasonableBytes(total)
|
||||||
|
if (totalSafe == 0 || usedSafe == 0) return 0
|
||||||
|
if (totalSafe <= usedSafe) return 1
|
||||||
|
return usedSafe / totalSafe
|
||||||
|
}
|
||||||
|
|
||||||
|
function reasonableBytes(bytes){
|
||||||
|
var safeBytes = bytes+0
|
||||||
|
if (safeBytes != bytes) return 0
|
||||||
|
if (safeBytes < 0) return 0
|
||||||
|
return Math.ceil(safeBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
function spaceWithUnits(bytes){
|
||||||
|
if (bytes*1 !== bytes || bytes == 0 ) return "0 kB"
|
||||||
|
var units = ['B',"kB", "MB", "GB", "TB"];
|
||||||
|
var i = parseInt(Math.floor(Math.log(bytes)/Math.log(1024)));
|
||||||
|
|
||||||
|
return Math.round(bytes*10 / Math.pow(1024, i))/10 + " " + units[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// width expected to be set by parent object
|
||||||
|
implicitHeight : children[0].implicitHeight
|
||||||
|
|
||||||
|
enum ViewType{
|
||||||
|
SmallView, LargeView
|
||||||
|
}
|
||||||
|
property var type : AccountDelegate.SmallView
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: root._spacing
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: root.top
|
||||||
|
left: root.left
|
||||||
|
right: root.rigth
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: avatar
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: height
|
||||||
|
|
||||||
|
radius: ProtonStyle.avatar_radius
|
||||||
|
|
||||||
|
color: root.colorScheme.background_avatar
|
||||||
|
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
anchors.fill: parent
|
||||||
|
text: root.user ? root.user.avatarText.toUpperCase(): ""
|
||||||
|
type: {
|
||||||
|
switch (root.type) {
|
||||||
|
case AccountDelegate.SmallView: return Label.Body
|
||||||
|
case AccountDelegate.LargeView: return Label.Title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font.weight: Font.Normal
|
||||||
|
color: "#FFFFFF"
|
||||||
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: account
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.maximumWidth: root.width - (
|
||||||
|
root._spacing + avatar.width
|
||||||
|
)
|
||||||
|
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: root.user ? user.username : ""
|
||||||
|
type: {
|
||||||
|
switch (root.type) {
|
||||||
|
case AccountDelegate.SmallView: return Label.Body
|
||||||
|
case AccountDelegate.LargeView: return Label.Title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elide: Text.ElideMiddle
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { implicitHeight: root.type == AccountDelegate.LargeView ? 6 * ProtonStyle.px : 0 }
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: 0
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: root.user && root.user.loggedIn ? root.usedSpace : qsTr("Signed out")
|
||||||
|
color: root.usedSpaceColor
|
||||||
|
type: {
|
||||||
|
switch (root.type) {
|
||||||
|
case AccountDelegate.SmallView: return Label.Caption
|
||||||
|
case AccountDelegate.LargeView: return Label.Body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: root.user && root.user.loggedIn ? " / " + root.totalSpace : ""
|
||||||
|
color: root.colorScheme.text_weak
|
||||||
|
type: {
|
||||||
|
switch (root.type) {
|
||||||
|
case AccountDelegate.SmallView: return Label.Caption
|
||||||
|
case AccountDelegate.LargeView: return Label.Body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: storage_bar
|
||||||
|
visible: root.user ? root.type == AccountDelegate.LargeView : false
|
||||||
|
width: 140 * ProtonStyle.px
|
||||||
|
height: 4 * ProtonStyle.px
|
||||||
|
radius: ProtonStyle.storage_bar_radius
|
||||||
|
color: root.colorScheme.border_weak
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: storage_bar_filled
|
||||||
|
radius: ProtonStyle.storage_bar_radius
|
||||||
|
color: root.usedSpaceColor
|
||||||
|
visible: root.user ? parent.visible && root.user.loggedIn : false
|
||||||
|
anchors {
|
||||||
|
top : parent.top
|
||||||
|
bottom : parent.bottom
|
||||||
|
left : parent.left
|
||||||
|
}
|
||||||
|
width: Math.min(1,Math.max(0.02,root.usedFraction)) * parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
251
internal/frontend/qml/AccountView.qml
Normal file
251
internal/frontend/qml/AccountView.qml
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
// Copyright (c) 2022 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/>.
|
||||||
|
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
|
||||||
|
import Proton 4.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
property ColorScheme colorScheme
|
||||||
|
property var backend
|
||||||
|
property var notifications
|
||||||
|
property var user
|
||||||
|
|
||||||
|
signal showSignIn()
|
||||||
|
signal showSetupGuide(var user, string address)
|
||||||
|
|
||||||
|
property int _leftMargin: 64
|
||||||
|
property int _rightMargin: 64
|
||||||
|
property int _topMargin: 32
|
||||||
|
property int _detailsTopMargin: 25
|
||||||
|
property int _bottomMargin: 12
|
||||||
|
property int _spacing: 20
|
||||||
|
property int _lineWidth: 1
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: scrollView
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Item {
|
||||||
|
// can't use parent here because parent is not ScrollView (Flickable inside contentItem inside ScrollView)
|
||||||
|
width: scrollView.availableWidth
|
||||||
|
height: scrollView.availableHeight
|
||||||
|
|
||||||
|
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||||
|
// do not set implicitWidth because implicit width of ColumnLayout will be equal to maximum implicit width of
|
||||||
|
// internal items. And if one of internal items would be a Text or Label - implicit width of those is always
|
||||||
|
// equal to non-wrapped text (i.e. one line only). That will lead to enabling horizontal scroll when not needed
|
||||||
|
implicitWidth: width
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: topRectangle
|
||||||
|
color: root.colorScheme.background_norm
|
||||||
|
|
||||||
|
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||||
|
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: root._spacing
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: root._leftMargin
|
||||||
|
anchors.rightMargin: root._rightMargin
|
||||||
|
anchors.topMargin: root._topMargin
|
||||||
|
anchors.bottomMargin: root._bottomMargin
|
||||||
|
|
||||||
|
RowLayout { // account delegate with action buttons
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
AccountDelegate {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
user: root.user
|
||||||
|
type: AccountDelegate.LargeView
|
||||||
|
enabled: root.user ? root.user.loggedIn : false
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: qsTr("Sign out")
|
||||||
|
secondary: true
|
||||||
|
visible: root.user ? root.user.loggedIn : false
|
||||||
|
onClicked: {
|
||||||
|
if (!root.user) return
|
||||||
|
root.user.logout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: qsTr("Sign in")
|
||||||
|
secondary: true
|
||||||
|
visible: root.user ? !root.user.loggedIn : false
|
||||||
|
onClicked: {
|
||||||
|
if (!root.user) return
|
||||||
|
root.showSignIn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
icon.source: "icons/ic-trash.svg"
|
||||||
|
secondary: true
|
||||||
|
onClicked: {
|
||||||
|
if (!root.user) return
|
||||||
|
root.notifications.askDeleteAccount(root.user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: root._lineWidth
|
||||||
|
color: root.colorScheme.border_weak
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsItem {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: qsTr("Email clients")
|
||||||
|
actionText: qsTr("Configure")
|
||||||
|
description: qsTr("Using the mailbox details below (re)configure your client.")
|
||||||
|
type: SettingsItem.Button
|
||||||
|
enabled: root.user ? root.user.loggedIn : false
|
||||||
|
visible: root.user ? !root.user.splitMode || root.user.addresses.length==1 : false
|
||||||
|
showSeparator: splitMode.visible
|
||||||
|
onClicked: {
|
||||||
|
if (!root.user) return
|
||||||
|
root.showSetupGuide(root.user, user.addresses[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsItem {
|
||||||
|
id: splitMode
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: qsTr("Split addresses")
|
||||||
|
description: qsTr("Setup multiple email addresses individually.")
|
||||||
|
type: SettingsItem.Toggle
|
||||||
|
checked: root.user ? root.user.splitMode : false
|
||||||
|
visible: root.user ? root.user.addresses.length > 1 : false
|
||||||
|
enabled: root.user ? root.user.loggedIn : false
|
||||||
|
showSeparator: addressSelector.visible
|
||||||
|
onClicked: {
|
||||||
|
if (!splitMode.checked){
|
||||||
|
root.notifications.askEnableSplitMode(user)
|
||||||
|
} else {
|
||||||
|
addressSelector.currentIndex = 0
|
||||||
|
root.user.toggleSplitMode(!splitMode.checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
enabled: root.user ? root.user.loggedIn : false
|
||||||
|
visible: root.user ? root.user.splitMode : false
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: addressSelector
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: root.user ? root.user.addresses : null
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: qsTr("Configure")
|
||||||
|
secondary: true
|
||||||
|
onClicked: {
|
||||||
|
if (!root.user) return
|
||||||
|
root.showSetupGuide(root.user, addressSelector.displayText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: root.colorScheme.background_weak
|
||||||
|
|
||||||
|
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||||
|
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: configuration
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: root._leftMargin
|
||||||
|
anchors.rightMargin: root._rightMargin
|
||||||
|
anchors.topMargin: root._detailsTopMargin
|
||||||
|
anchors.bottomMargin: root._spacing
|
||||||
|
|
||||||
|
spacing: root._spacing
|
||||||
|
visible: root.user ? root.user.loggedIn : false
|
||||||
|
|
||||||
|
property string currentAddress: addressSelector.displayText
|
||||||
|
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: qsTr("Mailbox details")
|
||||||
|
type: Label.Body_semibold
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
title: qsTr("IMAP")
|
||||||
|
hostname: root.backend.hostname
|
||||||
|
port: root.backend.portIMAP.toString()
|
||||||
|
username: configuration.currentAddress
|
||||||
|
password: root.user ? root.user.password : ""
|
||||||
|
security: "STARTTLS"
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
title: qsTr("SMTP")
|
||||||
|
hostname : root.backend.hostname
|
||||||
|
port : root.backend.portSMTP.toString()
|
||||||
|
username : configuration.currentAddress
|
||||||
|
password : root.user ? root.user.password : ""
|
||||||
|
security : root.backend.useSSLforSMTP ? "SSL" : "STARTTLS"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
234
internal/frontend/qml/Banner.qml
Normal file
234
internal/frontend/qml/Banner.qml
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
// Copyright (c) 2022 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/>.
|
||||||
|
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
import QtQuick.Controls.impl 2.12
|
||||||
|
|
||||||
|
import Proton 4.0
|
||||||
|
import Notifications 1.0
|
||||||
|
|
||||||
|
Popup {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property ColorScheme colorScheme
|
||||||
|
property Notification notification
|
||||||
|
property var mainWindow
|
||||||
|
|
||||||
|
topMargin: 37
|
||||||
|
leftMargin: (mainWindow.width - root.implicitWidth)/2
|
||||||
|
|
||||||
|
implicitHeight: contentLayout.implicitHeight + contentLayout.anchors.topMargin + contentLayout.anchors.bottomMargin
|
||||||
|
implicitWidth: 600 // contentLayout.implicitWidth + contentLayout.anchors.leftMargin + contentLayout.anchors.rightMargin
|
||||||
|
|
||||||
|
popupType: ApplicationWindow.PopupType.Banner
|
||||||
|
|
||||||
|
shouldShow: notification ? (notification.active && !notification.dismissed) : false
|
||||||
|
|
||||||
|
modal: false
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: defaultDismissAction
|
||||||
|
|
||||||
|
text: qsTr("OK")
|
||||||
|
onTriggered: {
|
||||||
|
if (!root.notification) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root.notification.dismissed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: contentLayout
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
implicitHeight: children[1].implicitHeight + children[1].anchors.topMargin + children[1].anchors.bottomMargin
|
||||||
|
implicitWidth: children[1].implicitWidth + children[1].anchors.leftMargin + children[1].anchors.rightMargin
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
width: parent.width + 10
|
||||||
|
radius: ProtonStyle.banner_radius
|
||||||
|
color: {
|
||||||
|
if (!root.notification) {
|
||||||
|
return "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (root.notification.type) {
|
||||||
|
case Notification.NotificationType.Info:
|
||||||
|
return root.colorScheme.signal_info
|
||||||
|
case Notification.NotificationType.Success:
|
||||||
|
return root.colorScheme.signal_success
|
||||||
|
case Notification.NotificationType.Warning:
|
||||||
|
return root.colorScheme.signal_warning
|
||||||
|
case Notification.NotificationType.Danger:
|
||||||
|
return root.colorScheme.signal_danger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
anchors.topMargin: 14
|
||||||
|
anchors.bottomMargin: 14
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
ColorImage {
|
||||||
|
color: root.colorScheme.text_invert
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
|
||||||
|
sourceSize.width: 24
|
||||||
|
sourceSize.height: 24
|
||||||
|
|
||||||
|
Layout.preferredHeight: 24
|
||||||
|
Layout.preferredWidth: 24
|
||||||
|
|
||||||
|
source: {
|
||||||
|
if (!root.notification) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (root.notification.type) {
|
||||||
|
case Notification.NotificationType.Info:
|
||||||
|
return "./icons/ic-info-circle-filled.svg"
|
||||||
|
case Notification.NotificationType.Success:
|
||||||
|
return "./icons/ic-info-circle-filled.svg"
|
||||||
|
case Notification.NotificationType.Warning:
|
||||||
|
return "./icons/ic-exclamation-circle-filled.svg"
|
||||||
|
case Notification.NotificationType.Danger:
|
||||||
|
return "./icons/ic-exclamation-circle-filled.svg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
|
||||||
|
color: root.colorScheme.text_invert
|
||||||
|
text: root.notification ? root.notification.description : ""
|
||||||
|
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
width: 1
|
||||||
|
color: {
|
||||||
|
if (!root.notification) {
|
||||||
|
return "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (root.notification.type) {
|
||||||
|
case Notification.NotificationType.Info:
|
||||||
|
return root.colorScheme.signal_info_active
|
||||||
|
case Notification.NotificationType.Success:
|
||||||
|
return root.colorScheme.signal_success_active
|
||||||
|
case Notification.NotificationType.Warning:
|
||||||
|
return root.colorScheme.signal_warning_active
|
||||||
|
case Notification.NotificationType.Danger:
|
||||||
|
return root.colorScheme.signal_danger_active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
id: actionButton
|
||||||
|
|
||||||
|
action: (root.notification && root.notification.action.length > 0) ? root.notification.action[0] : defaultDismissAction
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
clip: true
|
||||||
|
Rectangle {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
width: parent.width + 10
|
||||||
|
radius: ProtonStyle.banner_radius
|
||||||
|
color: {
|
||||||
|
if (!root.notification) {
|
||||||
|
return "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
|
var norm
|
||||||
|
var hover
|
||||||
|
var active
|
||||||
|
|
||||||
|
switch (root.notification.type) {
|
||||||
|
case Notification.NotificationType.Info:
|
||||||
|
norm = root.colorScheme.signal_info
|
||||||
|
hover = root.colorScheme.signal_info_hover
|
||||||
|
active = root.colorScheme.signal_info_active
|
||||||
|
break;
|
||||||
|
case Notification.NotificationType.Success:
|
||||||
|
norm = root.colorScheme.signal_success
|
||||||
|
hover = root.colorScheme.signal_success_hover
|
||||||
|
active = root.colorScheme.signal_success_active
|
||||||
|
break;
|
||||||
|
case Notification.NotificationType.Warning:
|
||||||
|
norm = root.colorScheme.signal_warning
|
||||||
|
hover = root.colorScheme.signal_warning_hover
|
||||||
|
active = root.colorScheme.signal_warning_active
|
||||||
|
break;
|
||||||
|
case Notification.NotificationType.Danger:
|
||||||
|
norm = root.colorScheme.signal_danger
|
||||||
|
hover = root.colorScheme.signal_danger_hover
|
||||||
|
active = root.colorScheme.signal_danger_active
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionButton.down) {
|
||||||
|
return active
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionButton.enabled && (actionButton.highlighted || actionButton.hovered || actionButton.checked)) {
|
||||||
|
return hover
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionButton.loading) {
|
||||||
|
return hover
|
||||||
|
}
|
||||||
|
|
||||||
|
return norm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
269
internal/frontend/qml/Bridge.qml
Normal file
269
internal/frontend/qml/Bridge.qml
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
// Copyright (c) 2022 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/>.
|
||||||
|
|
||||||
|
import QtQml 2.12
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Window 2.13
|
||||||
|
import Qt.labs.platform 1.1
|
||||||
|
|
||||||
|
import Proton 4.0
|
||||||
|
import Notifications 1.0
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
function isInInterval(num, lower_limit, upper_limit) {
|
||||||
|
return lower_limit <= num && num <= upper_limit
|
||||||
|
}
|
||||||
|
function bound(num, lower_limit, upper_limit) {
|
||||||
|
return Math.max(lower_limit, Math.min(upper_limit, num))
|
||||||
|
}
|
||||||
|
|
||||||
|
property var backend
|
||||||
|
property var title: "Proton Mail Bridge"
|
||||||
|
|
||||||
|
property Notifications _notifications: Notifications {
|
||||||
|
id: notifications
|
||||||
|
backend: root.backend
|
||||||
|
frontendMain: mainWindow
|
||||||
|
frontendStatus: statusWindow
|
||||||
|
frontendTray: trayIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
property MainWindow _mainWindow: MainWindow {
|
||||||
|
id: mainWindow
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
title: root.title
|
||||||
|
backend: root.backend
|
||||||
|
notifications: root._notifications
|
||||||
|
|
||||||
|
onVisibleChanged: {
|
||||||
|
backend.dockIconVisible = visible
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.backend
|
||||||
|
onCacheUnavailable: {
|
||||||
|
mainWindow.showAndRise()
|
||||||
|
}
|
||||||
|
onColorSchemeNameChanged: root.setColorScheme()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property StatusWindow _statusWindow: StatusWindow {
|
||||||
|
id: statusWindow
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
title: root.title
|
||||||
|
backend: root.backend
|
||||||
|
notifications: root._notifications
|
||||||
|
|
||||||
|
onShowMainWindow: {
|
||||||
|
mainWindow.showAndRise()
|
||||||
|
}
|
||||||
|
|
||||||
|
onShowHelp: {
|
||||||
|
mainWindow.showHelp()
|
||||||
|
mainWindow.showAndRise()
|
||||||
|
}
|
||||||
|
|
||||||
|
onShowSettings: {
|
||||||
|
mainWindow.showSettings()
|
||||||
|
mainWindow.showAndRise()
|
||||||
|
}
|
||||||
|
|
||||||
|
onShowSignIn: {
|
||||||
|
mainWindow.showSignIn(username)
|
||||||
|
mainWindow.showAndRise()
|
||||||
|
}
|
||||||
|
|
||||||
|
onQuit: {
|
||||||
|
backend.quit()
|
||||||
|
}
|
||||||
|
|
||||||
|
property rect screenRect
|
||||||
|
property rect iconRect
|
||||||
|
|
||||||
|
// use binding from function with width and height as arguments so it will be recalculated every time width and height are changed
|
||||||
|
property point position: getPosition(width, height)
|
||||||
|
x: position.x
|
||||||
|
y: position.y
|
||||||
|
|
||||||
|
function getPosition(_width, _height) {
|
||||||
|
if (screenRect.width === 0 || screenRect.height === 0) {
|
||||||
|
return Qt.point(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _x = 0
|
||||||
|
var _y = 0
|
||||||
|
|
||||||
|
// fit above
|
||||||
|
_y = iconRect.top - height
|
||||||
|
if (isInInterval(_y, screenRect.top, screenRect.bottom - height)) {
|
||||||
|
// position preferebly in the horizontal center but bound to the screen rect
|
||||||
|
_x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width)
|
||||||
|
return Qt.point(_x, _y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fit below
|
||||||
|
_y = iconRect.bottom
|
||||||
|
if (isInInterval(_y, screenRect.top, screenRect.bottom - height)) {
|
||||||
|
// position preferebly in the horizontal center but bound to the screen rect
|
||||||
|
_x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width)
|
||||||
|
return Qt.point(_x, _y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fit to the left
|
||||||
|
_x = iconRect.left - width
|
||||||
|
if (isInInterval(_x, screenRect.left, screenRect.right - width)) {
|
||||||
|
// position preferebly in the vertical center but bound to the screen rect
|
||||||
|
_y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height)
|
||||||
|
return Qt.point(_x, _y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fit to the right
|
||||||
|
_x = iconRect.right
|
||||||
|
if (isInInterval(_x, screenRect.left, screenRect.right - width)) {
|
||||||
|
// position preferebly in the vertical center but bound to the screen rect
|
||||||
|
_y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height)
|
||||||
|
return Qt.point(_x, _y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: position satatus window right above icon and let window manager decide.
|
||||||
|
console.warn("Can't position status window: screenRect =", screenRect, "iconRect =", iconRect)
|
||||||
|
_x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width)
|
||||||
|
_y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height)
|
||||||
|
return Qt.point(_x, _y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property SystemTrayIcon _trayIcon: SystemTrayIcon {
|
||||||
|
id: trayIcon
|
||||||
|
visible: true
|
||||||
|
icon.source: "./icons/systray-mono.png"
|
||||||
|
icon.mask: true // make sure that systems like macOS will use proper color
|
||||||
|
tooltip: `Proton Mail Bridge v${backend.version}`
|
||||||
|
onActivated: {
|
||||||
|
function calcStatusWindowPosition() {
|
||||||
|
// On some platforms (X11 / Plasma) Qt does not provide icon position and geometry info.
|
||||||
|
// In this case we rely on cursor position
|
||||||
|
var iconRect = Qt.rect(geometry.x, geometry.y, geometry.width, geometry.height)
|
||||||
|
if (geometry.width == 0 && geometry.height == 0) {
|
||||||
|
var mousePos = backend.getCursorPos()
|
||||||
|
iconRect.x = mousePos.x
|
||||||
|
iconRect.y = mousePos.y
|
||||||
|
iconRect.width = 0
|
||||||
|
iconRect.height = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find screen
|
||||||
|
var screen
|
||||||
|
for (var i in Qt.application.screens) {
|
||||||
|
var _screen = Qt.application.screens[i]
|
||||||
|
if (
|
||||||
|
isInInterval(iconRect.x, _screen.virtualX, _screen.virtualX + _screen.width) &&
|
||||||
|
isInInterval(iconRect.y, _screen.virtualY, _screen.virtualY + _screen.height)
|
||||||
|
) {
|
||||||
|
screen = _screen
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!screen) {
|
||||||
|
// Fallback to primary screen
|
||||||
|
screen = Qt.application.screens[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case we used mouse to detect icon position - we want to make a fake icon rectangle from a point
|
||||||
|
if (iconRect.width == 0 && iconRect.height == 0) {
|
||||||
|
iconRect.x = bound(iconRect.x - 16, screen.virtualX, screen.virtualX + screen.width - 32)
|
||||||
|
iconRect.y = bound(iconRect.y - 16, screen.virtualY, screen.virtualY + screen.height - 32)
|
||||||
|
iconRect.width = 32
|
||||||
|
iconRect.height = 32
|
||||||
|
}
|
||||||
|
|
||||||
|
statusWindow.screenRect = Qt.rect(screen.virtualX, screen.virtualY, screen.width, screen.height)
|
||||||
|
statusWindow.iconRect = iconRect
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleWindow(win) {
|
||||||
|
if (win.visible) {
|
||||||
|
win.close()
|
||||||
|
} else {
|
||||||
|
win.showAndRise()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (reason) {
|
||||||
|
case SystemTrayIcon.Unknown:
|
||||||
|
break;
|
||||||
|
case SystemTrayIcon.Context:
|
||||||
|
case SystemTrayIcon.Trigger:
|
||||||
|
case SystemTrayIcon.DoubleClick:
|
||||||
|
case SystemTrayIcon.MiddleClick:
|
||||||
|
calcStatusWindowPosition()
|
||||||
|
toggleWindow(statusWindow)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (!root.backend) {
|
||||||
|
console.log("backend not loaded")
|
||||||
|
}
|
||||||
|
|
||||||
|
root.setColorScheme()
|
||||||
|
|
||||||
|
|
||||||
|
if (!root.backend.users) {
|
||||||
|
console.log("users not loaded")
|
||||||
|
}
|
||||||
|
|
||||||
|
var c = root.backend.users.count
|
||||||
|
var u = root.backend.users.get(0)
|
||||||
|
// DEBUG
|
||||||
|
if (c != 0) {
|
||||||
|
console.log("users non zero", c)
|
||||||
|
console.log("first user", u )
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c === 0) {
|
||||||
|
mainWindow.showAndRise()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u) {
|
||||||
|
if (c === 1 && u.loggedIn === false) {
|
||||||
|
mainWindow.showAndRise()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.backend.showOnStartup) {
|
||||||
|
mainWindow.showAndRise()
|
||||||
|
}
|
||||||
|
|
||||||
|
root.backend.guiReady()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setColorScheme() {
|
||||||
|
if (root.backend.colorSchemeName == "light") ProtonStyle.currentStyle = ProtonStyle.lightStyle
|
||||||
|
if (root.backend.colorSchemeName == "dark") ProtonStyle.currentStyle = ProtonStyle.darkStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
316
internal/frontend/qml/BridgeTest/UserControl.qml
Normal file
316
internal/frontend/qml/BridgeTest/UserControl.qml
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
// Copyright (c) 2022 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/>.
|
||||||
|
|
||||||
|
import QtQml 2.12
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
|
||||||
|
import Proton 4.0
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var user
|
||||||
|
property var userIndex
|
||||||
|
property var backend
|
||||||
|
|
||||||
|
spacing : 5
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
//Layout.fillWidth: true
|
||||||
|
|
||||||
|
property ColorScheme colorScheme
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: user !== undefined ? user.username : ""
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
user.username = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Switch {
|
||||||
|
id: userLoginSwitch
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
|
||||||
|
text: "LoggedIn"
|
||||||
|
enabled: user !== undefined && user.username.length > 0
|
||||||
|
|
||||||
|
checked: user ? user.loggedIn : false
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (!user) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
if (user === backend.loginUser) {
|
||||||
|
var newUserObject = backend.userComponent.createObject(backend, {username: user.username, loggedIn: true, setupGuideSeen: user.setupGuideSeen})
|
||||||
|
backend.users.append( { object: newUserObject } )
|
||||||
|
|
||||||
|
user.username = ""
|
||||||
|
user.resetLoginRequests()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.loggedIn = true
|
||||||
|
user.resetLoginRequests()
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
user.loggedIn = false
|
||||||
|
user.resetLoginRequests()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Switch {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
|
||||||
|
text: "Setup guide seen"
|
||||||
|
enabled: user !== undefined && user.username.length > 0
|
||||||
|
|
||||||
|
checked: user ? user.setupGuideSeen : false
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (!user) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.setupGuideSeen = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
id: loginLabel
|
||||||
|
text: "Login:"
|
||||||
|
|
||||||
|
Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "name/pass error"
|
||||||
|
enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2FARequested && !user.isLogin2PasswordProvided
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.backend.loginUsernamePasswordError("")
|
||||||
|
user.resetLoginRequests()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "free user error"
|
||||||
|
enabled: user !== undefined //&& user.isLoginRequested
|
||||||
|
onClicked: {
|
||||||
|
root.backend.loginFreeUserError()
|
||||||
|
user.resetLoginRequests()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "connection error"
|
||||||
|
enabled: user !== undefined //&& user.isLoginRequested
|
||||||
|
onClicked: {
|
||||||
|
root.backend.loginConnectionError("")
|
||||||
|
user.resetLoginRequests()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
id: faLabel
|
||||||
|
text: "2FA:"
|
||||||
|
|
||||||
|
Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "request"
|
||||||
|
|
||||||
|
enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2FARequested && !user.isLogin2PasswordRequested
|
||||||
|
onClicked: {
|
||||||
|
root.backend.login2FARequested(user.username)
|
||||||
|
user.isLogin2FARequested = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "error"
|
||||||
|
|
||||||
|
enabled: user !== undefined //&& user.isLogin2FAProvided && !(user.isLogin2PasswordRequested && !user.isLogin2PasswordProvided)
|
||||||
|
onClicked: {
|
||||||
|
root.backend.login2FAError("")
|
||||||
|
user.isLogin2FAProvided = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "Abort"
|
||||||
|
|
||||||
|
enabled: user !== undefined //&& user.isLogin2FAProvided && !(user.isLogin2PasswordRequested && !user.isLogin2PasswordProvided)
|
||||||
|
onClicked: {
|
||||||
|
root.backend.login2FAErrorAbort("")
|
||||||
|
user.resetLoginRequests()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
id: passLabel
|
||||||
|
text: "2 Password:"
|
||||||
|
|
||||||
|
Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "request"
|
||||||
|
|
||||||
|
enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2PasswordRequested && !(user.isLogin2FARequested && !user.isLogin2FAProvided)
|
||||||
|
onClicked: {
|
||||||
|
root.backend.login2PasswordRequested("")
|
||||||
|
user.isLogin2PasswordRequested = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "error"
|
||||||
|
|
||||||
|
enabled: user !== undefined //&& user.isLogin2PasswordProvided && !(user.isLogin2FARequested && !user.isLogin2FAProvided)
|
||||||
|
onClicked: {
|
||||||
|
root.backend.login2PasswordError("")
|
||||||
|
|
||||||
|
user.isLogin2PasswordProvided = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "Abort"
|
||||||
|
|
||||||
|
enabled: user !== undefined //&& user.isLogin2PasswordProvided && !(user.isLogin2FARequested && !user.isLogin2FAProvided)
|
||||||
|
onClicked: {
|
||||||
|
root.backend.login2PasswordErrorAbort("")
|
||||||
|
user.resetLoginRequests()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "Login Finished"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.backend.loginFinished(0+loginFinishedIndex.text)
|
||||||
|
user.resetLoginRequests()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: loginFinishedIndex
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
label: "Index:"
|
||||||
|
text: root.userIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "Already logged in"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.backend.loginAlreadyLoggedIn(0+loginAlreadyLoggedInIndex.text)
|
||||||
|
user.resetLoginRequests()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: loginAlreadyLoggedInIndex
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
label: "Index:"
|
||||||
|
text: root.userIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
TextField {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
label: "used:"
|
||||||
|
text: user && user.usedBytes ? user.usedBytes : 0
|
||||||
|
onEditingFinished: {
|
||||||
|
user.usedBytes = parseFloat(text)
|
||||||
|
}
|
||||||
|
implicitWidth: 200
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
label: "total:"
|
||||||
|
text: user && user.totalBytes ? user.totalBytes : 0
|
||||||
|
onEditingFinished: {
|
||||||
|
user.totalBytes = parseFloat(text)
|
||||||
|
}
|
||||||
|
implicitWidth: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Label {colorScheme: root.colorScheme; text: "Split mode"}
|
||||||
|
Toggle { colorScheme: root.colorScheme; checked: user ? user.splitMode : false; onClicked: {user.splitMode = !user.splitMode}}
|
||||||
|
Button { colorScheme: root.colorScheme; text: "Toggle Finished"; onClicked: {user.toggleSplitModeFinished()}}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextArea { // TODO: this is causing binding loop on imlicitWidth
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: user && user.addresses ? user.addresses.join("\n") : "user@protonmail.com"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
user.addresses = text.split("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
}
|
||||||
102
internal/frontend/qml/BridgeTest/UserList.qml
Normal file
102
internal/frontend/qml/BridgeTest/UserList.qml
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Copyright (c) 2022 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/>.
|
||||||
|
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
|
||||||
|
import Proton 4.0
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property ColorScheme colorScheme
|
||||||
|
property var backend
|
||||||
|
|
||||||
|
property alias currentIndex: usersListView.currentIndex
|
||||||
|
ListView {
|
||||||
|
id: usersListView
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: 200
|
||||||
|
|
||||||
|
model: backend.usersTest
|
||||||
|
highlightFollowsCurrentItem: true
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
|
||||||
|
implicitHeight: children[0].implicitHeight + anchors.topMargin + anchors.bottomMargin
|
||||||
|
implicitWidth: children[0].implicitWidth + anchors.leftMargin + anchors.rightMargin
|
||||||
|
|
||||||
|
width: usersListView.width
|
||||||
|
|
||||||
|
anchors.margins: 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: modelData.username
|
||||||
|
anchors.margins: 10
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
usersListView.currentIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
highlight: Rectangle {
|
||||||
|
color: root.colorScheme.interaction_default_active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
|
||||||
|
text: "+"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
var newUserObject = backend.userComponent.createObject(backend)
|
||||||
|
newUserObject.username = backend.loginUser.username.length > 0 ? backend.loginUser.username : "test@protonmail.com"
|
||||||
|
newUserObject.loggedIn = true
|
||||||
|
newUserObject.setupGuideSeen = true // backend.loginUser.setupGuideSeen
|
||||||
|
|
||||||
|
backend.loginUser.username = ""
|
||||||
|
backend.loginUser.loggedIn = false
|
||||||
|
backend.loginUser.setupGuideSeen = false
|
||||||
|
|
||||||
|
backend.users.append( { object: newUserObject } )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
colorScheme: root.colorScheme
|
||||||
|
text: "-"
|
||||||
|
|
||||||
|
enabled: usersListView.currentIndex != 0
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
// var userObject = backend.users.get(usersListView.currentIndex - 1)
|
||||||
|
backend.users.remove(usersListView.currentIndex - 1)
|
||||||
|
// userObject.deleteLater()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
internal/frontend/qml/BridgeTest/UserModel.qml
Normal file
28
internal/frontend/qml/BridgeTest/UserModel.qml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) 2022 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/>.
|
||||||
|
|
||||||
|
import QtQml.Models 2.12
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
// overriding get method to ignore any role and return directly object itself
|
||||||
|
function get(row) {
|
||||||
|
if (row < 0 || row >= count) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return data(index(row, 0), Qt.DisplayRole)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,430 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import ProtonUI 1.0
|
|
||||||
import BridgeUI 1.0
|
|
||||||
|
|
||||||
// NOTE: Keep the Column so the height and width is inherited from content
|
|
||||||
Column {
|
|
||||||
id: root
|
|
||||||
state: status
|
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
property int row_width: 50 * Style.px
|
|
||||||
property int row_height: Style.accounts.heightAccount
|
|
||||||
property var listalias : aliases.split(";")
|
|
||||||
property int iAccount: index
|
|
||||||
|
|
||||||
Accessible.role: go.goos=="windows" ? Accessible.Grouping : Accessible.Row
|
|
||||||
Accessible.name: qsTr("Account %1, status %2", "Accessible text describing account row with arguments: account name and status (connected/disconnected), resp.").arg(account).arg(statusMark.text)
|
|
||||||
Accessible.description: Accessible.name
|
|
||||||
Accessible.ignored: !enabled || !visible
|
|
||||||
|
|
||||||
// Main row
|
|
||||||
Rectangle {
|
|
||||||
id: mainaccRow
|
|
||||||
anchors.left: parent.left
|
|
||||||
width : row_width
|
|
||||||
height : row_height
|
|
||||||
state: { return isExpanded ? "expanded" : "collapsed" }
|
|
||||||
color: Style.main.background
|
|
||||||
|
|
||||||
property string actionName : (
|
|
||||||
isExpanded ?
|
|
||||||
qsTr("Collapse row for account %2", "Accessible text of button showing additional configuration of account") :
|
|
||||||
qsTr("Expand row for account %2", "Accessible text of button hiding additional configuration of account")
|
|
||||||
). arg(account)
|
|
||||||
|
|
||||||
|
|
||||||
// override by other buttons
|
|
||||||
MouseArea {
|
|
||||||
id: mouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked : {
|
|
||||||
if (root.state=="connected") {
|
|
||||||
mainaccRow.toggle_accountSettings()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursorShape : root.state == "connected" ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
hoverEnabled: true
|
|
||||||
onEntered: {
|
|
||||||
if (mainaccRow.state=="collapsed") {
|
|
||||||
mainaccRow.color = Qt.lighter(Style.main.background,1.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onExited: {
|
|
||||||
if (mainaccRow.state=="collapsed") {
|
|
||||||
mainaccRow.color = Style.main.background
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// toggle down/up icon
|
|
||||||
Text {
|
|
||||||
id: toggleIcon
|
|
||||||
anchors {
|
|
||||||
left : parent.left
|
|
||||||
verticalCenter : parent.verticalCenter
|
|
||||||
leftMargin : Style.main.leftMargin
|
|
||||||
}
|
|
||||||
color: Style.main.text
|
|
||||||
font {
|
|
||||||
pointSize : Style.accounts.sizeChevron * Style.pt
|
|
||||||
family : Style.fontawesome.name
|
|
||||||
}
|
|
||||||
text: Style.fa.chevron_down
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
Accessible.role: Accessible.Button
|
|
||||||
Accessible.name: mainaccRow.actionName
|
|
||||||
Accessible.description: mainaccRow.actionName
|
|
||||||
Accessible.onPressAction : mainaccRow.toggle_accountSettings()
|
|
||||||
Accessible.ignored: root.state!="connected" || !root.enabled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// account name
|
|
||||||
TextMetrics {
|
|
||||||
id: accountMetrics
|
|
||||||
font : accountName.font
|
|
||||||
elide: Qt.ElideMiddle
|
|
||||||
elideWidth: Style.accounts.elideWidth
|
|
||||||
text: account
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
id: accountName
|
|
||||||
anchors {
|
|
||||||
verticalCenter : parent.verticalCenter
|
|
||||||
left : toggleIcon.left
|
|
||||||
leftMargin : Style.main.leftMargin
|
|
||||||
}
|
|
||||||
color: Style.main.text
|
|
||||||
font {
|
|
||||||
pointSize : (Style.main.fontSize+2*Style.px) * Style.pt
|
|
||||||
}
|
|
||||||
text: accountMetrics.elidedText
|
|
||||||
}
|
|
||||||
|
|
||||||
// status
|
|
||||||
ClickIconText {
|
|
||||||
id: statusMark
|
|
||||||
anchors {
|
|
||||||
verticalCenter : parent.verticalCenter
|
|
||||||
left : parent.left
|
|
||||||
leftMargin : Style.accounts.leftMargin2
|
|
||||||
}
|
|
||||||
text : qsTr("connected", "status of a listed logged-in account")
|
|
||||||
iconText : Style.fa.circle_o
|
|
||||||
textColor : Style.main.textGreen
|
|
||||||
enabled : false
|
|
||||||
Accessible.ignored: true
|
|
||||||
}
|
|
||||||
|
|
||||||
// logout
|
|
||||||
ClickIconText {
|
|
||||||
id: logoutAccount
|
|
||||||
anchors {
|
|
||||||
verticalCenter : parent.verticalCenter
|
|
||||||
left : parent.left
|
|
||||||
leftMargin : Style.accounts.leftMargin3
|
|
||||||
}
|
|
||||||
text : qsTr("Log out", "action to log out a connected account")
|
|
||||||
iconText : Style.fa.power_off
|
|
||||||
textBold : true
|
|
||||||
textColor : Style.main.textBlue
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove
|
|
||||||
ClickIconText {
|
|
||||||
id: deleteAccount
|
|
||||||
anchors {
|
|
||||||
verticalCenter : parent.verticalCenter
|
|
||||||
right : parent.right
|
|
||||||
rightMargin : Style.main.rightMargin
|
|
||||||
}
|
|
||||||
text : qsTr("Remove", "deletes an account from the account settings page")
|
|
||||||
iconText : Style.fa.trash_o
|
|
||||||
textColor : Style.main.text
|
|
||||||
onClicked : {
|
|
||||||
dialogGlobal.input=root.iAccount
|
|
||||||
dialogGlobal.state="deleteUser"
|
|
||||||
dialogGlobal.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// functions
|
|
||||||
function toggle_accountSettings() {
|
|
||||||
if (root.state=="connected") {
|
|
||||||
if (mainaccRow.state=="collapsed" ) {
|
|
||||||
mainaccRow.state="expanded"
|
|
||||||
} else {
|
|
||||||
mainaccRow.state="collapsed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
states: [
|
|
||||||
State {
|
|
||||||
name: "collapsed"
|
|
||||||
PropertyChanges { target : toggleIcon ; text : root.state=="connected" ? Style.fa.chevron_down : " " }
|
|
||||||
PropertyChanges { target : accountName ; font.bold : false }
|
|
||||||
PropertyChanges { target : mainaccRow ; color : Style.main.background }
|
|
||||||
PropertyChanges { target : addressList ; visible : false }
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "expanded"
|
|
||||||
PropertyChanges { target : toggleIcon ; text : Style.fa.chevron_up }
|
|
||||||
PropertyChanges { target : accountName ; font.bold : true }
|
|
||||||
PropertyChanges { target : mainaccRow ; color : Style.accounts.backgroundExpanded }
|
|
||||||
PropertyChanges { target : addressList ; visible : true }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// List of adresses
|
|
||||||
Column {
|
|
||||||
id: addressList
|
|
||||||
anchors.left : parent.left
|
|
||||||
width: row_width
|
|
||||||
visible: false
|
|
||||||
property alias model : repeaterAddresses.model
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: addressModeWrapper
|
|
||||||
anchors {
|
|
||||||
left : parent.left
|
|
||||||
right : parent.right
|
|
||||||
}
|
|
||||||
visible : mainaccRow.state=="expanded"
|
|
||||||
height : 2*Style.accounts.heightAddrRow/3
|
|
||||||
color : Style.accounts.backgroundExpanded
|
|
||||||
|
|
||||||
ClickIconText {
|
|
||||||
id: addressModeSwitch
|
|
||||||
anchors {
|
|
||||||
top : addressModeWrapper.top
|
|
||||||
right : addressModeWrapper.right
|
|
||||||
rightMargin : Style.main.rightMargin
|
|
||||||
}
|
|
||||||
textColor : Style.main.textBlue
|
|
||||||
iconText : Style.fa.exchange
|
|
||||||
iconOnRight : false
|
|
||||||
text : isCombinedAddressMode ?
|
|
||||||
qsTr("Switch to split addresses mode", "Text of button switching to mode with one configuration per each address.") :
|
|
||||||
qsTr("Switch to combined addresses mode", "Text of button switching to mode with one configuration for all addresses.")
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
dialogGlobal.input=root.iAccount
|
|
||||||
dialogGlobal.state="addressmode"
|
|
||||||
dialogGlobal.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ClickIconText {
|
|
||||||
id: combinedAddressConfig
|
|
||||||
anchors {
|
|
||||||
top : addressModeWrapper.top
|
|
||||||
left : addressModeWrapper.left
|
|
||||||
leftMargin : Style.accounts.leftMarginAddr+Style.main.leftMargin
|
|
||||||
}
|
|
||||||
visible : isCombinedAddressMode
|
|
||||||
text : qsTr("Mailbox configuration", "Displays IMAP/SMTP settings information for a given account")
|
|
||||||
iconText : Style.fa.gear
|
|
||||||
textColor : Style.main.textBlue
|
|
||||||
onClicked : {
|
|
||||||
infoWin.showInfo(root.iAccount,0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: repeaterAddresses
|
|
||||||
model: ["one", "two"]
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: addressRow
|
|
||||||
visible: !isCombinedAddressMode
|
|
||||||
anchors {
|
|
||||||
left : parent.left
|
|
||||||
right : parent.right
|
|
||||||
}
|
|
||||||
height: Style.accounts.heightAddrRow
|
|
||||||
color: Style.accounts.backgroundExpanded
|
|
||||||
|
|
||||||
// icon level down
|
|
||||||
Text {
|
|
||||||
id: levelDown
|
|
||||||
anchors {
|
|
||||||
left : parent.left
|
|
||||||
leftMargin : Style.accounts.leftMarginAddr
|
|
||||||
verticalCenter : wrapAddr.verticalCenter
|
|
||||||
}
|
|
||||||
text : Style.fa.level_up
|
|
||||||
font.family : Style.fontawesome.name
|
|
||||||
color : Style.main.textDisabled
|
|
||||||
rotation : 90
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: wrapAddr
|
|
||||||
anchors {
|
|
||||||
top : parent.top
|
|
||||||
left : levelDown.right
|
|
||||||
right : parent.right
|
|
||||||
leftMargin : Style.main.leftMargin
|
|
||||||
rightMargin : Style.main.rightMargin
|
|
||||||
}
|
|
||||||
height: Style.accounts.heightAddr
|
|
||||||
border {
|
|
||||||
width : Style.main.border
|
|
||||||
color : Style.main.line
|
|
||||||
}
|
|
||||||
color: Style.accounts.backgroundAddrRow
|
|
||||||
|
|
||||||
TextMetrics {
|
|
||||||
id: addressMetrics
|
|
||||||
font: address.font
|
|
||||||
elideWidth: 2*wrapAddr.width/3
|
|
||||||
elide: Qt.ElideMiddle
|
|
||||||
text: modelData
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: address
|
|
||||||
anchors {
|
|
||||||
verticalCenter : parent.verticalCenter
|
|
||||||
left: parent.left
|
|
||||||
leftMargin: Style.main.leftMargin
|
|
||||||
}
|
|
||||||
font.pointSize : Style.main.fontSize * Style.pt
|
|
||||||
color: Style.main.text
|
|
||||||
text: addressMetrics.elidedText
|
|
||||||
}
|
|
||||||
|
|
||||||
ClickIconText {
|
|
||||||
id: addressConfig
|
|
||||||
anchors {
|
|
||||||
verticalCenter : parent.verticalCenter
|
|
||||||
right: parent.right
|
|
||||||
rightMargin: Style.main.rightMargin
|
|
||||||
}
|
|
||||||
text : qsTr("Address configuration", "Display the IMAP/SMTP configuration for address")
|
|
||||||
iconText : Style.fa.gear
|
|
||||||
textColor : Style.main.textBlue
|
|
||||||
onClicked : infoWin.showInfo(root.iAccount,index)
|
|
||||||
|
|
||||||
Accessible.description: qsTr("Address configuration for %1", "Accessible text of button displaying the IMAP/SMTP configuration for address %1").arg(modelData)
|
|
||||||
Accessible.ignored: !enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: clickSettings
|
|
||||||
anchors.fill: wrapAddr
|
|
||||||
onClicked : addressConfig.clicked()
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
hoverEnabled: true
|
|
||||||
onPressed: {
|
|
||||||
wrapAddr.color = Qt.rgba(1,1,1,0.20)
|
|
||||||
}
|
|
||||||
onEntered: {
|
|
||||||
wrapAddr.color = Qt.rgba(1,1,1,0.15)
|
|
||||||
}
|
|
||||||
onExited: {
|
|
||||||
wrapAddr.color = Style.accounts.backgroundAddrRow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: line
|
|
||||||
color: Style.accounts.line
|
|
||||||
height: Style.accounts.heightLine
|
|
||||||
width: root.row_width
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
states: [
|
|
||||||
State {
|
|
||||||
name: "connected"
|
|
||||||
PropertyChanges {
|
|
||||||
target : addressList
|
|
||||||
model : listalias
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target : toggleIcon
|
|
||||||
color : Style.main.text
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target : accountName
|
|
||||||
color : Style.main.text
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target : statusMark
|
|
||||||
textColor : Style.main.textGreen
|
|
||||||
text : qsTr("connected", "status of a listed logged-in account")
|
|
||||||
iconText : Style.fa.circle
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target : logoutAccount
|
|
||||||
text : qsTr("Log out", "action to log out a connected account")
|
|
||||||
onClicked : {
|
|
||||||
mainaccRow.state="collapsed"
|
|
||||||
dialogGlobal.input = root.iAccount
|
|
||||||
dialogGlobal.state = "logout"
|
|
||||||
dialogGlobal.show()
|
|
||||||
dialogGlobal.confirmed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "disconnected"
|
|
||||||
PropertyChanges {
|
|
||||||
target : addressList
|
|
||||||
model : 0
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target : toggleIcon
|
|
||||||
color : Style.main.textDisabled
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target : accountName
|
|
||||||
color : Style.main.textDisabled
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target : statusMark
|
|
||||||
textColor : Style.main.textDisabled
|
|
||||||
text : qsTr("disconnected", "status of a listed logged-out account")
|
|
||||||
iconText : Style.fa.circle_o
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target : logoutAccount
|
|
||||||
text : qsTr("Log in", "action to log in a disconnected account")
|
|
||||||
onClicked : {
|
|
||||||
dialogAddUser.username = root.listalias[0]
|
|
||||||
dialogAddUser.show()
|
|
||||||
dialogAddUser.inputPassword.focusInput = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Dialog with main menu
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import BridgeUI 1.0
|
|
||||||
import ProtonUI 1.0
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: root
|
|
||||||
color: "#aaff5577"
|
|
||||||
anchors {
|
|
||||||
left : tabbar.left
|
|
||||||
right : tabbar.right
|
|
||||||
top : tabbar.bottom
|
|
||||||
bottom : parent.bottom
|
|
||||||
}
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: toggle()
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color : Style.menu.background
|
|
||||||
radius : Style.menu.radius
|
|
||||||
width : Style.menu.width
|
|
||||||
height : Style.menu.height
|
|
||||||
anchors {
|
|
||||||
top : parent.top
|
|
||||||
right : parent.right
|
|
||||||
topMargin : Style.menu.topMargin
|
|
||||||
rightMargin : Style.menu.rightMargin
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: qsTr("About")
|
|
||||||
color: Style.menu.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle(){
|
|
||||||
if (root.visible == false) {
|
|
||||||
root.visible = true
|
|
||||||
} else {
|
|
||||||
root.visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import BridgeUI 1.0
|
|
||||||
import ProtonUI 1.0
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: Style.main.width
|
|
||||||
height: 3*Style.main.height/4
|
|
||||||
color: "transparent"
|
|
||||||
//color: "red"
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
anchors.fill: parent
|
|
||||||
clip : true
|
|
||||||
model : go.credits.split(";")
|
|
||||||
|
|
||||||
delegate: AccessibleText {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: modelData
|
|
||||||
color: Style.main.text
|
|
||||||
font.pointSize : Style.main.fontSize * Style.pt
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: ButtonRounded {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: qsTr("Close", "close window")
|
|
||||||
onClicked: dialogCredits.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Dialog with Yes/No buttons
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import ProtonUI 1.0
|
|
||||||
|
|
||||||
Dialog {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
title : ""
|
|
||||||
isDialogBusy: false
|
|
||||||
property string firstParagraph : qsTr("The Bridge is an application that runs on your computer in the background and seamlessly encrypts and decrypts your mail as it enters and leaves your computer.", "instructions that appear on welcome screen at first start")
|
|
||||||
property string secondParagraph : qsTr("To add your ProtonMail account to the Bridge and <strong>generate your Bridge password</strong>, please see <a href=\"https://protonmail.com/bridge/install\">the installation guide</a> for detailed setup instructions.", "confirms and dismisses a notification (URL that leads to installation guide should stay intact)")
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: dialogMessage
|
|
||||||
property int heightInputs : welcome.height + middleSep.height + instructions.height + buttSep.height + buttonOkay.height + imageSep.height + logo.height
|
|
||||||
|
|
||||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-dialogMessage.heightInputs)/2 }
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id:welcome
|
|
||||||
color: Style.main.text
|
|
||||||
font.bold: true
|
|
||||||
font.pointSize: 1.5*Style.main.fontSize*Style.pt
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
text: qsTr("Welcome to the", "welcome screen that appears on first start")
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {id: imageSep; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator }
|
|
||||||
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
spacing: Style.dialog.spacing
|
|
||||||
Image {
|
|
||||||
id: logo
|
|
||||||
anchors.bottom : pmbridge.baseline
|
|
||||||
height : 2*Style.main.fontSize
|
|
||||||
fillMode : Image.PreserveAspectFit
|
|
||||||
mipmap : true
|
|
||||||
source : "../ProtonUI/images/pm_logo.png"
|
|
||||||
}
|
|
||||||
AccessibleText {
|
|
||||||
id:pmbridge
|
|
||||||
color: Style.main.text
|
|
||||||
font.bold: true
|
|
||||||
font.pointSize: 2.2*Style.main.fontSize*Style.pt
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
text: qsTr("ProtonMail Bridge", "app title")
|
|
||||||
|
|
||||||
Accessible.name: this.clearText(pmbridge.text)
|
|
||||||
Accessible.description: this.clearText(welcome.text+ " " + pmbridge.text + ". " + root.firstParagraph + ". " + root.secondParagraph)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Rectangle { id:middleSep; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator }
|
|
||||||
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id:instructions
|
|
||||||
color: Style.main.text
|
|
||||||
font.pointSize: Style.main.fontSize*Style.pt
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
width: root.width/1.5
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
textFormat: Text.RichText
|
|
||||||
text: "<html><style>a { color: "+Style.main.textBlue+"; text-decoration: none;}</style><body>"+
|
|
||||||
root.firstParagraph +
|
|
||||||
"<br/><br/>"+
|
|
||||||
root.secondParagraph +
|
|
||||||
"</body></html>"
|
|
||||||
onLinkActivated: {
|
|
||||||
Qt.openUrlExternally(link)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { id:buttSep; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
|
||||||
|
|
||||||
|
|
||||||
ButtonRounded {
|
|
||||||
id:buttonOkay
|
|
||||||
color_main: Style.dialog.text
|
|
||||||
color_minor: Style.main.textBlue
|
|
||||||
isOpaque: true
|
|
||||||
fa_icon: Style.fa.check
|
|
||||||
text: qsTr("Okay", "confirms and dismisses a notification")
|
|
||||||
onClicked : root.hide()
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.interval : 3000
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: timer
|
|
||||||
onTriggered: {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onShow : {
|
|
||||||
pmbridge.Accessible.selected = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,194 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Change default keychain dialog
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import BridgeUI 1.0
|
|
||||||
import ProtonUI 1.0
|
|
||||||
import QtQuick.Controls 2.2 as QC
|
|
||||||
import QtQuick.Layouts 1.0
|
|
||||||
|
|
||||||
Dialog {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
title : "Change which keychain Bridge uses as default"
|
|
||||||
subtitle : "Select which keychain is used (Bridge will automatically restart)"
|
|
||||||
isDialogBusy: currentIndex==1
|
|
||||||
|
|
||||||
property var selectedKeychain
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: go.selectedKeychain
|
|
||||||
onValueChanged: {
|
|
||||||
console.debug("go.selectedKeychain == ", go.selectedKeychain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.minimumHeight: root.titleHeight + Style.dialog.heightSeparator
|
|
||||||
Layout.maximumHeight: root.titleHeight + Style.dialog.heightSeparator
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: keychainRadioButtons
|
|
||||||
model: go.availableKeychain
|
|
||||||
QC.RadioButton {
|
|
||||||
id: radioDelegate
|
|
||||||
text: modelData
|
|
||||||
checked: go.selectedKeychain === modelData
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
spacing: Style.main.spacing
|
|
||||||
|
|
||||||
indicator: Text {
|
|
||||||
text : radioDelegate.checked ? Style.fa.check_circle : Style.fa.circle_o
|
|
||||||
color : radioDelegate.checked ? Style.main.textBlue : Style.main.textInactive
|
|
||||||
font {
|
|
||||||
pointSize: Style.dialog.iconSize * Style.pt
|
|
||||||
family: Style.fontawesome.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contentItem: Text {
|
|
||||||
text: radioDelegate.text
|
|
||||||
color: Style.main.text
|
|
||||||
font {
|
|
||||||
pointSize: Style.dialog.fontSize * Style.pt
|
|
||||||
bold: checked
|
|
||||||
}
|
|
||||||
horizontalAlignment : Text.AlignHCenter
|
|
||||||
verticalAlignment : Text.AlignVCenter
|
|
||||||
leftPadding: Style.dialog.iconSize
|
|
||||||
}
|
|
||||||
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked) {
|
|
||||||
root.selectedKeychain = modelData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.minimumHeight: Style.dialog.heightSeparator
|
|
||||||
Layout.maximumHeight: Style.dialog.heightSeparator
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttonRow
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
spacing: Style.dialog.spacing
|
|
||||||
ButtonRounded {
|
|
||||||
id:buttonNo
|
|
||||||
color_main: Style.dialog.text
|
|
||||||
fa_icon: Style.fa.times
|
|
||||||
text: qsTr("Cancel", "dismisses current action")
|
|
||||||
onClicked : root.hide()
|
|
||||||
}
|
|
||||||
ButtonRounded {
|
|
||||||
id: buttonYes
|
|
||||||
color_main: Style.dialog.text
|
|
||||||
color_minor: Style.main.textBlue
|
|
||||||
isOpaque: true
|
|
||||||
fa_icon: Style.fa.check
|
|
||||||
text: qsTr("Okay", "confirms and dismisses a notification")
|
|
||||||
onClicked : root.confirmed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.minimumHeight: root.titleHeight + Style.dialog.heightSeparator
|
|
||||||
Layout.maximumHeight: root.titleHeight + Style.dialog.heightSeparator
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: answ
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width : parent.width/2
|
|
||||||
color: Style.dialog.text
|
|
||||||
font {
|
|
||||||
pointSize : Style.dialog.fontSize * Style.pt
|
|
||||||
bold : true
|
|
||||||
}
|
|
||||||
text : "Default keychain is now set to " + root.selectedKeychain +
|
|
||||||
"\n\n" +
|
|
||||||
qsTr("Settings will be applied after the next start.", "notification about setting being applied after next start") +
|
|
||||||
"\n\n" +
|
|
||||||
qsTr("Bridge will now restart.", "notification about restarting")
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: StandardKey.Cancel
|
|
||||||
onActivated: root.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: "Enter"
|
|
||||||
onActivated: root.confirmed()
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmed() {
|
|
||||||
if (selectedKeychain === go.selectedKeychain) {
|
|
||||||
root.hide()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
incrementCurrentIndex()
|
|
||||||
timer.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.interval : 5000
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: timer
|
|
||||||
onTriggered: {
|
|
||||||
// This action triggers restart on the backend side.
|
|
||||||
go.selectedKeychain = selectedKeychain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,233 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Dialog with Yes/No buttons
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import BridgeUI 1.0
|
|
||||||
import ProtonUI 1.0
|
|
||||||
import QtQuick.Controls 2.2 as QC
|
|
||||||
|
|
||||||
Dialog {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
title : "Set IMAP & SMTP settings"
|
|
||||||
subtitle : "Changes require reconfiguration of Mail client. (Bridge will automatically restart)"
|
|
||||||
isDialogBusy: currentIndex==1
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: dialogMessage
|
|
||||||
property int heightInputs : imapPort.height + middleSep.height + smtpPort.height + buttonSep.height + buttonRow.height + secSMTPSep.height + securitySMTP.height
|
|
||||||
|
|
||||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-dialogMessage.heightInputs)/1.6 }
|
|
||||||
|
|
||||||
InputField {
|
|
||||||
id: imapPort
|
|
||||||
iconText : Style.fa.hashtag
|
|
||||||
label : qsTr("IMAP port", "entry field to choose port used for the IMAP server")
|
|
||||||
text : "undef"
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { id:middleSep; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator }
|
|
||||||
|
|
||||||
InputField {
|
|
||||||
id: smtpPort
|
|
||||||
iconText : Style.fa.hashtag
|
|
||||||
label : qsTr("SMTP port", "entry field to choose port used for the SMTP server")
|
|
||||||
text : "undef"
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { id:secSMTPSep; color : Style.transparent; width : Style.main.dummy; height : Style.dialog.heightSeparator }
|
|
||||||
|
|
||||||
// SSL button group
|
|
||||||
Rectangle {
|
|
||||||
anchors.horizontalCenter : parent.horizontalCenter
|
|
||||||
width : Style.dialog.widthInput
|
|
||||||
height : securitySMTPLabel.height + securitySMTP.height
|
|
||||||
color : "transparent"
|
|
||||||
|
|
||||||
AccessibleText {
|
|
||||||
id: securitySMTPLabel
|
|
||||||
anchors.left : parent.left
|
|
||||||
text:qsTr("SMTP connection mode")
|
|
||||||
color: Style.dialog.text
|
|
||||||
font {
|
|
||||||
pointSize : Style.dialog.fontSize * Style.pt
|
|
||||||
bold : true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QC.ButtonGroup {
|
|
||||||
buttons: securitySMTP.children
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
id: securitySMTP
|
|
||||||
spacing: Style.dialog.spacing
|
|
||||||
anchors.top: securitySMTPLabel.bottom
|
|
||||||
anchors.topMargin: Style.dialog.fontSize
|
|
||||||
|
|
||||||
CheckBoxLabel {
|
|
||||||
id: securitySMTPSSL
|
|
||||||
text: qsTr("SSL")
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckBoxLabel {
|
|
||||||
checked: true
|
|
||||||
id: securitySMTPSTARTTLS
|
|
||||||
text: qsTr("STARTTLS")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { id:buttonSep; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttonRow
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
spacing: Style.dialog.spacing
|
|
||||||
ButtonRounded {
|
|
||||||
id:buttonNo
|
|
||||||
color_main: Style.dialog.text
|
|
||||||
fa_icon: Style.fa.times
|
|
||||||
text: qsTr("Cancel", "dismisses current action")
|
|
||||||
onClicked : root.hide()
|
|
||||||
}
|
|
||||||
ButtonRounded {
|
|
||||||
id: buttonYes
|
|
||||||
color_main: Style.dialog.text
|
|
||||||
color_minor: Style.main.textBlue
|
|
||||||
isOpaque: true
|
|
||||||
fa_icon: Style.fa.check
|
|
||||||
text: qsTr("Okay", "confirms and dismisses a notification")
|
|
||||||
onClicked : root.confirmed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-answ.height)/2 }
|
|
||||||
Text {
|
|
||||||
id: answ
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
width : parent.width/2
|
|
||||||
color: Style.dialog.text
|
|
||||||
font {
|
|
||||||
pointSize : Style.dialog.fontSize * Style.pt
|
|
||||||
bold : true
|
|
||||||
}
|
|
||||||
text : "IMAP: " + imapPort.text + "\nSMTP: " + smtpPort.text + "\nSMTP Connection Mode: " + getSelectedSSLMode() + "\n\n" +
|
|
||||||
qsTr("Settings will be applied after the next start. You will need to reconfigure your email client(s).", "after user changes their ports they will see this notification to reconfigure their setup") +
|
|
||||||
"\n\n" +
|
|
||||||
qsTr("Bridge will now restart.", "after user changes their ports this appears to notify the user of restart")
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function areInputsOK() {
|
|
||||||
var isOK = true
|
|
||||||
var imapUnchanged = false
|
|
||||||
var secSMTPUnchanged = (securitySMTPSTARTTLS.checked == go.isSMTPSTARTTLS())
|
|
||||||
root.warning.text = ""
|
|
||||||
|
|
||||||
if (imapPort.text!=go.getIMAPPort()) {
|
|
||||||
if (go.isPortOpen(imapPort.text)!=0) {
|
|
||||||
imapPort.rightIcon = Style.fa.exclamation_triangle
|
|
||||||
root.warning.text = qsTr("Port number is not available.", "if the user changes one of their ports to a port that is occupied by another application")
|
|
||||||
isOK=false
|
|
||||||
} else {
|
|
||||||
imapPort.rightIcon = Style.fa.check_circle
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
imapPort.rightIcon = ""
|
|
||||||
imapUnchanged = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (smtpPort.text!=go.getSMTPPort()) {
|
|
||||||
if (go.isPortOpen(smtpPort.text)!=0) {
|
|
||||||
smtpPort.rightIcon = Style.fa.exclamation_triangle
|
|
||||||
root.warning.text = qsTr("Port number is not available.", "if the user changes one of their ports to a port that is occupied by another application")
|
|
||||||
isOK=false
|
|
||||||
} else {
|
|
||||||
smtpPort.rightIcon = Style.fa.check_circle
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
smtpPort.rightIcon = ""
|
|
||||||
if (imapUnchanged && secSMTPUnchanged) {
|
|
||||||
root.warning.text = qsTr("Please change at least one port number or SMTP security.", "if the user tries to change IMAP/SMTP ports to the same ports as before")
|
|
||||||
isOK=false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imapPort.text == smtpPort.text) {
|
|
||||||
smtpPort.rightIcon = Style.fa.exclamation_triangle
|
|
||||||
root.warning.text = qsTr("Port numbers must be different.", "if the user sets both the IMAP and SMTP ports to the same number")
|
|
||||||
isOK=false
|
|
||||||
}
|
|
||||||
|
|
||||||
root.warning.visible = !isOK
|
|
||||||
return isOK
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmed() {
|
|
||||||
if (areInputsOK()) {
|
|
||||||
incrementCurrentIndex()
|
|
||||||
timer.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSelectedSSLMode() {
|
|
||||||
if (securitySMTPSTARTTLS.checked == true) {
|
|
||||||
return "STARTTLS"
|
|
||||||
} else {
|
|
||||||
return "SSL"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onShow : {
|
|
||||||
imapPort.text = go.getIMAPPort()
|
|
||||||
smtpPort.text = go.getSMTPPort()
|
|
||||||
if (go.isSMTPSTARTTLS()) {
|
|
||||||
securitySMTPSTARTTLS.checked = true
|
|
||||||
} else {
|
|
||||||
securitySMTPSSL.checked = true
|
|
||||||
}
|
|
||||||
areInputsOK()
|
|
||||||
root.warning.visible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: StandardKey.Cancel
|
|
||||||
onActivated: root.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: "Enter"
|
|
||||||
onActivated: root.confirmed()
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.interval : 3000
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: timer
|
|
||||||
onTriggered: {
|
|
||||||
go.setPortsAndSecurity(imapPort.text, smtpPort.text, securitySMTPSTARTTLS.checked)
|
|
||||||
go.setToRestart()
|
|
||||||
Qt.quit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import BridgeUI 1.0
|
|
||||||
import ProtonUI 1.0
|
|
||||||
|
|
||||||
|
|
||||||
Dialog {
|
|
||||||
id: root
|
|
||||||
title: qsTr("Connection security error", "Title of modal explainning TLS issue")
|
|
||||||
|
|
||||||
property string par1Title : qsTr("Description:", "Title of paragraph describing the issue")
|
|
||||||
property string par1Text : qsTr (
|
|
||||||
"ProtonMail Bridge was not able to establish a secure connection to Proton servers due to a TLS certificate error. "+
|
|
||||||
"This means your connection may potentially be insecure and susceptible to monitoring by third parties.",
|
|
||||||
"A paragraph describing the issue"
|
|
||||||
)
|
|
||||||
|
|
||||||
property string par2Title : qsTr("Recommendation:", "Title of paragraph describing recommended steps")
|
|
||||||
property string par2Text : qsTr (
|
|
||||||
"If you are on a corporate or public network, the network administrator may be monitoring or intercepting all traffic.",
|
|
||||||
"A paragraph describing network issue"
|
|
||||||
)
|
|
||||||
property string par2ul1 : qsTr(
|
|
||||||
"If you trust your network operator, you can continue to use ProtonMail as usual.",
|
|
||||||
"A list item describing recomendation for trusted network"
|
|
||||||
)
|
|
||||||
|
|
||||||
property string par2ul2 : qsTr(
|
|
||||||
"If you don't trust your network operator, reconnect to ProtonMail over a VPN (such as ProtonVPN) "+
|
|
||||||
"which encrypts your Internet connection, or use a different network to access ProtonMail.",
|
|
||||||
"A list item describing recomendation for untrusted network"
|
|
||||||
)
|
|
||||||
property string par3Text : qsTr("Learn more on our knowledge base article","A paragraph describing where to find more information")
|
|
||||||
property string kbArticleText : qsTr("What is TLS certificate error.", "Link text for knowledge base article")
|
|
||||||
property string kbArticleLink : "https://protonmail.com/support/knowledge-base/"
|
|
||||||
|
|
||||||
|
|
||||||
Item {
|
|
||||||
AccessibleText {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
color: Style.old.pm_white
|
|
||||||
linkColor: color
|
|
||||||
width: parent.width - 50 * Style.px
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
font.pointSize: Style.main.fontSize*Style.pt
|
|
||||||
onLinkActivated: Qt.openUrlExternally(link)
|
|
||||||
text: "<h3>"+par1Title+"</h3>"+
|
|
||||||
par1Text+"<br>\n"+
|
|
||||||
"<h3>"+par2Title+"</h3>"+
|
|
||||||
par2Text+
|
|
||||||
"<ul>"+
|
|
||||||
"<li>"+par2ul1+"</li>"+
|
|
||||||
"<li>"+par2ul2+"</li>"+
|
|
||||||
"</ul>"+"<br>\n"+
|
|
||||||
""
|
|
||||||
//par3Text+
|
|
||||||
//" <a href='"+kbArticleLink+"'>"+kbArticleText+"</a>\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,403 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Dialog with Yes/No buttons
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import BridgeUI 1.0
|
|
||||||
import ProtonUI 1.0
|
|
||||||
|
|
||||||
Dialog {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
title : ""
|
|
||||||
|
|
||||||
property string input
|
|
||||||
|
|
||||||
property alias question : msg.text
|
|
||||||
property alias note : noteText.text
|
|
||||||
property alias answer : answ.text
|
|
||||||
property alias buttonYes : buttonYes
|
|
||||||
property alias buttonNo : buttonNo
|
|
||||||
|
|
||||||
isDialogBusy: currentIndex==1
|
|
||||||
|
|
||||||
signal confirmed()
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: dialogMessage
|
|
||||||
property int heightInputs : msg.height+
|
|
||||||
middleSep.height+
|
|
||||||
buttonRow.height +
|
|
||||||
(checkboxSep.visible ? checkboxSep.height : 0 ) +
|
|
||||||
(noteSep.visible ? noteSep.height : 0 ) +
|
|
||||||
(checkBoxWrapper.visible ? checkBoxWrapper.height : 0 ) +
|
|
||||||
(root.note!="" ? noteText.height : 0 )
|
|
||||||
|
|
||||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-dialogMessage.heightInputs)/2 }
|
|
||||||
|
|
||||||
AccessibleText {
|
|
||||||
id:noteText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: Style.dialog.text
|
|
||||||
font {
|
|
||||||
pointSize: Style.dialog.fontSize * Style.pt
|
|
||||||
bold: false
|
|
||||||
}
|
|
||||||
width: 2*root.width/3
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
}
|
|
||||||
Rectangle { id: noteSep; visible: note!=""; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator}
|
|
||||||
|
|
||||||
AccessibleText {
|
|
||||||
id: msg
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: Style.dialog.text
|
|
||||||
font {
|
|
||||||
pointSize: Style.dialog.fontSize * Style.pt
|
|
||||||
bold: true
|
|
||||||
}
|
|
||||||
width: 2*parent.width/3
|
|
||||||
text : ""
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { id: checkboxSep; visible: checkBoxWrapper.visible; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator}
|
|
||||||
Row {
|
|
||||||
id: checkBoxWrapper
|
|
||||||
property bool isChecked : false
|
|
||||||
visible: root.state=="deleteUser"
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
spacing: Style.dialog.spacing
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
checkBoxWrapper.isChecked = !checkBoxWrapper.isChecked
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: checkbox
|
|
||||||
font {
|
|
||||||
pointSize : Style.dialog.iconSize * Style.pt
|
|
||||||
family : Style.fontawesome.name
|
|
||||||
}
|
|
||||||
anchors.verticalCenter : parent.verticalCenter
|
|
||||||
text: checkBoxWrapper.isChecked ? Style.fa.check_square_o : Style.fa.square_o
|
|
||||||
color: checkBoxWrapper.isChecked ? Style.main.textBlue : Style.main.text
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onPressed: checkBoxWrapper.toggle()
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
id: checkBoxNote
|
|
||||||
anchors.verticalCenter : parent.verticalCenter
|
|
||||||
text: qsTr("Additionally delete all stored preferences and data", "when removing an account, this extra preference additionally deletes all cached data")
|
|
||||||
color: Style.main.text
|
|
||||||
font.pointSize: Style.dialog.fontSize * Style.pt
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onPressed: checkBoxWrapper.toggle()
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
|
|
||||||
Accessible.role: Accessible.CheckBox
|
|
||||||
Accessible.checked: checkBoxWrapper.isChecked
|
|
||||||
Accessible.name: checkBoxNote.text
|
|
||||||
Accessible.description: checkBoxNote.text
|
|
||||||
Accessible.ignored: checkBoxNote.text == ""
|
|
||||||
Accessible.onToggleAction: checkBoxWrapper.toggle()
|
|
||||||
Accessible.onPressAction: checkBoxWrapper.toggle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { id: middleSep; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttonRow
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
spacing: Style.dialog.spacing
|
|
||||||
ButtonRounded {
|
|
||||||
id:buttonNo
|
|
||||||
visible: root.state != "toggleEarlyAccess"
|
|
||||||
color_main: Style.dialog.text
|
|
||||||
fa_icon: Style.fa.times
|
|
||||||
text: qsTr("No")
|
|
||||||
onClicked : root.hide()
|
|
||||||
}
|
|
||||||
ButtonRounded {
|
|
||||||
id: buttonYes
|
|
||||||
color_main: Style.dialog.text
|
|
||||||
color_minor: Style.main.textBlue
|
|
||||||
isOpaque: true
|
|
||||||
fa_icon: Style.fa.check
|
|
||||||
text: root.state == "toggleEarlyAccess" ? qsTr("Ok") : qsTr("Yes")
|
|
||||||
onClicked : {
|
|
||||||
currentIndex=1
|
|
||||||
root.confirmed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Column {
|
|
||||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-answ.height)/2 }
|
|
||||||
AccessibleText {
|
|
||||||
id: answ
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: Style.old.pm_white
|
|
||||||
font {
|
|
||||||
pointSize : Style.dialog.fontSize * Style.pt
|
|
||||||
bold : true
|
|
||||||
}
|
|
||||||
width: 3*parent.width/4
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
text : qsTr("Waiting...", "in general this displays between screens when processing data takes a long time")
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
states : [
|
|
||||||
State {
|
|
||||||
name: "quit"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 0
|
|
||||||
title : qsTr("Close Bridge", "quits the application")
|
|
||||||
question : qsTr("Are you sure you want to close the Bridge?", "asked when user tries to quit the application")
|
|
||||||
note : ""
|
|
||||||
answer : qsTr("Closing Bridge...", "displayed when user is quitting application")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "logout"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 1
|
|
||||||
title : qsTr("Logout", "title of page that displays during account logout")
|
|
||||||
question : ""
|
|
||||||
note : ""
|
|
||||||
answer : qsTr("Logging out...", "displays during account logout")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "deleteUser"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 0
|
|
||||||
title : qsTr("Delete account", "title of page that displays during account deletion")
|
|
||||||
question : qsTr("Are you sure you want to remove this account?", "displays during account deletion")
|
|
||||||
note : ""
|
|
||||||
answer : qsTr("Deleting ...", "displays during account deletion")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "clearChain"
|
|
||||||
PropertyChanges {
|
|
||||||
target : root
|
|
||||||
currentIndex : 0
|
|
||||||
title : qsTr("Clear keychain", "title of page that displays during keychain clearing")
|
|
||||||
question : qsTr("Are you sure you want to clear your keychain?", "displays during keychain clearing")
|
|
||||||
note : qsTr("This will remove all accounts that you have added to the Bridge and disconnect you from your email client(s).", "displays during keychain clearing")
|
|
||||||
answer : qsTr("Clearing the keychain ...", "displays during keychain clearing")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "clearCache"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 0
|
|
||||||
title : qsTr("Clear cache", "title of page that displays during cache clearing")
|
|
||||||
question : qsTr("Are you sure you want to clear your local cache?", "displays during cache clearing")
|
|
||||||
note : qsTr("This will delete all of your stored preferences as well as cached email data for all accounts, and requires you to reconfigure your client.", "displays during cache clearing")
|
|
||||||
answer : qsTr("Clearing the cache ...", "displays during cache clearing")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "checkUpdates"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 1
|
|
||||||
title : ""
|
|
||||||
question : ""
|
|
||||||
note : ""
|
|
||||||
answer : qsTr("Checking for updates ...", "displays if user clicks the Check for Updates button in the Help tab")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "addressmode"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 0
|
|
||||||
title : ""
|
|
||||||
question : qsTr("Do you want to continue?", "asked when the user changes between split and combined address mode")
|
|
||||||
note : qsTr("Changing between split and combined address mode will require you to delete your account(s) from your email client and begin the setup process from scratch.", "displayed when the user changes between split and combined address mode")
|
|
||||||
answer : qsTr("Configuring address mode...", "displayed when the user changes between split and combined address mode")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "toggleAutoStart"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 1
|
|
||||||
question : ""
|
|
||||||
note : ""
|
|
||||||
title : ""
|
|
||||||
answer : {
|
|
||||||
var msgTurnOn = qsTr("Turning on automatic start of Bridge...", "when the automatic start feature is selected")
|
|
||||||
var msgTurnOff = qsTr("Turning off automatic start of Bridge...", "when the automatic start feature is deselected")
|
|
||||||
return go.isAutoStart==false ? msgTurnOff : msgTurnOn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "toggleAllowProxy"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 0
|
|
||||||
question : {
|
|
||||||
var questionTurnOn = qsTr("Do you want to allow alternative routing?")
|
|
||||||
var questionTurnOff = qsTr("Do you want to disallow alternative routing?")
|
|
||||||
return go.isProxyAllowed==false ? questionTurnOn : questionTurnOff
|
|
||||||
}
|
|
||||||
note : qsTr("In case Proton sites are blocked, this setting allows Bridge to try alternative network routing to reach Proton, which can be useful for bypassing firewalls or network issues. We recommend keeping this setting on for greater reliability.")
|
|
||||||
title : {
|
|
||||||
var titleTurnOn = qsTr("Allow alternative routing")
|
|
||||||
var titleTurnOff = qsTr("Disallow alternative routing")
|
|
||||||
return go.isProxyAllowed==false ? titleTurnOn : titleTurnOff
|
|
||||||
}
|
|
||||||
answer : {
|
|
||||||
var msgTurnOn = qsTr("Allowing Bridge to use alternative routing to connect to Proton...", "when the allow proxy feature is selected")
|
|
||||||
var msgTurnOff = qsTr("Disallowing Bridge to use alternative routing to connect to Proton...", "when the allow proxy feature is deselected")
|
|
||||||
return go.isProxyAllowed==false ? msgTurnOn : msgTurnOff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "toggleEarlyAccessOn"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 0
|
|
||||||
question : qsTr("Do you want to be the first to get the latest updates? Please keep in mind that early versions may be less stable.")
|
|
||||||
note : ""
|
|
||||||
title : qsTr("Enable early access")
|
|
||||||
answer : qsTr("Enabling early access...")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "toggleEarlyAccessOff"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 0
|
|
||||||
question : qsTr("Are you sure you want to leave early access? Please keep in mind this operation clears the cache and restarts Bridge.")
|
|
||||||
note : qsTr("This will delete all of your stored preferences as well as cached email data for all accounts, and requires you to reconfigure your client.")
|
|
||||||
title : qsTr("Disable early access")
|
|
||||||
answer : qsTr("Disabling early access...")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "noKeychain"
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 0
|
|
||||||
note : qsTr(
|
|
||||||
"%1 is not able to detected a supported password manager (pass, gnome-keyring). Please install and setup supported password manager and restart the application.",
|
|
||||||
"Error message when no keychain is detected"
|
|
||||||
).arg(go.programTitle)
|
|
||||||
question : qsTr("Do you want to close application now?", "when no password manager found." )
|
|
||||||
title : "No system password manager detected"
|
|
||||||
answer : qsTr("Closing Bridge...", "displayed when user is quitting application")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "undef";
|
|
||||||
PropertyChanges {
|
|
||||||
target: root
|
|
||||||
currentIndex : 1
|
|
||||||
question : ""
|
|
||||||
note : ""
|
|
||||||
title : ""
|
|
||||||
answer : ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: StandardKey.Cancel
|
|
||||||
onActivated: root.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: "Enter"
|
|
||||||
onActivated: root.confirmed()
|
|
||||||
}
|
|
||||||
|
|
||||||
onHide: {
|
|
||||||
checkBoxWrapper.isChecked = false
|
|
||||||
state = "undef"
|
|
||||||
}
|
|
||||||
|
|
||||||
onShow: {
|
|
||||||
// hide all other dialogs
|
|
||||||
winMain.dialogAddUser .visible = false
|
|
||||||
winMain.dialogChangePort .visible = false
|
|
||||||
winMain.dialogCredits .visible = false
|
|
||||||
root.visible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfirmed : {
|
|
||||||
if (state == "quit" || state == "instance exists" ) {
|
|
||||||
timer.interval = 1000
|
|
||||||
} else {
|
|
||||||
timer.interval = 300
|
|
||||||
}
|
|
||||||
answ.forceActiveFocus()
|
|
||||||
timer.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: timer
|
|
||||||
onTriggered: {
|
|
||||||
if ( state == "addressmode" ) { go.switchAddressMode (input) }
|
|
||||||
if ( state == "clearChain" ) { go.clearKeychain () }
|
|
||||||
if ( state == "clearCache" ) { go.clearCache () }
|
|
||||||
if ( state == "deleteUser" ) { go.deleteAccount (input, checkBoxWrapper.isChecked) }
|
|
||||||
if ( state == "logout" ) { go.logoutAccount (input) }
|
|
||||||
if ( state == "toggleAutoStart" ) { go.toggleAutoStart () }
|
|
||||||
if ( state == "toggleAllowProxy" ) { go.toggleAllowProxy () }
|
|
||||||
if ( state == "toggleEarlyAccessOn" ) { go.toggleEarlyAccess () }
|
|
||||||
if ( state == "toggleEarlyAccessOff" ) { go.toggleEarlyAccess () }
|
|
||||||
if ( state == "quit" ) { Qt.quit () }
|
|
||||||
if ( state == "instance exists" ) { Qt.quit () }
|
|
||||||
if ( state == "noKeychain" ) { Qt.quit () }
|
|
||||||
if ( state == "checkUpdates" ) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: {
|
|
||||||
if (event.key == Qt.Key_Enter) {
|
|
||||||
root.confirmed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,143 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// List the settings
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import BridgeUI 1.0
|
|
||||||
import ProtonUI 1.0
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
// must have wrapper
|
|
||||||
Rectangle {
|
|
||||||
id: wrapper
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
color: Style.main.background
|
|
||||||
|
|
||||||
// content
|
|
||||||
Column {
|
|
||||||
anchors.horizontalCenter : parent.horizontalCenter
|
|
||||||
|
|
||||||
ButtonIconText {
|
|
||||||
id: logs
|
|
||||||
anchors.left: parent.left
|
|
||||||
text: qsTr("Logs", "title of button that takes user to logs directory")
|
|
||||||
leftIcon.text : Style.fa.align_justify
|
|
||||||
rightIcon.text : Style.fa.chevron_circle_right
|
|
||||||
rightIcon.font.pointSize : Style.settings.toggleSize * Style.pt
|
|
||||||
onClicked: go.openLogs()
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonIconText {
|
|
||||||
id: bugreport
|
|
||||||
anchors.left: parent.left
|
|
||||||
text: qsTr("Report Bug", "title of button that takes user to bug report form")
|
|
||||||
leftIcon.text : Style.fa.bug
|
|
||||||
rightIcon.text : Style.fa.chevron_circle_right
|
|
||||||
rightIcon.font.pointSize : Style.settings.toggleSize * Style.pt
|
|
||||||
onClicked: bugreportWin.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonIconText {
|
|
||||||
id: manual
|
|
||||||
anchors.left: parent.left
|
|
||||||
text: qsTr("Setup Guide", "title of button that opens setup and installation guide")
|
|
||||||
leftIcon.text : Style.fa.book
|
|
||||||
rightIcon.text : Style.fa.chevron_circle_right
|
|
||||||
rightIcon.font.pointSize : Style.settings.toggleSize * Style.pt
|
|
||||||
onClicked: go.openManual()
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonIconText {
|
|
||||||
id: updates
|
|
||||||
anchors.left: parent.left
|
|
||||||
text: qsTr("Check for Updates", "title of button to check for any app updates")
|
|
||||||
leftIcon.text : Style.fa.refresh
|
|
||||||
rightIcon.text : Style.fa.chevron_circle_right
|
|
||||||
rightIcon.font.pointSize : Style.settings.toggleSize * Style.pt
|
|
||||||
onClicked: {
|
|
||||||
go.checkForUpdates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bottom version notes
|
|
||||||
Rectangle {
|
|
||||||
anchors.horizontalCenter : parent.horizontalCenter
|
|
||||||
height: viewAccount.separatorNoAccount - 3.2*manual.height
|
|
||||||
width: wrapper.width
|
|
||||||
color : "transparent"
|
|
||||||
AccessibleText {
|
|
||||||
anchors {
|
|
||||||
bottom: parent.bottom
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
color: Style.main.textDisabled
|
|
||||||
horizontalAlignment: Qt.AlignHCenter
|
|
||||||
font.pointSize : Style.main.fontSize * Style.pt
|
|
||||||
text:
|
|
||||||
"ProtonMail Bridge "+go.getBackendVersion()+"\n"+
|
|
||||||
"© 2021 Proton Technologies AG"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
anchors.left : parent.left
|
|
||||||
|
|
||||||
Rectangle { height: Style.dialog.spacing; width: (wrapper.width - credits.width - licenseFile.width - release.width - sepaCreditsRelease.width)/2; color: "transparent"}
|
|
||||||
|
|
||||||
ClickIconText {
|
|
||||||
id:credits
|
|
||||||
iconText : ""
|
|
||||||
text : qsTr("Credits", "link to click on to view list of credited libraries")
|
|
||||||
textColor : Style.main.textDisabled
|
|
||||||
fontSize : Style.main.fontSize
|
|
||||||
textUnderline : true
|
|
||||||
onClicked : winMain.dialogCredits.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {id: sepaLicenseFile ; height: Style.dialog.spacing; width: Style.main.dummy; color: "transparent"}
|
|
||||||
|
|
||||||
ClickIconText {
|
|
||||||
id:licenseFile
|
|
||||||
iconText : ""
|
|
||||||
text : qsTr("License", "link to click on to view license file")
|
|
||||||
textColor : Style.main.textDisabled
|
|
||||||
fontSize : Style.main.fontSize
|
|
||||||
textUnderline : true
|
|
||||||
onClicked : {
|
|
||||||
go.openLicenseFile()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {id: sepaCreditsRelease ; height: Style.dialog.spacing; width: Style.main.dummy; color: "transparent"}
|
|
||||||
|
|
||||||
ClickIconText {
|
|
||||||
id:release
|
|
||||||
iconText : ""
|
|
||||||
text : qsTr("Release notes", "link to click on to view release notes for this version of the app")
|
|
||||||
textColor : Style.main.textDisabled
|
|
||||||
fontSize : Style.main.fontSize
|
|
||||||
textUnderline : true
|
|
||||||
onClicked : gui.openReleaseNotes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,144 +0,0 @@
|
|||||||
// Copyright (c) 2021 Proton Technologies AG
|
|
||||||
//
|
|
||||||
// This file is part of ProtonMail Bridge.
|
|
||||||
//
|
|
||||||
// ProtonMail 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.
|
|
||||||
//
|
|
||||||
// ProtonMail 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Window for imap and smtp settings
|
|
||||||
|
|
||||||
import QtQuick 2.8
|
|
||||||
import QtQuick.Window 2.2
|
|
||||||
import BridgeUI 1.0
|
|
||||||
import ProtonUI 1.0
|
|
||||||
|
|
||||||
|
|
||||||
Window {
|
|
||||||
id:root
|
|
||||||
width : Style.info.width
|
|
||||||
height : Style.info.height
|
|
||||||
minimumWidth : Style.info.width
|
|
||||||
minimumHeight : Style.info.height
|
|
||||||
maximumWidth : Style.info.width
|
|
||||||
maximumHeight : Style.info.height
|
|
||||||
color: "transparent"
|
|
||||||
flags : Qt.Window | Qt.Dialog | Qt.FramelessWindowHint
|
|
||||||
title : address
|
|
||||||
|
|
||||||
Accessible.role: Accessible.Window
|
|
||||||
Accessible.name: qsTr("Configuration information for %1").arg(address)
|
|
||||||
Accessible.description: Accessible.name
|
|
||||||
|
|
||||||
property QtObject accData : QtObject { // avoid null-pointer error
|
|
||||||
property string account : "undef"
|
|
||||||
property string aliases : "undef"
|
|
||||||
property string hostname : "undef"
|
|
||||||
property string password : "undef"
|
|
||||||
property int portIMAP : 0
|
|
||||||
property int portSMTP : 0
|
|
||||||
}
|
|
||||||
property string address : "undef"
|
|
||||||
property int indexAccount : 0
|
|
||||||
property int indexAddress : 0
|
|
||||||
|
|
||||||
WindowTitleBar {
|
|
||||||
id: titleBar
|
|
||||||
window: root
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { // background
|
|
||||||
color: Style.main.background
|
|
||||||
anchors {
|
|
||||||
left : parent.left
|
|
||||||
right : parent.right
|
|
||||||
top : titleBar.bottom
|
|
||||||
bottom : parent.bottom
|
|
||||||
}
|
|
||||||
border {
|
|
||||||
width: Style.main.border
|
|
||||||
color: Style.tabbar.background
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// info content
|
|
||||||
Column {
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
top: titleBar.bottom
|
|
||||||
leftMargin: Style.main.leftMargin
|
|
||||||
topMargin: Style.info.topMargin
|
|
||||||
}
|
|
||||||
width : root.width - Style.main.leftMargin - Style.main.rightMargin
|
|
||||||
|
|
||||||
TextLabel { text: qsTr("IMAP SETTINGS", "title of the portion of the configuration screen that contains IMAP settings"); state: "heading" }
|
|
||||||
Rectangle { width: parent.width; height: Style.info.topMargin; color: "#00000000"}
|
|
||||||
Grid {
|
|
||||||
columns: 2
|
|
||||||
rowSpacing: Style.main.fontSize
|
|
||||||
TextLabel { text: qsTr("Hostname", "in configuration screen, displays the server hostname (127.0.0.1)") + ":"} TextValue { text: root.accData.hostname }
|
|
||||||
TextLabel { text: qsTr("Port", "in configuration screen, displays the server port (ex. 1025)") + ":"} TextValue { text: root.accData.portIMAP }
|
|
||||||
TextLabel { text: qsTr("Username", "in configuration screen, displays the username to use with the desktop client") + ":"} TextValue { text: root.address }
|
|
||||||
TextLabel { text: qsTr("Password", "in configuration screen, displays the Bridge password to use with the desktop client") + ":"} TextValue { text: root.accData.password }
|
|
||||||
TextLabel { text: qsTr("Security", "in configuration screen, displays the IMAP security settings") + ":"} TextValue { text: "STARTTLS" }
|
|
||||||
}
|
|
||||||
Rectangle { width: Style.main.dummy; height: Style.main.fontSize; color: "#00000000"}
|
|
||||||
Rectangle { width: Style.main.dummy; height: Style.info.topMargin; color: "#00000000"}
|
|
||||||
|
|
||||||
TextLabel { text: qsTr("SMTP SETTINGS", "title of the portion of the configuration screen that contains SMTP settings"); state: "heading" }
|
|
||||||
Rectangle { width: Style.main.dummy; height: Style.info.topMargin; color: "#00000000"}
|
|
||||||
Grid {
|
|
||||||
columns: 2
|
|
||||||
rowSpacing: Style.main.fontSize
|
|
||||||
TextLabel { text: qsTr("Hostname", "in configuration screen, displays the server hostname (127.0.0.1)") + ":"} TextValue { text: root.accData.hostname }
|
|
||||||
TextLabel { text: qsTr("Port", "in configuration screen, displays the server port (ex. 1025)") + ":"} TextValue { text: root.accData.portSMTP }
|
|
||||||
TextLabel { text: qsTr("Username", "in configuration screen, displays the username to use with the desktop client") + ":"} TextValue { text: root.address }
|
|
||||||
TextLabel { text: qsTr("Password", "in configuration screen, displays the Bridge password to use with the desktop client") + ":"} TextValue { text: root.accData.password }
|
|
||||||
TextLabel { text: qsTr("Security", "in configuration screen, displays the SMTP security settings") + ":"} TextValue { text: go.isSMTPSTARTTLS() ? "STARTTLS" : "SSL" }
|
|
||||||
}
|
|
||||||
Rectangle { width: Style.main.dummy; height: Style.main.fontSize; color: "#00000000"}
|
|
||||||
Rectangle { width: Style.main.dummy; height: Style.info.topMargin; color: "#00000000"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// apple mail button
|
|
||||||
ButtonRounded{
|
|
||||||
anchors {
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: Style.info.topMargin
|
|
||||||
}
|
|
||||||
color_main : Style.main.textBlue
|
|
||||||
isOpaque: false
|
|
||||||
text: qsTr("Configure Apple Mail", "button on configuration screen to automatically configure Apple Mail")
|
|
||||||
height: Style.main.fontSize*2
|
|
||||||
width: 2*parent.width/3
|
|
||||||
onClicked: {
|
|
||||||
go.configureAppleMail(root.indexAccount, root.indexAddress)
|
|
||||||
}
|
|
||||||
visible: go.goos == "darwin"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function showInfo(iAccount, iAddress) {
|
|
||||||
root.indexAccount = iAccount
|
|
||||||
root.indexAddress = iAddress
|
|
||||||
root.accData = accountsModel.get(iAccount)
|
|
||||||
root.address = accData.aliases.split(";")[iAddress]
|
|
||||||
root.show()
|
|
||||||
root.raise()
|
|
||||||
root.requestActivate()
|
|
||||||
}
|
|
||||||
|
|
||||||
function hide() {
|
|
||||||
root.visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user