Compare commits

..

11 Commits

46 changed files with 379 additions and 133 deletions

View File

@ -2,6 +2,23 @@
Changelog [format](http://keepachangelog.com/en/1.0.0/) Changelog [format](http://keepachangelog.com/en/1.0.0/)
## [Bridge 1.6.6] HZM
### Added
* Other: QA build checks for update every 5 minutes.
* Other: QA build adds debug message dump when sending.
### Changed
* GODT-1045 build without Qt by default.
### Fixed
* GODT-1029 Fix tray icon not updating under certain conditions.
* GODT-1062 Fix lost notification bar when window is closed.
* GODT-1058 Install version after chaning channel right away only in case of downgrade.
* GODT-1073 Re-write autostart link on every start if turned on in preferences.
* GODT-1055 Fix flaky empty trash test.
## [Bridge 1.6.5] HZM ## [Bridge 1.6.5] HZM
### Changed ### Changed

View File

@ -10,7 +10,7 @@ TARGET_OS?=${GOOS}
.PHONY: build build-ie build-nogui build-ie-nogui build-launcher build-launcher-ie versioner hasher .PHONY: build build-ie build-nogui build-ie-nogui build-launcher build-launcher-ie 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.6.5+git BRIDGE_APP_VERSION?=1.6.6+git
IE_APP_VERSION?=1.3.0+git IE_APP_VERSION?=1.3.0+git
APP_VERSION:=${BRIDGE_APP_VERSION} APP_VERSION:=${BRIDGE_APP_VERSION}
SRC_ICO:=logo.ico SRC_ICO:=logo.ico
@ -33,7 +33,7 @@ BUILD_TIME:=$(shell date +%FT%T%z)
BUILD_FLAGS:=-tags='${BUILD_TAGS}' BUILD_FLAGS:=-tags='${BUILD_TAGS}'
BUILD_FLAGS_LAUNCHER:=${BUILD_FLAGS} BUILD_FLAGS_LAUNCHER:=${BUILD_FLAGS}
BUILD_FLAGS_NOGUI:=-tags='${BUILD_TAGS} nogui' BUILD_FLAGS_GUI:=-tags='${BUILD_TAGS} build_qt'
GO_LDFLAGS:=$(addprefix -X github.com/ProtonMail/proton-bridge/internal/constants.,Version=${APP_VERSION} Revision=${REVISION} BuildTime=${BUILD_TIME}) GO_LDFLAGS:=$(addprefix -X github.com/ProtonMail/proton-bridge/internal/constants.,Version=${APP_VERSION} Revision=${REVISION} BuildTime=${BUILD_TIME})
ifneq "${BUILD_LDFLAGS}" "" ifneq "${BUILD_LDFLAGS}" ""
GO_LDFLAGS+=${BUILD_LDFLAGS} GO_LDFLAGS+=${BUILD_LDFLAGS}
@ -45,7 +45,7 @@ ifeq "${TARGET_OS}" "windows"
endif endif
BUILD_FLAGS+=-ldflags '${GO_LDFLAGS}' BUILD_FLAGS+=-ldflags '${GO_LDFLAGS}'
BUILD_FLAGS_NOGUI+=-ldflags '${GO_LDFLAGS}' BUILD_FLAGS_GUI+=-ldflags '${GO_LDFLAGS}'
BUILD_FLAGS_LAUNCHER+=-ldflags '${GO_LDFLAGS_LAUNCHER}' BUILD_FLAGS_LAUNCHER+=-ldflags '${GO_LDFLAGS_LAUNCHER}'
DEPLOY_DIR:=cmd/${TARGET_CMD}/deploy DEPLOY_DIR:=cmd/${TARGET_CMD}/deploy
@ -84,7 +84,7 @@ build-ie:
TARGET_CMD=Import-Export $(MAKE) build TARGET_CMD=Import-Export $(MAKE) build
build-nogui: gofiles build-nogui: gofiles
go build ${BUILD_FLAGS_NOGUI} -o ${EXE_NAME} cmd/${TARGET_CMD}/main.go go build ${BUILD_FLAGS} -o ${EXE_NAME} cmd/${TARGET_CMD}/main.go
build-ie-nogui: build-ie-nogui:
TARGET_CMD=Import-Export $(MAKE) build-nogui TARGET_CMD=Import-Export $(MAKE) build-nogui
@ -137,7 +137,7 @@ endif
${EXE_TARGET}: check-has-go gofiles ${ICO_FILES} ${VENDOR_TARGET} ${EXE_TARGET}: check-has-go gofiles ${ICO_FILES} ${VENDOR_TARGET}
rm -rf deploy ${TARGET_OS} ${DEPLOY_DIR} rm -rf deploy ${TARGET_OS} ${DEPLOY_DIR}
cp cmd/${TARGET_CMD}/main.go . cp cmd/${TARGET_CMD}/main.go .
qtdeploy ${BUILD_FLAGS} ${QT_BUILD_TARGET} qtdeploy ${BUILD_FLAGS_GUI} ${QT_BUILD_TARGET}
mv deploy cmd/${TARGET_CMD} mv deploy cmd/${TARGET_CMD}
if [ "${EXE_QT_TARGET}" != "${EXE_TARGET}" ]; then mv ${EXE_QT_TARGET} ${EXE_TARGET}; fi if [ "${EXE_QT_TARGET}" != "${EXE_TARGET}" ]; then mv ${EXE_QT_TARGET} ${EXE_TARGET}; fi
rm -rf ${TARGET_OS} main.go rm -rf ${TARGET_OS} main.go
@ -303,12 +303,12 @@ run-qt-cli: ${EXE_TARGET}
PROTONMAIL_ENV=dev ./$< ${RUN_FLAGS} -c PROTONMAIL_ENV=dev ./$< ${RUN_FLAGS} -c
run-nogui: clean-vendor gofiles run-nogui: clean-vendor gofiles
PROTONMAIL_ENV=dev go run ${BUILD_FLAGS_NOGUI} cmd/${TARGET_CMD}/main.go ${RUN_FLAGS} | tee last.log PROTONMAIL_ENV=dev go run ${BUILD_FLAGS} cmd/${TARGET_CMD}/main.go ${RUN_FLAGS} | tee last.log
run-nogui-cli: clean-vendor gofiles run-nogui-cli: clean-vendor gofiles
PROTONMAIL_ENV=dev go run ${BUILD_FLAGS_NOGUI} 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_NOGUI}" cmd/${TARGET_CMD}/main.go -- ${RUN_FLAGS} PROTONMAIL_ENV=dev dlv debug --build-flags "${BUILD_FLAGS}" cmd/${TARGET_CMD}/main.go -- ${RUN_FLAGS}
run-qml-preview: run-qml-preview:
$(MAKE) -C internal/frontend/qt -f Makefile.local qmlpreview $(MAKE) -C internal/frontend/qt -f Makefile.local qmlpreview

View File

@ -139,7 +139,7 @@ func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
// Watch for updates routine // Watch for updates routine
go func() { go func() {
ticker := time.NewTicker(time.Hour) ticker := time.NewTicker(constants.UpdateCheckInterval)
for { for {
checkAndHandleUpdate(b.Updater, f, b.Settings.GetBool(settings.AutoUpdateKey)) checkAndHandleUpdate(b.Updater, f, b.Settings.GetBool(settings.AutoUpdateKey))

View File

@ -151,28 +151,33 @@ func (b *Bridge) GetUpdateChannel() updater.UpdateChannel {
// Downgrading to previous version (by switching from early to stable, for example) // Downgrading to previous version (by switching from early to stable, for example)
// requires clearing all data including update files due to possibility of // requires clearing all data including update files due to possibility of
// inconsistency between versions and absence of backwards migration scripts. // inconsistency between versions and absence of backwards migration scripts.
func (b *Bridge) SetUpdateChannel(channel updater.UpdateChannel) error { 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))
version, err := b.updater.Check() version, err := b.updater.Check()
if err != nil { if err != nil {
return err return false, err
} }
if b.updater.IsDowngrade(version) { // We have to deal right away only with downgrade - that action needs to
if err := b.Users.ClearData(); err != nil { // clear data and updates, and install bridge right away. But regular
log.WithError(err).Error("Failed to clear data while downgrading channel") // upgrade can be leaved out for periodic check.
} if !b.updater.IsDowngrade(version) {
if err := b.locations.ClearUpdates(); err != nil { return false, nil
log.WithError(err).Error("Failed to clear updates while downgrading channel") }
}
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 err return false, err
} }
return b.versioner.RemoveOtherVersions(version.Version) return true, b.versioner.RemoveOtherVersions(version.Version)
} }
// GetKeychainApp returns current keychain helper. // GetKeychainApp returns current keychain helper.

View File

@ -0,0 +1,28 @@
// 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/>.
// +build !build_qa
package constants
import "time"
// nolint[gochecknoglobals]
var (
// UpdateCheckInterval defines how often we check for new version
UpdateCheckInterval = time.Hour //nolint[gochecknoglobals]
)

View File

@ -0,0 +1,28 @@
// 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/>.
// +build build_qa
package constants
import "time"
// nolint[gochecknoglobals]
var (
// UpdateCheckInterval defines how often we check for new version
UpdateCheckInterval = time.Duration(5 * time.Minute)
)

View File

@ -81,9 +81,13 @@ 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") {
if err := f.bridge.SetUpdateChannel(updater.EarlyChannel); err != nil { needRestart, err := f.bridge.SetUpdateChannel(updater.EarlyChannel)
if err != nil {
f.Println("There was a problem switching update channel.") f.Println("There was a problem switching update channel.")
} }
if needRestart {
f.restarter.SetToRestart()
}
} }
} }
@ -97,9 +101,12 @@ 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") {
if err := f.bridge.SetUpdateChannel(updater.StableChannel); err != nil { needRestart, err := f.bridge.SetUpdateChannel(updater.StableChannel)
if err != nil {
f.Println("There was a problem switching update channel.") f.Println("There was a problem switching update channel.")
} }
f.restarter.SetToRestart() if needRestart {
f.restarter.SetToRestart()
}
} }
} }

View File

@ -229,7 +229,7 @@ Dialog {
currentIndex : 0 currentIndex : 0
title : qsTr("Clear cache", "title of page that displays during cache clearing") 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") 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, temporarily slowing down the email download process significantly.", "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") answer : qsTr("Clearing the cache ...", "displays during cache clearing")
} }
}, },
@ -310,7 +310,7 @@ Dialog {
target: root target: root
currentIndex : 0 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.") 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, temporarily slowing down the email download process significantly.") 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") title : qsTr("Disable early access")
answer : qsTr("Disabling early access...") answer : qsTr("Disabling early access...")
} }

View File

@ -107,17 +107,53 @@ Item {
gui.openMainWindow(false) gui.openMainWindow(false)
if (go.isConnectionOK) { if (go.isConnectionOK) {
if( winMain.updateState=="noInternet") { if( winMain.updateState=="noInternet") {
go.setUpdateState("upToDate") go.updateState = "upToDate"
} }
} else { } else {
go.setUpdateState("noInternet") go.updateState = "noInternet"
} }
} }
onSetUpdateState : { onUpdateStateChanged : {
// Update tray icon if needed
switch (go.updateState) {
case "internetCheck":
break;
case "noInternet" :
gui.warningFlags |= Style.warnInfoBar
break;
case "oldVersion":
gui.warningFlags |= Style.warnInfoBar
break;
case "forceUpdate":
// Force update should presist once it happened and never be overwritten.
// That means that tray icon should allways remain in error state.
// But since we have only two sources of error icon in tray (force update
// + installation fail) and both are unrecoverable and we do not ever remove
// error flag from gui.warningFlags - it is ok to rely on gui.warningFlags and
// not on winMain.updateState (which presist forceUpdate)
gui.warningFlags |= Style.errorInfoBar
break;
case "upToDate":
gui.warningFlags &= ~Style.warnInfoBar
break;
case "updateRestart":
gui.warningFlags |= Style.warnInfoBar
break;
case "updateError":
gui.warningFlags |= Style.errorInfoBar
break;
default :
break;
}
// if main window is closed - most probably it is destroyed (see closeMainWindow())
if (winMain == null) {
return
}
// once app is outdated prevent from state change // once app is outdated prevent from state change
if (winMain.updateState != "forceUpdate") { if (winMain.updateState != "forceUpdate") {
winMain.updateState = updateState winMain.updateState = go.updateState
} }
} }
@ -129,15 +165,14 @@ Item {
} }
onNotifyManualUpdate: { onNotifyManualUpdate: {
go.setUpdateState("oldVersion") go.updateState = "oldVersion"
} }
onNotifyManualUpdateRestartNeeded: { onNotifyManualUpdateRestartNeeded: {
if (!winMain.dialogUpdate.visible) { if (!winMain.dialogUpdate.visible) {
gui.openMainWindow(true)
winMain.dialogUpdate.show() winMain.dialogUpdate.show()
} }
go.setUpdateState("updateRestart") go.updateState = "updateRestart"
winMain.dialogUpdate.finished(false) winMain.dialogUpdate.finished(false)
// after manual update - just retart immidiatly // after manual update - just retart immidiatly
@ -147,28 +182,25 @@ Item {
onNotifyManualUpdateError: { onNotifyManualUpdateError: {
if (!winMain.dialogUpdate.visible) { if (!winMain.dialogUpdate.visible) {
gui.openMainWindow(true)
winMain.dialogUpdate.show() winMain.dialogUpdate.show()
} }
go.setUpdateState("updateError") go.updateState = "updateError"
winMain.dialogUpdate.finished(true) winMain.dialogUpdate.finished(true)
} }
onNotifyForceUpdate : { onNotifyForceUpdate : {
go.setUpdateState("forceUpdate") go.updateState = "forceUpdate"
if (!winMain.dialogUpdate.visible) { if (!winMain.dialogUpdate.visible) {
gui.openMainWindow(true)
winMain.dialogUpdate.show() winMain.dialogUpdate.show()
} }
} }
onNotifySilentUpdateRestartNeeded: { onNotifySilentUpdateRestartNeeded: {
go.setUpdateState("updateRestart") go.updateState = "updateRestart"
} }
onNotifySilentUpdateError: { onNotifySilentUpdateError: {
go.setUpdateState("updateError") go.updateState = "updateError"
gui.openMainWindow(true)
} }
onNotifyLogout : { onNotifyLogout : {
@ -287,9 +319,17 @@ Item {
if (showAndRise) { if (showAndRise) {
gui.winMain.showAndRise() gui.winMain.showAndRise()
} }
// restore update notification bar: trigger updateStateChanged
var tmp = go.updateState
go.updateState = ""
go.updateState = tmp
} }
function closeMainWindow () { function closeMainWindow () {
// Historical reasons: once upon a time there was a report about high GPU
// usage on MacOS while bridge is closed. Legends say that destroying
// MainWindow solved this.
gui.winMain.hide() gui.winMain.hide()
gui.winMain.destroy(5000) gui.winMain.destroy(5000)
gui.winMain = null gui.winMain = null

View File

@ -30,7 +30,6 @@ Item {
id: gui id: gui
property alias winMain: winMain property alias winMain: winMain
property bool isFirstWindow: true property bool isFirstWindow: true
property int warningFlags: 0
property var locale : Qt.locale("en_US") property var locale : Qt.locale("en_US")
property date netBday : new Date("1989-03-13T00:00:00") property date netBday : new Date("1989-03-13T00:00:00")
@ -96,17 +95,17 @@ Item {
go.isConnectionOK = isAvailable go.isConnectionOK = isAvailable
if (go.isConnectionOK) { if (go.isConnectionOK) {
if( winMain.updateState==gui.enums.statusNoInternet) { if( winMain.updateState==gui.enums.statusNoInternet) {
go.setUpdateState(gui.enums.statusUpToDate) go.updateState = gui.enums.statusUpToDate
} }
} else { } else {
go.setUpdateState(gui.enums.statusNoInternet) go.updateState = gui.enums.statusNoInternet
} }
} }
onSetUpdateState : { onUpdateStateChanged : {
// once app is outdated prevent from state change // once app is outdated prevent from state change
if (winMain.updateState != "forceUpdate") { if (winMain.updateState != "forceUpdate") {
winMain.updateState = updateState winMain.updateState = go.updateState
} }
} }
@ -207,14 +206,14 @@ Item {
} }
onNotifyManualUpdate: { onNotifyManualUpdate: {
go.setUpdateState("oldVersion") go.updateState = "oldVersion"
} }
onNotifyManualUpdateRestartNeeded: { onNotifyManualUpdateRestartNeeded: {
if (!winMain.dialogUpdate.visible) { if (!winMain.dialogUpdate.visible) {
winMain.dialogUpdate.show() winMain.dialogUpdate.show()
} }
go.setUpdateState("updateRestart") go.updateState = "updateRestart"
winMain.dialogUpdate.finished(false) winMain.dialogUpdate.finished(false)
// after manual update - just retart immidiatly // after manual update - just retart immidiatly
@ -226,23 +225,23 @@ Item {
if (!winMain.dialogUpdate.visible) { if (!winMain.dialogUpdate.visible) {
winMain.dialogUpdate.show() winMain.dialogUpdate.show()
} }
go.setUpdateState("updateError") go.updateState = "updateError"
winMain.dialogUpdate.finished(true) winMain.dialogUpdate.finished(true)
} }
onNotifyForceUpdate : { onNotifyForceUpdate : {
go.setUpdateState("forceUpdate") go.updateState = "forceUpdate"
if (!winMain.dialogUpdate.visible) { if (!winMain.dialogUpdate.visible) {
winMain.dialogUpdate.show() winMain.dialogUpdate.show()
} }
} }
onNotifySilentUpdateRestartNeeded: { onNotifySilentUpdateRestartNeeded: {
go.setUpdateState("updateRestart") go.updateState = "updateRestart"
} }
onNotifySilentUpdateError: { onNotifySilentUpdateError: {
go.setUpdateState("updateError") go.updateState = "updateError"
} }
onNotifyLogout : { onNotifyLogout : {

View File

@ -108,31 +108,25 @@ Rectangle {
onStateChanged : { onStateChanged : {
switch (root.state) { switch (root.state) {
case "internetCheck": case "internetCheck":
break; break;
case "noInternet" : case "noInternet" :
gui.warningFlags |= Style.warnInfoBar retryInternet.start()
retryInternet.start() secLeft=checkInterval[iTry]
secLeft=checkInterval[iTry] break;
break;
case "oldVersion": case "oldVersion":
gui.warningFlags |= Style.warnInfoBar break;
break;
case "forceUpdate": case "forceUpdate":
gui.warningFlags |= Style.errorInfoBar break;
break;
case "upToDate": case "upToDate":
gui.warningFlags &= ~Style.warnInfoBar iTry = 0
iTry = 0 secLeft=checkInterval[iTry]
secLeft=checkInterval[iTry] break;
break;
case "updateRestart": case "updateRestart":
gui.warningFlags |= Style.warnInfoBar break;
break;
case "updateError": case "updateError":
gui.warningFlags |= Style.errorInfoBar break;
break;
default : default :
break; break;
} }
if (root.state!="noInternet") { if (root.state!="noInternet") {
@ -271,7 +265,7 @@ Rectangle {
target: closeSign target: closeSign
visible: true visible: true
onClicked: { onClicked: {
root.state = "upToDate" go.updateState = "upToDate"
} }
} }
}, },

View File

@ -24,7 +24,7 @@ import QtQuick.Window 2.2
Window { Window {
id: testroot id: testroot
width : 150 width : 250
height : 600 height : 600
flags : Qt.Window | Qt.Dialog | Qt.FramelessWindowHint flags : Qt.Window | Qt.Dialog | Qt.FramelessWindowHint
visible : true visible : true
@ -60,7 +60,7 @@ Window {
Text { Text {
id: systrText id: systrText
anchors { anchors {
right : test_systray.right horizontalCenter: parent.horizontalCenter
verticalCenter: test_systray.verticalCenter verticalCenter: test_systray.verticalCenter
} }
text: "unset" text: "unset"
@ -299,6 +299,7 @@ Window {
property string fullversion : "QA.1.0 (d9f8sdf9) 2020-02-19T10:57:23+01:00" property string fullversion : "QA.1.0 (d9f8sdf9) 2020-02-19T10:57:23+01:00"
property string downloadLink: "https://protonmail.com/download/beta/protonmail-bridge-1.1.5-1.x86_64.rpm;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;" property string downloadLink: "https://protonmail.com/download/beta/protonmail-bridge-1.1.5-1.x86_64.rpm;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;"
property string updateState
property string updateVersion : "QA.1.0" property string updateVersion : "QA.1.0"
property bool updateCanInstall: true property bool updateCanInstall: true
property string updateLandingPage : "https://protonmail.com/bridge/download/" property string updateLandingPage : "https://protonmail.com/bridge/download/"
@ -340,7 +341,6 @@ Window {
signal notifyPortIssue(bool busyPortIMAP, bool busyPortSMTP) signal notifyPortIssue(bool busyPortIMAP, bool busyPortSMTP)
signal notifyVersionIsTheLatest() signal notifyVersionIsTheLatest()
signal setUpdateState(string updateState)
signal notifyKeychainRebuild() signal notifyKeychainRebuild()
signal notifyHasNoKeychain() signal notifyHasNoKeychain()

View File

@ -856,6 +856,7 @@ Window {
property string fullversion : "QA.1.0 (d9f8sdf9) 2020-02-19T10:57:23+01:00" property string fullversion : "QA.1.0 (d9f8sdf9) 2020-02-19T10:57:23+01:00"
property string downloadLink: "https://protonmail.com/download/beta/protonmail-bridge-1.1.5-1.x86_64.rpm;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;" property string downloadLink: "https://protonmail.com/download/beta/protonmail-bridge-1.1.5-1.x86_64.rpm;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;"
property string updateState
property string updateVersion : "q0.1.0" property string updateVersion : "q0.1.0"
property bool updateCanInstall: true property bool updateCanInstall: true
property string updateLandingPage : "https://protonmail.com/import-export/download/" property string updateLandingPage : "https://protonmail.com/import-export/download/"
@ -900,7 +901,6 @@ Window {
signal showQuit() signal showQuit()
signal notifyVersionIsTheLatest() signal notifyVersionIsTheLatest()
signal setUpdateState(string updateState)
signal showMainWin() signal showMainWin()
signal hideMainWin() signal hideMainWin()

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtcommon package qtcommon

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtcommon package qtcommon

View File

@ -1,4 +1,4 @@
// +build !nogui // +build build_qt
#include "common.h" #include "common.h"
#include "_cgo_export.h" #include "_cgo_export.h"

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtcommon package qtcommon

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtcommon package qtcommon

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build nogui // +build !build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -16,7 +16,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qtie package qtie
@ -53,6 +53,7 @@ type GoQMLInterface struct {
_ string `property:"fullversion"` _ string `property:"fullversion"`
_ string `property:"downloadLink"` _ string `property:"downloadLink"`
_ string `property:"updateState"`
_ string `property:"updateVersion"` _ string `property:"updateVersion"`
_ bool `property:"updateCanInstall"` _ bool `property:"updateCanInstall"`
_ string `property:"updateLandingPage"` _ string `property:"updateLandingPage"`
@ -77,7 +78,6 @@ type GoQMLInterface struct {
_ string `property:"versionCheckFailed"` _ string `property:"versionCheckFailed"`
// //
_ func(isAvailable bool) `signal:"setConnectionStatus"` _ func(isAvailable bool) `signal:"setConnectionStatus"`
_ func(updateState string) `signal:"setUpdateState"`
_ func() `slot:"checkInternet"` _ func() `slot:"checkInternet"`
_ func() `slot:"setToRestart"` _ func() `slot:"setToRestart"`

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qt package qt

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qt package qt
@ -84,7 +84,7 @@ func (s *FrontendQt) clearCache() {
channel := s.bridge.GetUpdateChannel() channel := s.bridge.GetUpdateChannel()
if channel == updater.EarlyChannel { if channel == updater.EarlyChannel {
if err := s.bridge.SetUpdateChannel(updater.StableChannel); err != nil { if _, err := s.bridge.SetUpdateChannel(updater.StableChannel); err != nil {
s.Qml.NotifyManualUpdateError() s.Qml.NotifyManualUpdateError()
return return
} }

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
// Package qt is the Qt User interface for Desktop bridge. // Package qt is the Qt User interface for Desktop bridge.
// //
@ -340,27 +340,35 @@ func (s *FrontendQt) qtExecute(Procedure func(*FrontendQt) error) error {
s.Qml.SetCredits(bridge.Credits) s.Qml.SetCredits(bridge.Credits)
s.Qml.SetFullversion(s.buildVersion) s.Qml.SetFullversion(s.buildVersion)
// Autostart. // Autostart: rewrite the current definition of autostart
if s.Qml.IsFirstStart() { // - when it is the first time
if s.autostart.IsEnabled() { // - when starting after clear cache
// - when there is already autostart file from past
//
// This will make sure that autostart will use the latest path to
// launcher or bridge.
isAutoStartEnabled := s.autostart.IsEnabled()
if s.Qml.IsFirstStart() || isAutoStartEnabled {
if isAutoStartEnabled {
if err := s.autostart.Disable(); err != nil { if err := s.autostart.Disable(); err != nil {
log.Error("First disable ", err) log.
WithField("first", s.Qml.IsFirstStart()).
WithField("wasEnabled", isAutoStartEnabled).
WithError(err).
Error("Disable on start failed.")
s.autostartError(err) s.autostartError(err)
} }
} }
s.toggleAutoStart() if err := s.autostart.Enable(); err != nil {
} log.
if s.autostart.IsEnabled() { WithField("first", s.Qml.IsFirstStart()).
s.Qml.SetIsAutoStart(true) WithField("wasEnabled", isAutoStartEnabled).
} else { WithError(err).
s.Qml.SetIsAutoStart(false) Error("Enable on start failed.")
} s.autostartError(err)
}
if s.settings.GetBool(settings.AutoUpdateKey) {
s.Qml.SetIsAutoUpdate(true)
} else {
s.Qml.SetIsAutoUpdate(false)
} }
s.Qml.SetIsAutoStart(s.autostart.IsEnabled())
if s.settings.GetBool(settings.AllowProxyKey) { if s.settings.GetBool(settings.AllowProxyKey) {
s.Qml.SetIsProxyAllowed(true) s.Qml.SetIsProxyAllowed(true)
@ -557,20 +565,22 @@ func (s *FrontendQt) configureAppleMail(iAccount, iAddress int) {
func (s *FrontendQt) toggleAutoStart() { func (s *FrontendQt) toggleAutoStart() {
defer s.Qml.ProcessFinished() defer s.Qml.ProcessFinished()
var err error var err error
if s.autostart.IsEnabled() { wasEnabled := s.autostart.IsEnabled()
if wasEnabled {
err = s.autostart.Disable() err = s.autostart.Disable()
} else { } else {
err = s.autostart.Enable() err = s.autostart.Enable()
} }
isEnabled := s.autostart.IsEnabled()
if err != nil { if err != nil {
log.Error("Enable autostart: ", err) log.
WithField("wasEnabled", wasEnabled).
WithField("isEnabled", isEnabled).
WithError(err).
Error("Autostart change failed.")
s.autostartError(err) s.autostartError(err)
} }
if s.autostart.IsEnabled() { s.Qml.SetIsAutoStart(isEnabled)
s.Qml.SetIsAutoStart(true)
} else {
s.Qml.SetIsAutoStart(false)
}
} }
func (s *FrontendQt) toggleAutoUpdate() { func (s *FrontendQt) toggleAutoUpdate() {
@ -595,14 +605,16 @@ func (s *FrontendQt) toggleEarlyAccess() {
channel = updater.EarlyChannel channel = updater.EarlyChannel
} }
err := s.bridge.SetUpdateChannel(channel) needRestart, err := s.bridge.SetUpdateChannel(channel)
s.Qml.SetIsEarlyAccess(channel == updater.EarlyChannel) s.Qml.SetIsEarlyAccess(channel == updater.EarlyChannel)
if err != nil { if err != nil {
s.Qml.NotifyManualUpdateError() s.Qml.NotifyManualUpdateError()
return return
} }
s.restarter.SetToRestart() if needRestart {
s.App.Quit() s.restarter.SetToRestart()
s.App.Quit()
}
} }
func (s *FrontendQt) toggleAllowProxy() { func (s *FrontendQt) toggleAllowProxy() {
@ -733,4 +745,4 @@ func (s *FrontendQt) setKeychain(keychain string) {
s.restarter.SetToRestart() s.restarter.SetToRestart()
s.App.Quit() s.App.Quit()
} }
} }

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build nogui // +build !build_qt
package qt package qt

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qt package qt

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qt package qt

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qt package qt

View File

@ -15,7 +15,7 @@
// 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 ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui // +build build_qt
package qt package qt
@ -50,6 +50,7 @@ type GoQMLInterface struct {
_ string `property:"fullversion"` _ string `property:"fullversion"`
_ string `property:"downloadLink"` _ string `property:"downloadLink"`
_ string `property:"updateState"`
_ string `property:"updateVersion"` _ string `property:"updateVersion"`
_ bool `property:"updateCanInstall"` _ bool `property:"updateCanInstall"`
_ string `property:"updateLandingPage"` _ string `property:"updateLandingPage"`
@ -82,9 +83,8 @@ type GoQMLInterface struct {
_ float32 `property:"progress"` _ float32 `property:"progress"`
_ string `property:"progressDescription"` _ string `property:"progressDescription"`
_ func(isAvailable bool) `signal:"setConnectionStatus"` _ func(isAvailable bool) `signal:"setConnectionStatus"`
_ func(updateState string) `signal:"setUpdateState"` _ func() `slot:"checkInternet"`
_ func() `slot:"checkInternet"`
_ func() `slot:"setToRestart"` _ func() `slot:"setToRestart"`

View File

@ -79,7 +79,7 @@ type Bridger interface {
AllowProxy() AllowProxy()
DisallowProxy() DisallowProxy()
GetUpdateChannel() updater.UpdateChannel GetUpdateChannel() updater.UpdateChannel
SetUpdateChannel(updater.UpdateChannel) error SetUpdateChannel(updater.UpdateChannel) (needRestart bool, err error)
GetKeychainApp() string GetKeychainApp() string
SetKeychainApp(keychain string) SetKeychainApp(keychain string)
} }

View File

@ -0,0 +1,22 @@
// 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/>.
// +build !build_qa
package smtp
func dumpMessageData([]byte, string) {}

60
internal/smtp/dump_qa.go Normal file
View File

@ -0,0 +1,60 @@
// 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/>.
// +build build_qa
package smtp
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/sirupsen/logrus"
)
func dumpMessageData(b []byte, subject string) {
home, err := os.UserHomeDir()
if err != nil {
logrus.WithError(err).Error("Failed to dump raw message data")
return
}
path := filepath.Join(home, "bridge-qa")
if err := os.MkdirAll(path, 0700); err != nil {
logrus.WithError(err).Error("Failed to dump raw message data")
return
}
if len(subject) > 16 {
subject = subject[:16]
}
if err := ioutil.WriteFile(
filepath.Join(path, fmt.Sprintf("%v-%v.eml", subject, time.Now().Format(time.RFC3339Nano))),
b,
0600,
); err != nil {
logrus.WithError(err).Error("Failed to dump raw message data")
return
}
logrus.WithField("path", path).Info("Dumped raw message data")
}

View File

@ -215,6 +215,10 @@ func (su *smtpUser) Send(returnPath string, to []string, messageReader io.Reader
// Called from go-smtp in goroutines - we need to handle panics for each function. // Called from go-smtp in goroutines - we need to handle panics for each function.
defer su.panicHandler.HandlePanic() defer su.panicHandler.HandlePanic()
b := new(bytes.Buffer)
messageReader = io.TeeReader(messageReader, b)
mailSettings, err := su.client().GetMailSettings() mailSettings, err := su.client().GetMailSettings()
if err != nil { if err != nil {
return err return err
@ -405,6 +409,8 @@ func (su *smtpUser) Send(returnPath string, to []string, messageReader io.Reader
req.PreparePackages() req.PreparePackages()
dumpMessageData(b.Bytes(), message.Subject)
return su.storeUser.SendMessage(message.ID, req) return su.storeUser.SendMessage(message.ID, req)
} }

View File

@ -1,3 +1,19 @@
## v1.6.5
- 2021-02-22
### New
- Allow to choose which keychain is used by Bridge on Linux
- Added automatic update CLI commands
- Improved performance during slow connection
- Added IMAP requests to the logs for easier debugging
### Fixed
- NoGUI bulid
- Background of GUI welcome message
- Incorrect total mailbox size displayed in Apple Mail
## v1.6.3 ## v1.6.3
- 2021-02-16 - 2021-02-16

View File

@ -18,6 +18,8 @@
package tests package tests
import ( import (
"time"
"github.com/cucumber/godog" "github.com/cucumber/godog"
) )
@ -44,6 +46,16 @@ func imapClientRenamesMailboxTo(mailboxName, newMailboxName string) error {
} }
func imapClientDeletesMailbox(mailboxName string) error { func imapClientDeletesMailbox(mailboxName string) error {
if mailboxName == "Trash" {
// Delete of Trash mailbox calls empty label on API.
// Empty label means delete all messages in that label with time
// creation before time of execution. But creation time is in
// seconds, not miliseconds. That's why message created at the
// same second as emptying label is called is not deleted.
// Tests might be that fast and therefore we need to sleep for
// a second to make sure test doesn't produce fake failure.
time.Sleep(time.Second)
}
res := ctx.GetIMAPClient("imap").DeleteMailbox(mailboxName) res := ctx.GetIMAPClient("imap").DeleteMailbox(mailboxName)
ctx.SetIMAPLastResponse("imap", res) ctx.SetIMAPLastResponse("imap", res)
return nil return nil