From 3da97dea09276db54b7007d4e49664674c2f8132 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Thu, 29 Sep 2022 20:02:27 -0500 Subject: [PATCH 01/85] Feature fix in 6/8 (#4539) --- src/models/featuremodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/featuremodel.cpp b/src/models/featuremodel.cpp index 686ac10d1de..4bd96f6e1e0 100644 --- a/src/models/featuremodel.cpp +++ b/src/models/featuremodel.cpp @@ -146,7 +146,7 @@ QVariant FeatureModel::data(const QModelIndex& index, int role) const { }; QObject* FeatureModel::get(const QString& feature) { - const Feature* f = Feature::get(feature); + const Feature* f = Feature::getOrNull(feature); auto obj = (QObject*)f; QQmlEngine::setObjectOwnership(obj, QQmlEngine::CppOwnership); return obj; From 247a6c550fe89ad6b99c573ac7c3addb7086a2cd Mon Sep 17 00:00:00 2001 From: Owen Kirby Date: Sat, 1 Oct 2022 07:48:18 -1000 Subject: [PATCH 02/85] Update stale copy of ios/gobridge (#4547) --- ios/gobridge/go.mod | 8 +++++--- ios/gobridge/go.sum | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/ios/gobridge/go.mod b/ios/gobridge/go.mod index 8ec48163b6f..af3aaf44625 100644 --- a/ios/gobridge/go.mod +++ b/ios/gobridge/go.mod @@ -1,8 +1,10 @@ module golang.zx2c4.com/wireguard/apple -go 1.16 +go 1.17 require ( - golang.org/x/sys v0.0.0-20210308170721-88b6017d0656 - golang.zx2c4.com/wireguard v0.0.0-20210307162820-f4695db51c39 + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/net v0.0.0-20210917221730-978cfadd31cf // indirect + golang.org/x/sys v0.0.0-20210921065528-437939a70204 + golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c ) diff --git a/ios/gobridge/go.sum b/ios/gobridge/go.sum index 89d522bb399..1bb4e81f796 100644 --- a/ios/gobridge/go.sum +++ b/ios/gobridge/go.sum @@ -1,19 +1,24 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305215415-5cdee2b1b5a0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210308170721-88b6017d0656 h1:FuBaiPCiXkq4v+JY5JEGPU/HwEZwpVyDbu/KBz9fU+4= -golang.org/x/sys v0.0.0-20210308170721-88b6017d0656/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-20210921065528-437939a70204 h1:JJhkWtBuTQKyz2bd5WG9H8iUsJRU3En/KRfN8B2RnDs= +golang.org/x/sys v0.0.0-20210921065528-437939a70204/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.zx2c4.com/wireguard v0.0.0-20210307162820-f4695db51c39 h1:yv331J9aB1fuvxzneUKsRnWyhwK+aj495rADUXSP7Uk= -golang.zx2c4.com/wireguard v0.0.0-20210307162820-f4695db51c39/go.mod h1:ojGPy+9W6ZSM8anL+xC67fvh8zPQJwA6KpFOHyDWLX4= +golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c h1:IsAez/yRA23H/i9A02IHbYnmtVOs7DsP3aVP2cu5SNE= +golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= From 24c28b19348cff1d375a9ac84b3b02217c49f37b Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 3 Oct 2022 18:55:35 +0200 Subject: [PATCH 03/85] Make xcode build yellow/green instead of red - VPN-2971 (#4560) --- scripts/macos/utils/xcode_patcher.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/macos/utils/xcode_patcher.rb b/scripts/macos/utils/xcode_patcher.rb index a80435c7dab..300129ee3dd 100644 --- a/scripts/macos/utils/xcode_patcher.rb +++ b/scripts/macos/utils/xcode_patcher.rb @@ -52,7 +52,8 @@ def setup_target_main(configHash, adjust_sdk_token) config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= [ "$(inherited)", - "$(PROJECT_DIR)/3rdparty" + "$(PROJECT_DIR)/3rdparty", + "$(PROJECT_DIR)/3rdparty/wireguard-apple/Sources/WireGuardKitC", ] config.build_settings['PRODUCT_NAME'] = 'Mozilla VPN' @@ -223,6 +224,10 @@ def setup_target_extension(shortVersion, fullVersion, configHash) config.build_settings['ENABLE_BITCODE'] ||= 'NO' config.build_settings['SDKROOT'] = 'iphoneos' + config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= [ + "$(PROJECT_DIR)/ios/gobridge", + "$(PROJECT_DIR)/3rdparty/wireguard-apple/Sources/WireGuardKitC", + ] config.build_settings['OTHER_LDFLAGS'] ||= [ "-stdlib=libc++", "-Wl,-rpath,@executable_path/Frameworks", From 888ce38861685bed0520ff123e9d4decdd410bb6 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 3 Oct 2022 19:58:23 +0200 Subject: [PATCH 04/85] Rename the network extension as MozillaVPNNetworkExtension - VPN-2972 (#4562) --- scripts/macos/utils/xcode_patcher.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/macos/utils/xcode_patcher.rb b/scripts/macos/utils/xcode_patcher.rb index 300129ee3dd..682dbee383d 100644 --- a/scripts/macos/utils/xcode_patcher.rb +++ b/scripts/macos/utils/xcode_patcher.rb @@ -198,7 +198,7 @@ def setup_target_main(configHash, adjust_sdk_token) end def setup_target_extension(shortVersion, fullVersion, configHash) - @target_extension = @project.new_target(:app_extension, 'WireGuardNetworkExtension', :ios) + @target_extension = @project.new_target(:app_extension, 'MozillaVPNNetworkExtension', :ios) @target_extension.build_configurations.each do |config| config.base_configuration_reference = @configFile @@ -214,7 +214,7 @@ def setup_target_extension(shortVersion, fullVersion, configHash) config.build_settings['MARKETING_VERSION'] ||= shortVersion config.build_settings['CURRENT_PROJECT_VERSION'] ||= fullVersion config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] ||= configHash['NETEXT_ID_IOS'] - config.build_settings['PRODUCT_NAME'] = 'WireGuardNetworkExtension' + config.build_settings['PRODUCT_NAME'] = 'MozillaVPNNetworkExtension' # other configs config.build_settings['INFOPLIST_FILE'] ||= 'ios/networkextension/Info.plist' From f2639df1ef528ce07db52401dceaa221acc12471 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 4 Oct 2022 15:54:27 +0200 Subject: [PATCH 05/85] Set the installation time via the inspector for addon messaging testing - VPN-2977 (#4568) --- src/inspector/inspectorhandler.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/inspector/inspectorhandler.cpp b/src/inspector/inspectorhandler.cpp index d9cace6daad..d5de7ab266a 100644 --- a/src/inspector/inspectorhandler.cpp +++ b/src/inspector/inspectorhandler.cpp @@ -956,6 +956,14 @@ static QList s_commands{ message.executeAction(); return QJsonObject(); }}, + + InspectorCommand{"set_installation_time", "Set the installation time", 1, + [](InspectorHandler*, const QList& arguments) { + qint64 epoch = arguments[1].toLongLong(); + SettingsHolder::instance()->setInstallationTime( + QDateTime::fromSecsSinceEpoch(epoch)); + return QJsonObject(); + }}, }; // static From 2ff6163f124c3a64093063ae9e22eceb49f74a3a Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 5 Oct 2022 09:18:34 +0200 Subject: [PATCH 06/85] Deprecate the message bundle addon - VPN-2979 (#4572) --- .../message_privacy_bundle_staging/EnableBundleUpgrade.js | 0 .../message_privacy_bundle_staging/OpenBundleUpgradeFlow.js | 0 .../message_privacy_bundle_staging/OpenGetHelpScreen.js | 0 .../{ => deprecated}/message_privacy_bundle_staging/manifest.json | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename addons/{ => deprecated}/message_privacy_bundle_staging/EnableBundleUpgrade.js (100%) rename addons/{ => deprecated}/message_privacy_bundle_staging/OpenBundleUpgradeFlow.js (100%) rename addons/{ => deprecated}/message_privacy_bundle_staging/OpenGetHelpScreen.js (100%) rename addons/{ => deprecated}/message_privacy_bundle_staging/manifest.json (100%) diff --git a/addons/message_privacy_bundle_staging/EnableBundleUpgrade.js b/addons/deprecated/message_privacy_bundle_staging/EnableBundleUpgrade.js similarity index 100% rename from addons/message_privacy_bundle_staging/EnableBundleUpgrade.js rename to addons/deprecated/message_privacy_bundle_staging/EnableBundleUpgrade.js diff --git a/addons/message_privacy_bundle_staging/OpenBundleUpgradeFlow.js b/addons/deprecated/message_privacy_bundle_staging/OpenBundleUpgradeFlow.js similarity index 100% rename from addons/message_privacy_bundle_staging/OpenBundleUpgradeFlow.js rename to addons/deprecated/message_privacy_bundle_staging/OpenBundleUpgradeFlow.js diff --git a/addons/message_privacy_bundle_staging/OpenGetHelpScreen.js b/addons/deprecated/message_privacy_bundle_staging/OpenGetHelpScreen.js similarity index 100% rename from addons/message_privacy_bundle_staging/OpenGetHelpScreen.js rename to addons/deprecated/message_privacy_bundle_staging/OpenGetHelpScreen.js diff --git a/addons/message_privacy_bundle_staging/manifest.json b/addons/deprecated/message_privacy_bundle_staging/manifest.json similarity index 100% rename from addons/message_privacy_bundle_staging/manifest.json rename to addons/deprecated/message_privacy_bundle_staging/manifest.json From 5d4900449c64cddf259939a9b22776eec820c795 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 5 Oct 2022 09:18:50 +0200 Subject: [PATCH 07/85] Show the thank-you view after the give-us-5-starts - VPN-2976 (#4570) --- src/ui/screens/getHelp/giveFeedback/ViewGiveFeedbackReview.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/screens/getHelp/giveFeedback/ViewGiveFeedbackReview.qml b/src/ui/screens/getHelp/giveFeedback/ViewGiveFeedbackReview.qml index 924694db6c6..8b9fa77dccb 100644 --- a/src/ui/screens/getHelp/giveFeedback/ViewGiveFeedbackReview.qml +++ b/src/ui/screens/getHelp/giveFeedback/ViewGiveFeedbackReview.qml @@ -49,7 +49,7 @@ VPNViewBase { id: skipLink labelText: qsTrId("vpn.feedbackForm.skip") - onClicked: getHelpStackView.pop(null, StackView.Immediate); + onClicked: getHelpStackView.push("qrc:/ui/screens/getHelp/giveFeedback/ViewGiveFeedbackThankYou.qml"); implicitHeight: VPNTheme.theme.rowHeight Layout.alignment: Qt.AlignHCenter } From 8f138f99c573219b17aafcb1619ddc07336085ae Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 5 Oct 2022 20:41:37 +0200 Subject: [PATCH 08/85] Use a timer to check the status when connected - ios (#4578) --- src/platforms/ios/ioscontroller.swift | 29 ++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/platforms/ios/ioscontroller.swift b/src/platforms/ios/ioscontroller.swift index f5d3f321049..da052118f0d 100644 --- a/src/platforms/ios/ioscontroller.swift +++ b/src/platforms/ios/ioscontroller.swift @@ -106,7 +106,34 @@ public class IOSControllerImpl : NSObject { return } - stateChangeCallback?(session.status == .connected) + // If disconnected, we know for sure that this is true + if (session.status == .disconnected) { + stateChangeCallback?(false) + return + } + + _ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) {_ in + self.monitorConnection() + } + } + + private func monitorConnection() -> Void { + self.checkStatus { _, _, configString in + if self.tunnel?.connection.status != .connected { return; } + + let lines = configString.splitToArray(separator: "\n") + if let line = lines.first(where: { $0.starts(with: "last_handshake_time_sec") }) { + let parts = line.splitToArray(separator: "=") + if parts.count > 1 && Int(parts[1]) ?? 0 > 0 { + self.stateChangeCallback?(true) + return + } + } + + _ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in + self.monitorConnection() + } + } } private static func isOurManager(_ manager: NETunnelProviderManager) -> Bool { From 59749cb76ac89fdfcf69bc71cb93cb65db49d623 Mon Sep 17 00:00:00 2001 From: Gabriel Bustamante Date: Wed, 5 Oct 2022 13:47:23 -0500 Subject: [PATCH 09/85] Sign the VPN addons using the release key (#4577) --- taskcluster/mozillavpn_taskgraph/transforms/signing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/taskcluster/mozillavpn_taskgraph/transforms/signing.py b/taskcluster/mozillavpn_taskgraph/transforms/signing.py index a1d79ed722d..2c635d73a6d 100644 --- a/taskcluster/mozillavpn_taskgraph/transforms/signing.py +++ b/taskcluster/mozillavpn_taskgraph/transforms/signing.py @@ -20,13 +20,14 @@ "linux/opt", "macos/opt", "windows/opt", + "addons/opt", ] SIGNING_BUILD_TYPES = PRODUCTION_SIGNING_BUILD_TYPES + [ # Note: it appears we don't have infra for debug signing # android builds. Contact releng if you need it :) # "android-debug", - "addons/opt", + # "addons/opt", # TODO: Add addons debug builds? We have the infra to debug sign them. ] From 5599cb4a58d861b55bdf0c69f4e9845123b7d61f Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 5 Oct 2022 21:11:22 +0200 Subject: [PATCH 10/85] Cleanup ios integration (#4574) --- ios/app/WireGuard-Bridging-Header.h | 2 +- ios/gobridge/.gitignore | 3 - ios/gobridge/Makefile | 59 ----- ios/gobridge/api.go | 225 ------------------ ios/gobridge/dummy.c | 1 - ios/gobridge/go.mod | 10 - ios/gobridge/go.sum | 24 -- .../goruntime-boottime-over-monotonic.diff | 61 ----- ios/gobridge/module.modulemap | 5 - ios/gobridge/wireguard.h | 23 -- ...ireGuardNetworkExtension-Bridging-Header.h | 4 +- scripts/macos/apple_compile.sh | 2 +- scripts/macos/utils/xcode_patcher.rb | 7 +- src/platforms/ios/ioslogger.swift | 3 +- 14 files changed, 9 insertions(+), 420 deletions(-) delete mode 100644 ios/gobridge/.gitignore delete mode 100644 ios/gobridge/Makefile delete mode 100644 ios/gobridge/api.go delete mode 100644 ios/gobridge/dummy.c delete mode 100644 ios/gobridge/go.mod delete mode 100644 ios/gobridge/go.sum delete mode 100644 ios/gobridge/goruntime-boottime-over-monotonic.diff delete mode 100644 ios/gobridge/module.modulemap delete mode 100644 ios/gobridge/wireguard.h diff --git a/ios/app/WireGuard-Bridging-Header.h b/ios/app/WireGuard-Bridging-Header.h index 405a8879244..e3b27030e2f 100644 --- a/ios/app/WireGuard-Bridging-Header.h +++ b/ios/app/WireGuard-Bridging-Header.h @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "wireguard-go-version.h" +#include "3rdparty/wireguard-apple/Sources/WireGuardKitGo/wireguard-go-version.h" #include "3rdparty/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h" #include diff --git a/ios/gobridge/.gitignore b/ios/gobridge/.gitignore deleted file mode 100644 index 5d25f8f5f9e..00000000000 --- a/ios/gobridge/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.cache/ -.tmp/ -out/ diff --git a/ios/gobridge/Makefile b/ios/gobridge/Makefile deleted file mode 100644 index 1d89b5a11db..00000000000 --- a/ios/gobridge/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Copyright (C) 2018-2019 Jason A. Donenfeld . All Rights Reserved. - -# These are generally passed to us by xcode, but we set working defaults for standalone compilation too. -ARCHS ?= x86_64 arm64 -PLATFORM_NAME ?= macosx -SDKROOT ?= $(shell xcrun --sdk $(PLATFORM_NAME) --show-sdk-path) -CONFIGURATION_BUILD_DIR ?= $(CURDIR)/out -CONFIGURATION_TEMP_DIR ?= $(CURDIR)/.tmp - -export CC ?= clang -LIPO ?= lipo -DESTDIR ?= $(CONFIGURATION_BUILD_DIR) -BUILDDIR ?= $(CONFIGURATION_TEMP_DIR)/wireguard-go-bridge - -CFLAGS_PREFIX := $(if $(DEPLOYMENT_TARGET_CLANG_FLAG_NAME),-$(DEPLOYMENT_TARGET_CLANG_FLAG_NAME)=$($(DEPLOYMENT_TARGET_CLANG_ENV_NAME)),) -isysroot $(SDKROOT) -arch -GOARCH_arm64 := arm64 -GOARCH_x86_64 := amd64 -GOOS_macosx := darwin -GOOS_iphoneos := ios - -build: $(DESTDIR)/libwg-go.a -version-header: $(DESTDIR)/wireguard-go-version.h - -REAL_GOROOT := $(shell go env GOROOT 2>/dev/null) -export GOROOT := $(BUILDDIR)/goroot -$(GOROOT)/.prepared: - [ -n "$(REAL_GOROOT)" ] - mkdir -p "$(GOROOT)" - rsync -a --delete --exclude=pkg/obj/go-build "$(REAL_GOROOT)/" "$(GOROOT)/" - cat goruntime-*.diff | patch -p1 -f -N -r- -d "$(GOROOT)" - touch "$@" - -define libwg-go-a -$(BUILDDIR)/libwg-go-$(1).a: export CGO_ENABLED := 1 -$(BUILDDIR)/libwg-go-$(1).a: export CGO_CFLAGS := $(CFLAGS_PREFIX) $(ARCH) -$(BUILDDIR)/libwg-go-$(1).a: export CGO_LDFLAGS := $(CFLAGS_PREFIX) $(ARCH) -$(BUILDDIR)/libwg-go-$(1).a: export GOOS := $(GOOS_$(PLATFORM_NAME)) -$(BUILDDIR)/libwg-go-$(1).a: export GOARCH := $(GOARCH_$(1)) -$(BUILDDIR)/libwg-go-$(1).a: $(GOROOT)/.prepared go.mod - go build -ldflags=-w -trimpath -v -o "$(BUILDDIR)/libwg-go-$(1).a" -buildmode c-archive - rm -f "$(BUILDDIR)/libwg-go-$(1).h" -endef -$(foreach ARCH,$(ARCHS),$(eval $(call libwg-go-a,$(ARCH)))) - -$(DESTDIR)/wireguard-go-version.h: go.mod $(GOROOT)/.prepared - sed -E -n 's/.*golang\.zx2c4\.com\/wireguard +v[0-9.]+-[0-9]+-([0-9a-f]{8})[0-9a-f]{4}.*/#define WIREGUARD_GO_VERSION "\1"/p' "$<" > "$@" - -$(DESTDIR)/libwg-go.a: $(foreach ARCH,$(ARCHS),$(BUILDDIR)/libwg-go-$(ARCH).a) - @mkdir -vp "$(DESTDIR)" - $(LIPO) -create -output "$@" $^ - -clean: - rm -rf "$(BUILDDIR)" "$(DESTDIR)/libwg-go.a" "$(DESTDIR)/wireguard-go-version.h" - -install: build - -.PHONY: clean build version-header install diff --git a/ios/gobridge/api.go b/ios/gobridge/api.go deleted file mode 100644 index b6b4d311e38..00000000000 --- a/ios/gobridge/api.go +++ /dev/null @@ -1,225 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2018-2019 Jason A. Donenfeld . All Rights Reserved. - */ - -package main - -// #include -// #include -// static void callLogger(void *func, void *ctx, int level, const char *msg) -// { -// ((void(*)(void *, int, const char *))func)(ctx, level, msg); -// } -import "C" - -import ( - "fmt" - "math" - "os" - "os/signal" - "runtime" - "runtime/debug" - "strings" - "time" - "unsafe" - - "golang.org/x/sys/unix" - "golang.zx2c4.com/wireguard/conn" - "golang.zx2c4.com/wireguard/device" - "golang.zx2c4.com/wireguard/tun" -) - -var loggerFunc unsafe.Pointer -var loggerCtx unsafe.Pointer - -type CLogger int - -func cstring(s string) *C.char { - b, err := unix.BytePtrFromString(s) - if err != nil { - b := [1]C.char{} - return &b[0] - } - return (*C.char)(unsafe.Pointer(b)) -} - -func (l CLogger) Printf(format string, args ...interface{}) { - if uintptr(loggerFunc) == 0 { - return - } - C.callLogger(loggerFunc, loggerCtx, C.int(l), cstring(fmt.Sprintf(format, args...))) -} - -type tunnelHandle struct { - *device.Device - *device.Logger -} - -var tunnelHandles = make(map[int32]tunnelHandle) - -func init() { - signals := make(chan os.Signal) - signal.Notify(signals, unix.SIGUSR2) - go func() { - buf := make([]byte, os.Getpagesize()) - for { - select { - case <-signals: - n := runtime.Stack(buf, true) - buf[n] = 0 - if uintptr(loggerFunc) != 0 { - C.callLogger(loggerFunc, loggerCtx, 0, (*C.char)(unsafe.Pointer(&buf[0]))) - } - } - } - }() -} - -//export wgSetLogger -func wgSetLogger(context, loggerFn uintptr) { - loggerCtx = unsafe.Pointer(context) - loggerFunc = unsafe.Pointer(loggerFn) -} - -//export wgTurnOn -func wgTurnOn(settings *C.char, tunFd int32) int32 { - logger := &device.Logger{ - Verbosef: CLogger(0).Printf, - Errorf: CLogger(1).Printf, - } - dupTunFd, err := unix.Dup(int(tunFd)) - if err != nil { - logger.Errorf("Unable to dup tun fd: %v", err) - return -1 - } - - err = unix.SetNonblock(dupTunFd, true) - if err != nil { - logger.Errorf("Unable to set tun fd as non blocking: %v", err) - unix.Close(dupTunFd) - return -1 - } - tun, err := tun.CreateTUNFromFile(os.NewFile(uintptr(dupTunFd), "/dev/tun"), 0) - if err != nil { - logger.Errorf("Unable to create new tun device from fd: %v", err) - unix.Close(dupTunFd) - return -1 - } - logger.Verbosef("Attaching to interface") - dev := device.NewDevice(tun, conn.NewStdNetBind(), logger) - - err = dev.IpcSet(C.GoString(settings)) - if err != nil { - logger.Errorf("Unable to set IPC settings: %v", err) - unix.Close(dupTunFd) - dev.Close() - return -1 - } - - dev.Up() - logger.Verbosef("Device started") - - var i int32 - for i = 0; i < math.MaxInt32; i++ { - if _, exists := tunnelHandles[i]; !exists { - break - } - } - if i == math.MaxInt32 { - unix.Close(dupTunFd) - dev.Close() - return -1 - } - tunnelHandles[i] = tunnelHandle{dev, logger} - return i -} - -//export wgTurnOff -func wgTurnOff(tunnelHandle int32) { - dev, ok := tunnelHandles[tunnelHandle] - if !ok { - return - } - delete(tunnelHandles, tunnelHandle) - dev.Close() -} - -//export wgSetConfig -func wgSetConfig(tunnelHandle int32, settings *C.char) int64 { - dev, ok := tunnelHandles[tunnelHandle] - if !ok { - return 0 - } - err := dev.IpcSet(C.GoString(settings)) - if err != nil { - dev.Errorf("Unable to set IPC settings: %v", err) - if ipcErr, ok := err.(*device.IPCError); ok { - return ipcErr.ErrorCode() - } - return -1 - } - return 0 -} - -//export wgGetConfig -func wgGetConfig(tunnelHandle int32) *C.char { - device, ok := tunnelHandles[tunnelHandle] - if !ok { - return nil - } - settings, err := device.IpcGet() - if err != nil { - return nil - } - return C.CString(settings) -} - -//export wgBumpSockets -func wgBumpSockets(tunnelHandle int32) { - dev, ok := tunnelHandles[tunnelHandle] - if !ok { - return - } - go func() { - for i := 0; i < 10; i++ { - err := dev.BindUpdate() - if err == nil { - dev.SendKeepalivesToPeersWithCurrentKeypair() - return - } - dev.Errorf("Unable to update bind, try %d: %v", i+1, err) - time.Sleep(time.Second / 2) - } - dev.Errorf("Gave up trying to update bind; tunnel is likely dysfunctional") - }() -} - -//export wgDisableSomeRoamingForBrokenMobileSemantics -func wgDisableSomeRoamingForBrokenMobileSemantics(tunnelHandle int32) { - dev, ok := tunnelHandles[tunnelHandle] - if !ok { - return - } - dev.DisableSomeRoamingForBrokenMobileSemantics() -} - -//export wgVersion -func wgVersion() *C.char { - info, ok := debug.ReadBuildInfo() - if !ok { - return C.CString("unknown") - } - for _, dep := range info.Deps { - if dep.Path == "golang.zx2c4.com/wireguard" { - parts := strings.Split(dep.Version, "-") - if len(parts) == 3 && len(parts[2]) == 12 { - return C.CString(parts[2][:7]) - } - return C.CString(dep.Version) - } - } - return C.CString("unknown") -} - -func main() {} diff --git a/ios/gobridge/dummy.c b/ios/gobridge/dummy.c deleted file mode 100644 index d15abba5976..00000000000 --- a/ios/gobridge/dummy.c +++ /dev/null @@ -1 +0,0 @@ -// Empty diff --git a/ios/gobridge/go.mod b/ios/gobridge/go.mod deleted file mode 100644 index af3aaf44625..00000000000 --- a/ios/gobridge/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module golang.zx2c4.com/wireguard/apple - -go 1.17 - -require ( - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/net v0.0.0-20210917221730-978cfadd31cf // indirect - golang.org/x/sys v0.0.0-20210921065528-437939a70204 - golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c -) diff --git a/ios/gobridge/go.sum b/ios/gobridge/go.sum deleted file mode 100644 index 1bb4e81f796..00000000000 --- a/ios/gobridge/go.sum +++ /dev/null @@ -1,24 +0,0 @@ -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ= -golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20210921065528-437939a70204 h1:JJhkWtBuTQKyz2bd5WG9H8iUsJRU3En/KRfN8B2RnDs= -golang.org/x/sys v0.0.0-20210921065528-437939a70204/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c h1:IsAez/yRA23H/i9A02IHbYnmtVOs7DsP3aVP2cu5SNE= -golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= diff --git a/ios/gobridge/goruntime-boottime-over-monotonic.diff b/ios/gobridge/goruntime-boottime-over-monotonic.diff deleted file mode 100644 index 2f7f54edd01..00000000000 --- a/ios/gobridge/goruntime-boottime-over-monotonic.diff +++ /dev/null @@ -1,61 +0,0 @@ -From 516dc0c15ff1ab781e0677606b5be72919251b3e Mon Sep 17 00:00:00 2001 -From: "Jason A. Donenfeld" -Date: Wed, 9 Dec 2020 14:07:06 +0100 -Subject: [PATCH] runtime: use libc_mach_continuous_time in nanotime on Darwin - -This makes timers account for having expired while a computer was -asleep, which is quite common on mobile devices. Note that -continuous_time absolute_time, except that it takes into account -time spent in suspend. - -Fixes #24595 - -Change-Id: Ia3282e8bd86f95ad2b76427063e60a005563f4eb ---- - src/runtime/sys_darwin.go | 2 +- - src/runtime/sys_darwin_amd64.s | 2 +- - src/runtime/sys_darwin_arm64.s | 2 +- - 3 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go -index 4a3f2fc453..4a69403b32 100644 ---- a/src/runtime/sys_darwin.go -+++ b/src/runtime/sys_darwin.go -@@ -440,7 +440,7 @@ func setNonblock(fd int32) { - //go:cgo_import_dynamic libc_usleep usleep "/usr/lib/libSystem.B.dylib" - - //go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib" --//go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib" -+//go:cgo_import_dynamic libc_mach_continuous_time mach_continuous_time "/usr/lib/libSystem.B.dylib" - //go:cgo_import_dynamic libc_clock_gettime clock_gettime "/usr/lib/libSystem.B.dylib" - //go:cgo_import_dynamic libc_sigaction sigaction "/usr/lib/libSystem.B.dylib" - //go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib" -diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s -index 630fb5df64..4499c88802 100644 ---- a/src/runtime/sys_darwin_amd64.s -+++ b/src/runtime/sys_darwin_amd64.s -@@ -114,7 +114,7 @@ TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0 - PUSHQ BP - MOVQ SP, BP - MOVQ DI, BX -- CALL libc_mach_absolute_time(SB) -+ CALL libc_mach_continuous_time(SB) - MOVQ AX, 0(BX) - MOVL timebase<>+machTimebaseInfo_numer(SB), SI - MOVL timebase<>+machTimebaseInfo_denom(SB), DI // atomic read -diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s -index 96d2ed1076..f046545395 100644 ---- a/src/runtime/sys_darwin_arm64.s -+++ b/src/runtime/sys_darwin_arm64.s -@@ -143,7 +143,7 @@ GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size) - - TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$40 - MOVD R0, R19 -- BL libc_mach_absolute_time(SB) -+ BL libc_mach_continuous_time(SB) - MOVD R0, 0(R19) - MOVW timebase<>+machTimebaseInfo_numer(SB), R20 - MOVD $timebase<>+machTimebaseInfo_denom(SB), R21 --- -2.30.1 - diff --git a/ios/gobridge/module.modulemap b/ios/gobridge/module.modulemap deleted file mode 100644 index 2ca39160f10..00000000000 --- a/ios/gobridge/module.modulemap +++ /dev/null @@ -1,5 +0,0 @@ -module WireGuardKitGo { - umbrella header "wireguard.h" - link "wg-go" - export * -} diff --git a/ios/gobridge/wireguard.h b/ios/gobridge/wireguard.h deleted file mode 100644 index b442173f4ef..00000000000 --- a/ios/gobridge/wireguard.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * - * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved. - */ - -#ifndef WIREGUARD_H -#define WIREGUARD_H - -#include -#include -#include - -typedef void (*logger_fn_t)(void* context, int level, const char* msg); -extern void wgSetLogger(void* context, logger_fn_t logger_fn); -extern int wgTurnOn(const char* settings, int32_t tun_fd); -extern void wgTurnOff(int handle); -extern int64_t wgSetConfig(int handle, const char* settings); -extern char* wgGetConfig(int handle); -extern void wgBumpSockets(int handle); -extern void wgDisableSomeRoamingForBrokenMobileSemantics(int handle); -extern const char* wgVersion(); - -#endif diff --git a/ios/networkextension/WireGuardNetworkExtension-Bridging-Header.h b/ios/networkextension/WireGuardNetworkExtension-Bridging-Header.h index e39386929bd..25c7aac5cc5 100644 --- a/ios/networkextension/WireGuardNetworkExtension-Bridging-Header.h +++ b/ios/networkextension/WireGuardNetworkExtension-Bridging-Header.h @@ -2,8 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "ios/gobridge/wireguard.h" -#include "wireguard-go-version.h" +#include "3rdparty/wireguard-apple/Sources/WireGuardKitGo/wireguard.h" +#include "3rdparty/wireguard-apple/Sources/WireGuardKitGo/wireguard-go-version.h" #include "3rdparty/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h" #include diff --git a/scripts/macos/apple_compile.sh b/scripts/macos/apple_compile.sh index 0a6894f98e7..b99afbb09d6 100755 --- a/scripts/macos/apple_compile.sh +++ b/scripts/macos/apple_compile.sh @@ -95,7 +95,7 @@ export PATH="$QT_BIN:$PATH" if [[ "$OS" == "ios" ]]; then printn Y "Retrieve the wireguard-go version... " - (cd ios/gobridge && go list -m golang.zx2c4.com/wireguard | sed -n 's/.*v\([0-9.]*\).*/#define WIREGUARD_GO_VERSION "\1"/p') > ios/gobridge/wireguard-go-version.h + (cd 3rdparty/wireguard-apple/Sources/WireGuardKitGo/ && go list -m golang.zx2c4.com/wireguard | sed -n 's/.*v\([0-9.]*\).*/#define WIREGUARD_GO_VERSION "\1"/p') > 3rdparty/wireguard-apple/Sources/WireGuardKitGo/wireguard-go-version.h print G "done." fi diff --git a/scripts/macos/utils/xcode_patcher.rb b/scripts/macos/utils/xcode_patcher.rb index 682dbee383d..3b0fe19bdba 100644 --- a/scripts/macos/utils/xcode_patcher.rb +++ b/scripts/macos/utils/xcode_patcher.rb @@ -54,6 +54,7 @@ def setup_target_main(configHash, adjust_sdk_token) "$(inherited)", "$(PROJECT_DIR)/3rdparty", "$(PROJECT_DIR)/3rdparty/wireguard-apple/Sources/WireGuardKitC", + "$(PROJECT_DIR)/3rdparty/wireguard-apple/Sources/WireGuardKitGo", ] config.build_settings['PRODUCT_NAME'] = 'Mozilla VPN' @@ -74,7 +75,7 @@ def setup_target_main(configHash, adjust_sdk_token) group = @project.main_group.new_group('WireGuard') [ - 'ios/gobridge/wireguard-go-version.h', + '3rdparty/wireguard-apple/Sources/WireGuardKitGo/wireguard-go-version.h', '3rdparty/wireguard-apple/Sources/Shared/Keychain.swift', '3rdparty/wireguard-apple/Sources/WireGuardKit/IPAddressRange.swift', '3rdparty/wireguard-apple/Sources/WireGuardKit/InterfaceConfiguration.swift', @@ -225,8 +226,8 @@ def setup_target_extension(shortVersion, fullVersion, configHash) config.build_settings['SDKROOT'] = 'iphoneos' config.build_settings['FRAMEWORK_SEARCH_PATHS'] ||= [ - "$(PROJECT_DIR)/ios/gobridge", "$(PROJECT_DIR)/3rdparty/wireguard-apple/Sources/WireGuardKitC", + "$(PROJECT_DIR)/3rdparty/wireguard-apple/Sources/WireGuardKitGo", ] config.build_settings['OTHER_LDFLAGS'] ||= [ "-stdlib=libc++", @@ -318,7 +319,7 @@ def setup_target_extension(shortVersion, fullVersion, configHash) def setup_target_gobridge target_gobridge = legacy_target = @project.new(Xcodeproj::Project::PBXLegacyTarget) - target_gobridge.build_working_directory = 'ios/gobridge' + target_gobridge.build_working_directory = '3rdparty/wireguard-apple/Sources/WireGuardKitGo' target_gobridge.build_tool_path = 'make' target_gobridge.pass_build_settings_in_environment = '1' target_gobridge.build_arguments_string = '$(ACTION)' diff --git a/src/platforms/ios/ioslogger.swift b/src/platforms/ios/ioslogger.swift index deb2285ea5b..9f873755d95 100644 --- a/src/platforms/ios/ioslogger.swift +++ b/src/platforms/ios/ioslogger.swift @@ -37,8 +37,7 @@ public class Logger { appVersion += " (\(appBuild))" } - let goBackendVersion = WIREGUARD_GO_VERSION - Logger.global?.log(message: "App version: \(appVersion); Go backend version: \(goBackendVersion)") + Logger.global?.log(message: "App version: \(appVersion)") } } From 1cf35ae5ef977ff1b4a35473d1f7161e17a09767 Mon Sep 17 00:00:00 2001 From: Matt Lichtenstein Date: Wed, 5 Oct 2022 15:49:24 -0400 Subject: [PATCH 11/85] Fix when edit callback is triggered for search bar (#4528) --- nebula/ui/components/forms/VPNSearchBar.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nebula/ui/components/forms/VPNSearchBar.qml b/nebula/ui/components/forms/VPNSearchBar.qml index 9df3606a454..6878b1d1ae1 100644 --- a/nebula/ui/components/forms/VPNSearchBar.qml +++ b/nebula/ui/components/forms/VPNSearchBar.qml @@ -46,7 +46,7 @@ ColumnLayout { Keys.onPressed: event => { - if (focus && _searchBarHasError && (/[\w\[\]`!@#$%\^&*()={}:;<>+'-]/).test(event.text)) { + if (focus && ((/[\w\[\]`!@#$%\^&*()={}:;<>+'-]/).test(event.text) || event.key === Qt.Key_Backspace || event.key === Qt.Key_Delete)) { _editCallback(); } } From 93fff2b1b1f85424d0a50fee55426b058259fb21 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Thu, 6 Oct 2022 10:24:15 +0200 Subject: [PATCH 12/85] Add comments to the IOSController to explain why of the timer (#4580) --- src/platforms/ios/ioscontroller.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/platforms/ios/ioscontroller.swift b/src/platforms/ios/ioscontroller.swift index da052118f0d..68315692756 100644 --- a/src/platforms/ios/ioscontroller.swift +++ b/src/platforms/ios/ioscontroller.swift @@ -112,12 +112,18 @@ public class IOSControllerImpl : NSObject { return } + // This timer is used to workaround a Schrödinger's cat bug: if we check + // the connection status immediately when connected, we alter the iOS16 + // connectivity state and we break the VPN tunnel (intermittently). With + // a timer this does not happen. _ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) {_ in self.monitorConnection() } } private func monitorConnection() -> Void { + // Let's call `stateChangeCallback` if connected and if + // last_handshake_time_sec is not 0. self.checkStatus { _, _, configString in if self.tunnel?.connection.status != .connected { return; } From e02d0060376d2a3c72e09aeb6c004d79e8f99933 Mon Sep 17 00:00:00 2001 From: Beatriz Rizental Date: Thu, 6 Oct 2022 15:25:37 +0200 Subject: [PATCH 13/85] Do not set Glean debug view tag by default (#4584) The debug view tag is a feature that should really only be used when developing / testing Glean instrumentation, because it will redirect pings to the Glean ping debug viewer (https://debug-ping-preview.firebaseapp.com/pings/MozillaVPN). By leaving it default on we are in practice just flooding the data pipeline and debug viewer for no reason. --- src/ui/main.qml | 7 +++++-- tests/qml/tst_mainWindowGleanMocks.qml | 11 ++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/ui/main.qml b/src/ui/main.qml index 7ee80d9ea8e..f2cb9a2d52a 100644 --- a/src/ui/main.qml +++ b/src/ui/main.qml @@ -141,7 +141,10 @@ Window { if (VPN.debugMode) { console.debug("Initializing glean with debug mode"); Glean.setLogPings(true); - Glean.setDebugViewTag("MozillaVPN"); + // Uncomment for debugging purposes. + // See: https://mozilla.github.io/glean/book/reference/debug/debugViewTag.html#debug-view-tag + // + // Glean.setDebugViewTag("MozillaVPN"); } var channel = VPN.stagingMode ? "staging" : "production"; @@ -176,7 +179,7 @@ Window { } function onAboutToQuit() { - console.debug("about to quit, shutdown Glean"); + console.debug("about to quit, shutdown Glean"); // Submit the main ping in case there are outstading metrics in storage before shutdown. Pings.main.submit(); // Use glean's built-in shutdown method - https://mozilla.github.io/glean/book/reference/general/shutdown.html diff --git a/tests/qml/tst_mainWindowGleanMocks.qml b/tests/qml/tst_mainWindowGleanMocks.qml index 16f14fe7878..0f263713b09 100644 --- a/tests/qml/tst_mainWindowGleanMocks.qml +++ b/tests/qml/tst_mainWindowGleanMocks.qml @@ -19,7 +19,6 @@ Item { property var spyConfig property var spyTags property var spyLogPings - property var spySetDebugViewTag property var spyShutdownCalled: false property var spyUploadEnabled @@ -40,10 +39,6 @@ Item { spyLogPings = flag } Glean.setLogPings = mockGleanSetLogPings; - function mockGleanSetDebugViewTag(tag) { - spySetDebugViewTag = tag - } - Glean.setDebugViewTag = mockGleanSetDebugViewTag; function mockGleanShutdown() { // Should be false before setting it to true in this function. // Helps protect us from bad testing state. @@ -112,22 +107,20 @@ Item { TestHelper.debugMode = false TestHelper.triggerInitializeGlean() compare(spyLogPings, undefined) - compare(spySetDebugViewTag, undefined) TestHelper.debugMode = true TestHelper.triggerInitializeGlean() compare(spyLogPings, true) - compare(spySetDebugViewTag, "MozillaVPN") } /* - * TODO - We should also have a companion unit test for the + * TODO - We should also have a companion unit test for the * mozillavpn method mainWindowLoaded that checks that: * a) mainWindowLoaded calls initializeGlean * b) sets up a timer * * But we don't have a way to test mozillavpn.cpp functions yet. - * I have added to the integration test cases to cover our bases + * I have added to the integration test cases to cover our bases * on these test cases. */ } From 09be7f1e13a24f8e22eb9ac9947e8fcc4f7e9e5e Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Thu, 6 Oct 2022 15:51:27 +0200 Subject: [PATCH 14/85] Fix the compilation of Qt6.4 (#4586) QDnsLookup is still not implemented for android. Let's see with qt6.5 --- src/connectionbenchmark/benchmarktaskdownload.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/connectionbenchmark/benchmarktaskdownload.cpp b/src/connectionbenchmark/benchmarktaskdownload.cpp index d109ba8e61f..5d9389feff5 100644 --- a/src/connectionbenchmark/benchmarktaskdownload.cpp +++ b/src/connectionbenchmark/benchmarktaskdownload.cpp @@ -47,7 +47,7 @@ void BenchmarkTaskDownload::handleState(BenchmarkTask::State state) { m_dnsLookup.setNameserver(QHostAddress(MULLVAD_DEFAULT_DNS)); #endif -#if QT_VERSION >= 0x060400 +#if QT_VERSION >= 0x060500 # error Check if QT added support for QDnsLookup::lookup() on Android #endif From 834ad13af777ab8c363c379d49dfbdbb60f50e9d Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Thu, 6 Oct 2022 18:32:51 +0200 Subject: [PATCH 15/85] New public-key for addons in prod (#4588) --- src/resources/public_keys/production.der | Bin 526 -> 526 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/resources/public_keys/production.der b/src/resources/public_keys/production.der index dda72abe4b82b61fb7b8b18c840e48e223bc1f21..f2f00b98d7c263f798a0f5a07c42e5b6793540b3 100644 GIT binary patch literal 526 zcmV+p0`dJYf&vNxf&u{mk_W$ioGQ3l_b(ym(NY5!WG zwI`6LF=UpdDmsPFrE-S>^NZo;4V%8JPw2#TAL+skq$lx?{K;_ZJo zqD$69X&cqSp2KB+?fEO9s_>n^?FkjWnG~TiG(;cPLp43qc*t#d?<@A8_mQmRP`-F{ zpw{k)u=4H*&>fy9Ch|-y*17hJUV6Nm5-+YYFcNj&2T7E#Lo(2Pf&7=fOKldlKSg*+ zW|o5wgI-KE1}6le>W5*tM~QsA`NHBN_Ye(+H}~Qdy$>|dH-iJZ^sM#;R2g>;e*!C` zK-qQ+=;BvU!s5EV`}#%PJVJo3^P|krHMJ19P%(3|jX$mhM(|RR;DR%glygbg-Ubdk Q?(>R|hy+gb_907ZFzsiygALs>w!;J`&uSh*LxZu}pcg z){dls(#i0YVMpWNs4S0`Q8TC_1h0o10ibLJ9_(De0U!eW`8uR9>OG@qG_JR&ohpiX z^8|mK^zte<46Il1=QE2d9gr%4%Ye0=YxY4#76^M)W?ry4`^pPhvA!H90?!um6amEVKyKUwwjKLP!k4K(}5Q8m?*SI%qTEs zWu?~|&a~;rQ5k*P02y}L3_*+vEwLVt#E9ey#_4x5JWDO$cBr}Ueqm3YDzNT^5D^vl Qz)oi)5b}=M0s{d60rSG}4gdfE From 90dc16a4bfe26f18b1b904af6a93198b9e5f083f Mon Sep 17 00:00:00 2001 From: Owen Kirby Date: Thu, 6 Oct 2022 08:17:48 -1000 Subject: [PATCH 16/85] Fix android exception when no fallback server is present. (#4581) --- .../java/org/mozilla/firefox/vpn/daemon/VPNService.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/android/daemon/src/main/java/org/mozilla/firefox/vpn/daemon/VPNService.kt b/android/daemon/src/main/java/org/mozilla/firefox/vpn/daemon/VPNService.kt index 9392f056de2..e6cf828ee30 100644 --- a/android/daemon/src/main/java/org/mozilla/firefox/vpn/daemon/VPNService.kt +++ b/android/daemon/src/main/java/org/mozilla/firefox/vpn/daemon/VPNService.kt @@ -235,17 +235,21 @@ class VPNService : android.net.VpnService() { if (useFallbackServer) { mConnectionHealth.start( - json.getJSONObject("server").getString("ipv4AddrIn"), + json.getJSONObject("serverFallback").getString("ipv4AddrIn"), json.getJSONObject("serverFallback").getString("ipv4Gateway"), json.getJSONObject("serverFallback").getString("ipv4Gateway"), - json.getJSONObject("serverFallback").getString("ipv4AddrIn") + json.getJSONObject("server").getString("ipv4AddrIn") ) } else { + var fallbackIpv4 = "" + if (json.has("serverFallback")) { + fallbackIpv4 = json.getJSONObject("serverFallback").getString("ipv4AddrIn") + } mConnectionHealth.start( json.getJSONObject("server").getString("ipv4AddrIn"), json.getJSONObject("server").getString("ipv4Gateway"), json.getString("dns"), - json.getJSONObject("serverFallback").getString("ipv4Gateway") + fallbackIpv4 ) } } From f26fd8bff14ac11f03f3e9b47fb464779590ad25 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 7 Oct 2022 02:50:03 +0200 Subject: [PATCH 17/85] Rename manifest.json.sign to manifest.json.sig (#4591) --- .github/workflows/gh_pages.yaml | 4 ++-- docs/add-on.md | 2 +- src/addons/manager/addonindex.h | 2 +- src/tasks/addonindex/taskaddonindex.cpp | 2 +- taskcluster/scripts/push-addons/deploy.sh | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/gh_pages.yaml b/.github/workflows/gh_pages.yaml index e0fd4696cb6..68329e4cab7 100644 --- a/.github/workflows/gh_pages.yaml +++ b/.github/workflows/gh_pages.yaml @@ -112,7 +112,7 @@ jobs: ADDON_PRIVATE_KEY: ${{ secrets.ADDON_PRIVATE_KEY }} run: | echo -n "$ADDON_PRIVATE_KEY" > addon_private_key.pem - openssl dgst -sha256 -sign addon_private_key.pem -out addons/generated/addons/manifest.json.sign addons/generated/addons/manifest.json + openssl dgst -sha256 -sign addon_private_key.pem -out addons/generated/addons/manifest.json.sig addons/generated/addons/manifest.json rm addon_private_key.pem - name: Uploading @@ -166,4 +166,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v1 \ No newline at end of file + uses: actions/deploy-pages@v1 diff --git a/docs/add-on.md b/docs/add-on.md index cb630d40ef7..4c2cfa02217 100644 --- a/docs/add-on.md +++ b/docs/add-on.md @@ -114,4 +114,4 @@ If you want to implement new add-ons, you need to follow these steps: 7. be sure you are doing all of this using a staging environment If all has done correctly, you can see the app fetching the manifest.json (and -not! the manifest.json.sign) resource from the webservice. +not! the manifest.json.sig) resource from the webservice. diff --git a/src/addons/manager/addonindex.h b/src/addons/manager/addonindex.h index 36f9ff28b04..e98d183e8f1 100644 --- a/src/addons/manager/addonindex.h +++ b/src/addons/manager/addonindex.h @@ -17,7 +17,7 @@ class Addon; constexpr const char* ADDONS_API_VERSION = "0.1"; constexpr const char* ADDON_INDEX_FILENAME = "manifest.json"; -constexpr const char* ADDON_INDEX_SIGNATURE_FILENAME = "manifest.json.sign"; +constexpr const char* ADDON_INDEX_SIGNATURE_FILENAME = "manifest.json.sig"; // This struct can be partially empty in case the sha does not match, or the // addon does not need to be loaded for unmatched conditions. diff --git a/src/tasks/addonindex/taskaddonindex.cpp b/src/tasks/addonindex/taskaddonindex.cpp index 228204e79cd..5584aa31b89 100644 --- a/src/tasks/addonindex/taskaddonindex.cpp +++ b/src/tasks/addonindex/taskaddonindex.cpp @@ -46,7 +46,7 @@ void TaskAddonIndex::run() { if (Feature::get(Feature::Feature_addonSignature)->isSupported()) { NetworkRequest* request = NetworkRequest::createForGetUrl( this, - QString("%1manifest.json.sign").arg(AddonManager::addonServerAddress()), + QString("%1manifest.json.sig").arg(AddonManager::addonServerAddress()), 200); connect(request, &NetworkRequest::requestFailed, this, diff --git a/taskcluster/scripts/push-addons/deploy.sh b/taskcluster/scripts/push-addons/deploy.sh index b64a970bf00..b1ba3bf8305 100755 --- a/taskcluster/scripts/push-addons/deploy.sh +++ b/taskcluster/scripts/push-addons/deploy.sh @@ -16,6 +16,6 @@ echo "Fetching Tokens!" ls cd /builds/worker/fetches/ ls -openssl dgst -sha256 -sign /builds/worker/checkouts/vcs/addons_key.pem -out addons/manifest.json.sign addons/manifest.json +openssl dgst -sha256 -sign /builds/worker/checkouts/vcs/addons_key.pem -out addons/manifest.json.sig addons/manifest.json -cp -r /builds/worker/fetches/addons /builds/worker/artifacts \ No newline at end of file +cp -r /builds/worker/fetches/addons /builds/worker/artifacts From df7517bc5aeda13601891d9ff448cef0b8249e19 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 7 Oct 2022 08:27:35 +0200 Subject: [PATCH 18/85] Fix the try-again button in the contact-us-form - VPN-2908 (#4579) --- .../screens/getHelp/contactUs/ViewContactUsForm.qml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ui/screens/getHelp/contactUs/ViewContactUsForm.qml b/src/ui/screens/getHelp/contactUs/ViewContactUsForm.qml index 80564aa0c66..bb1fa1955b0 100644 --- a/src/ui/screens/getHelp/contactUs/ViewContactUsForm.qml +++ b/src/ui/screens/getHelp/contactUs/ViewContactUsForm.qml @@ -25,11 +25,6 @@ VPNViewBase { VPN.createSupportTicket(email, subject, issueText, category); } - function fxaBrowserLink() { - VPNUrlOpener.openLink(VPNUrlOpener.LinkHelpSupport); - contactUsRoot.tryAgain(); - } - Connections { target: VPN function onTicketCreationAnswer(successful) { @@ -41,12 +36,15 @@ VPNViewBase { headlineText: VPNl18n.InAppSupportWorkflowSupportErrorHeader, errorMessage: VPNl18n.InAppSupportWorkflowSupportErrorText, primaryButtonText: VPNl18n.InAppSupportWorkflowSupportErrorButton, - primaryButtonOnClick: contactUsRoot.tryAgain, + primaryButtonOnClick: () => getHelpStackView.pop(), primaryButtonObjectName: "errorTryAgainButton", secondaryButtonIsSignOff: false, secondaryButtonText: VPNl18n.InAppSupportWorkflowSupportErrorBrowserButton, secondaryButtonObjectName: "errorFxALinkButton", - secondaryButtonOnClick: contactUsRoot.fxaBrowserLink + secondaryButtonOnClick: () => { + VPNUrlOpener.openLink(VPNUrlOpener.LinkHelpSupport); + getHelpStackView.pop(); + }, } ); } From a9870b6579febcc71ba3cf42d377040f9ad1c048 Mon Sep 17 00:00:00 2001 From: Beatriz Rizental Date: Fri, 7 Oct 2022 18:38:34 +0200 Subject: [PATCH 19/85] VPN-2988 - Record events on controller error steps (#4594) --- glean/metrics.yaml | 20 +++++++++++++++++--- src/controller.cpp | 1 + src/telemetry.cpp | 7 +++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/glean/metrics.yaml b/glean/metrics.yaml index eed7f43c62f..4ca46f10833 100644 --- a/glean/metrics.yaml +++ b/glean/metrics.yaml @@ -18,7 +18,6 @@ $schema: moz://mozilla.org/schemas/glean/metrics/2-0-0 sample: - addon_state_changed: type: event lifetime: ping @@ -71,7 +70,6 @@ sample: Received, Notified, Read, or Dismissed type: string - addon_cta_clicked: type: event lifetime: ping @@ -566,7 +564,6 @@ sample: - amarchesini@mozilla.com expires: never - connection_health_no_signal: type: event lifetime: ping @@ -1047,6 +1044,23 @@ sample: description: The Host network type (i.e wifi or 4g) type: string + server_unavailable_error: + type: event + lifetime: ping + send_in_pings: + - main + description: | + A "Server unavailable" error has occured. + bugs: + - https://github.com/mozilla-mobile/mozilla-vpn-client/issues/4589 + data_reviews: + - https://github.com/mozilla-mobile/mozilla-vpn-client/pull/4594#issuecomment-1271601927 + data_sensitivity: + - technical + notification_emails: + - brizental@mozilla.com + expires: never + app_step: type: event lifetime: ping diff --git a/src/controller.cpp b/src/controller.cpp index abe7fb9caf9..d2da2492e8a 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -608,6 +608,7 @@ bool Controller::processNextStep() { if (nextStep == ServerUnavailable) { logger.info() << "Server Unavailable - Ping succeeded: " << m_ping_received; + emit readyToServerUnavailable(m_ping_received); return true; } diff --git a/src/telemetry.cpp b/src/telemetry.cpp index 181193387fb..ec5ef29e021 100644 --- a/src/telemetry.cpp +++ b/src/telemetry.cpp @@ -75,6 +75,13 @@ void Telemetry::initialize() { emit vpn->recordGleanEvent(GleanSample::controllerStateOff); } }); + + connect(controller, &Controller::readyToServerUnavailable, this, []() { + MozillaVPN* vpn = MozillaVPN::instance(); + Q_ASSERT(vpn); + + emit vpn->recordGleanEvent(GleanSample::serverUnavailableError); + }); } void Telemetry::connectionStabilityEvent() { From 931652970ec93fbcc34b10f6d3216a0f8c39dcc7 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 7 Oct 2022 18:54:46 +0200 Subject: [PATCH 20/85] Move error handling in a separate class (#4597) --- nebula/ui/components/VPNSystemAlert.qml | 24 ++-- src/commands/commandlogin.cpp | 6 +- src/controller.cpp | 4 +- src/errorhandler.cpp | 107 ++++++++++++++++ src/errorhandler.h | 34 ++++- src/inspector/inspectorhandler.cpp | 2 +- src/localsocketcontroller.cpp | 5 +- src/mozillavpn.cpp | 121 ++---------------- src/mozillavpn.h | 28 +--- src/platforms/android/androidcontroller.cpp | 4 +- src/platforms/android/androidiaphandler.cpp | 2 +- src/platforms/ios/iosiaphandler.mm | 8 +- src/platforms/linux/linuxcontroller.cpp | 5 +- src/platforms/wasm/wasmiaphandler.cpp | 3 +- src/profileflow.cpp | 2 +- src/tasks/account/taskaccount.cpp | 2 +- src/tasks/adddevice/taskadddevice.cpp | 16 +-- src/tasks/authenticate/taskauthenticate.cpp | 13 +- .../taskcaptiveportallookup.cpp | 2 +- src/tasks/deleteaccount/taskdeleteaccount.cpp | 6 +- .../taskgetsubscriptiondetails.cpp | 10 +- src/tasks/ipfinder/taskipfinder.cpp | 3 +- src/tasks/products/taskproducts.cpp | 4 +- src/tasks/removedevice/taskremovedevice.cpp | 2 +- src/tasks/servers/taskservers.cpp | 2 +- .../ViewAuthenticationUnblockCodeNeeded.qml | 2 +- ...cationVerificationSessionByEmailNeeded.qml | 2 +- src/update/balrog.cpp | 7 +- tests/auth/CMakeLists.txt | 12 ++ tests/auth/auth.pro | 12 ++ tests/auth/mocmozillavpn.cpp | 6 +- tests/qml/CMakeLists.txt | 8 +- tests/qml/mocmozillavpn.cpp | 6 +- tests/qml/qml.pro | 8 +- tests/unit/mocmozillavpn.cpp | 6 +- 35 files changed, 254 insertions(+), 230 deletions(-) diff --git a/nebula/ui/components/VPNSystemAlert.qml b/nebula/ui/components/VPNSystemAlert.qml index f1bacee164c..bce2144f3b9 100644 --- a/nebula/ui/components/VPNSystemAlert.qml +++ b/nebula/ui/components/VPNSystemAlert.qml @@ -14,17 +14,17 @@ VPNAlert { Item { id: alertStates - state: VPN.alert + state: VPNErrorHandler.alert states: [ State { - name: VPN.NoAlert + name: VPNErrorHandler.NoAlert PropertyChanges { target: alertBox visible: false } }, State{ - name: VPN.AuthCodeSentAlert + name: VPNErrorHandler.AuthCodeSentAlert PropertyChanges { target: alertBox alertType: alertTypes.success @@ -33,7 +33,7 @@ VPNAlert { } }, State { - name: VPN.AuthenticationFailedAlert + name: VPNErrorHandler.AuthenticationFailedAlert PropertyChanges { target: alertBox //% "Authentication error" @@ -48,7 +48,7 @@ VPNAlert { } }, State { - name: VPN.ConnectionFailedAlert + name: VPNErrorHandler.ConnectionFailedAlert PropertyChanges { target: alertBox //% "Unable to connect" @@ -58,7 +58,7 @@ VPNAlert { } }, State { - name: VPN.NoConnectionAlert + name: VPNErrorHandler.NoConnectionAlert PropertyChanges { target: alertBox //% "No internet connection" @@ -68,7 +68,7 @@ VPNAlert { } }, State { - name: VPN.ControllerErrorAlert + name: VPNErrorHandler.ControllerErrorAlert PropertyChanges { target: alertBox //% "Background service error" @@ -83,7 +83,7 @@ VPNAlert { } }, State { - name: VPN.UnrecoverableErrorAlert + name: VPNErrorHandler.UnrecoverableErrorAlert PropertyChanges { target: alertBox alertText: qsTrId("vpn.alert.backendServiceError") @@ -94,7 +94,7 @@ VPNAlert { } }, State { - name: VPN.RemoteServiceErrorAlert + name: VPNErrorHandler.RemoteServiceErrorAlert PropertyChanges { target: alertBox //% "Remote service error" @@ -106,7 +106,7 @@ VPNAlert { } }, State { - name: VPN.SubscriptionFailureAlert + name: VPNErrorHandler.SubscriptionFailureAlert PropertyChanges { target: alertBox //% "Subscription failed" @@ -116,7 +116,7 @@ VPNAlert { } }, State { - name: VPN.GeoIpRestrictionAlert + name: VPNErrorHandler.GeoIpRestrictionAlert PropertyChanges { target: alertBox //% "Operation not allowed from current location" @@ -125,7 +125,7 @@ VPNAlert { } }, State { - name: VPN.LogoutAlert + name: VPNErrorHandler.LogoutAlert PropertyChanges { target: alertBox alertType: alertTypes.success diff --git a/src/commands/commandlogin.cpp b/src/commands/commandlogin.cpp index 4df649d1d7a..000d4b2e100 100644 --- a/src/commands/commandlogin.cpp +++ b/src/commands/commandlogin.cpp @@ -207,14 +207,16 @@ int CommandLogin::run(QStringList& tokens) { vpn.state() == MozillaVPN::StateMain) { loop.exit(); } - if (vpn.alert() == MozillaVPN::AuthenticationFailedAlert) { + if (ErrorHandler::instance()->alert() == + ErrorHandler::AuthenticationFailedAlert) { loop.exit(); } }); loop.exec(); - if (vpn.alert() == MozillaVPN::AuthenticationFailedAlert) { + if (ErrorHandler::instance()->alert() == + ErrorHandler::AuthenticationFailedAlert) { QTextStream stream(stdout); stream << "Authentication failed" << Qt::endl; return 1; diff --git a/src/controller.cpp b/src/controller.cpp index d2da2492e8a..3d223304124 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -144,7 +144,7 @@ void Controller::implInitialized(bool status, bool a_connected, Q_ASSERT(m_state == StateInitializing); if (!status) { - MozillaVPN::instance()->errorHandle(ErrorHandler::ControllerError); + ErrorHandler::instance()->errorHandle(ErrorHandler::ControllerError); setState(StateOff); return; } @@ -293,7 +293,7 @@ void Controller::activateNext() { MozillaVPN* vpn = MozillaVPN::instance(); const Device* device = vpn->deviceModel()->currentDevice(vpn->keys()); if (device == nullptr) { - vpn->errorHandle(ErrorHandler::AuthenticationError); + ErrorHandler::instance()->errorHandle(ErrorHandler::AuthenticationError); vpn->reset(false); return; } diff --git a/src/errorhandler.cpp b/src/errorhandler.cpp index f74848841af..83b61896cf1 100644 --- a/src/errorhandler.cpp +++ b/src/errorhandler.cpp @@ -5,9 +5,14 @@ #include "errorhandler.h" #include "leakdetector.h" #include "logger.h" +#include "mozillavpn.h" +#include "telemetry/gleansample.h" #include +// in seconds, hide alerts +constexpr const uint32_t HIDE_ALERT_SEC = 4; + namespace { ErrorHandler* s_instance = nullptr; Logger logger(LOG_MAIN, "ErrorHandler"); @@ -23,6 +28,9 @@ ErrorHandler* ErrorHandler::instance() { ErrorHandler::ErrorHandler(QObject* parent) : QObject(parent) { MVPN_COUNT_CTOR(ErrorHandler); + + connect(&m_alertTimer, &QTimer::timeout, this, + [this]() { setAlert(NoAlert); }); } ErrorHandler::~ErrorHandler() { MVPN_COUNT_DTOR(ErrorHandler); } @@ -119,3 +127,102 @@ ErrorHandler::ErrorType ErrorHandler::toErrorType( return IgnoredError; } + +void ErrorHandler::errorHandle(ErrorHandler::ErrorType error) { + logger.debug() << "Handling error" << error; + + Q_ASSERT(error != ErrorHandler::NoError); + + AlertType alert = NoAlert; + + MozillaVPN* vpn = MozillaVPN::instance(); + Q_ASSERT(vpn); + + switch (error) { + case ErrorHandler::VPNDependentConnectionError: + if (vpn->controller()->state() == Controller::State::StateOn || + vpn->controller()->state() == Controller::State::StateConfirming) { + // connection likely isn't stable yet + logger.error() << "Ignore network error probably caused by enabled VPN"; + return; + } else if (vpn->controller()->state() == Controller::State::StateOff) { + // We are off, so this means a request failed, not the + // VPN. Change it to No Connection + alert = NoConnectionAlert; + break; + } + [[fallthrough]]; + case ErrorHandler::ConnectionFailureError: + alert = ConnectionFailedAlert; + break; + + case ErrorHandler::NoConnectionError: + if (vpn->connectionHealth() && vpn->connectionHealth()->isUnsettled()) { + return; + } + alert = NoConnectionAlert; + break; + + case ErrorHandler::AuthenticationError: + alert = AuthenticationFailedAlert; + break; + + case ErrorHandler::ControllerError: + alert = ControllerErrorAlert; + break; + + case ErrorHandler::RemoteServiceError: + alert = RemoteServiceErrorAlert; + break; + + case ErrorHandler::SubscriptionFailureError: + alert = SubscriptionFailureAlert; + break; + + case ErrorHandler::GeoIpRestrictionError: + alert = GeoIpRestrictionAlert; + break; + + case ErrorHandler::UnrecoverableError: + alert = UnrecoverableErrorAlert; + break; + + default: + break; + } + + setAlert(alert); + + logger.error() << "Alert:" << alert << "State:" << vpn->state(); + + if (alert == NoAlert) { + return; + } + + // Any error in authenticating state sends to the Initial state. + if (vpn->state() == MozillaVPN::StateAuthenticating) { + if (alert == GeoIpRestrictionAlert) { + emit vpn->recordGleanEvent(GleanSample::authenticationFailureByGeo); + } else { + emit vpn->recordGleanEvent(GleanSample::authenticationFailure); + } + vpn->reset(true); + return; + } + + if (alert == AuthenticationFailedAlert) { + vpn->reset(true); + return; + } +} + +void ErrorHandler::setAlert(AlertType alert) { + m_alertTimer.stop(); + + if (alert != NoAlert) { + m_alertTimer.start(1000 * HIDE_ALERT_SEC); + } + + m_alert = alert; + emit alertChanged(); +} diff --git a/src/errorhandler.h b/src/errorhandler.h index 24cafd49985..a23b8f52ef7 100644 --- a/src/errorhandler.h +++ b/src/errorhandler.h @@ -5,13 +5,16 @@ #ifndef ERRORHANDLER_H #define ERRORHANDLER_H -#include #include +#include +#include class ErrorHandler final : public QObject { Q_OBJECT Q_DISABLE_COPY_MOVE(ErrorHandler) + Q_PROPERTY(AlertType alert READ alert NOTIFY alertChanged) + private: explicit ErrorHandler(QObject* parent); @@ -30,17 +33,46 @@ class ErrorHandler final : public QObject { IgnoredError, }; + enum AlertType { + NoAlert, + AuthenticationFailedAlert, + ConnectionFailedAlert, + LogoutAlert, + NoConnectionAlert, + ControllerErrorAlert, + RemoteServiceErrorAlert, + SubscriptionFailureAlert, + GeoIpRestrictionAlert, + UnrecoverableErrorAlert, + AuthCodeSentAlert, + }; + Q_ENUM(AlertType) + static ErrorType toErrorType(QNetworkReply::NetworkError error); ~ErrorHandler(); static ErrorHandler* instance(); + AlertType alert() const { return m_alert; } + + void errorHandle(ErrorType error); + + void hideAlert() { setAlert(NoAlert); } + Q_INVOKABLE void setAlert(AlertType alert); + #define ERRORSTATE(name) \ void name##Error(); \ Q_SIGNAL void name(); #include "errorlist.h" #undef ERRORSTATE + + signals: + void alertChanged(); + + private: + AlertType m_alert = NoAlert; + QTimer m_alertTimer; }; #endif // ERRORHANDLER_H diff --git a/src/inspector/inspectorhandler.cpp b/src/inspector/inspectorhandler.cpp index d5de7ab266a..ecc8cbdcd6e 100644 --- a/src/inspector/inspectorhandler.cpp +++ b/src/inspector/inspectorhandler.cpp @@ -252,7 +252,7 @@ static QList s_commands{ Q_ASSERT(vpn); vpn->reset(true); - vpn->hideAlert(); + ErrorHandler::instance()->hideAlert(); SettingsHolder* settingsHolder = SettingsHolder::instance(); diff --git a/src/localsocketcontroller.cpp b/src/localsocketcontroller.cpp index e45d3acaa8a..ef9a286e8d9 100644 --- a/src/localsocketcontroller.cpp +++ b/src/localsocketcontroller.cpp @@ -10,7 +10,6 @@ #include "models/device.h" #include "models/keys.h" #include "models/server.h" -#include "mozillavpn.h" #include "settingsholder.h" #include @@ -67,7 +66,7 @@ void LocalSocketController::errorOccurred( emit initialized(false, false, QDateTime()); } - MozillaVPN::instance()->errorHandle(ErrorHandler::ControllerError); + ErrorHandler::instance()->errorHandle(ErrorHandler::ControllerError); disconnectInternal(); } @@ -360,7 +359,7 @@ void LocalSocketController::parseCommand(const QByteArray& command) { } if (type == "backendFailure") { - MozillaVPN::instance()->errorHandle(ErrorHandler::ControllerError); + ErrorHandler::instance()->errorHandle(ErrorHandler::ControllerError); return; } diff --git a/src/mozillavpn.cpp b/src/mozillavpn.cpp index 59eab600ee5..9cd0b583f86 100644 --- a/src/mozillavpn.cpp +++ b/src/mozillavpn.cpp @@ -75,9 +75,6 @@ #include #include -// in seconds, hide alerts -constexpr const uint32_t HIDE_ALERT_SEC = 4; - namespace { Logger logger(LOG_MAIN, "MozillaVPN"); MozillaVPN* s_instance = nullptr; @@ -100,9 +97,6 @@ MozillaVPN::MozillaVPN() : m_private(new Private()) { Q_ASSERT(!s_instance); s_instance = this; - connect(&m_alertTimer, &QTimer::timeout, this, - [this]() { setAlert(NoAlert); }); - connect(&m_periodicOperationsTimer, &QTimer::timeout, []() { TaskScheduler::scheduleTask(new TaskGroup( {new TaskAccount(), new TaskServers(), new TaskCaptivePortalLookup(), @@ -194,6 +188,10 @@ MozillaVPN::~MozillaVPN() { delete m_private; } +ConnectionHealth* MozillaVPN::connectionHealth() { + return &m_private->m_connectionHealth; +} + Controller* MozillaVPN::controller() { return &m_private->m_controller; } MozillaVPN::State MozillaVPN::state() const { return m_state; } @@ -401,7 +399,7 @@ void MozillaVPN::maybeStateMain() { if (!modelsInitialized()) { logger.warning() << "Models not initialized yet"; SettingsHolder::instance()->clear(); - errorHandle(ErrorHandler::RemoteServiceError); + ErrorHandler::instance()->errorHandle(ErrorHandler::RemoteServiceError); setUserState(UserNotAuthenticated); setState(StateInitialize); return; @@ -456,7 +454,7 @@ void MozillaVPN::authenticateWithType( setState(StateAuthenticating); - hideAlert(); + ErrorHandler::instance()->hideAlert(); if (m_userState != UserNotAuthenticated) { // If we try to start an authentication flow when already logged in, there @@ -500,13 +498,13 @@ void MozillaVPN::authenticationCompleted(const QByteArray& json, if (!m_private->m_user.fromJson(json)) { logger.error() << "Failed to parse the User JSON data"; - errorHandle(ErrorHandler::RemoteServiceError); + ErrorHandler::instance()->errorHandle(ErrorHandler::RemoteServiceError); return; } if (!m_private->m_deviceModel.fromJson(keys(), json)) { logger.error() << "Failed to parse the DeviceModel JSON data"; - errorHandle(ErrorHandler::RemoteServiceError); + ErrorHandler::instance()->errorHandle(ErrorHandler::RemoteServiceError); return; } @@ -835,7 +833,7 @@ bool MozillaVPN::checkCurrentDevice() { void MozillaVPN::logout() { logger.debug() << "Logout"; - setAlert(LogoutAlert); + ErrorHandler::instance()->setAlert(ErrorHandler::LogoutAlert); setUserState(UserLoggingOut); TaskScheduler::deleteTasks(); @@ -880,102 +878,6 @@ void MozillaVPN::reset(bool forceInitialState) { } } -void MozillaVPN::setAlert(AlertType alert) { - m_alertTimer.stop(); - - if (alert != NoAlert) { - m_alertTimer.start(1000 * HIDE_ALERT_SEC); - } - - m_alert = alert; - emit alertChanged(); -} - -void MozillaVPN::errorHandle(ErrorHandler::ErrorType error) { - logger.debug() << "Handling error" << error; - - Q_ASSERT(error != ErrorHandler::NoError); - - AlertType alert = NoAlert; - - switch (error) { - case ErrorHandler::VPNDependentConnectionError: - if (controller()->state() == Controller::State::StateOn || - controller()->state() == Controller::State::StateConfirming) { - // connection likely isn't stable yet - logger.error() << "Ignore network error probably caused by enabled VPN"; - return; - } else if (controller()->state() == Controller::State::StateOff) { - // We are off, so this means a request failed, not the - // VPN. Change it to No Connection - alert = NoConnectionAlert; - break; - } - [[fallthrough]]; - case ErrorHandler::ConnectionFailureError: - alert = ConnectionFailedAlert; - break; - - case ErrorHandler::NoConnectionError: - if (connectionHealth()->isUnsettled()) { - return; - } - alert = NoConnectionAlert; - break; - - case ErrorHandler::AuthenticationError: - alert = AuthenticationFailedAlert; - break; - - case ErrorHandler::ControllerError: - alert = ControllerErrorAlert; - break; - - case ErrorHandler::RemoteServiceError: - alert = RemoteServiceErrorAlert; - break; - - case ErrorHandler::SubscriptionFailureError: - alert = SubscriptionFailureAlert; - break; - - case ErrorHandler::GeoIpRestrictionError: - alert = GeoIpRestrictionAlert; - break; - - case ErrorHandler::UnrecoverableError: - alert = UnrecoverableErrorAlert; - break; - - default: - break; - } - - setAlert(alert); - - logger.error() << "Alert:" << alert << "State:" << m_state; - - if (alert == NoAlert) { - return; - } - - // Any error in authenticating state sends to the Initial state. - if (m_state == StateAuthenticating) { - if (alert == GeoIpRestrictionAlert) { - emit recordGleanEvent(GleanSample::authenticationFailureByGeo); - } else { - emit recordGleanEvent(GleanSample::authenticationFailure); - } - reset(true); - return; - } - - if (alert == AuthenticationFailedAlert) { - reset(true); - return; - } -} - void MozillaVPN::setServerCooldown(const QString& publicKey) { m_private->m_serverCountryModel.setServerCooldown( publicKey, Constants::SERVER_UNRESPONSIVE_COOLDOWN_SEC); @@ -1512,7 +1414,8 @@ void MozillaVPN::subscriptionFailedInternal(bool canceledByUser) { setState(StateSubscriptionNeeded); if (!canceledByUser) { - errorHandle(ErrorHandler::SubscriptionFailureError); + ErrorHandler::instance()->errorHandle( + ErrorHandler::SubscriptionFailureError); } TaskScheduler::scheduleTask( @@ -1657,7 +1560,7 @@ void MozillaVPN::maybeRegenerateDeviceKey() { TaskScheduler::scheduleTask(new TaskFunction([this]() { if (!modelsInitialized()) { logger.error() << "Failed to complete the key regeneration"; - errorHandle(ErrorHandler::RemoteServiceError); + ErrorHandler::instance()->errorHandle(ErrorHandler::RemoteServiceError); setUserState(UserNotAuthenticated); return; } diff --git a/src/mozillavpn.h b/src/mozillavpn.h index a668faea1c4..a4b577d19ba 100644 --- a/src/mozillavpn.h +++ b/src/mozillavpn.h @@ -80,24 +80,8 @@ class MozillaVPN final : public QObject { }; Q_ENUM(UserState); - enum AlertType { - NoAlert, - AuthenticationFailedAlert, - ConnectionFailedAlert, - LogoutAlert, - NoConnectionAlert, - ControllerErrorAlert, - RemoteServiceErrorAlert, - SubscriptionFailureAlert, - GeoIpRestrictionAlert, - UnrecoverableErrorAlert, - AuthCodeSentAlert, - }; - Q_ENUM(AlertType) - private: Q_PROPERTY(State state READ state NOTIFY stateChanged) - Q_PROPERTY(AlertType alert READ alert NOTIFY alertChanged) Q_PROPERTY(QString devVersion READ devVersion CONSTANT) Q_PROPERTY(const Env* env READ env CONSTANT) Q_PROPERTY(UserState userState READ userState NOTIFY userStateChanged) @@ -121,7 +105,6 @@ class MozillaVPN final : public QObject { void initialize(); State state() const; - AlertType alert() const { return m_alert; } const QString& exitServerPublicKey() const { return m_exitServerPublicKey; } const QString& entryServerPublicKey() const { return m_entryServerPublicKey; } @@ -139,8 +122,6 @@ class MozillaVPN final : public QObject { Q_INVOKABLE void authenticate(); Q_INVOKABLE void cancelAuthentication(); Q_INVOKABLE void removeDeviceFromPublicKey(const QString& publicKey); - Q_INVOKABLE void hideAlert() { setAlert(NoAlert); } - Q_INVOKABLE void setAlert(AlertType alert); Q_INVOKABLE void postAuthenticationCompleted(); Q_INVOKABLE void telemetryPolicyCompleted(); Q_INVOKABLE void mainWindowLoaded(); @@ -182,9 +163,7 @@ class MozillaVPN final : public QObject { ConnectionBenchmark* connectionBenchmark() { return &m_private->m_connectionBenchmark; } - ConnectionHealth* connectionHealth() { - return &m_private->m_connectionHealth; - } + ConnectionHealth* connectionHealth(); Controller* controller(); ServerData* currentServer() { return &m_private->m_serverData; } DeviceModel* deviceModel() { return &m_private->m_deviceModel; } @@ -234,8 +213,6 @@ class MozillaVPN final : public QObject { const QList entryServers() const; bool multihop() const { return m_private->m_serverData.multihop(); } - void errorHandle(ErrorHandler::ErrorType error); - void abortAuthentication(); void changeServer(const QString& countryCode, const QString& city, @@ -353,7 +330,6 @@ class MozillaVPN final : public QObject { signals: void stateChanged(); - void alertChanged(); void userStateChanged(); void deviceRemoving(const QString& publicKey); void aboutNeeded(); @@ -411,7 +387,6 @@ class MozillaVPN final : public QObject { Private* m_private = nullptr; State m_state = StateInitialize; - AlertType m_alert = NoAlert; QString m_currentView; UserState m_userState = UserNotAuthenticated; @@ -419,7 +394,6 @@ class MozillaVPN final : public QObject { QString m_exitServerPublicKey; QString m_entryServerPublicKey; - QTimer m_alertTimer; QTimer m_periodicOperationsTimer; QTimer m_gleanTimer; diff --git a/src/platforms/android/androidcontroller.cpp b/src/platforms/android/androidcontroller.cpp index 2c33b7abc8b..bbeb2d7382c 100644 --- a/src/platforms/android/androidcontroller.cpp +++ b/src/platforms/android/androidcontroller.cpp @@ -93,7 +93,7 @@ AndroidController::AndroidController() { logger.error() << "Service Error while activating the VPN: " << parcelBody; } - MozillaVPN::instance()->errorHandle( + ErrorHandler::instance()->errorHandle( ErrorHandler::ConnectionFailureError); emit disconnected(); }, @@ -101,7 +101,7 @@ AndroidController::AndroidController() { connect( activity, &AndroidVPNActivity::serviceDisconnected, this, []() { - MozillaVPN::instance()->errorHandle(ErrorHandler::ControllerError); + ErrorHandler::instance()->errorHandle(ErrorHandler::ControllerError); }, Qt::QueuedConnection); } diff --git a/src/platforms/android/androidiaphandler.cpp b/src/platforms/android/androidiaphandler.cpp index 19991e2b372..bff022c2b6d 100644 --- a/src/platforms/android/androidiaphandler.cpp +++ b/src/platforms/android/androidiaphandler.cpp @@ -323,7 +323,7 @@ void AndroidIAPHandler::validatePurchase(QJsonObject purchase) { purchaseTask, &TaskPurchase::failed, this, [this](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Purchase validation request to guardian failed"; - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); stopSubscription(); emit subscriptionNotValidated(); }); diff --git a/src/platforms/ios/iosiaphandler.mm b/src/platforms/ios/iosiaphandler.mm index 4c80fdd42a3..580a1a61b09 100644 --- a/src/platforms/ios/iosiaphandler.mm +++ b/src/platforms/ios/iosiaphandler.mm @@ -339,7 +339,7 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(nonnull SKPaymentQueue QJsonDocument json = QJsonDocument::fromJson(data); if (!json.isObject()) { - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit subscriptionFailed(); ErrorHandler::instance()->subscriptionGenericError(); return; @@ -348,7 +348,7 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(nonnull SKPaymentQueue QJsonObject obj = json.object(); QJsonValue errorValue = obj.value("errno"); if (!errorValue.isDouble()) { - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit subscriptionFailed(); ErrorHandler::instance()->subscriptionGenericError(); return; @@ -356,14 +356,14 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(nonnull SKPaymentQueue int errorNumber = errorValue.toInt(); if (errorNumber == GUARDIAN_ERROR_RECEIPT_NOT_VALID) { - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit subscriptionFailed(); ErrorHandler::instance()->subscriptionExpiredError(); return; } if (errorNumber == GUARDIAN_ERROR_RECEIPT_IN_USE) { - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit subscriptionFailed(); ErrorHandler::instance()->subscriptionInUseError(); return; diff --git a/src/platforms/linux/linuxcontroller.cpp b/src/platforms/linux/linuxcontroller.cpp index cb3a595efce..6f2b564d255 100644 --- a/src/platforms/linux/linuxcontroller.cpp +++ b/src/platforms/linux/linuxcontroller.cpp @@ -12,7 +12,6 @@ #include "models/device.h" #include "models/keys.h" #include "models/server.h" -#include "mozillavpn.h" #include #include @@ -98,7 +97,7 @@ void LinuxController::operationCompleted(QDBusPendingCallWatcher* call) { QDBusPendingReply reply = *call; if (reply.isError()) { logger.error() << "Error received from the DBus service"; - MozillaVPN::instance()->errorHandle(ErrorHandler::ControllerError); + ErrorHandler::instance()->errorHandle(ErrorHandler::ControllerError); emit disconnected(); return; } @@ -111,7 +110,7 @@ void LinuxController::operationCompleted(QDBusPendingCallWatcher* call) { } logger.error() << "DBus service says: error."; - MozillaVPN::instance()->errorHandle(ErrorHandler::ControllerError); + ErrorHandler::instance()->errorHandle(ErrorHandler::ControllerError); emit disconnected(); } diff --git a/src/platforms/wasm/wasmiaphandler.cpp b/src/platforms/wasm/wasmiaphandler.cpp index 229d7215fc0..64efe43fe46 100644 --- a/src/platforms/wasm/wasmiaphandler.cpp +++ b/src/platforms/wasm/wasmiaphandler.cpp @@ -6,7 +6,6 @@ #include "errorhandler.h" #include "leakdetector.h" #include "logger.h" -#include "mozillavpn.h" #include "tasks/purchase/taskpurchase.h" #include "taskscheduler.h" @@ -52,7 +51,7 @@ void WasmIAPHandler::nativeStartSubscription(Product* product) { purchaseTask, &TaskPurchase::failed, this, [this](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Purchase validation request to guardian failed"; - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); stopSubscription(); emit subscriptionNotValidated(); }); diff --git a/src/profileflow.cpp b/src/profileflow.cpp index 1dc67586e94..9b1d3d0ee6b 100644 --- a/src/profileflow.cpp +++ b/src/profileflow.cpp @@ -26,7 +26,7 @@ void ProfileFlow::setState(State state) { logger.debug() << "Set state" << state; if (state == StateError) { - MozillaVPN::instance()->errorHandle(ErrorHandler::RemoteServiceError); + ErrorHandler::instance()->errorHandle(ErrorHandler::RemoteServiceError); } m_state = state; diff --git a/src/tasks/account/taskaccount.cpp b/src/tasks/account/taskaccount.cpp index 295c9581cd3..428c497f0e6 100644 --- a/src/tasks/account/taskaccount.cpp +++ b/src/tasks/account/taskaccount.cpp @@ -26,7 +26,7 @@ void TaskAccount::run() { request, &NetworkRequest::requestFailed, this, [this](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Account request failed" << error; - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit completed(); }); diff --git a/src/tasks/adddevice/taskadddevice.cpp b/src/tasks/adddevice/taskadddevice.cpp index 74e575a82d8..7b48f7af520 100644 --- a/src/tasks/adddevice/taskadddevice.cpp +++ b/src/tasks/adddevice/taskadddevice.cpp @@ -55,15 +55,13 @@ void TaskAddDevice::run() { request->disableTimeout(); - connect(request, &NetworkRequest::requestFailed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - logger.error() << "Failed to add the device" << error; - MozillaVPN* vpn = MozillaVPN::instance(); - Q_ASSERT(vpn); - - vpn->errorHandle(ErrorHandler::toErrorType(error)); - emit completed(); - }); + connect( + request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + logger.error() << "Failed to add the device" << error; + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); + emit completed(); + }); connect(request, &NetworkRequest::requestCompleted, this, [this, publicKey, privateKey](const QByteArray&) { diff --git a/src/tasks/authenticate/taskauthenticate.cpp b/src/tasks/authenticate/taskauthenticate.cpp index 68768f9d5ce..9936777f7f6 100644 --- a/src/tasks/authenticate/taskauthenticate.cpp +++ b/src/tasks/authenticate/taskauthenticate.cpp @@ -59,7 +59,7 @@ void TaskAuthenticate::run() { [](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Failed to complete the authentication" << error; - MozillaVPN::instance()->errorHandle( + ErrorHandler::instance()->errorHandle( ErrorHandler::toErrorType(error)); }); @@ -72,7 +72,7 @@ void TaskAuthenticate::run() { connect(m_authenticationListener, &AuthenticationListener::failed, this, [this](const ErrorHandler::ErrorType error) { - MozillaVPN::instance()->errorHandle(error); + ErrorHandler::instance()->errorHandle(error); m_authenticationListener->aboutToFinish(); }); @@ -89,19 +89,16 @@ void TaskAuthenticate::run() { void TaskAuthenticate::authenticationCompleted(const QByteArray& data) { logger.debug() << "Authentication completed"; - MozillaVPN* vpn = MozillaVPN::instance(); - Q_ASSERT(vpn); - QJsonDocument json = QJsonDocument::fromJson(data); if (json.isNull()) { - vpn->errorHandle(ErrorHandler::RemoteServiceError); + ErrorHandler::instance()->errorHandle(ErrorHandler::RemoteServiceError); return; } QJsonObject obj = json.object(); QJsonValue userObj = obj.value("user"); if (!userObj.isObject()) { - vpn->errorHandle(ErrorHandler::RemoteServiceError); + ErrorHandler::instance()->errorHandle(ErrorHandler::RemoteServiceError); return; } @@ -111,7 +108,7 @@ void TaskAuthenticate::authenticationCompleted(const QByteArray& data) { QJsonValue tokenValue = obj.value("token"); if (!tokenValue.isString()) { - vpn->errorHandle(ErrorHandler::RemoteServiceError); + ErrorHandler::instance()->errorHandle(ErrorHandler::RemoteServiceError); return; } diff --git a/src/tasks/captiveportallookup/taskcaptiveportallookup.cpp b/src/tasks/captiveportallookup/taskcaptiveportallookup.cpp index 84d377d587c..7ce9f91b1d6 100644 --- a/src/tasks/captiveportallookup/taskcaptiveportallookup.cpp +++ b/src/tasks/captiveportallookup/taskcaptiveportallookup.cpp @@ -33,7 +33,7 @@ void TaskCaptivePortalLookup::run() { return; } logger.error() << "Failed to obtain captive portal IPs" << error; - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit completed(); }); diff --git a/src/tasks/deleteaccount/taskdeleteaccount.cpp b/src/tasks/deleteaccount/taskdeleteaccount.cpp index 9ccb9b00a63..b4d382cba87 100644 --- a/src/tasks/deleteaccount/taskdeleteaccount.cpp +++ b/src/tasks/deleteaccount/taskdeleteaccount.cpp @@ -54,7 +54,7 @@ void TaskDeleteAccount::run() { [this](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Failed to complete the authentication" << error; - MozillaVPN::instance()->errorHandle( + ErrorHandler::instance()->errorHandle( ErrorHandler::toErrorType(error)); m_authenticationInAppSession->terminate(); }); @@ -69,7 +69,7 @@ void TaskDeleteAccount::run() { connect(m_authenticationInAppSession, &AuthenticationInAppSession::failed, this, [this](const ErrorHandler::ErrorType error) { - MozillaVPN::instance()->errorHandle(error); + ErrorHandler::instance()->errorHandle(error); m_authenticationInAppSession->terminate(); }); @@ -86,7 +86,7 @@ void TaskDeleteAccount::run() { case AuthenticationInApp::StateSignUp: [[fallthrough]]; case AuthenticationInApp::StateFallbackInBrowser: - MozillaVPN::instance()->errorHandle( + ErrorHandler::instance()->errorHandle( ErrorHandler::AuthenticationError); m_authenticationInAppSession->terminate(); break; diff --git a/src/tasks/getsubscriptiondetails/taskgetsubscriptiondetails.cpp b/src/tasks/getsubscriptiondetails/taskgetsubscriptiondetails.cpp index 226f88d868b..73c353625aa 100644 --- a/src/tasks/getsubscriptiondetails/taskgetsubscriptiondetails.cpp +++ b/src/tasks/getsubscriptiondetails/taskgetsubscriptiondetails.cpp @@ -9,7 +9,6 @@ #include "errorhandler.h" #include "leakdetector.h" #include "logger.h" -#include "mozillavpn.h" #include "networkrequest.h" namespace { @@ -53,7 +52,8 @@ void TaskGetSubscriptionDetails::run() { if (m_authenticationInAppSession) { logger.error() << "Network request failed after authentication"; - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle( + ErrorHandler::toErrorType(error)); emit failed(); m_authenticationInAppSession->terminate(); return; @@ -66,7 +66,7 @@ void TaskGetSubscriptionDetails::run() { return; } - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); // We need to emit two separate signals here. // `failed`: Signal for connected objects that are monitoring this Task @@ -135,7 +135,7 @@ void TaskGetSubscriptionDetails::initAuthentication() { connect(m_authenticationInAppSession, &AuthenticationInAppSession::failed, this, [this](const ErrorHandler::ErrorType error) { - MozillaVPN::instance()->errorHandle(error); + ErrorHandler::instance()->errorHandle(error); m_authenticationInAppSession->terminate(); }); @@ -145,7 +145,7 @@ void TaskGetSubscriptionDetails::initAuthentication() { case AuthenticationInApp::StateSignUp: [[fallthrough]]; case AuthenticationInApp::StateFallbackInBrowser: - MozillaVPN::instance()->errorHandle( + ErrorHandler::instance()->errorHandle( ErrorHandler::AuthenticationError); emit failed(); m_authenticationInAppSession->terminate(); diff --git a/src/tasks/ipfinder/taskipfinder.cpp b/src/tasks/ipfinder/taskipfinder.cpp index 981adf70991..7c6c4bcf674 100644 --- a/src/tasks/ipfinder/taskipfinder.cpp +++ b/src/tasks/ipfinder/taskipfinder.cpp @@ -7,7 +7,6 @@ #include "errorhandler.h" #include "leakdetector.h" #include "logger.h" -#include "mozillavpn.h" #include "networkrequest.h" #include "settingsholder.h" @@ -102,7 +101,7 @@ void TaskIPFinder::createRequest(const QHostAddress& address, bool ipv6) { ErrorHandler::ErrorType errorType = ErrorHandler::toErrorType(error); if (errorType == ErrorHandler::AuthenticationError) { - MozillaVPN::instance()->errorHandle(errorType); + ErrorHandler::instance()->errorHandle(errorType); } m_requestCount = 0; diff --git a/src/tasks/products/taskproducts.cpp b/src/tasks/products/taskproducts.cpp index bad1c781df1..b14ea7ee3b8 100644 --- a/src/tasks/products/taskproducts.cpp +++ b/src/tasks/products/taskproducts.cpp @@ -3,10 +3,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "taskproducts.h" +#include "errorhandler.h" #include "iaphandler.h" #include "leakdetector.h" #include "logger.h" -#include "mozillavpn.h" #include "networkrequest.h" namespace { @@ -26,7 +26,7 @@ void TaskProducts::run() { request, &NetworkRequest::requestFailed, this, [this](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Products request to guardian failed" << error; - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit completed(); }); diff --git a/src/tasks/removedevice/taskremovedevice.cpp b/src/tasks/removedevice/taskremovedevice.cpp index 842c8a4af81..135289f1753 100644 --- a/src/tasks/removedevice/taskremovedevice.cpp +++ b/src/tasks/removedevice/taskremovedevice.cpp @@ -52,7 +52,7 @@ void TaskRemoveDevice::run() { } logger.error() << "Failed to remove the device" << error; - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit completed(); }); diff --git a/src/tasks/servers/taskservers.cpp b/src/tasks/servers/taskservers.cpp index 65e86bfe5c6..feeeea978bb 100644 --- a/src/tasks/servers/taskservers.cpp +++ b/src/tasks/servers/taskservers.cpp @@ -26,7 +26,7 @@ void TaskServers::run() { request, &NetworkRequest::requestFailed, this, [this](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Failed to retrieve servers"; - MozillaVPN::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); emit completed(); }); diff --git a/src/ui/authenticationInApp/ViewAuthenticationUnblockCodeNeeded.qml b/src/ui/authenticationInApp/ViewAuthenticationUnblockCodeNeeded.qml index e5d7ab6f2c3..e0dc0addb88 100644 --- a/src/ui/authenticationInApp/ViewAuthenticationUnblockCodeNeeded.qml +++ b/src/ui/authenticationInApp/ViewAuthenticationUnblockCodeNeeded.qml @@ -49,7 +49,7 @@ VPNInAppAuthenticationBase { anchors.horizontalCenter: parent.horizontalCenter onClicked: { VPNAuthInApp.resendUnblockCodeEmail(); - VPN.setAlert(VPN.AuthCodeSentAlert); + VPNErrorHandler.setAlert(VPNErrorHandler.AuthCodeSentAlert); } } diff --git a/src/ui/authenticationInApp/ViewAuthenticationVerificationSessionByEmailNeeded.qml b/src/ui/authenticationInApp/ViewAuthenticationVerificationSessionByEmailNeeded.qml index 98718135696..74fb7d47681 100644 --- a/src/ui/authenticationInApp/ViewAuthenticationVerificationSessionByEmailNeeded.qml +++ b/src/ui/authenticationInApp/ViewAuthenticationVerificationSessionByEmailNeeded.qml @@ -45,7 +45,7 @@ VPNInAppAuthenticationBase { anchors.horizontalCenter: parent.horizontalCenter onClicked: { VPNAuthInApp.resendVerificationSessionCodeEmail(); - VPN.setAlert(VPN.AuthCodeSentAlert); + VPNErrorHandler.setAlert(VPNErrorHandler.AuthCodeSentAlert); } } diff --git a/src/update/balrog.cpp b/src/update/balrog.cpp index 6d5df486278..5732a1d7616 100644 --- a/src/update/balrog.cpp +++ b/src/update/balrog.cpp @@ -503,15 +503,12 @@ void Balrog::propagateError(NetworkRequest* request, QNetworkReply::NetworkError error) { Q_ASSERT(request); - MozillaVPN* vpn = MozillaVPN::instance(); - Q_ASSERT(vpn); - // 451 Unavailable For Legal Reasons if (request->statusCode() == 451) { logger.debug() << "Geo IP restriction detected"; - vpn->errorHandle(ErrorHandler::GeoIpRestrictionError); + ErrorHandler::instance()->errorHandle(ErrorHandler::GeoIpRestrictionError); return; } - vpn->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); } diff --git a/tests/auth/CMakeLists.txt b/tests/auth/CMakeLists.txt index de3fe518451..0079c1bdba6 100644 --- a/tests/auth/CMakeLists.txt +++ b/tests/auth/CMakeLists.txt @@ -46,6 +46,9 @@ target_sources(auth_tests PRIVATE ${MVPN_SOURCE_DIR}/authenticationlistener.h ${MVPN_SOURCE_DIR}/constants.cpp ${MVPN_SOURCE_DIR}/constants.h + ${MVPN_SOURCE_DIR}/controller.h + ${MVPN_SOURCE_DIR}/dnspingsender.cpp + ${MVPN_SOURCE_DIR}/dnspingsender.h ${MVPN_SOURCE_DIR}/env.h ${MVPN_SOURCE_DIR}/errorhandler.cpp ${MVPN_SOURCE_DIR}/errorhandler.h @@ -73,6 +76,14 @@ target_sources(auth_tests PRIVATE ${MVPN_SOURCE_DIR}/networkmanager.h ${MVPN_SOURCE_DIR}/networkrequest.cpp ${MVPN_SOURCE_DIR}/networkrequest.h + ${MVPN_SOURCE_DIR}/pinghelper.cpp + ${MVPN_SOURCE_DIR}/pinghelper.h + ${MVPN_SOURCE_DIR}/pingsender.cpp + ${MVPN_SOURCE_DIR}/pingsender.h + ${MVPN_SOURCE_DIR}/pingsenderfactory.cpp + ${MVPN_SOURCE_DIR}/pingsenderfactory.h + ${MVPN_SOURCE_DIR}/platforms/dummy/dummypingsender.cpp + ${MVPN_SOURCE_DIR}/platforms/dummy/dummypingsender.h ${MVPN_SOURCE_DIR}/rfc/rfc1918.cpp ${MVPN_SOURCE_DIR}/rfc/rfc1918.h ${MVPN_SOURCE_DIR}/rfc/rfc4193.cpp @@ -126,6 +137,7 @@ target_sources(auth_tests PRIVATE testsignupandin.cpp testsignupandin.h mocmozillavpn.cpp + ../qml/moccontroller.cpp ../unit/mocinspectorhandler.cpp ) diff --git a/tests/auth/auth.pro b/tests/auth/auth.pro index aecc39dc065..839481833cb 100644 --- a/tests/auth/auth.pro +++ b/tests/auth/auth.pro @@ -42,6 +42,8 @@ HEADERS += \ ../../src/authenticationinapp/incrementaldecoder.h \ ../../src/authenticationlistener.h \ ../../src/constants.h \ + ../../src/controller.h \ + ../../src/dnspingsender.h \ ../../src/env.h \ ../../src/errorhandler.h \ ../../src/hawkauth.h \ @@ -57,6 +59,10 @@ HEADERS += \ ../../src/mozillavpn.h \ ../../src/networkmanager.h \ ../../src/networkrequest.h \ + ../../src/pinghelper.h \ + ../../src/pingsender.h \ + ../../src/pingsenderfactory.h \ + ../../src/platforms/dummy/dummypingsender.h \ ../../src/rfc/rfc1918.h \ ../../src/rfc/rfc4193.h \ ../../src/rfc/rfc4291.h \ @@ -79,6 +85,7 @@ HEADERS += \ SOURCES += \ mocmozillavpn.cpp \ + ../qml/moccontroller.cpp \ ../unit/mocinspectorhandler.cpp \ ../../src/authenticationinapp/authenticationinapp.cpp \ ../../src/authenticationinapp/authenticationinapplistener.cpp \ @@ -86,6 +93,7 @@ SOURCES += \ ../../src/authenticationinapp/incrementaldecoder.cpp \ ../../src/authenticationlistener.cpp \ ../../src/constants.cpp \ + ../../src/dnspingsender.cpp \ ../../src/errorhandler.cpp \ ../../src/hawkauth.cpp \ ../../src/hkdf.cpp \ @@ -98,6 +106,10 @@ SOURCES += \ ../../src/models/server.cpp \ ../../src/networkmanager.cpp \ ../../src/networkrequest.cpp \ + ../../src/pinghelper.cpp \ + ../../src/pingsender.cpp \ + ../../src/pingsenderfactory.cpp \ + ../../src/platforms/dummy/dummypingsender.cpp \ ../../src/rfc/rfc1918.cpp \ ../../src/rfc/rfc4193.cpp \ ../../src/rfc/rfc4291.cpp \ diff --git a/tests/auth/mocmozillavpn.cpp b/tests/auth/mocmozillavpn.cpp index a6f27696c20..2b6149ad882 100644 --- a/tests/auth/mocmozillavpn.cpp +++ b/tests/auth/mocmozillavpn.cpp @@ -23,6 +23,8 @@ MozillaVPN::MozillaVPN() {} MozillaVPN::~MozillaVPN() {} +ConnectionHealth* MozillaVPN::connectionHealth() { return nullptr; } + Controller* MozillaVPN::controller() { return nullptr; } MozillaVPN::State MozillaVPN::state() const { return StateInitialize; } @@ -62,10 +64,6 @@ void MozillaVPN::cancelAuthentication() {} void MozillaVPN::logout() {} -void MozillaVPN::setAlert(AlertType) {} - -void MozillaVPN::errorHandle(ErrorHandler::ErrorType) {} - const QList MozillaVPN::exitServers() const { return QList(); } const QList MozillaVPN::entryServers() const { return QList(); } diff --git a/tests/qml/CMakeLists.txt b/tests/qml/CMakeLists.txt index 2b962cf90d4..1e7efae9028 100644 --- a/tests/qml/CMakeLists.txt +++ b/tests/qml/CMakeLists.txt @@ -30,6 +30,8 @@ target_link_libraries(qml_tests PRIVATE glean lottie nebula translations) target_sources(qml_tests PRIVATE ${MVPN_SOURCE_DIR}/constants.h ${MVPN_SOURCE_DIR}/controller.h + ${MVPN_SOURCE_DIR}/dnspingsender.cpp + ${MVPN_SOURCE_DIR}/dnspingsender.h ${MVPN_SOURCE_DIR}/env.h ${MVPN_SOURCE_DIR}/externalophandler.cpp ${MVPN_SOURCE_DIR}/externalophandler.h @@ -64,12 +66,10 @@ target_sources(qml_tests PRIVATE ${MVPN_SOURCE_DIR}/pinghelper.h ${MVPN_SOURCE_DIR}/pingsender.cpp ${MVPN_SOURCE_DIR}/pingsender.h - ${MVPN_SOURCE_DIR}/platforms/dummy/dummypingsender.cpp - ${MVPN_SOURCE_DIR}/platforms/dummy/dummypingsender.h - ${MVPN_SOURCE_DIR}/dnspingsender.cpp - ${MVPN_SOURCE_DIR}/dnspingsender.h ${MVPN_SOURCE_DIR}/pingsenderfactory.cpp ${MVPN_SOURCE_DIR}/pingsenderfactory.h + ${MVPN_SOURCE_DIR}/platforms/dummy/dummypingsender.cpp + ${MVPN_SOURCE_DIR}/platforms/dummy/dummypingsender.h ${MVPN_SOURCE_DIR}/update/updater.cpp ${MVPN_SOURCE_DIR}/update/updater.h ${MVPN_SOURCE_DIR}/update/versionapi.cpp diff --git a/tests/qml/mocmozillavpn.cpp b/tests/qml/mocmozillavpn.cpp index fc516c4ca17..f923550bd54 100644 --- a/tests/qml/mocmozillavpn.cpp +++ b/tests/qml/mocmozillavpn.cpp @@ -25,6 +25,8 @@ MozillaVPN::MozillaVPN() {} MozillaVPN::~MozillaVPN() {} +ConnectionHealth* MozillaVPN::connectionHealth() { return nullptr; } + Controller* MozillaVPN::controller() { return new Controller(); } MozillaVPN::State MozillaVPN::state() const { return StateInitialize; } @@ -68,10 +70,6 @@ void MozillaVPN::cancelAuthentication() {} void MozillaVPN::logout() {} -void MozillaVPN::setAlert(AlertType) {} - -void MozillaVPN::errorHandle(ErrorHandler::ErrorType) {} - const QList MozillaVPN::exitServers() const { return QList(); } const QList MozillaVPN::entryServers() const { return QList(); } diff --git a/tests/qml/qml.pro b/tests/qml/qml.pro index 46f64380c6f..87a5935fc19 100644 --- a/tests/qml/qml.pro +++ b/tests/qml/qml.pro @@ -43,6 +43,7 @@ SOURCES += \ moccontroller.cpp \ mocmozillavpn.cpp \ ../unit/mocinspectorhandler.cpp \ + ../../src/dnspingsender.cpp \ ../../src/externalophandler.cpp \ ../../src/filterproxymodel.cpp \ ../../src/hawkauth.cpp \ @@ -60,11 +61,10 @@ SOURCES += \ ../../src/update/updater.cpp \ ../../src/update/versionapi.cpp \ ../../src/update/webupdater.cpp \ - ../../src/pinghelper.cpp \ + ../../src/pinghelper.cpp \ ../../src/pingsender.cpp \ - ../../src/platforms/dummy/dummypingsender.cpp \ - ../../src/dnspingsender.cpp \ ../../src/pingsenderfactory.cpp \ + ../../src/platforms/dummy/dummypingsender.cpp \ ../../src/qmlengineholder.cpp \ ../../src/urlopener.cpp @@ -87,7 +87,7 @@ HEADERS += \ ../../src/networkmanager.h \ ../../src/networkrequest.h \ ../../src/settingsholder.h \ - ../../src/pinghelper.h \ + ../../src/pinghelper.h \ ../../src/pingsender.h \ ../../src/platforms/dummy/dummypingsender.h \ ../../src/dnspingsender.h \ diff --git a/tests/unit/mocmozillavpn.cpp b/tests/unit/mocmozillavpn.cpp index ff6afb6d81c..a1cb67595b6 100644 --- a/tests/unit/mocmozillavpn.cpp +++ b/tests/unit/mocmozillavpn.cpp @@ -34,6 +34,8 @@ MozillaVPN::UserState MozillaVPN::userState() const { bool MozillaVPN::stagingMode() const { return true; } bool MozillaVPN::debugMode() const { return true; } +ConnectionHealth* MozillaVPN::connectionHealth() { return nullptr; } + Controller* MozillaVPN::controller() { return new Controller(); } void MozillaVPN::initialize() {} @@ -67,10 +69,6 @@ void MozillaVPN::cancelAuthentication() {} void MozillaVPN::logout() {} -void MozillaVPN::setAlert(AlertType) {} - -void MozillaVPN::errorHandle(ErrorHandler::ErrorType) {} - const QList MozillaVPN::exitServers() const { return QList(); } const QList MozillaVPN::entryServers() const { return QList(); } From 4a598ecb7f013a193b6f4f3e78f6698f3c91c8d5 Mon Sep 17 00:00:00 2001 From: Gabriel Bustamante Date: Fri, 7 Oct 2022 12:40:43 -0500 Subject: [PATCH 21/85] Fix release-promotion trying to push to dep bucket in prod (#4598) --- taskcluster/ci/beetmover/kind.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/taskcluster/ci/beetmover/kind.yml b/taskcluster/ci/beetmover/kind.yml index a303800a62e..54c235356cc 100644 --- a/taskcluster/ci/beetmover/kind.yml +++ b/taskcluster/ci/beetmover/kind.yml @@ -20,7 +20,7 @@ tasks: worker: chain-of-trust: true max-run-time: 1800 - run-on-tasks-for: [github-release, action:release-promotion] + run-on-tasks-for: [action] release-artifacts: [MozillaVPN.pkg] dependencies: signing: signing-macos/opt @@ -37,7 +37,7 @@ tasks: worker: chain-of-trust: true max-run-time: 1800 - run-on-tasks-for: [github-release, action:release-promotion] + run-on-tasks-for: [action] release-artifacts: [MozillaVPN.msi] dependencies: repackage-signing: repackage-signing-msi @@ -54,7 +54,7 @@ tasks: worker: chain-of-trust: true max-run-time: 1800 - run-on-tasks-for: [action:release-promotion] + run-on-tasks-for: [action] # The addons-bundle release-artifacts are dynamically generated in the beetmover transform release-artifacts: [] dependencies: @@ -72,7 +72,7 @@ tasks: worker: chain-of-trust: true max-run-time: 1800 - run-on-tasks-for: [action:release-promotion] + run-on-tasks-for: [action] release-artifacts: - manifest.json - manifest.json.sig From 1898331c753c52f7eeeda40141e2b37230cf8cc7 Mon Sep 17 00:00:00 2001 From: Gabriel Bustamante Date: Fri, 7 Oct 2022 16:48:57 -0500 Subject: [PATCH 22/85] Ignore addons/deprecated directory when populating addons release-artifacts (#4599) --- taskcluster/mozillavpn_taskgraph/transforms/beetmover.py | 1 + 1 file changed, 1 insertion(+) diff --git a/taskcluster/mozillavpn_taskgraph/transforms/beetmover.py b/taskcluster/mozillavpn_taskgraph/transforms/beetmover.py index db711e24698..0d7260ff05b 100644 --- a/taskcluster/mozillavpn_taskgraph/transforms/beetmover.py +++ b/taskcluster/mozillavpn_taskgraph/transforms/beetmover.py @@ -16,6 +16,7 @@ def add_addons_release_artifacts(config, tasks): if task["attributes"]["build-type"] == "addons/opt" and task["name"] == "addons-bundle": addons = set(os.listdir("addons")) addons.remove("examples") + addons.remove("deprecated") for addon in addons: task["attributes"]["release-artifacts"].append( { From c17397ff61424cfb86b6bff291ebb8802033091d Mon Sep 17 00:00:00 2001 From: Owen Kirby Date: Sat, 8 Oct 2022 21:15:55 -0700 Subject: [PATCH 23/85] Convert windows balrog library back to a DLL (#4600) * Fix build errors when compiling via VS2019 IDE. * Revert balrog library back to a DLL for Windows --- src/cmake/golang.cmake | 7 ------ src/cmake/windows.cmake | 22 +++++++++++++++---- src/platforms/windows/golang-msvc-fixup.cpp | 10 --------- .../windows/windowsnetworkwatcher.cpp | 1 + src/update/balrog.cpp | 6 ++--- windows/installer/MozillaVPN_cmake.wxs | 1 + windows/installer/MozillaVPN_prod.wxs | 1 + 7 files changed, 24 insertions(+), 24 deletions(-) delete mode 100644 src/platforms/windows/golang-msvc-fixup.cpp diff --git a/src/cmake/golang.cmake b/src/cmake/golang.cmake index 923e51370f5..64847a61cf0 100644 --- a/src/cmake/golang.cmake +++ b/src/cmake/golang.cmake @@ -52,11 +52,4 @@ function(add_go_library GOTARGET SOURCE) INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR} INTERFACE_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${HEADER_NAME} IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${ARCHIVE_NAME}) - - if(MSVC) - # prevent error LNK2019: unresolved external symbol fprintf referenced in function ... - set_property(TARGET ${GOTARGET} APPEND PROPERTY - INTERFACE_SOURCES ${CMAKE_SOURCE_DIR}/src/platforms/windows/golang-msvc-fixup.cpp) - endif() - endfunction(add_go_library) diff --git a/src/cmake/windows.cmake b/src/cmake/windows.cmake index 0a73f8fcfd0..35f9dbf2933 100644 --- a/src/cmake/windows.cmake +++ b/src/cmake/windows.cmake @@ -14,7 +14,7 @@ set_target_properties(mozillavpn PROPERTIES # and then we can remove this :) target_compile_options(mozillavpn PRIVATE - $<$:/ZI>> + $<$:/ZI> ) # Generate the Windows version resource file. @@ -87,10 +87,24 @@ endif() include(cmake/golang.cmake) -# Enable Balrog for update support. +# Build the Balrog library as a DLL +add_custom_target(balrogdll ALL + BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/balrog.dll ${CMAKE_CURRENT_BINARY_DIR}/balrog.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/balrog + COMMAND ${CMAKE_COMMAND} -E env + GOCACHE=${CMAKE_BINARY_DIR}/go-cache + GOOS=windows CGO_ENABLED=1 + CC=gcc + CGO_CFLAGS="-O3 -Wall -Wno-unused-function -Wno-switch -std=gnu11 -DWINVER=0x0601" + CGO_LDFLAGS="-Wl,--dynamicbase -Wl,--nxcompat -Wl,--export-all-symbols -Wl,--high-entropy-va" + go build -buildmode c-shared -ldflags="-w -s" -trimpath -v -o "${CMAKE_CURRENT_BINARY_DIR}/balrog.dll" +) +set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/go-cache) +add_dependencies(mozillavpn balrogdll) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/balrog.dll DESTINATION .) + +# Use Balrog for update support. add_definitions(-DMVPN_BALROG) -add_go_library(balrog ../balrog/balrog-api.go) -target_link_libraries(mozillavpn PRIVATE balrog) target_sources(mozillavpn PRIVATE update/balrog.cpp update/balrog.h diff --git a/src/platforms/windows/golang-msvc-fixup.cpp b/src/platforms/windows/golang-msvc-fixup.cpp deleted file mode 100644 index 18b478d4d36..00000000000 --- a/src/platforms/windows/golang-msvc-fixup.cpp +++ /dev/null @@ -1,10 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include - -#pragma comment(lib, "legacy_stdio_definitions.lib") - -extern "C" { -FILE __iob_func[3] = {*stdin, *stdout, *stderr}; -} diff --git a/src/platforms/windows/windowsnetworkwatcher.cpp b/src/platforms/windows/windowsnetworkwatcher.cpp index 2b4f87352a0..e0bb6d70347 100644 --- a/src/platforms/windows/windowsnetworkwatcher.cpp +++ b/src/platforms/windows/windowsnetworkwatcher.cpp @@ -11,6 +11,7 @@ #include #pragma comment(lib, "Wlanapi.lib") +#pragma comment(lib, "windowsapp.lib") #include // See diff --git a/src/update/balrog.cpp b/src/update/balrog.cpp index 5732a1d7616..c23e70be2c3 100644 --- a/src/update/balrog.cpp +++ b/src/update/balrog.cpp @@ -27,8 +27,8 @@ # include "platforms/windows/golang-msvc-types.h" #endif -// Import balrog C/Go library (unless we are building on Windows with qmake) -#if !(defined(MVPN_WINDOWS) && defined(BUILD_QMAKE)) +// Import balrog C/Go library, except on windows where we need to use a DLL. +#if !defined(MVPN_WINDOWS) extern "C" { # include "balrog-api.h" } @@ -184,7 +184,7 @@ bool Balrog::checkSignature(Task* task, const QByteArray& x5uData, bool Balrog::validateSignature(const QByteArray& x5uData, const QByteArray& updateData, const QByteArray& signatureBlob) { -#if defined(MVPN_WINDOWS) && defined(BUILD_QMAKE) +#if defined(MVPN_WINDOWS) typedef void BalrogSetLogger(GoUintptr func); typedef GoUint8 BalrogValidate(GoString x5uData, GoString updateData, GoString signature, GoString rootHash, diff --git a/windows/installer/MozillaVPN_cmake.wxs b/windows/installer/MozillaVPN_cmake.wxs index 645c7811f6c..4293e59794a 100644 --- a/windows/installer/MozillaVPN_cmake.wxs +++ b/windows/installer/MozillaVPN_cmake.wxs @@ -72,6 +72,7 @@ + diff --git a/windows/installer/MozillaVPN_prod.wxs b/windows/installer/MozillaVPN_prod.wxs index c506f447a8e..c2ec106ef71 100644 --- a/windows/installer/MozillaVPN_prod.wxs +++ b/windows/installer/MozillaVPN_prod.wxs @@ -77,6 +77,7 @@ + From 9d64b0912ae7118053aea15fb15594f6b1e69ca9 Mon Sep 17 00:00:00 2001 From: Owen Kirby Date: Mon, 10 Oct 2022 08:39:02 -0700 Subject: [PATCH 24/85] Gracefully handle external activation of VPN service. (#4592) * Gracefully handle external activation of VPN service. * Linter fixes --- src/controller.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/controller.cpp b/src/controller.cpp index 3d223304124..8929f5417e6 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -361,21 +361,27 @@ bool Controller::deactivate() { void Controller::connected(const QString& pubkey) { logger.debug() << "handshake completed with:" << logger.keys(pubkey); if (m_activationQueue.isEmpty()) { - logger.warning() << "Unexpected handshake: no pending connections."; - return; - } - if (m_activationQueue.first().m_server.publicKey() != pubkey) { + MozillaVPN* vpn = MozillaVPN::instance(); + Q_ASSERT(vpn); + if (vpn->exitServerPublicKey() != pubkey) { + logger.warning() << "Unexpected handshake: no pending connections."; + return; + } + // Continue anyways if the VPN service was activated externally. + logger.info() << "Unexpected handshake: external VPN activation."; + } else if (m_activationQueue.first().m_server.publicKey() != pubkey) { logger.warning() << "Unexpected handshake: public key mismatch."; return; + } else { + // Start the next connection if there is more work to do. + m_activationQueue.removeFirst(); + if (!m_activationQueue.isEmpty()) { + activateNext(); + return; + } } m_handshakeTimer.stop(); m_ping_canary.stop(); - // Start the next connection if there is more work to do. - m_activationQueue.removeFirst(); - if (!m_activationQueue.isEmpty()) { - activateNext(); - return; - } // Clear the retry counter after all connections have succeeded. m_connectionRetry = 0; From 1f6794aaa271004064073f40e79092d998bb71c7 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 10 Oct 2022 17:39:46 +0200 Subject: [PATCH 25/85] Better error propagation (#4604) * Better error propagation * Comment applied --- src/commands/commandservers.cpp | 2 +- src/commands/commandstatus.cpp | 2 +- src/errorhandler.cpp | 9 ++ src/errorhandler.h | 15 ++ src/keyregenerator.cpp | 2 +- src/mozillavpn.cpp | 22 ++- .../android/androidapplistprovider.cpp | 5 +- src/platforms/android/androidiaphandler.cpp | 15 +- src/platforms/ios/iosiaphandler.mm | 8 +- src/platforms/wasm/wasmiaphandler.cpp | 15 +- src/releasemonitor.cpp | 149 +++++++++--------- src/releasemonitor.h | 84 +++++----- src/tasks/account/taskaccount.cpp | 18 +-- src/tasks/account/taskaccount.h | 8 +- src/tasks/adddevice/taskadddevice.cpp | 13 +- src/tasks/authenticate/taskauthenticate.cpp | 3 +- .../taskcaptiveportallookup.cpp | 25 +-- .../taskcaptiveportallookup.h | 8 +- src/tasks/deleteaccount/taskdeleteaccount.cpp | 3 +- .../taskgetsubscriptiondetails.cpp | 61 ++++--- src/tasks/products/taskproducts.cpp | 13 +- src/tasks/release/taskrelease.cpp | 9 +- src/tasks/release/taskrelease.h | 8 +- src/tasks/removedevice/taskremovedevice.cpp | 29 ++-- src/tasks/servers/taskservers.cpp | 17 +- src/tasks/servers/taskservers.h | 8 +- src/update/balrog.cpp | 9 +- src/update/balrog.h | 6 +- src/update/updater.cpp | 12 +- src/update/updater.h | 6 +- tests/unit/testtasks.cpp | 8 +- 31 files changed, 334 insertions(+), 258 deletions(-) diff --git a/src/commands/commandservers.cpp b/src/commands/commandservers.cpp index 3198cf558b3..02dcfb43d6c 100644 --- a/src/commands/commandservers.cpp +++ b/src/commands/commandservers.cpp @@ -58,7 +58,7 @@ int CommandServers::run(QStringList& tokens) { MozillaVPN vpn; if (!cacheOption.m_set) { - TaskServers task; + TaskServers task(ErrorHandler::PropagateError); task.run(); QEventLoop loop; diff --git a/src/commands/commandstatus.cpp b/src/commands/commandstatus.cpp index 2fc75cd2b1e..465377037e1 100644 --- a/src/commands/commandstatus.cpp +++ b/src/commands/commandstatus.cpp @@ -62,7 +62,7 @@ int CommandStatus::run(QStringList& tokens) { } if (!cacheOption.m_set) { - TaskAccount task; + TaskAccount task(ErrorHandler::PropagateError); task.run(); QEventLoop loop; diff --git a/src/errorhandler.cpp b/src/errorhandler.cpp index 83b61896cf1..32be84af1d4 100644 --- a/src/errorhandler.cpp +++ b/src/errorhandler.cpp @@ -226,3 +226,12 @@ void ErrorHandler::setAlert(AlertType alert) { m_alert = alert; emit alertChanged(); } + +// static +void ErrorHandler::networkErrorHandle( + QNetworkReply::NetworkError error, + ErrorPropagationPolicy errorPropagationPolicy) { + if (errorPropagationPolicy == PropagateError) { + ErrorHandler::instance()->errorHandle(toErrorType(error)); + } +} diff --git a/src/errorhandler.h b/src/errorhandler.h index a23b8f52ef7..9d13a2a7da9 100644 --- a/src/errorhandler.h +++ b/src/errorhandler.h @@ -48,8 +48,23 @@ class ErrorHandler final : public QObject { }; Q_ENUM(AlertType) + enum ErrorPropagationPolicy { + // Do not propagate the error up to the frontend code. The error will be + // logged but it will not be shown to the user. + DoNotPropagateError, + + // The error needs to be propagated through the frontend code and shown to + // the user as an alert or something else. + PropagateError, + }; + Q_ENUM(ErrorPropagationPolicy); + static ErrorType toErrorType(QNetworkReply::NetworkError error); + static void networkErrorHandle( + QNetworkReply::NetworkError error, + ErrorPropagationPolicy errorPropagationPolicy = PropagateError); + ~ErrorHandler(); static ErrorHandler* instance(); diff --git a/src/keyregenerator.cpp b/src/keyregenerator.cpp index 2116c31d8a7..86edc8e8515 100644 --- a/src/keyregenerator.cpp +++ b/src/keyregenerator.cpp @@ -78,7 +78,7 @@ void KeyRegenerator::stateChanged() { TaskScheduler::scheduleTask( new TaskAddDevice(Device::currentDeviceName(), Device::uniqueDeviceId())); - TaskScheduler::scheduleTask(new TaskAccount()); + TaskScheduler::scheduleTask(new TaskAccount(ErrorHandler::PropagateError)); m_timer.start(Constants::keyRegeneratorTimeSec() * 1000); } diff --git a/src/mozillavpn.cpp b/src/mozillavpn.cpp index 9cd0b583f86..23986e8db52 100644 --- a/src/mozillavpn.cpp +++ b/src/mozillavpn.cpp @@ -99,7 +99,9 @@ MozillaVPN::MozillaVPN() : m_private(new Private()) { connect(&m_periodicOperationsTimer, &QTimer::timeout, []() { TaskScheduler::scheduleTask(new TaskGroup( - {new TaskAccount(), new TaskServers(), new TaskCaptivePortalLookup(), + {new TaskAccount(ErrorHandler::DoNotPropagateError), + new TaskServers(ErrorHandler::DoNotPropagateError), + new TaskCaptivePortalLookup(ErrorHandler::DoNotPropagateError), new TaskHeartbeat(), new TaskGetFeatureList(), new TaskAddonIndex()})); }); @@ -326,8 +328,10 @@ void MozillaVPN::initialize() { m_private->m_serverData.writeSettings(); } - QList refreshTasks{new TaskAccount(), new TaskServers(), - new TaskCaptivePortalLookup()}; + QList refreshTasks{ + new TaskAccount(ErrorHandler::PropagateError), + new TaskServers(ErrorHandler::PropagateError), + new TaskCaptivePortalLookup(ErrorHandler::PropagateError)}; if (Feature::get(Feature::Feature_inAppPurchase)->isSupported()) { refreshTasks.append(new TaskProducts()); @@ -568,7 +572,8 @@ void MozillaVPN::completeActivation() { } else { // Let's fetch the account and the servers. TaskScheduler::scheduleTask( - new TaskGroup({new TaskAccount(), new TaskServers()})); + new TaskGroup({new TaskAccount(ErrorHandler::PropagateError), + new TaskServers(ErrorHandler::PropagateError)})); } if (Feature::get(Feature::Feature_inAppPurchase)->isSupported()) { @@ -1288,7 +1293,8 @@ void MozillaVPN::refreshDevices() { if (m_state == StateMain) { TaskScheduler::scheduleTask( - new TaskGroup({new TaskAccount(), new TaskServers()})); + new TaskGroup({new TaskAccount(ErrorHandler::DoNotPropagateError), + new TaskServers(ErrorHandler::DoNotPropagateError)})); } } @@ -1419,7 +1425,8 @@ void MozillaVPN::subscriptionFailedInternal(bool canceledByUser) { } TaskScheduler::scheduleTask( - new TaskGroup({new TaskAccount(), new TaskServers()})); + new TaskGroup({new TaskAccount(ErrorHandler::PropagateError), + new TaskServers(ErrorHandler::PropagateError)})); TaskScheduler::scheduleTask(new TaskFunction([this]() { if (!m_private->m_user.subscriptionNeeded() && m_state == StateSubscriptionNeeded) { @@ -1522,7 +1529,8 @@ void MozillaVPN::addCurrentDeviceAndRefreshData() { TaskScheduler::scheduleTask( new TaskAddDevice(Device::currentDeviceName(), Device::uniqueDeviceId())); TaskScheduler::scheduleTask( - new TaskGroup({new TaskAccount(), new TaskServers()})); + new TaskGroup({new TaskAccount(ErrorHandler::PropagateError), + new TaskServers(ErrorHandler::PropagateError)})); } void MozillaVPN::openAppStoreReviewLink() { diff --git a/src/platforms/android/androidapplistprovider.cpp b/src/platforms/android/androidapplistprovider.cpp index dd16857df2a..de96d9774ef 100644 --- a/src/platforms/android/androidapplistprovider.cpp +++ b/src/platforms/android/androidapplistprovider.cpp @@ -38,7 +38,10 @@ void AndroidAppListProvider::getApplicationList() { QStringList keys = listObj.keys(); QMap out; - foreach (auto key, keys) { out[key] = listObj[key].toString(); } + foreach (auto key, keys) { + // This comment is to make linter happy. + out[key] = listObj[key].toString(); + } emit newAppList(out); } diff --git a/src/platforms/android/androidiaphandler.cpp b/src/platforms/android/androidiaphandler.cpp index bff022c2b6d..efc744a118d 100644 --- a/src/platforms/android/androidiaphandler.cpp +++ b/src/platforms/android/androidiaphandler.cpp @@ -319,14 +319,13 @@ void AndroidIAPHandler::validatePurchase(QJsonObject purchase) { TaskPurchase* purchaseTask = TaskPurchase::createForAndroid(sku, token); Q_ASSERT(purchaseTask); - connect( - purchaseTask, &TaskPurchase::failed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - logger.error() << "Purchase validation request to guardian failed"; - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - stopSubscription(); - emit subscriptionNotValidated(); - }); + connect(purchaseTask, &TaskPurchase::failed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + logger.error() << "Purchase validation request to guardian failed"; + ErrorHandler::networkErrorHandle(error); + stopSubscription(); + emit subscriptionNotValidated(); + }); connect(purchaseTask, &TaskPurchase::succeeded, this, [this, token](const QByteArray& data) { diff --git a/src/platforms/ios/iosiaphandler.mm b/src/platforms/ios/iosiaphandler.mm index 580a1a61b09..4b0f60a0f0e 100644 --- a/src/platforms/ios/iosiaphandler.mm +++ b/src/platforms/ios/iosiaphandler.mm @@ -339,7 +339,7 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(nonnull SKPaymentQueue QJsonDocument json = QJsonDocument::fromJson(data); if (!json.isObject()) { - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::networkErrorHandle(error); emit subscriptionFailed(); ErrorHandler::instance()->subscriptionGenericError(); return; @@ -348,7 +348,7 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(nonnull SKPaymentQueue QJsonObject obj = json.object(); QJsonValue errorValue = obj.value("errno"); if (!errorValue.isDouble()) { - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::networkErrorHandle(error); emit subscriptionFailed(); ErrorHandler::instance()->subscriptionGenericError(); return; @@ -356,14 +356,14 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(nonnull SKPaymentQueue int errorNumber = errorValue.toInt(); if (errorNumber == GUARDIAN_ERROR_RECEIPT_NOT_VALID) { - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::networkErrorHandle(error); emit subscriptionFailed(); ErrorHandler::instance()->subscriptionExpiredError(); return; } if (errorNumber == GUARDIAN_ERROR_RECEIPT_IN_USE) { - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::networkErrorHandle(error); emit subscriptionFailed(); ErrorHandler::instance()->subscriptionInUseError(); return; diff --git a/src/platforms/wasm/wasmiaphandler.cpp b/src/platforms/wasm/wasmiaphandler.cpp index 64efe43fe46..13b2937970e 100644 --- a/src/platforms/wasm/wasmiaphandler.cpp +++ b/src/platforms/wasm/wasmiaphandler.cpp @@ -47,14 +47,13 @@ void WasmIAPHandler::nativeStartSubscription(Product* product) { TaskPurchase* purchaseTask = TaskPurchase::createForWasm(product->m_name); Q_ASSERT(purchaseTask); - connect( - purchaseTask, &TaskPurchase::failed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - logger.error() << "Purchase validation request to guardian failed"; - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - stopSubscription(); - emit subscriptionNotValidated(); - }); + connect(purchaseTask, &TaskPurchase::failed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + logger.error() << "Purchase validation request to guardian failed"; + ErrorHandler::networkErrorHandle(error); + stopSubscription(); + emit subscriptionNotValidated(); + }); connect(purchaseTask, &TaskPurchase::succeeded, this, [this](const QByteArray& data) { diff --git a/src/releasemonitor.cpp b/src/releasemonitor.cpp index 8a5d4ae2e57..c01bafd90fa 100644 --- a/src/releasemonitor.cpp +++ b/src/releasemonitor.cpp @@ -1,72 +1,77 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "releasemonitor.h" -#include "constants.h" -#include "leakdetector.h" -#include "logger.h" -#include "mozillavpn.h" -#include "tasks/release/taskrelease.h" -#include "taskscheduler.h" -#include "timersingleshot.h" -#include "update/updater.h" - -namespace { -Logger logger(LOG_MAIN, "ReleaseMonitor"); -} - -ReleaseMonitor::ReleaseMonitor() { - MVPN_COUNT_CTOR(ReleaseMonitor); - - m_timer.setSingleShot(true); - connect(&m_timer, &QTimer::timeout, this, &ReleaseMonitor::runSoon); -} - -ReleaseMonitor::~ReleaseMonitor() { MVPN_COUNT_DTOR(ReleaseMonitor); } - -void ReleaseMonitor::runSoon() { - logger.debug() << "Scheduling a release-check task"; - - TimerSingleShot::create(this, 0, [this] { - TaskRelease* task = new TaskRelease(TaskRelease::Check); - - connect(task, &TaskRelease::updateRequired, this, - &ReleaseMonitor::updateRequired); - connect(task, &TaskRelease::updateRequiredOrRecommended, this, - &ReleaseMonitor::updateRequiredOrRecommended); - connect(task, &TaskRelease::updateNotAvailable, this, - &ReleaseMonitor::updateNotAvailable); - connect(task, &Task::completed, this, &ReleaseMonitor::releaseChecked); - connect(task, &Task::completed, this, &ReleaseMonitor::schedule); - - TaskScheduler::scheduleTask(task); - }); -} - -void ReleaseMonitor::schedule() { - logger.debug() << "ReleaseMonitor scheduling"; - m_timer.start(Constants::releaseMonitorMsec()); -} - -void ReleaseMonitor::updateRequired() { - logger.warning() << "update required"; - MozillaVPN::instance()->controller()->updateRequired(); -} - -void ReleaseMonitor::updateSoon() { - logger.debug() << "Scheduling a release-update task"; - - TimerSingleShot::create(this, 0, [] { - TaskRelease* task = new TaskRelease(TaskRelease::Update); - // The updater, in download mode, is not destroyed. So, if this happens, - // probably something went wrong. - connect(task, &Task::completed, [] { - MozillaVPN* vpn = MozillaVPN::instance(); - Q_ASSERT(vpn); - vpn->setUpdating(false); - }); - - TaskScheduler::scheduleTask(task); - }); -} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "releasemonitor.h" +#include "constants.h" +#include "leakdetector.h" +#include "logger.h" +#include "mozillavpn.h" +#include "tasks/release/taskrelease.h" +#include "taskscheduler.h" +#include "timersingleshot.h" +#include "update/updater.h" + +namespace { +Logger logger(LOG_MAIN, "ReleaseMonitor"); +} + +ReleaseMonitor::ReleaseMonitor() { + MVPN_COUNT_CTOR(ReleaseMonitor); + + m_timer.setSingleShot(true); + connect(&m_timer, &QTimer::timeout, this, [this]() { + ReleaseMonitor::runSoon(ErrorHandler::DoNotPropagateError); + }); +} + +ReleaseMonitor::~ReleaseMonitor() { MVPN_COUNT_DTOR(ReleaseMonitor); } + +void ReleaseMonitor::runSoon( + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy) { + logger.debug() << "Scheduling a release-check task"; + + TimerSingleShot::create(this, 0, [this, errorPropagationPolicy] { + TaskRelease* task = + new TaskRelease(TaskRelease::Check, errorPropagationPolicy); + + connect(task, &TaskRelease::updateRequired, this, + &ReleaseMonitor::updateRequired); + connect(task, &TaskRelease::updateRequiredOrRecommended, this, + &ReleaseMonitor::updateRequiredOrRecommended); + connect(task, &TaskRelease::updateNotAvailable, this, + &ReleaseMonitor::updateNotAvailable); + connect(task, &Task::completed, this, &ReleaseMonitor::releaseChecked); + connect(task, &Task::completed, this, &ReleaseMonitor::schedule); + + TaskScheduler::scheduleTask(task); + }); +} + +void ReleaseMonitor::schedule() { + logger.debug() << "ReleaseMonitor scheduling"; + m_timer.start(Constants::releaseMonitorMsec()); +} + +void ReleaseMonitor::updateRequired() { + logger.warning() << "update required"; + MozillaVPN::instance()->controller()->updateRequired(); +} + +void ReleaseMonitor::updateSoon() { + logger.debug() << "Scheduling a release-update task"; + + TimerSingleShot::create(this, 0, [] { + TaskRelease* task = + new TaskRelease(TaskRelease::Update, ErrorHandler::PropagateError); + // The updater, in download mode, is not destroyed. So, if this happens, + // probably something went wrong. + connect(task, &Task::completed, [] { + MozillaVPN* vpn = MozillaVPN::instance(); + Q_ASSERT(vpn); + vpn->setUpdating(false); + }); + + TaskScheduler::scheduleTask(task); + }); +} diff --git a/src/releasemonitor.h b/src/releasemonitor.h index bd4b18c1615..89f9fa44aa1 100644 --- a/src/releasemonitor.h +++ b/src/releasemonitor.h @@ -1,40 +1,44 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef RELEASEMONITOR_H -#define RELEASEMONITOR_H - -#include -#include - -class ReleaseMonitor final : public QObject { - Q_OBJECT - Q_DISABLE_COPY_MOVE(ReleaseMonitor) - - public: - ReleaseMonitor(); - ~ReleaseMonitor(); - - Q_INVOKABLE void runSoon(); - - void updateSoon(); - - signals: - // for testing - void releaseChecked(); - // Is fired once balrog/guardian was checked - // Retuns if any update is available (both recommended/required) - void updateRequiredOrRecommended(); - void updateNotAvailable(); - - private: - void schedule(); - - void updateRequired(); - - private: - QTimer m_timer; -}; - -#endif // RELEASEMONITOR_H +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef RELEASEMONITOR_H +#define RELEASEMONITOR_H + +#include "errorhandler.h" + +#include +#include + +class ReleaseMonitor final : public QObject { + Q_OBJECT + Q_DISABLE_COPY_MOVE(ReleaseMonitor) + + public: + ReleaseMonitor(); + ~ReleaseMonitor(); + + Q_INVOKABLE void runSoon( + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy = + ErrorHandler::PropagateError); + + void updateSoon(); + + signals: + // for testing + void releaseChecked(); + // Is fired once balrog/guardian was checked + // Retuns if any update is available (both recommended/required) + void updateRequiredOrRecommended(); + void updateNotAvailable(); + + private: + void schedule(); + + void updateRequired(); + + private: + QTimer m_timer; +}; + +#endif // RELEASEMONITOR_H diff --git a/src/tasks/account/taskaccount.cpp b/src/tasks/account/taskaccount.cpp index 428c497f0e6..cc539e03338 100644 --- a/src/tasks/account/taskaccount.cpp +++ b/src/tasks/account/taskaccount.cpp @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "taskaccount.h" -#include "errorhandler.h" #include "leakdetector.h" #include "logger.h" #include "mozillavpn.h" @@ -13,7 +12,9 @@ namespace { Logger logger(LOG_MAIN, "TaskAccount"); } -TaskAccount::TaskAccount() : Task("TaskAccount") { +TaskAccount::TaskAccount( + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy) + : Task("TaskAccount"), m_errorPropagationPolicy(errorPropagationPolicy) { MVPN_COUNT_CTOR(TaskAccount); } @@ -22,13 +23,12 @@ TaskAccount::~TaskAccount() { MVPN_COUNT_DTOR(TaskAccount); } void TaskAccount::run() { NetworkRequest* request = NetworkRequest::createForAccount(this); - connect( - request, &NetworkRequest::requestFailed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - logger.error() << "Account request failed" << error; - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - emit completed(); - }); + connect(request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + logger.error() << "Account request failed" << error; + ErrorHandler::networkErrorHandle(error, m_errorPropagationPolicy); + emit completed(); + }); connect(request, &NetworkRequest::requestCompleted, this, [this](const QByteArray& data) { diff --git a/src/tasks/account/taskaccount.h b/src/tasks/account/taskaccount.h index 09ebc41dc58..f3b6bd388e5 100644 --- a/src/tasks/account/taskaccount.h +++ b/src/tasks/account/taskaccount.h @@ -5,6 +5,7 @@ #ifndef TASKACCOUNT_H #define TASKACCOUNT_H +#include "errorhandler.h" #include "task.h" #include @@ -13,10 +14,15 @@ class TaskAccount final : public Task { Q_DISABLE_COPY_MOVE(TaskAccount) public: - TaskAccount(); + explicit TaskAccount( + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy); ~TaskAccount(); void run() override; + + private: + ErrorHandler::ErrorPropagationPolicy m_errorPropagationPolicy = + ErrorHandler::DoNotPropagateError; }; #endif // TASKACCOUNT_H diff --git a/src/tasks/adddevice/taskadddevice.cpp b/src/tasks/adddevice/taskadddevice.cpp index 7b48f7af520..c4b9153326e 100644 --- a/src/tasks/adddevice/taskadddevice.cpp +++ b/src/tasks/adddevice/taskadddevice.cpp @@ -55,13 +55,12 @@ void TaskAddDevice::run() { request->disableTimeout(); - connect( - request, &NetworkRequest::requestFailed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - logger.error() << "Failed to add the device" << error; - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - emit completed(); - }); + connect(request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + logger.error() << "Failed to add the device" << error; + ErrorHandler::networkErrorHandle(error); + emit completed(); + }); connect(request, &NetworkRequest::requestCompleted, this, [this, publicKey, privateKey](const QByteArray&) { diff --git a/src/tasks/authenticate/taskauthenticate.cpp b/src/tasks/authenticate/taskauthenticate.cpp index 9936777f7f6..032db29f2a9 100644 --- a/src/tasks/authenticate/taskauthenticate.cpp +++ b/src/tasks/authenticate/taskauthenticate.cpp @@ -59,8 +59,7 @@ void TaskAuthenticate::run() { [](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Failed to complete the authentication" << error; - ErrorHandler::instance()->errorHandle( - ErrorHandler::toErrorType(error)); + ErrorHandler::networkErrorHandle(error); }); connect(request, &NetworkRequest::requestCompleted, this, diff --git a/src/tasks/captiveportallookup/taskcaptiveportallookup.cpp b/src/tasks/captiveportallookup/taskcaptiveportallookup.cpp index 7ce9f91b1d6..d893e69d965 100644 --- a/src/tasks/captiveportallookup/taskcaptiveportallookup.cpp +++ b/src/tasks/captiveportallookup/taskcaptiveportallookup.cpp @@ -13,8 +13,10 @@ namespace { Logger logger(LOG_NETWORKING, "TaskCaptivePortalLookup"); } -TaskCaptivePortalLookup::TaskCaptivePortalLookup() - : Task("TaskCaptivePortalLookup") { +TaskCaptivePortalLookup::TaskCaptivePortalLookup( + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy) + : Task("TaskCaptivePortalLookup"), + m_errorPropagationPolicy(errorPropagationPolicy) { MVPN_COUNT_CTOR(TaskCaptivePortalLookup); } @@ -26,16 +28,15 @@ void TaskCaptivePortalLookup::run() { logger.debug() << "Resolving the captive portal detector URL"; NetworkRequest* request = NetworkRequest::createForCaptivePortalLookup(this); - connect( - request, &NetworkRequest::requestFailed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - if (m_cancelled) { - return; - } - logger.error() << "Failed to obtain captive portal IPs" << error; - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - emit completed(); - }); + connect(request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + if (m_cancelled) { + return; + } + logger.error() << "Failed to obtain captive portal IPs" << error; + ErrorHandler::networkErrorHandle(error, m_errorPropagationPolicy); + emit completed(); + }); connect(request, &NetworkRequest::requestCompleted, this, [this](const QByteArray& data) { diff --git a/src/tasks/captiveportallookup/taskcaptiveportallookup.h b/src/tasks/captiveportallookup/taskcaptiveportallookup.h index 2fff5c5ce86..462aac67c1c 100644 --- a/src/tasks/captiveportallookup/taskcaptiveportallookup.h +++ b/src/tasks/captiveportallookup/taskcaptiveportallookup.h @@ -5,6 +5,7 @@ #ifndef TASKCAPTIVEPORTALLOOKUP_H #define TASKCAPTIVEPORTALLOOKUP_H +#include "errorhandler.h" #include "task.h" #include @@ -13,10 +14,15 @@ class TaskCaptivePortalLookup final : public Task { Q_DISABLE_COPY_MOVE(TaskCaptivePortalLookup) public: - TaskCaptivePortalLookup(); + explicit TaskCaptivePortalLookup( + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy); ~TaskCaptivePortalLookup(); void run() override; + + private: + ErrorHandler::ErrorPropagationPolicy m_errorPropagationPolicy = + ErrorHandler::DoNotPropagateError; }; #endif // TASKCAPTIVEPORTALLOOKUP_H diff --git a/src/tasks/deleteaccount/taskdeleteaccount.cpp b/src/tasks/deleteaccount/taskdeleteaccount.cpp index b4d382cba87..0709852919f 100644 --- a/src/tasks/deleteaccount/taskdeleteaccount.cpp +++ b/src/tasks/deleteaccount/taskdeleteaccount.cpp @@ -54,8 +54,7 @@ void TaskDeleteAccount::run() { [this](QNetworkReply::NetworkError error, const QByteArray&) { logger.error() << "Failed to complete the authentication" << error; - ErrorHandler::instance()->errorHandle( - ErrorHandler::toErrorType(error)); + ErrorHandler::networkErrorHandle(error); m_authenticationInAppSession->terminate(); }); diff --git a/src/tasks/getsubscriptiondetails/taskgetsubscriptiondetails.cpp b/src/tasks/getsubscriptiondetails/taskgetsubscriptiondetails.cpp index 73c353625aa..f9d52958236 100644 --- a/src/tasks/getsubscriptiondetails/taskgetsubscriptiondetails.cpp +++ b/src/tasks/getsubscriptiondetails/taskgetsubscriptiondetails.cpp @@ -43,37 +43,36 @@ void TaskGetSubscriptionDetails::run() { NetworkRequest* request = NetworkRequest::createForGetSubscriptionDetails(this); - connect( - request, &NetworkRequest::requestFailed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - logger.error() << "Get subscription details failed" << error; - - // Network request failed after authentication for a second time - if (m_authenticationInAppSession) { - logger.error() << "Network request failed after authentication"; - - ErrorHandler::instance()->errorHandle( - ErrorHandler::toErrorType(error)); - emit failed(); - m_authenticationInAppSession->terminate(); - return; - } - - // User needs to (re)authenticate - if (error == QNetworkReply::AuthenticationRequiredError) { - logger.error() << "Needs authentication"; - initAuthentication(); - return; - } - - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - - // We need to emit two separate signals here. - // `failed`: Signal for connected objects that are monitoring this Task - // `completed`: Notify `TaskScheduler` that this Task can be deleted - emit failed(); - emit completed(); - }); + connect(request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + logger.error() << "Get subscription details failed" << error; + + // Network request failed after authentication for a second time + if (m_authenticationInAppSession) { + logger.error() << "Network request failed after authentication"; + + ErrorHandler::networkErrorHandle(error); + emit failed(); + m_authenticationInAppSession->terminate(); + return; + } + + // User needs to (re)authenticate + if (error == QNetworkReply::AuthenticationRequiredError) { + logger.error() << "Needs authentication"; + initAuthentication(); + return; + } + + ErrorHandler::networkErrorHandle(error); + + // We need to emit two separate signals here. + // `failed`: Signal for connected objects that are monitoring this + // Task `completed`: Notify `TaskScheduler` that this Task can be + // deleted + emit failed(); + emit completed(); + }); connect(request, &NetworkRequest::requestCompleted, this, [this](const QByteArray& data) { diff --git a/src/tasks/products/taskproducts.cpp b/src/tasks/products/taskproducts.cpp index b14ea7ee3b8..f13fd12d903 100644 --- a/src/tasks/products/taskproducts.cpp +++ b/src/tasks/products/taskproducts.cpp @@ -22,13 +22,12 @@ TaskProducts::~TaskProducts() { MVPN_COUNT_DTOR(TaskProducts); } void TaskProducts::run() { NetworkRequest* request = NetworkRequest::createForProducts(this); - connect( - request, &NetworkRequest::requestFailed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - logger.error() << "Products request to guardian failed" << error; - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - emit completed(); - }); + connect(request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + logger.error() << "Products request to guardian failed" << error; + ErrorHandler::networkErrorHandle(error); + emit completed(); + }); connect(request, &NetworkRequest::requestCompleted, this, [this](const QByteArray& data) { diff --git a/src/tasks/release/taskrelease.cpp b/src/tasks/release/taskrelease.cpp index a59f1614382..35998c80d8c 100644 --- a/src/tasks/release/taskrelease.cpp +++ b/src/tasks/release/taskrelease.cpp @@ -11,7 +11,11 @@ namespace { Logger logger(LOG_MAIN, "TaskRelease"); } -TaskRelease::TaskRelease(Op op) : Task("TaskRelease"), m_op(op) { +TaskRelease::TaskRelease( + Op op, ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy) + : Task("TaskRelease"), + m_op(op), + m_errorPropagationPolicy(errorPropagationPolicy) { MVPN_COUNT_CTOR(TaskRelease); } @@ -20,7 +24,8 @@ TaskRelease::~TaskRelease() { MVPN_COUNT_DTOR(TaskRelease); } void TaskRelease::run() { logger.debug() << "Release check started"; - Updater* updater = Updater::create(this, m_op == Update); + Updater* updater = + Updater::create(this, m_op == Update, m_errorPropagationPolicy); Q_ASSERT(updater); connect(updater, &Updater::updateRequired, this, diff --git a/src/tasks/release/taskrelease.h b/src/tasks/release/taskrelease.h index 4c96f0ee452..6e80443a0fa 100644 --- a/src/tasks/release/taskrelease.h +++ b/src/tasks/release/taskrelease.h @@ -5,6 +5,7 @@ #ifndef TASKRELEASE_H #define TASKRELEASE_H +#include "errorhandler.h" #include "task.h" #include @@ -19,7 +20,8 @@ class TaskRelease final : public Task { Update, }; - explicit TaskRelease(Op op); + TaskRelease(Op op, + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy); ~TaskRelease(); void run() override; @@ -35,7 +37,9 @@ class TaskRelease final : public Task { void updateNotAvailable(); private: - Op m_op; + Op m_op = Check; + ErrorHandler::ErrorPropagationPolicy m_errorPropagationPolicy = + ErrorHandler::DoNotPropagateError; }; #endif // TASKRELEASE_H diff --git a/src/tasks/removedevice/taskremovedevice.cpp b/src/tasks/removedevice/taskremovedevice.cpp index 135289f1753..67decb2e3b9 100644 --- a/src/tasks/removedevice/taskremovedevice.cpp +++ b/src/tasks/removedevice/taskremovedevice.cpp @@ -39,22 +39,21 @@ void TaskRemoveDevice::run() { NetworkRequest* request = NetworkRequest::createForDeviceRemoval(this, m_publicKey); - connect( - request, &NetworkRequest::requestFailed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - if (error == QNetworkReply::ContentNotFoundError) { - logger.error() << "The device has been removed in the meantime. " - "Let's consider it a success"; - MozillaVPN::instance()->deviceRemoved(m_publicKey, - "TaskRemoveDevice"); - emit completed(); - return; - } + connect(request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + if (error == QNetworkReply::ContentNotFoundError) { + logger.error() << "The device has been removed in the meantime. " + "Let's consider it a success"; + MozillaVPN::instance()->deviceRemoved(m_publicKey, + "TaskRemoveDevice"); + emit completed(); + return; + } - logger.error() << "Failed to remove the device" << error; - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - emit completed(); - }); + logger.error() << "Failed to remove the device" << error; + ErrorHandler::networkErrorHandle(error); + emit completed(); + }); connect(request, &NetworkRequest::requestCompleted, this, [this](const QByteArray&) { diff --git a/src/tasks/servers/taskservers.cpp b/src/tasks/servers/taskservers.cpp index feeeea978bb..a9413cf91a1 100644 --- a/src/tasks/servers/taskservers.cpp +++ b/src/tasks/servers/taskservers.cpp @@ -13,7 +13,9 @@ namespace { Logger logger(LOG_MAIN, "TaskServers"); } -TaskServers::TaskServers() : Task("TaskServers") { +TaskServers::TaskServers( + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy) + : Task("TaskServers"), m_errorPropagationPolicy(errorPropagationPolicy) { MVPN_COUNT_CTOR(TaskServers); } @@ -22,13 +24,12 @@ TaskServers::~TaskServers() { MVPN_COUNT_DTOR(TaskServers); } void TaskServers::run() { NetworkRequest* request = NetworkRequest::createForServers(this); - connect( - request, &NetworkRequest::requestFailed, this, - [this](QNetworkReply::NetworkError error, const QByteArray&) { - logger.error() << "Failed to retrieve servers"; - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); - emit completed(); - }); + connect(request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + logger.error() << "Failed to retrieve servers"; + ErrorHandler::networkErrorHandle(error, m_errorPropagationPolicy); + emit completed(); + }); connect(request, &NetworkRequest::requestCompleted, this, [this](const QByteArray& data) { diff --git a/src/tasks/servers/taskservers.h b/src/tasks/servers/taskservers.h index d3d6c08a7a6..99b8ef0347c 100644 --- a/src/tasks/servers/taskservers.h +++ b/src/tasks/servers/taskservers.h @@ -5,6 +5,7 @@ #ifndef TASKSERVERS_H #define TASKSERVERS_H +#include "errorhandler.h" #include "task.h" #include @@ -13,10 +14,15 @@ class TaskServers final : public Task { Q_DISABLE_COPY_MOVE(TaskServers) public: - TaskServers(); + explicit TaskServers( + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy); ~TaskServers(); void run() override; + + private: + ErrorHandler::ErrorPropagationPolicy m_errorPropagationPolicy = + ErrorHandler::DoNotPropagateError; }; #endif // TASKSERVERS_H diff --git a/src/update/balrog.cpp b/src/update/balrog.cpp index c23e70be2c3..4f926e22710 100644 --- a/src/update/balrog.cpp +++ b/src/update/balrog.cpp @@ -55,8 +55,11 @@ void balrogLogger(int level, const char* msg) { } // namespace -Balrog::Balrog(QObject* parent, bool downloadAndInstall) - : Updater(parent), m_downloadAndInstall(downloadAndInstall) { +Balrog::Balrog(QObject* parent, bool downloadAndInstall, + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy) + : Updater(parent), + m_downloadAndInstall(downloadAndInstall), + m_errorPropagationPolicy(errorPropagationPolicy) { MVPN_COUNT_CTOR(Balrog); logger.debug() << "Balrog created"; } @@ -510,5 +513,5 @@ void Balrog::propagateError(NetworkRequest* request, return; } - ErrorHandler::instance()->errorHandle(ErrorHandler::toErrorType(error)); + ErrorHandler::networkErrorHandle(error, m_errorPropagationPolicy); } diff --git a/src/update/balrog.h b/src/update/balrog.h index ff307dfb04a..632e300598f 100644 --- a/src/update/balrog.h +++ b/src/update/balrog.h @@ -5,6 +5,7 @@ #ifndef BALROG_H #define BALROG_H +#include "errorhandler.h" #include "updater.h" #include @@ -17,7 +18,8 @@ class Balrog final : public Updater { Q_DISABLE_COPY_MOVE(Balrog) public: - Balrog(QObject* parent, bool downloadAndInstall); + Balrog(QObject* parent, bool downloadAndInstall, + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy); ~Balrog(); void start(Task* task) override; @@ -44,6 +46,8 @@ class Balrog final : public Updater { private: QTemporaryDir m_tmpDir; bool m_downloadAndInstall; + ErrorHandler::ErrorPropagationPolicy m_errorPropagationPolicy = + ErrorHandler::DoNotPropagateError; }; #endif // BALROG_H diff --git a/src/update/updater.cpp b/src/update/updater.cpp index ca909f70e16..80214bb7909 100644 --- a/src/update/updater.cpp +++ b/src/update/updater.cpp @@ -21,15 +21,15 @@ Logger logger(LOG_NETWORKING, "Updater"); } // static -Updater* Updater::create(QObject* parent, bool downloadAndInstall) { +Updater* Updater::create( + QObject* parent, bool downloadAndInstall, + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy) { #ifdef MVPN_BALROG - if (!downloadAndInstall) { - return new Balrog(parent, false); - } - - return new Balrog(parent, true); + return new Balrog(parent, downloadAndInstall, errorPropagationPolicy); #endif + Q_UNUSED(errorPropagationPolicy); + if (!downloadAndInstall) { return new VersionApi(parent); } diff --git a/src/update/updater.h b/src/update/updater.h index 33a57e7be24..37191427f01 100644 --- a/src/update/updater.h +++ b/src/update/updater.h @@ -5,6 +5,8 @@ #ifndef UPDATER_H #define UPDATER_H +#include "errorhandler.h" + #include class Task; @@ -27,7 +29,9 @@ class Updater : public QObject { }; Q_ENUM(Step); - static Updater* create(QObject* parent, bool downloadAndInstall); + static Updater* create( + QObject* parent, bool downloadAndInstall, + ErrorHandler::ErrorPropagationPolicy errorPropagationPolicy); static void updateViewShown(); diff --git a/tests/unit/testtasks.cpp b/tests/unit/testtasks.cpp index 3f168edde2a..363dc3a4c1f 100644 --- a/tests/unit/testtasks.cpp +++ b/tests/unit/testtasks.cpp @@ -17,7 +17,7 @@ void TestTasks::account() { TestHelper::networkConfig.append(TestHelper::NetworkConfig( TestHelper::NetworkConfig::Failure, QByteArray())); - TaskAccount* task = new TaskAccount(); + TaskAccount* task = new TaskAccount(ErrorHandler::PropagateError); QEventLoop loop; connect(task, &Task::completed, [&]() { loop.exit(); }); @@ -31,7 +31,7 @@ void TestTasks::account() { TestHelper::networkConfig.append(TestHelper::NetworkConfig( TestHelper::NetworkConfig::Success, QByteArray())); - TaskAccount* task = new TaskAccount(); + TaskAccount* task = new TaskAccount(ErrorHandler::DoNotPropagateError); QEventLoop loop; connect(task, &Task::completed, [&]() { loop.exit(); }); @@ -47,7 +47,7 @@ void TestTasks::servers() { TestHelper::networkConfig.append(TestHelper::NetworkConfig( TestHelper::NetworkConfig::Failure, QByteArray())); - TaskServers* task = new TaskServers(); + TaskServers* task = new TaskServers(ErrorHandler::DoNotPropagateError); QEventLoop loop; connect(task, &Task::completed, [&]() { loop.exit(); }); @@ -61,7 +61,7 @@ void TestTasks::servers() { TestHelper::networkConfig.append(TestHelper::NetworkConfig( TestHelper::NetworkConfig::Success, QByteArray())); - TaskServers* task = new TaskServers(); + TaskServers* task = new TaskServers(ErrorHandler::PropagateError); QEventLoop loop; connect(task, &Task::completed, [&]() { loop.exit(); }); From 28ab59a291ca2bab3334e22842c18142c6af36e7 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 10 Oct 2022 17:55:02 +0200 Subject: [PATCH 26/85] Fix a wrong connection between addonMessage and its composer - VPN-2997 (#4609) --- src/addons/addonmessage.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/addons/addonmessage.cpp b/src/addons/addonmessage.cpp index 014bca956b5..acdfdf927e9 100644 --- a/src/addons/addonmessage.cpp +++ b/src/addons/addonmessage.cpp @@ -66,6 +66,10 @@ Addon* AddonMessage::create(QObject* parent, const QString& manifestFileName, message->setBadge(messageObj["badge"].toString()); guard.dismiss(); + + connect(message, &Addon::retranslationCompleted, message->m_composer, + &Composer::retranslationCompleted); + return message; } @@ -73,9 +77,6 @@ AddonMessage::AddonMessage(QObject* parent, const QString& manifestFileName, const QString& id, const QString& name) : Addon(parent, manifestFileName, id, name, "message") { MVPN_COUNT_CTOR(AddonMessage); - - connect(this, &Addon::retranslationCompleted, m_composer, - &Composer::retranslationCompleted); } AddonMessage::~AddonMessage() { MVPN_COUNT_DTOR(AddonMessage); } From 0546076c4631d3abc32c15d6d401b4d196999208 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 10 Oct 2022 18:00:41 +0200 Subject: [PATCH 27/85] Recompute the notification flag when the addons are loaded - VPN-2996 (#4610) --- src/ui/navigator/navigationBar/VPNBottomNavigationBar.qml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ui/navigator/navigationBar/VPNBottomNavigationBar.qml b/src/ui/navigator/navigationBar/VPNBottomNavigationBar.qml index 963d21226f0..686d15dcf6f 100644 --- a/src/ui/navigator/navigationBar/VPNBottomNavigationBar.qml +++ b/src/ui/navigator/navigationBar/VPNBottomNavigationBar.qml @@ -173,6 +173,13 @@ Rectangle { } } + Connections { + target: VPNAddonManager + function onLoadCompletedChanged() { + root.getUnreadNotificationStatus() + } + } + function setNavBarOpacity() { if (VPNNavigator.screen === VPNNavigator.ScreenHome) { navbar.opacity = VPNConnectionBenchmark.state === VPNConnectionBenchmark.StateInitial ? 1 : 0 From 21373b6e92fd0e4e9fffba56719f4af2da04cc51 Mon Sep 17 00:00:00 2001 From: Florian Zia Date: Mon, 10 Oct 2022 18:13:21 +0200 Subject: [PATCH 28/85] fix: VPN disconnects after swipe kill on iOS (#4606) --- src/platforms/ios/ioscontroller.mm | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/platforms/ios/ioscontroller.mm b/src/platforms/ios/ioscontroller.mm index 0a7c08aa427..5d98645d322 100644 --- a/src/platforms/ios/ioscontroller.mm +++ b/src/platforms/ios/ioscontroller.mm @@ -4,6 +4,7 @@ #include "ioscontroller.h" #include "Mozilla_VPN-Swift.h" +#include "controller.h" #include "device.h" #include "ipaddress.h" #include "keys.h" @@ -81,8 +82,13 @@ return; } case ConnectionStateDisconnected: - // Just in case we are connecting, let's call disconnect. - [impl disconnect]; + Controller* controller = MozillaVPN::instance()->controller(); + Q_ASSERT(controller); + if (controller->state() != Controller::StateInitializing) { + // Just in case we are connecting, let's call disconnect. + [impl disconnect]; + } + emit initialized(true, false, QDateTime()); return; } From deb8f1633f58f6366cca12cf4c4d0b188b3f8882 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Tue, 11 Oct 2022 04:52:05 -0500 Subject: [PATCH 29/85] Fix app permissions success banners (#4613) --- src/ui/screens/settings/appPermissions/ViewAppPermissions.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/screens/settings/appPermissions/ViewAppPermissions.qml b/src/ui/screens/settings/appPermissions/ViewAppPermissions.qml index 059d3d589fd..439dc625add 100644 --- a/src/ui/screens/settings/appPermissions/ViewAppPermissions.qml +++ b/src/ui/screens/settings/appPermissions/ViewAppPermissions.qml @@ -66,7 +66,7 @@ VPNViewBase { console.debug("Error:"+ component.errorString() ); } - var alert = component.createObject(root, { + var alert = component.createObject(vpnFlickable, { isLayout:false, visible:true, alertText: message, From 905ba7450eda12e6bc007cdd16b405727e2a05a7 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Tue, 11 Oct 2022 04:52:42 -0500 Subject: [PATCH 30/85] Remove incorrect string from message_whats_new_v2.10 (#4611) --- addons/message_whats_new_v2.10/manifest.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/message_whats_new_v2.10/manifest.json b/addons/message_whats_new_v2.10/manifest.json index ca8914e3bf1..49f61188ac2 100644 --- a/addons/message_whats_new_v2.10/manifest.json +++ b/addons/message_whats_new_v2.10/manifest.json @@ -23,8 +23,6 @@ "content": "Easier-to-use navigation bar" }, { "id": "l_3", "content": "New tips and tricks to help you use the app’s features and settings" }, - { "id": "l_4", - "content": "The speed test feature now also tests upload speeds in addition to download speeds" }, { "id": "l_5", "content": "Other bug fixes and UI adjustments" }, { "id": "l_6", From d009f5033fcdc27d31600b7eb59d2f50a951d5f5 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 11 Oct 2022 12:10:58 +0200 Subject: [PATCH 31/85] Kill the previous instance of MozillaVPN even when the name has a space (post cmake thing) (#4618) --- windows/installer/MozillaVPN.wxs | 2 +- windows/installer/MozillaVPN_cmake.wxs | 13 ++++++++++--- windows/installer/MozillaVPN_prod.wxs | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/windows/installer/MozillaVPN.wxs b/windows/installer/MozillaVPN.wxs index 3fddd222876..0e0c1521389 100644 --- a/windows/installer/MozillaVPN.wxs +++ b/windows/installer/MozillaVPN.wxs @@ -165,7 +165,7 @@ - + diff --git a/windows/installer/MozillaVPN_cmake.wxs b/windows/installer/MozillaVPN_cmake.wxs index 4293e59794a..398807d121d 100644 --- a/windows/installer/MozillaVPN_cmake.wxs +++ b/windows/installer/MozillaVPN_cmake.wxs @@ -25,6 +25,11 @@ Description="Mozilla VPN" ReadOnly="yes" /> + + = 603)]]> + + %PROCESSOR_ARCHITECTURE="AMD64" + - + @@ -147,9 +152,11 @@ - + + - NOT Installed OR WIX_UPGRADE_DETECTED + NOT WIX_UPGRADE_DETECTED + WIX_UPGRADE_DETECTED - + From 546c574c1fef27ec7faaf24231fae14befc70f51 Mon Sep 17 00:00:00 2001 From: mozrokafor <94625718+mozrokafor@users.noreply.github.com> Date: Tue, 11 Oct 2022 14:56:03 -0400 Subject: [PATCH 32/85] adding multihop functional tests, some optimizations to helper class (#4409) * adding multihop functional tests, some optimizations to helper class * addressing pr feedbacks * addressing pr feedbacks for additional coverage * updating tests with single and multihop switch coverage * adding asserts for notifications for switching * revamped implementation, addressed pr feedback * completed pr feedbacks * specified servers to verify all potential situations for switching servers * updated actions to more appropriate naming conventions * updating connectionchangenotification to setconnectionchangenotification * update to add boolean to methods --- nebula/ui/components/VPNCollapsibleCard.qml | 2 + nebula/ui/components/VPNSegmentedToggle.qml | 1 + tests/functional/actions.js | 37 ++ tests/functional/elements.js | 28 ++ tests/functional/helper.js | 19 +- tests/functional/testMultihop.js | 530 ++++++++++++++++++++ 6 files changed, 613 insertions(+), 4 deletions(-) create mode 100644 tests/functional/actions.js create mode 100644 tests/functional/elements.js create mode 100644 tests/functional/testMultihop.js diff --git a/nebula/ui/components/VPNCollapsibleCard.qml b/nebula/ui/components/VPNCollapsibleCard.qml index 6e1e481b167..b774439aaae 100644 --- a/nebula/ui/components/VPNCollapsibleCard.qml +++ b/nebula/ui/components/VPNCollapsibleCard.qml @@ -10,6 +10,7 @@ import Mozilla.VPN 1.0 Rectangle { id: root + objectName: "vpnCollapsibleCard" property int animationDuration: 150 property bool expanded: false @@ -128,6 +129,7 @@ Rectangle { VPNIconButton { id: stateIndicator + objectName: "vpnCollapsibleCardChevron" onClicked: { handleToggleCard(); diff --git a/nebula/ui/components/VPNSegmentedToggle.qml b/nebula/ui/components/VPNSegmentedToggle.qml index 10432f327d6..3bf92942ec3 100644 --- a/nebula/ui/components/VPNSegmentedToggle.qml +++ b/nebula/ui/components/VPNSegmentedToggle.qml @@ -74,6 +74,7 @@ Rectangle { RowLayout { + objectName: "multiHopSelector" anchors { fill: parent topMargin: 8 diff --git a/tests/functional/actions.js b/tests/functional/actions.js new file mode 100644 index 00000000000..644e5edfb9b --- /dev/null +++ b/tests/functional/actions.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const elements = require('./elements.js'); +const vpn = require('./helper.js'); + +const setConnectionChangeNotification = async (status) => { + return await vpn.setSetting('connection-change-notification', status ? "true" : "false"); +} + +const setServerSwitchNotification = async (status) => { + return await vpn.setSetting('server-switch-notification', status ? "true" : "false"); +} + +const selectCountryFromList = async (countryId) => { + await vpn.setElementProperty(elements.SERVER_COUNTRY_VIEW, 'contentY', 'i', parseInt(await vpn.getElementProperty(countryId, 'y'))); + await vpn.wait() +} + +const selectCityFromList = async (cityId, countryId) => { + await vpn.setElementProperty(elements.SERVER_COUNTRY_VIEW, 'contentY', 'i', parseInt(await vpn.getElementProperty(cityId, 'y')) + parseInt(await vpn.getElementProperty(countryId, 'y'))); + await vpn.wait() +} + +module.exports = { + actions: { + settings: { + setConnectionChangeNotification, + setServerSwitchNotification, + }, + locations: { + selectCountryFromList, + selectCityFromList + } + } +} \ No newline at end of file diff --git a/tests/functional/elements.js b/tests/functional/elements.js new file mode 100644 index 00000000000..2add06f6cfe --- /dev/null +++ b/tests/functional/elements.js @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const elements = { + MULTIHOP_SELECTOR_TAB: "multiHopSelector/tabMultiHop", + SINGLEHOP_SELECTOR_TAB: "multiHopSelector/tabSingleHop", + SERVERLIST_BACK_BUTTON: "serverListBackButton", + SERVER_ENTRY_BUTTON: "buttonSelectEntry", + SERVER_EXIT_BUTTON: "buttonSelectExit", + SERVER_LIST_BUTTON: "serverListButton", + SERVER_COUNTRY_VIEW: "serverCountryView", + CONTROLLER_TITLE: "controllerTitle", + CITYLIST_VISIBLE: "cityListVisible", + VPN_MULTHOP_CHEVRON: 'vpnCollapsibleCardChevron', + VPN_COLLAPSIBLE_CARD: 'vpnCollapsibleCard', + + generateCountryId: (serverCode) => { + return 'serverCountryList/serverCountry-' + serverCode; + }, + + generateCityId: (countryId, cityName) => { + return countryId + '/serverCityList/serverCity-' + cityName.replace(/ /g, '_'); + } +} + + +module.exports = elements \ No newline at end of file diff --git a/tests/functional/helper.js b/tests/functional/helper.js index 9dd8e96f1f9..55e368c01e1 100644 --- a/tests/functional/helper.js +++ b/tests/functional/helper.js @@ -160,6 +160,12 @@ module.exports = { `Command failed: ${json.error}`); }, + async waitForElementAndClick(id) { + await this.waitForElementAndProperty(id, 'visible', 'true'); + await this.clickOnElement(id) + await this.wait() + }, + async clickOnNotification() { const json = await this._writeCommand('click_notification'); assert( @@ -223,6 +229,11 @@ module.exports = { } }, + async waitForElementAndProperty(id, property, value) { + await this.waitForElement(id) + await this.waitForElementProperty(id, property, value) + }, + async setGleanAutomationHeader() { const json = await this._writeCommand('set_glean_source_tags automation'); assert( @@ -235,15 +246,15 @@ module.exports = { return await this.getElementProperty('VPNUrlOpener', 'lastUrl'); }, - async waitForCondition(condition) { + async waitForCondition(condition, waitTimeInMilliSecs = 200) { while (true) { if (await condition()) return; - await new Promise(resolve => setTimeout(resolve, 200)); + await new Promise(resolve => setTimeout(resolve, waitTimeInMilliSecs)); } }, - wait() { - return new Promise(resolve => setTimeout(resolve, 1000)); + wait(waitTimeInMilliSecs = 1000) { + return new Promise(resolve => setTimeout(resolve, waitTimeInMilliSecs)); }, // TODO - The expected staging urls are hardcoded, we may want to diff --git a/tests/functional/testMultihop.js b/tests/functional/testMultihop.js new file mode 100644 index 00000000000..4ecb3b25404 --- /dev/null +++ b/tests/functional/testMultihop.js @@ -0,0 +1,530 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + const assert = require('assert'); + const { actions } = require('./actions.js'); + const elements = require('./elements.js'); + const vpn = require('./helper.js'); + +describe('Server list', function() { + let servers; + let currentCountryCode; + let currentCity; + + this.timeout(240000); + this.ctx.authenticationNeeded = true; + + beforeEach(async () => { + await vpn.waitForElementAndClick(elements.SERVER_LIST_BUTTON); + + servers = await vpn.servers(); + currentCountryCode = await vpn.getSetting('current-server-country-code'); + currentCity = await vpn.getSetting('current-server-city'); + + for (let server of servers) { + if (currentCountryCode === server.code) { + for (let city of server.cities) { + if (city.name == currentCity) { + currentCity = city.localizedName; + break; + } + } + } + } + console.log( + 'Current city (localized):', currentCity, + '| Current country code:', currentCountryCode); + }); + + it('opening the entry and exit server list', async () => { + await vpn.waitForElementAndClick(elements.MULTIHOP_SELECTOR_TAB); + assert(await vpn.getElementProperty(elements.VPN_COLLAPSIBLE_CARD, 'expanded') === 'false') + + await vpn.waitForElement(elements.SERVER_ENTRY_BUTTON); + await vpn.waitForElementProperty(elements.SERVER_ENTRY_BUTTON, 'visible', 'true'); + + await vpn.waitForElement(elements.SERVER_EXIT_BUTTON); + await vpn.waitForElementProperty(elements.SERVER_EXIT_BUTTON, 'visible', 'true'); + + await vpn.waitForElementAndClick(elements.VPN_MULTHOP_CHEVRON) + assert(await vpn.getElementProperty(elements.VPN_COLLAPSIBLE_CARD, 'expanded')) + }); + + it('check the countries and cities for multihop entries', async () => { + await vpn.waitForElementAndClick(elements.MULTIHOP_SELECTOR_TAB); + await vpn.waitForElementAndClick(elements.SERVER_ENTRY_BUTTON); + + for (let server of servers) { + const countryId = elements.generateCountryId(server.code); + await vpn.waitForElement(countryId); + await vpn.waitForElementProperty(countryId, 'visible', 'true'); + + await actions.locations.selectCountryFromList(countryId); + await vpn.wait(); + + if (currentCountryCode === server.code) { + assert( + await vpn.getElementProperty(countryId, elements.CITYLIST_VISIBLE) === + 'true'); + } + + if (await vpn.getElementProperty(countryId, elements.CITYLIST_VISIBLE) === + 'false') { + await vpn.clickOnElement(countryId); + } + + for (let city of server.cities) { + const cityId = countryId + '/serverCityList/serverCity-' + + city.name.replace(/ /g, '_'); + + await vpn.waitForElement(cityId); + await vpn.waitForElementProperty(cityId, 'visible', 'true'); + } + } + }) + + it('check the countries and cities for multihop exits', async () => { + await vpn.waitForElementAndClick(elements.MULTIHOP_SELECTOR_TAB); + + await vpn.waitForElementAndClick(elements.SERVER_EXIT_BUTTON); + + for (let server of servers) { + const countryId = elements.generateCountryId(server.code); + + await vpn.waitForElement(countryId); + await vpn.waitForElementProperty(countryId, 'visible', 'true'); + + await actions.locations.selectCountryFromList(countryId); + await vpn.wait(); + + if (currentCountryCode === server.code) { + assert( + await vpn.getElementProperty(countryId, elements.CITYLIST_VISIBLE) === + 'true'); + } + + if (await vpn.getElementProperty(countryId, elements.CITYLIST_VISIBLE) === + 'false') { + await vpn.clickOnElement(countryId); + } + + for (let city of server.cities) { + const cityId = countryId + '/serverCityList/serverCity-' + + city.name.replace(/ /g, '_'); + + await vpn.waitForElement(cityId); + await vpn.waitForElementProperty(cityId, 'visible', 'true'); + await vpn.waitForElementProperty( + cityId, 'checked', + currentCountryCode === server.code && + currentCity === city.localizedName ? + 'true' : + 'false'); + } + } + }) + + it('Pick cities for entries', async () => { + let countryId; + await vpn.waitForElementAndClick(elements.MULTIHOP_SELECTOR_TAB); + await vpn.waitForElementAndClick(elements.SERVER_ENTRY_BUTTON); + + for (let server of servers) { + countryId = elements.generateCountryId(server.code); + await vpn.waitForElement(countryId); + + await actions.locations.selectCountryFromList(countryId); + await vpn.wait(); + + if (await vpn.getElementProperty(countryId, elements.CITYLIST_VISIBLE) === 'false') { + await vpn.clickOnElement(countryId); + } + + await vpn.waitForElementProperty(countryId, elements.CITYLIST_VISIBLE, 'true'); + + for (let city of server.cities) { + const cityId = countryId + '/serverCityList/serverCity-' + city.name.replace(/ /g, '_'); + await vpn.waitForElement(cityId); + + await actions.locations.selectCityFromList(cityId, countryId); + await vpn.waitForElementProperty(cityId, 'visible', 'true'); + const cityName = await vpn.getElementProperty(cityId, 'radioButtonLabelText'.split(" ")); + + await vpn.wait(); + await vpn.clickOnElement(cityId); + await vpn.wait(); + + // Back to the main view. + await vpn.waitForElement(elements.SERVER_ENTRY_BUTTON); + await vpn.waitForElementProperty(elements.SERVER_ENTRY_BUTTON, 'visible', 'true'); + await vpn.waitForElementAndClick(elements.SERVER_ENTRY_BUTTON); + + // One selected + await vpn.waitForElement(cityId); + await vpn.waitForElementProperty(cityId, 'checked', 'true'); + assert(cityName.includes(city.name)) + } + } + }); + + it('Pick cities for exits', async () => { + let countryId; + await vpn.waitForElementAndClick(elements.MULTIHOP_SELECTOR_TAB); + await vpn.waitForElementAndClick(elements.SERVER_EXIT_BUTTON); + + for (let server of servers) { + countryId = elements.generateCountryId(server.code); + await vpn.waitForElement(countryId); + + await actions.locations.selectCountryFromList(countryId) + await vpn.wait(); + + if (await vpn.getElementProperty(countryId, elements.CITYLIST_VISIBLE) === 'false') { + await vpn.clickOnElement(countryId); + } + + await vpn.waitForElementProperty(countryId, elements.CITYLIST_VISIBLE, 'true'); + + for (let city of server.cities) { + const cityId = countryId + '/serverCityList/serverCity-' + city.name.replace(/ /g, '_'); + await vpn.waitForElement(cityId); + + await actions.locations.selectCityFromList(cityId, countryId) + await vpn.waitForElementProperty(cityId, 'visible', 'true'); + const cityName = await vpn.getElementProperty(cityId, 'radioButtonLabelText'.split(" ")); + + await vpn.wait(); + await vpn.clickOnElement(cityId); + await vpn.wait(); + + // Back to the main view. + await vpn.waitForElement(elements.SERVER_EXIT_BUTTON); + await vpn.waitForElementProperty(elements.SERVER_EXIT_BUTTON, 'visible', 'true'); + await vpn.waitForElementAndClick(elements.SERVER_EXIT_BUTTON); + + // One selected + await vpn.waitForElement(cityId); + await vpn.waitForElementProperty(cityId, 'checked', 'true'); + assert(cityName.includes(city.name)) + } + } + }); + + it('Server switching -- same country different cities', async () => { + await actions.settings.setServerSwitchNotification(true) + await actions.settings.setConnectionChangeNotification(true) + + let newCurrentCountry; + let newCurrentCity; + let currentCountry; + let currentCity; + + // wait for select entry and select entry + await vpn.waitForElementAndClick(elements.MULTIHOP_SELECTOR_TAB); + await vpn.waitForElementAndClick(elements.SERVER_ENTRY_BUTTON); + + // exit server details + const firstServer = servers[0] + const cityTwo = firstServer.cities[0] + const cityThree = firstServer.cities[1] + const exitFirstCountryId = elements.generateCountryId(firstServer.code); + + // entry server details + const secondServer = servers[1] + const cityOne = secondServer.cities[0] + const entryCountryId = elements.generateCountryId(secondServer.code); + + // select the first country + await actions.locations.selectCountryFromList(entryCountryId); + await vpn.wait() + if (await vpn.getElementProperty(entryCountryId, 'cityListVisible') === 'false') { + await vpn.clickOnElement(entryCountryId); + } + await vpn.waitForElementProperty(entryCountryId, 'cityListVisible', 'true'); + + // select first city + const cityOneId = elements.generateCityId(entryCountryId, cityOne.name); + + await vpn.setElementProperty( + elements.SERVER_COUNTRY_VIEW, 'contentY', 'i', + parseInt(await vpn.getElementProperty(cityOneId, 'y')) + + parseInt(await vpn.getElementProperty(entryCountryId, 'y'))); + await vpn.wait() + await vpn.waitForElementAndClick(cityOneId) + + // Back at the main view. select the exit entries + await vpn.waitForElementAndClick(elements.SERVER_EXIT_BUTTON); + + // select first country again + await actions.locations.selectCountryFromList(exitFirstCountryId) + await vpn.wait(); + if (await vpn.getElementProperty(exitFirstCountryId, 'cityListVisible') === 'false') { + await vpn.clickOnElement(exitFirstCountryId); + } + await vpn.waitForElementProperty(exitFirstCountryId, 'cityListVisible', 'true'); + + // select first city in exit country + const cityTwoId = elements.generateCityId(exitFirstCountryId, cityTwo.name); + + await vpn.setElementProperty( + elements.SERVER_COUNTRY_VIEW, 'contentY', 'i', + parseInt(await vpn.getElementProperty(cityTwoId, 'y')) + + parseInt(await vpn.getElementProperty(exitFirstCountryId, 'y'))); + await vpn.wait() + await vpn.waitForElementAndClick(cityTwoId); + + // navigate back to connection view + await vpn.waitForElementAndClick(elements.SERVERLIST_BACK_BUTTON); + + // define connected server + currentCountry = firstServer.localizedName; + currentCity = cityTwo.localizedName; + + // connect vpn + await vpn.activate(); + + // wait and assert vpn connection + await vpn.waitForCondition(async () => { + return await vpn.getElementProperty(elements.CONTROLLER_TITLE, 'text') == + 'VPN is on'; + }); + assert.strictEqual(vpn.lastNotification().title, 'VPN Connected'); + assert.strictEqual(vpn.lastNotification().message, `Connected to ${currentCountry}, ${currentCity}`); + + // back to main view + await vpn.waitForElementAndClick(elements.SERVER_LIST_BUTTON); + + // Back at the main view. select the exit entries + await vpn.waitForElementAndClick(elements.SERVER_EXIT_BUTTON); + + // select first country again + await actions.locations.selectCountryFromList(exitFirstCountryId) + await vpn.wait(); + if (await vpn.getElementProperty(exitFirstCountryId, 'cityListVisible') === 'false') { + await vpn.clickOnElement(exitFirstCountryId); + } + await vpn.waitForElementProperty(exitFirstCountryId, 'cityListVisible', 'true'); + + // select first city in exit country + const cityThreeId = elements.generateCityId(exitFirstCountryId, cityThree.name); + + await vpn.setElementProperty( + elements.SERVER_COUNTRY_VIEW, 'contentY', 'i', + parseInt(await vpn.getElementProperty(cityThreeId, 'y')) + + parseInt(await vpn.getElementProperty(exitFirstCountryId, 'y'))); + await vpn.waitForElementAndClick(cityThreeId); + + // Back at the main view. select the exit entries + await vpn.waitForElementAndClick(elements.SERVERLIST_BACK_BUTTON); + + // define new connected server + newCurrentCountry = firstServer.localizedName; + newCurrentCity = cityThree.localizedName; + + // wait and assert server switching for multihop + await vpn.waitForCondition(async () => { + return vpn.lastNotification().title == "VPN Switched Servers" + }, 20) + assert.strictEqual( + vpn.lastNotification().message, + `Switched from ${currentCountry}, ${currentCity} to ${ + newCurrentCountry}, ${newCurrentCity}`); + }); + + it.only('Server switching -- different country different cities', async () => { + await actions.settings.setServerSwitchNotification(true) + await actions.settings.setConnectionChangeNotification(true) + + let newCurrentCountry; + let newCurrentCity; + let currentCountry; + let currentCity; + + // wait for select entry and select entry + await vpn.waitForElementAndClick(elements.MULTIHOP_SELECTOR_TAB); + await vpn.waitForElementAndClick(elements.SERVER_ENTRY_BUTTON); + + // exit server details + const firstServer = servers[0] + const cityTwo = firstServer.cities[0] + const exitFirstCountryId = elements.generateCountryId(firstServer.code); + + // second exit server details + const thirdServer = servers[2] + const cityThree = thirdServer.cities[0] + const exitThirdCountryId = elements.generateCountryId(thirdServer.code); + + // entry server details + const secondServer = servers[1] + const cityOne = secondServer.cities[0] + const entryCountryId = elements.generateCountryId(secondServer.code); + + // select the first country + await actions.locations.selectCountryFromList(entryCountryId); + await vpn.wait() + if (await vpn.getElementProperty(entryCountryId, 'cityListVisible') === 'false') { + await vpn.clickOnElement(entryCountryId); + } + await vpn.waitForElementProperty(entryCountryId, 'cityListVisible', 'true'); + + // select first city + const cityOneId = elements.generateCityId(entryCountryId, cityOne.name); + await actions.locations.selectCityFromList(cityOneId, entryCountryId) + await vpn.waitForElementAndClick(cityOneId) + + // Back at the main view. select the exit entries + await vpn.waitForElementAndClick(elements.SERVER_EXIT_BUTTON); + + // select first country again + await actions.locations.selectCountryFromList(exitFirstCountryId) + await vpn.wait(); + if (await vpn.getElementProperty(exitFirstCountryId, 'cityListVisible') === 'false') { + await vpn.clickOnElement(exitFirstCountryId); + } + await vpn.waitForElementProperty(exitFirstCountryId, 'cityListVisible', 'true'); + + // select first city in exit country + const cityTwoId = elements.generateCityId(exitFirstCountryId, cityTwo.name); + await actions.locations.selectCityFromList(cityTwoId, exitFirstCountryId) + await vpn.waitForElementAndClick(cityTwoId); + + // navigate back to connection view + await vpn.waitForElementAndClick(elements.SERVERLIST_BACK_BUTTON); + + // define connected server + currentCountry = firstServer.localizedName; + currentCity = cityTwo.localizedName; + + // connect vpn + await vpn.activate(); + + // wait and assert vpn connection + await vpn.waitForCondition(async () => { + return await vpn.getElementProperty(elements.CONTROLLER_TITLE, 'text') == + 'VPN is on'; + }); + assert.strictEqual(vpn.lastNotification().title, 'VPN Connected'); + assert.strictEqual(vpn.lastNotification().message, `Connected to ${currentCountry}, ${currentCity}`); + + // back to main view + await vpn.waitForElementAndClick(elements.SERVER_LIST_BUTTON); + + // Back at the main view. select the exit entries + await vpn.waitForElementAndClick(elements.SERVER_EXIT_BUTTON); + + // select first country again + await actions.locations.selectCountryFromList(exitThirdCountryId) + await vpn.wait(); + if (await vpn.getElementProperty(exitThirdCountryId, 'cityListVisible') === 'false') { + await vpn.clickOnElement(exitThirdCountryId); + } + await vpn.waitForElementProperty(exitThirdCountryId, 'cityListVisible', 'true'); + + // select first city in exit country + const cityThreeId = elements.generateCityId(exitThirdCountryId, cityThree.name); + await actions.locations.selectCityFromList(cityThreeId, exitThirdCountryId) + await vpn.waitForElementAndClick(cityThreeId); + + // Back at the main view. select the exit entries + await vpn.waitForElementAndClick(elements.SERVERLIST_BACK_BUTTON); + + // define new connected server + newCurrentCountry = thirdServer.localizedName; + newCurrentCity = cityThree.localizedName; + + // wait and assert server switching for multihop + await vpn.waitForCondition(async () => { + return vpn.lastNotification().title == "VPN Switched Servers" + }, 20) + assert.strictEqual( + vpn.lastNotification().message, + `Switched from ${currentCountry}, ${currentCity} to ${ + newCurrentCountry}, ${newCurrentCity}`); + }); + + it('Single and multihop switching', async () => { + await actions.settings.setServerSwitchNotification(true) + await actions.settings.setConnectionChangeNotification(true) + + let currentCountry; + let currentCity; + + // wait for select entry and select entry + await vpn.waitForElementAndClick(elements.MULTIHOP_SELECTOR_TAB); + await vpn.waitForElementAndClick(elements.SERVER_ENTRY_BUTTON); + + // exit server details + const firstServer = servers[0] + const cityTwo = firstServer.cities[0] + const exitFirstCountryId = elements.generateCountryId(firstServer.code); + + // entry server details + const secondServer = servers[1] + const cityOne = secondServer.cities[0] + const entryCountryId = elements.generateCountryId(secondServer.code); + + // select the first country + await actions.locations.selectCountryFromList(entryCountryId); + await vpn.wait() + if (await vpn.getElementProperty(entryCountryId, 'cityListVisible') === 'false') { + await vpn.clickOnElement(entryCountryId); + } + await vpn.waitForElementProperty(entryCountryId, 'cityListVisible', 'true'); + + // select first city + const cityOneId = elements.generateCityId(entryCountryId, cityOne.name); + await actions.locations.selectCityFromList(cityOneId, entryCountryId) + await vpn.waitForElementAndClick(cityOneId) + + // Back at the main view. select the exit entries + await vpn.waitForElementAndClick(elements.SERVER_EXIT_BUTTON); + + // select first country again + await actions.locations.selectCountryFromList(exitFirstCountryId) + await vpn.wait(); + if (await vpn.getElementProperty(exitFirstCountryId, 'cityListVisible') === 'false') { + await vpn.clickOnElement(exitFirstCountryId); + } + await vpn.waitForElementProperty(exitFirstCountryId, 'cityListVisible', 'true'); + + // select first city in exit country + const cityTwoId = elements.generateCityId(exitFirstCountryId, cityTwo.name); + await actions.locations.selectCityFromList(cityTwoId, exitFirstCountryId) + await vpn.waitForElementAndClick(cityTwoId); + + // navigate back to connection view + await vpn.waitForElementAndClick(elements.SERVERLIST_BACK_BUTTON); + + // define connected server + currentCountry = firstServer.localizedName; + currentCity = cityTwo.localizedName; + + // connect vpn + await vpn.activate(); + + // wait and assert vpn connection + await vpn.waitForCondition(async () => { + return await vpn.getElementProperty(elements.CONTROLLER_TITLE, 'text') == + 'VPN is on'; + }); + assert.strictEqual(vpn.lastNotification().title, 'VPN Connected'); + assert.strictEqual(vpn.lastNotification().message, `Connected to ${currentCountry}, ${currentCity}`); + + // back to main view + await vpn.waitForElementAndClick(elements.SERVER_LIST_BUTTON); + + + // switch from multihop to singlehop + await vpn.waitForElementAndClick(elements.SINGLEHOP_SELECTOR_TAB) + await vpn.waitForElementAndClick(elements.SERVERLIST_BACK_BUTTON) + + // wait and assert vpn connection + await vpn.waitForCondition(async () => { + return await vpn.getElementProperty(elements.CONTROLLER_TITLE, 'text') == + 'VPN is on'; + }); + assert.strictEqual(vpn.lastNotification().title, 'VPN Connected'); + assert.strictEqual(vpn.lastNotification().message, `Connected to ${currentCountry}, ${currentCity}`); + }); +}); \ No newline at end of file From 7b1e22623b25a9979acd72ade970c3a7fdc9e1b0 Mon Sep 17 00:00:00 2001 From: Matt Lichtenstein Date: Wed, 12 Oct 2022 09:44:19 -0400 Subject: [PATCH 33/85] Fix edit mode bugs in message inbox (#4612) --- nebula/ui/components/forms/VPNSearchBar.qml | 14 ++++---- .../screens/messaging/ViewMessagesInbox.qml | 36 +++++++++++-------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/nebula/ui/components/forms/VPNSearchBar.qml b/nebula/ui/components/forms/VPNSearchBar.qml index 6878b1d1ae1..9eec8cf8054 100644 --- a/nebula/ui/components/forms/VPNSearchBar.qml +++ b/nebula/ui/components/forms/VPNSearchBar.qml @@ -31,7 +31,12 @@ ColumnLayout { leftPadding: 48 onActiveFocusChanged: if (focus && vpnFlickable.ensureVisible) vpnFlickable.ensureVisible(searchBar) Layout.fillWidth: true - onTextChanged: hasError = _searchBarHasError + onTextChanged: { + hasError = _searchBarHasError + if (focus) { + _editCallback(); + } + } onLengthChanged: text => model.invalidate() VPNIcon { @@ -43,13 +48,6 @@ ColumnLayout { sourceSize.width: VPNTheme.theme.windowMargin opacity: parent.focus ? 1 : 0.8 } - - - Keys.onPressed: event => { - if (focus && ((/[\w\[\]`!@#$%\^&*()={}:;<>+'-]/).test(event.text) || event.key === Qt.Key_Backspace || event.key === Qt.Key_Delete)) { - _editCallback(); - } - } } VPNContextualAlerts { diff --git a/src/ui/screens/messaging/ViewMessagesInbox.qml b/src/ui/screens/messaging/ViewMessagesInbox.qml index d49280ba179..6537a2be9f0 100644 --- a/src/ui/screens/messaging/ViewMessagesInbox.qml +++ b/src/ui/screens/messaging/ViewMessagesInbox.qml @@ -33,6 +33,11 @@ VPNViewBase { } } + signal editModeChanged + + //Weird workaround to fix VPN-2895 + onIsEditingChanged: editModeChanged() + _menuTitle: VPNl18n.InAppMessagingMenuTitle onVisibleChanged: if (!visible) resetPage() @@ -178,7 +183,6 @@ VPNViewBase { VPNSwipeDelegate { id: swipeDelegate - property bool isEditing: vpnFlickable.isEditing property real deleteLabelWidth: 0.0 //avoids qml warnings when addon messages get disabled via condition @@ -190,24 +194,14 @@ VPNViewBase { Layout.preferredHeight: content.item.implicitHeight Accessible.name: swipeDelegate.title + ". " + swipeDelegate.formattedDate + ". " + swipeDelegate.subtitle - onIsEditingChanged: { - if(isEditing) { - swipe.open(SwipeDelegate.Left) - } - else { - swipe.close() - } - } - onSwipeOpen: () => { deleteLabelWidth = swipe.leftItem.width if (vpnFlickable.allSwipesOpen() && !vpnFlickable.isEditing) vpnFlickable.isEditing = true } - onSwipeClose: () => { - if (!vpnFlickable.anySwipesOpen() && vpnFlickable.isEditing) vpnFlickable.isEditing = false - - } + onIsSwipeOpenChanged: { + if(!isSwipeOpen && !vpnFlickable.anySwipesOpen() && vpnFlickable.isEditing) vpnFlickable.isEditing = false + } onClicked: { if (vpnFlickable.anySwipesOpen()) vpnFlickable.closeAllSwipes() @@ -230,6 +224,7 @@ VPNViewBase { SwipeDelegate.onClicked: { swipeDelegate.swipe.close() // prevents weird iOS animation bug + swipeDelegate.isSwipeOpen = false divider.visible = false if(index === listView.count - 1) { dismissMessageAnimation.start() @@ -316,6 +311,19 @@ VPNViewBase { maximumLineCount: 1 } } + + Connections { + target: vpnFlickable + function onEditModeChanged() { + if(vpnFlickable.isEditing) { + swipeDelegate.swipe.open(SwipeDelegate.Left) + } + else { + swipeDelegate.swipe.close() + } + } + } + } Rectangle { From 30fdaa0b634fb5748f6382bee27fa266586d5deb Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Wed, 12 Oct 2022 11:43:14 -0500 Subject: [PATCH 34/85] Update metrics.yaml (#4622) --- glean/metrics.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/glean/metrics.yaml b/glean/metrics.yaml index 4ca46f10833..4fa239c320c 100644 --- a/glean/metrics.yaml +++ b/glean/metrics.yaml @@ -26,9 +26,9 @@ sample: description: | An addon's state changed bugs: - - https://github.com/mozilla-mobile/mozilla-vpn-client/issues/1620 + - https://github.com/mozilla-mobile/mozilla-vpn-client/pull/4487 data_reviews: - - https://bugzilla.mozilla.org/show_bug.cgi?id=1746457 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1794825 data_sensitivity: - technical notification_emails: @@ -52,9 +52,9 @@ sample: description: | The addon message' state changed bugs: - - https://github.com/mozilla-mobile/mozilla-vpn-client/issues/1620 + - https://github.com/mozilla-mobile/mozilla-vpn-client/pull/4487 data_reviews: - - https://bugzilla.mozilla.org/show_bug.cgi?id=1746457 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1794825 data_sensitivity: - technical notification_emails: @@ -78,9 +78,9 @@ sample: description: | User clicked primary CTA in an addon bugs: - - https://bugzilla.mozilla.org/show_bug.cgi?id=1711123 + - https://github.com/mozilla-mobile/mozilla-vpn-client/pull/4487 data_reviews: - - https://bugzilla.mozilla.org/show_bug.cgi?id=1711123#c1 + - https://bugzilla.mozilla.org/show_bug.cgi?id=1794825 data_sensitivity: - interaction extra_keys: From 15ff5e9749a22b910fbb61eb17b4ae42bfca3575 Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Wed, 12 Oct 2022 14:50:01 -0500 Subject: [PATCH 35/85] Header clearance for iPhone 14 Pro & iPhone 14 Pro Max (#4625) --- src/ui/main.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/main.qml b/src/ui/main.qml index f2cb9a2d52a..526a4f82b8d 100644 --- a/src/ui/main.qml +++ b/src/ui/main.qml @@ -43,6 +43,10 @@ Window { case 2778: // iPhone_12_Pro_Max case 2340: // iPhone_12_mini return 34; + case 2556: // iPhone_14_Pro + return 48; + case 2796: // iPhone_14_Pro_Max + return 48; default: return 20; } From f665873a29e59400867ce920b4c021d4c3f81453 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 14 Oct 2022 07:16:33 +0200 Subject: [PATCH 36/85] Cache the conditionEnabled status to avoid race conditions - VPN-3006 (#4630) * Cache the conditionEnabled status to avoid race conditions - VPN-3006 * Emit AddonManager::loadCompleted each time a list of addons has been loaded - VPN-3005 * Remove loadCompleted * Fix the unit-tests --- src/addons/addon.cpp | 25 ++++++++++++------------- src/addons/addon.h | 4 +++- src/addons/manager/addonmanager.cpp | 24 ++++++++++-------------- tests/unit/testaddon.cpp | 12 +++++++++++- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/addons/addon.cpp b/src/addons/addon.cpp index da6659c8c9c..5c016312474 100644 --- a/src/addons/addon.cpp +++ b/src/addons/addon.cpp @@ -354,7 +354,8 @@ Addon* Addon::create(QObject* parent, const QString& manifestFileName) { addon->maybeCreateConditionWatchers(conditions); - if (addon->enabled()) { + if (!addon->m_conditionWatcher || + addon->m_conditionWatcher->conditionApplied()) { addon->enable(); } @@ -469,10 +470,12 @@ void Addon::maybeCreateConditionWatchers(const QJsonObject& conditions) { connect(m_conditionWatcher, &AddonConditionWatcher::conditionChanged, this, [this](bool enabled) { - if (enabled) { - enable(); - } else { - disable(); + if (enabled != m_enabled) { + if (enabled) { + enable(); + } else { + disable(); + } } }); } @@ -500,15 +503,9 @@ bool Addon::evaluateConditions(const QJsonObject& conditions) { return true; } -bool Addon::enabled() const { - if (!m_conditionWatcher) { - return true; - } - - return m_conditionWatcher->conditionApplied(); -} - void Addon::enable() { + m_enabled = true; + QCoreApplication::installTranslator(&m_translator); retranslate(); @@ -529,6 +526,8 @@ void Addon::enable() { } void Addon::disable() { + m_enabled = false; + QCoreApplication::removeTranslator(&m_translator); if (m_jsDisableFunction.isCallable()) { diff --git a/src/addons/addon.h b/src/addons/addon.h index 8d274e2f500..2bae25407b8 100644 --- a/src/addons/addon.h +++ b/src/addons/addon.h @@ -55,7 +55,7 @@ class Addon : public QObject { virtual void retranslate(); - virtual bool enabled() const; + virtual bool enabled() const { return m_enabled; } AddonApi* api(); @@ -100,6 +100,8 @@ class Addon : public QObject { QJSValue m_jsEnableFunction; QJSValue m_jsDisableFunction; + + bool m_enabled = false; }; #endif // ADDON_H diff --git a/src/addons/manager/addonmanager.cpp b/src/addons/manager/addonmanager.cpp index 5849cb4219a..00b79c72de7 100644 --- a/src/addons/manager/addonmanager.cpp +++ b/src/addons/manager/addonmanager.cpp @@ -128,18 +128,16 @@ void AddonManager::updateAddonsList(QList addons) { } } - if (!m_loadCompleted) { - if (taskAdded) { - TaskScheduler::scheduleTask(new TaskFunction( - [this]() { - m_loadCompleted = true; - emit loadCompletedChanged(); - }, - Task::Reschedulable)); - } else { - m_loadCompleted = true; - emit loadCompletedChanged(); - } + if (taskAdded) { + TaskScheduler::scheduleTask(new TaskFunction( + [this]() { + m_loadCompleted = true; + emit loadCompletedChanged(); + }, + Task::Reschedulable)); + } else { + m_loadCompleted = true; + emit loadCompletedChanged(); } } @@ -174,11 +172,9 @@ bool AddonManager::loadManifest(const QString& manifestFileName) { } if (!enabled) { beginRemoveRows(QModelIndex(), pos, pos); - removeRow(pos); endRemoveRows(); } else { beginInsertRows(QModelIndex(), pos, pos); - insertRow(pos); endInsertRows(); } break; diff --git a/tests/unit/testaddon.cpp b/tests/unit/testaddon.cpp index cb141ae9dbb..26824ec83c8 100644 --- a/tests/unit/testaddon.cpp +++ b/tests/unit/testaddon.cpp @@ -26,6 +26,7 @@ #include "helper.h" #include +#include void TestAddon::property() { AddonProperty p; @@ -1052,9 +1053,18 @@ void TestAddon::message_dismiss() { QJsonObject obj; obj["message"] = messageObj; + obj["type"] = "message"; + obj["api_version"] = "0.1"; + obj["id"] = "bar"; + obj["name"] = "bar"; + + QTemporaryFile file; + QVERIFY(file.open()); + file.write(QJsonDocument(obj).toJson()); + file.close(); QObject parent; - Addon* message = AddonMessage::create(&parent, "foo", "bar", "name", obj); + Addon* message = Addon::create(&parent, file.fileName()); QVERIFY(!!message); QVERIFY(message->enabled()); From d28d183018317597057646d5fe51b96795ddeab5 Mon Sep 17 00:00:00 2001 From: Beatriz Rizental Date: Fri, 14 Oct 2022 12:14:28 +0200 Subject: [PATCH 37/85] VPN-2886 - Fix warning about titleComponent not being defined (#4481) --- nebula/ui/components/VPNViewBase.qml | 2 +- src/ui/screens/tipsAndTricks/ViewTipsAndTricks.qml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/nebula/ui/components/VPNViewBase.qml b/nebula/ui/components/VPNViewBase.qml index a8747ca75de..71ce9d1107a 100644 --- a/nebula/ui/components/VPNViewBase.qml +++ b/nebula/ui/components/VPNViewBase.qml @@ -20,7 +20,7 @@ Item { anchors { top: if (parent) parent.top - topMargin: _menuTitle !== "" || titleComponent || rightMenuButton ? VPNTheme.theme.menuHeight : 0 + topMargin: menu.visible ? VPNTheme.theme.menuHeight : 0 } Rectangle { diff --git a/src/ui/screens/tipsAndTricks/ViewTipsAndTricks.qml b/src/ui/screens/tipsAndTricks/ViewTipsAndTricks.qml index fca78a31042..de2f60d05bf 100644 --- a/src/ui/screens/tipsAndTricks/ViewTipsAndTricks.qml +++ b/src/ui/screens/tipsAndTricks/ViewTipsAndTricks.qml @@ -79,6 +79,7 @@ VPNViewBase { // All VPNViewBase { objectName: 'allTab' + anchors.topMargin: 0 _viewContentData: ColumnLayout { id: layoutAll @@ -135,6 +136,8 @@ VPNViewBase { // Tutorials VPNViewBase { + anchors.topMargin: 0 + _viewContentData: ColumnLayout { id: layoutTutorial @@ -166,6 +169,8 @@ VPNViewBase { // Tips VPNViewBase { + anchors.topMargin: 0 + _viewContentData: ColumnLayout { id: layoutGuide From 53d5400a2769b0e88f4fb0a8e36d9ca759adf6f0 Mon Sep 17 00:00:00 2001 From: Beatriz Rizental Date: Fri, 14 Oct 2022 18:05:56 +0200 Subject: [PATCH 38/85] Update functional tests docs to mention that a dummy build is required (#4638) --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 594274a8846..6d599037464 100644 --- a/README.md +++ b/README.md @@ -392,11 +392,22 @@ cmake --build build -j$(nproc) [Docs](https://www.selenium.dev/documentation/getting_started/installing_browser_drivers/) * Make a .env file with: * `MVPN_API_BASE_URL` (where proxy runs, most likely http://localhost:5000) - * `MVPN_BIN` (location of compiled mvpn binary) + * `MVPN_BIN` (location of compiled mvpn binary. This must be a dummy binary, see note below.) * `ARTIFACT_DIR` (directory to put screenshots from test failures) * (Optional) In one window run `./tests/proxy/wsgi.py --mock-devices` * Run a test from the root of the project: `./scripts/tests/functional_tests.sh {test_file}.js`. To run, say, the authentication tests: `./scripts/tests/functional_tests.sh tests/functional/testAuthentication.js`. + +> **Note**: Functional tests require a dummy build of the application. +> In order to create such a build, on the root folder of this repository run: +> +> ``` +> cmake -S . -B ./dummybuild -DBUILD_DUMMY=ON +> cmake --build dummybuild -j$(nproc) +> ``` +> +> This will create a dummy build under the `dummybuild/` folder. To run the functional tests against this build, +> make sure the `MVPN_BIN` environment variable is pointing to the application under the `dummybuild/` folder. ## Developer Options and staging environment From 52da60430a459ca04fed9d0bc84b3c142ede99f8 Mon Sep 17 00:00:00 2001 From: Matt Lichtenstein Date: Fri, 14 Oct 2022 14:46:46 -0400 Subject: [PATCH 39/85] Fix link button crash when clicked via space bar (#4644) --- nebula/ui/components/VPNLinkButton.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/nebula/ui/components/VPNLinkButton.qml b/nebula/ui/components/VPNLinkButton.qml index 12d499d4675..0d3604f07f2 100644 --- a/nebula/ui/components/VPNLinkButton.qml +++ b/nebula/ui/components/VPNLinkButton.qml @@ -27,7 +27,6 @@ VPNButtonBase { return } if (event.key === Qt.Key_Return || event.key === Qt.Key_Space) { - root.clicked(); state = uiState.stateDefault; } } From 064ded06f03d187779f7dc2f733bd8340ef2c22e Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 14 Oct 2022 23:11:03 +0200 Subject: [PATCH 40/85] Drop support for qt5 (#4633) --- .github/workflows/functional_tests.yaml | 2 +- README.md | 4 - linux/bionic/qt_ppa.sh | 222 ------------------ linux/debian/{control.qt6 => control} | 0 linux/debian/control.beineri | 93 -------- linux/debian/control.focal | 94 -------- linux/debian/control.qt5 | 59 ----- linux/debian/{rules.qt6 => rules} | 0 linux/debian/rules.beineri | 36 --- linux/debian/rules.qt5 | 33 --- nebula/nebula.cpp | 4 - nebula/nebula.pri | 8 +- .../ui/compat/qt5/VPNAnimatedRingsShader.qml | 66 ------ nebula/ui/compat/qt5/VPNColorOverlay.qml | 9 - nebula/ui/compat/qt5/VPNDropShadow.qml | 10 - nebula/ui/compat/qt5/VPNLinearGradient.qml | 9 - nebula/ui/compat/qt5/VPNOpacityMask.qml | 9 - nebula/ui/compat/qt5/VPNRadialGradient.qml | 9 - nebula/ui/compat/qt5/VPNRectangularGlow.qml | 9 - nebula/ui/compat/qt5/qmldir | 7 - nebula/ui/compatQt5.qrc | 12 - scripts/README.md | 1 - scripts/linux/script.sh | 21 -- scripts/utils/import_languages.py | 4 - scripts/utils/qt5_compile.sh | 123 ---------- src/appimageprovider.h | 17 +- src/mozillavpn.cpp | 4 - src/platforms/dummy/dummyappimageprovider.cpp | 34 --- src/platforms/dummy/dummyappimageprovider.h | 19 -- taskcluster/docker/lint/Dockerfile | 4 +- 30 files changed, 6 insertions(+), 916 deletions(-) delete mode 100755 linux/bionic/qt_ppa.sh rename linux/debian/{control.qt6 => control} (100%) delete mode 100644 linux/debian/control.beineri delete mode 100644 linux/debian/control.focal delete mode 100644 linux/debian/control.qt5 rename linux/debian/{rules.qt6 => rules} (100%) delete mode 100755 linux/debian/rules.beineri delete mode 100755 linux/debian/rules.qt5 delete mode 100644 nebula/ui/compat/qt5/VPNAnimatedRingsShader.qml delete mode 100644 nebula/ui/compat/qt5/VPNColorOverlay.qml delete mode 100644 nebula/ui/compat/qt5/VPNDropShadow.qml delete mode 100644 nebula/ui/compat/qt5/VPNLinearGradient.qml delete mode 100644 nebula/ui/compat/qt5/VPNOpacityMask.qml delete mode 100644 nebula/ui/compat/qt5/VPNRadialGradient.qml delete mode 100644 nebula/ui/compat/qt5/VPNRectangularGlow.qml delete mode 100644 nebula/ui/compat/qt5/qmldir delete mode 100644 nebula/ui/compatQt5.qrc delete mode 100755 scripts/utils/qt5_compile.sh delete mode 100644 src/platforms/dummy/dummyappimageprovider.cpp delete mode 100644 src/platforms/dummy/dummyappimageprovider.h diff --git a/.github/workflows/functional_tests.yaml b/.github/workflows/functional_tests.yaml index 772bf714a34..4a61fdf8d1d 100644 --- a/.github/workflows/functional_tests.yaml +++ b/.github/workflows/functional_tests.yaml @@ -43,7 +43,7 @@ jobs: # Download the build and runtime package dependencies. sudo apt-get -o "Dir::Cache::archives=$(pwd)/build/archive" install -y \ - $(./scripts/linux/getdeps.py -a linux/debian/control.qt6) + $(./scripts/linux/getdeps.py -a linux/debian/control) sudo chown -R $USER:$USER build/archive - name: Compile test client diff --git a/README.md b/README.md index 6d599037464..338441ea162 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,6 @@ Qt6 can be installed in a number of ways: can use our bash script for macOS and Linux: ```bash ./scripts/utils/qt6_compile.sh -``` - ... or our batch script for windows: -```bash -./scripts/Qt5_static_compile.bat ``` #### Install Python 3 diff --git a/linux/bionic/qt_ppa.sh b/linux/bionic/qt_ppa.sh deleted file mode 100755 index aaf795e5920..00000000000 --- a/linux/bionic/qt_ppa.sh +++ /dev/null @@ -1,222 +0,0 @@ -#!/bin/bash - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -printv() { - if [ -t 1 ]; then - NCOLORS=$(tput colors) - - if test -n "$NCOLORS" && test "$NCOLORS" -ge 8; then - NORMAL="$(tput sgr0)" - RED="$(tput setaf 1)" - GREEN="$(tput setaf 2)" - YELLOW="$(tput setaf 3)" - fi - fi - - if [[ $2 = 'G' ]]; then - # shellcheck disable=SC2086 - echo $1 -e "${GREEN}$3${NORMAL}" - elif [[ $2 = 'Y' ]]; then - # shellcheck disable=SC2086 - echo $1 -e "${YELLOW}$3${NORMAL}" - elif [[ $2 = 'N' ]]; then - # shellcheck disable=SC2086 - echo $1 -e "$3" - else - # shellcheck disable=SC2086 - echo $1 -e "${RED}$3${NORMAL}" - fi -} - -print() { - printv '' "$1" "$2" -} - -printn() { - printv "-n" "$1" "$2" -} - -error() { - printv '' R "$1" -} - -die() { - if [[ "$1" ]]; then - error "$1" - else - error Failed - fi - - exit 1 -} - -print Y "Installing dependencies..." -apt-get update || die -apt-get install -y \ - wget \ - xz-utils \ - devscripts || die - -printn Y "Creating /tmp/qt_ppa_final... " -rm -rf /tmp/qt_ppa_final || die -mkdir /tmp/qt_ppa_final || die -print G "done." - -printn Y "Creating /tmp/qt_ppa... " -rm -rf /tmp/qt_ppa || die -mkdir /tmp/qt_ppa || die -cd /tmp/qt_ppa || die -print G "done." - -magic() { - NAME=$1 - FOLDER=$2 - ORIGURL=$3 - ORIG=$4 - DEBURL=$5 - DEB=$6 - - if ! [[ -f $ORIG ]]; then - print Y "Downloading the orig... " - wget $ORIGURL || die - tar xf $ORIG || die - fi - - [[ -d $FOLDER ]] || die "$FOLDER doesn't exist." - - print Y "Downloading the deb for qt base... " - wget $DEBURL || die - tar xf $DEB || die - rm -f $DEB || die - print G "done." - - print Y "Patching debian files... " - cat > tmp << EOF -$NAME (5.15.2-bionic1) bionic; urgency=low - - * Bionic build - - -- Andrea Marchesini $(date -R) - -EOF - - cat debian/changelog >> tmp || die - mv tmp debian/changelog || die - print G "done." - - print Y "Installing dependencies... " - - BD= - LIST=$( - cat debian/control | while read LINE; do - if [[ $(echo $LINE | grep "^Build-Depends:") ]]; then - BD=1 - LINE=$(echo $LINE | cut -d: -f2) - elif [[ $(echo $LINE | grep ":") ]]; then - BD= - fi - - if [[ $BD ]]; then - echo $LINE | cut -d, -f1 | cut -d\[ -f1 | cut -d\( -f1 | grep -v g++-4.6 - fi - done - ) - - echo $LIST - apt-get install -y $LIST - - print Y "Configuring the source folder... " - mv debian $FOLDER || die - cd $FOLDER || die - - print Y "Creating the debian package... " - debuild -S --no-sign || die - - dpkg-buildpackage -b -rfakeroot -us -uc || die - - dpkg -i ../"$NAME"_*.deb - - print Y "Clean up... " - cd .. || die - rm -rf $FOLDER || die - mv * /tmp/qt_ppa_final || die - cp /tmp/qt_ppa_final/*orig.tar.xz . || die - print G "done." -} - -magic \ - qt515base \ - qtbase-everywhere-src-5.15.2 \ - https://launchpad.net/~mozillacorp/+archive/ubuntu/mozillavpn/+sourcefiles/qt515base/5.15.2-1basyskom4/qt515base_5.15.2.orig.tar.xz \ - qt515base_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515base/5.15.2-1basyskom4/qt515base_5.15.2-1basyskom4.debian.tar.xz \ - qt515base_5.15.2-1basyskom4.debian.tar.xz || die - -magic \ - qt515xmlpatterns \ - qtxmlpatterns-everywhere-src-5.15.2 \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515xmlpatterns/5.15.2-1basyskom1/qt515xmlpatterns_5.15.2.orig.tar.xz \ - qt515xmlpatterns_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515xmlpatterns/5.15.2-1basyskom1/qt515xmlpatterns_5.15.2-1basyskom1.debian.tar.xz \ - qt515xmlpatterns_5.15.2-1basyskom1.debian.tar.xz || die - -magic \ - qt515declarative \ - qtdeclarative-everywhere-src-5.15.2 \ - https://launchpad.net/~mozillacorp/+archive/ubuntu/mozillavpn/+sourcefiles/qt515declarative/5.15.2-1basyskom1/qt515declarative_5.15.2.orig.tar.xz \ - qt515declarative_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515declarative/5.15.2-1basyskom1/qt515declarative_5.15.2-1basyskom1.debian.tar.xz \ - qt515declarative_5.15.2-1basyskom1.debian.tar.xz || die - -magic \ - qt515graphicaleffects \ - qtgraphicaleffects-everywhere-src-5.15.2 \ - https://launchpad.net/~mozillacorp/+archive/ubuntu/mozillavpn/+sourcefiles/qt515graphicaleffects/5.15.2-1basyskom1/qt515graphicaleffects_5.15.2.orig.tar.xz \ - qt515graphicaleffects_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515graphicaleffects/5.15.2-1basyskom1/qt515graphicaleffects_5.15.2-1basyskom1.debian.tar.xz \ - qt515graphicaleffects_5.15.2-1basyskom1.debian.tar.xz || die - -magic \ - qt515imageformats \ - qtimageformats-everywhere-src-5.15.2 \ - https://launchpad.net/~mozillacorp/+archive/ubuntu/mozillavpn/+sourcefiles/qt515imageformats/5.15.2-1basyskom1/qt515imageformats_5.15.2.orig.tar.xz \ - qt515imageformats_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515imageformats/5.15.2-1basyskom2/qt515imageformats_5.15.2-1basyskom2.debian.tar.xz \ - qt515imageformats_5.15.2-1basyskom2.debian.tar.xz || die - -magic \ - qt515networkauth-no-lgpl \ - qtnetworkauth-everywhere-src-5.15.2 \ - https://launchpad.net/~mozillacorp/+archive/ubuntu/mozillavpn/+sourcefiles/qt515networkauth-no-lgpl/5.15.2-1basyskom1/qt515networkauth-no-lgpl_5.15.2.orig.tar.xz \ - qt515networkauth-no-lgpl_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515networkauth-no-lgpl/5.15.2-1basyskom1/qt515networkauth-no-lgpl_5.15.2-1basyskom1.debian.tar.xz \ - qt515networkauth-no-lgpl_5.15.2-1basyskom1.debian.tar.xz || die - -magic \ - qt515quickcontrols \ - qtquickcontrols-everywhere-src-5.15.2 \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515quickcontrols/5.15.2-1basyskom1/qt515quickcontrols_5.15.2.orig.tar.xz \ - qt515quickcontrols_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515quickcontrols/5.15.2-1basyskom1/qt515quickcontrols_5.15.2-1basyskom1.debian.tar.xz \ - qt515quickcontrols_5.15.2-1basyskom1.debian.tar.xz || die - -magic \ - qt515quickcontrols2 \ - qtquickcontrols2-everywhere-src-5.15.2 \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515quickcontrols2/5.15.2-1basyskom1/qt515quickcontrols2_5.15.2.orig.tar.xz \ - qt515quickcontrols2_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515quickcontrols2/5.15.2-1basyskom1/qt515quickcontrols2_5.15.2-1basyskom1.debian.tar.xz \ - qt515quickcontrols2_5.15.2-1basyskom1.debian.tar.xz || die - -magic \ - qt515svg \ - qtsvg-everywhere-src-5.15.2 \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515svg/5.15.2-1basyskom1/qt515svg_5.15.2.orig.tar.xz \ - qt515svg_5.15.2.orig.tar.xz \ - https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.15.2-bionic/+sourcefiles/qt515svg/5.15.2-1basyskom1/qt515svg_5.15.2-1basyskom1.debian.tar.xz \ - qt515svg_5.15.2-1basyskom1.debian.tar.xz || die - -print G "Now, upload all the files from /tmp/qt_ppa_final" diff --git a/linux/debian/control.qt6 b/linux/debian/control similarity index 100% rename from linux/debian/control.qt6 rename to linux/debian/control diff --git a/linux/debian/control.beineri b/linux/debian/control.beineri deleted file mode 100644 index 16d8d38336e..00000000000 --- a/linux/debian/control.beineri +++ /dev/null @@ -1,93 +0,0 @@ -Source: mozillavpn -Section: net -Priority: optional -Maintainer: mozilla -Build-Depends: debhelper (>= 9.20160709), - cdbs, - quilt, - flex, - golang (>=2:1.13~) | golang-1.13, - cargo, - python3-yaml, - python3-lxml, - qt515base (>=5.15.2-1basyskom4), - qt515declarative (>= 5.15.2-1basyskom1), - qt515graphicaleffects (>= 5.15.2-1basyskom1), - qt515imageformats (>= 5.15.2-1basyskom), - qt515networkauth-no-lgpl (>= 5.15.2-1basyskom1), - qt515quickcontrols2 (>=5.15.2-1basyskom1), - qt515svg (>=5.15.2-1basyskom1), - qt515tools (>=5.15.2-1basyskom1), - qt515websockets (>=5.15.2-1basyskom1), - libxcb-render0-dev, - libxcb-image0-dev, - libxcb-shape0-dev, - libxcb-sync0-dev, - libxcb-render-util0-dev, - libxcb1-dev, - libxcb-xfixes0-dev, - libxcb-icccm4-dev, - libxcb1-dev, - libx11-xcb-dev, - libxcb-keysyms1-dev, - libxcb-image0-dev, - libxcb-shm0-dev, - libxcb-icccm4-dev, - libxcb-sync0-dev, - libxcb-xfixes0-dev, - libxrender-dev, - libxcb-shape0-dev, - libasound2-dev [linux-any], - libaudio-dev, - libcups2-dev, - libdbus-1-dev, - libfreetype6-dev, - libgl1-mesa-dev [!armel !armhf] | libgl-dev [!armel !armhf], - libgles2-mesa-dev [armel armhf] | libgles2-dev [armel armhf], - libglib2.0-dev, - libglu1-mesa-dev [!armel !armhf] | libglu-dev [!armel !armhf], - libice-dev, - libjpeg-dev, - libmng-dev, - libpng-dev, - libsm-dev, - libsqlite3-dev, - libssl-dev, - libtiff5-dev, - libx11-dev, - libxcursor-dev, - libxext-dev, - libxft-dev, - libxi-dev, - libxinerama-dev, - libxmu-dev, - libxrandr-dev, - libxrender-dev, - libxt-dev, - libxv-dev, - zlib1g-dev, - libedit-dev, - libvulkan-dev, - libpolkit-gobject-1-dev -Standards-Version: 4.4.1 -Homepage: https://vpn.mozilla.org/ -Vcs-Git: https://github.com/mozilla-mobile/mozilla-vpn-client - -Package: mozillavpn -Architecture: any -Depends: libpolkit-gobject-1-0 (>=0.105), - wireguard (>=1.0.20200319), - wireguard-tools (>=1.0.20200319), - libxcb-xinerama0 (>=1.13-1), - qt515base (>=5.15.2-1basyskom4), - qt515declarative (>= 5.15.2-1basyskom1), - qt515graphicaleffects (>= 5.15.2-1basyskom1), - qt515imageformats (>= 5.15.2-1basyskom), - qt515networkauth-no-lgpl (>= 5.15.2-1basyskom1), - qt515quickcontrols2 (>=5.15.2-1basyskom1), - qt515svg (>=5.15.2-1basyskom1), - qt515websockets (>=5.15.2-1basyskom1) -Description: A fast, secure and easy to use VPN. Built by the makers of Firefox. - Read more on https://vpn.mozilla.org - - diff --git a/linux/debian/control.focal b/linux/debian/control.focal deleted file mode 100644 index 379ac7ae8ff..00000000000 --- a/linux/debian/control.focal +++ /dev/null @@ -1,94 +0,0 @@ -Source: mozillavpn -Section: net -Priority: optional -Maintainer: mozilla -Build-Depends: debhelper (>= 9.20160709), - cdbs, - quilt, - flex, - golang (>=1.13), - cargo, - python3-yaml, - python3-lxml, - qt515base (>=5.15.2-1basyskom4), - qt515declarative (>= 5.15.2-1basyskom1), - qt515graphicaleffects (>= 5.15.2-1basyskom1), - qt515imageformats (>= 5.15.2-1basyskom), - qt515networkauth-no-lgpl (>= 5.15.2-1basyskom1), - qt515quickcontrols2 (>=5.15.2-1basyskom1), - qt515svg (>=5.15.2-1basyskom1), - qt515tools (>=5.15.2-1basyskom1), - qt515websockets (>=5.15.2-1basyskom1), - libxcb-render0-dev, - libxcb-image0-dev, - libxcb-shape0-dev, - libxcb-sync0-dev, - libxcb-render-util0-dev, - libxcb1-dev, - libxcb-xfixes0-dev, - libxcb-icccm4-dev, - libxcb1-dev, - libx11-xcb-dev, - libxcb-keysyms1-dev, - libxcb-image0-dev, - libxcb-shm0-dev, - libxcb-icccm4-dev, - libxcb-sync0-dev, - libxcb-xfixes0-dev, - libxrender-dev, - libxcb-shape0-dev, - g++-4.6 (>= 4.6.0-7~) [armel], - libasound2-dev [linux-any], - libaudio-dev, - libcups2-dev, - libdbus-1-dev, - libfreetype6-dev, - libgl1-mesa-dev [!armel !armhf] | libgl-dev [!armel !armhf], - libgles2-mesa-dev [armel armhf] | libgles2-dev [armel armhf], - libglib2.0-dev, - libglu1-mesa-dev [!armel !armhf] | libglu-dev [!armel !armhf], - libice-dev, - libjpeg-dev, - libmng-dev, - libpng-dev, - libsm-dev, - libsqlite3-dev, - libssl-dev, - libtiff5-dev, - libx11-dev, - libxcursor-dev, - libxext-dev, - libxft-dev, - libxi-dev, - libxinerama-dev, - libxmu-dev, - libxrandr-dev, - libxrender-dev, - libxt-dev, - libxv-dev, - zlib1g-dev, - libedit-dev, - libvulkan-dev, - libpolkit-gobject-1-dev -Standards-Version: 4.4.1 -Homepage: https://vpn.mozilla.org/ -Vcs-Git: https://github.com/mozilla-mobile/mozilla-vpn-client - -Package: mozillavpn -Architecture: any -Depends: libpolkit-gobject-1-0 (>=0.105-20ubuntu0.18.04.5), - wireguard (>=1.0.20200513-1~18.04.2), - wireguard-tools (>=1.0.20200513-1~18.04.2), - libicu66 (>=66.1-2ubuntu2), - libxcb-xinerama0 (>=1.14-2), - resolvconf (>=1.82), - qt515base (>=5.15.2-1basyskom4), - qt515declarative (>= 5.15.2-1basyskom1), - qt515graphicaleffects (>= 5.15.2-1basyskom1), - qt515imageformats (>= 5.15.2-1basyskom), - qt515networkauth-no-lgpl (>= 5.15.2-1basyskom1), - qt515quickcontrols2 (>=5.15.2-1basyskom1), - qt515svg (>=5.15.2-1basyskom1), - qt515websockets (>=5.15.2-1basyskom1) -Description: A fast, secure and easy to use VPN. Built by the makers of Firefox. - Read more on https://vpn.mozilla.org diff --git a/linux/debian/control.qt5 b/linux/debian/control.qt5 deleted file mode 100644 index 13c8a138779..00000000000 --- a/linux/debian/control.qt5 +++ /dev/null @@ -1,59 +0,0 @@ -Source: mozillavpn -Section: net -Priority: optional -Maintainer: mozilla -Build-Depends: debhelper (>= 9.20160709), - cdbs, - quilt, - flex, - golang (>=2:1.13~) | golang-1.13, - cargo, - python3-yaml, - python3-lxml, - libqt5networkauth5-dev (>=5.15.2), - libqt5websockets5-dev (>=5.15.2), - qtbase5-dev (>=5.15.2), - qtbase5-dev-tools (>=5.15.2), - qtdeclarative5-dev (>=5.15.2), - qtdeclarative5-dev-tools (>=5.15.2), - qt5-qmake-bin (>=5.15.2), - qttools5-dev-tools (>=5.15.2), - libpolkit-gobject-1-dev -Standards-Version: 4.4.1 -Homepage: https://vpn.mozilla.org/ -Vcs-Git: https://github.com/mozilla-mobile/mozilla-vpn-client - -Package: mozillavpn -Architecture: any -Depends: libpolkit-gobject-1-0 (>=0.105), - wireguard (>=1.0.20200319), - wireguard-tools (>=1.0.20200319), - resolvconf (>=1.82), - libqt5quick5 (>=5.15.2), - libqt5widgets5 (>=5.15.2), - libqt5gui5 (>=5.15.2), - libqt5qml5 (>=5.15.2), - libqt5network5 (>=5.15.2), - libqt5networkauth5 (>=5.15.2), - libqt5dbus5 (>=5.15.2), - libqt5core5a (>=5.15.2), - libqt5qmlmodels5 (>=5.15.2), - libqt5svg5 (>=5.15.2), - libqt5quickcontrols2-5 (>=5.15.2), - libqt5websockets5 (>= 5.15.2), - libqt5test5 (>=5.15.2), - qml-module-qtgraphicaleffects (>=5.15.2), - qml-module-qtquick-controls (>=5.15.2), - qml-module-qtquick-controls2 (>=5.15.2), - qml-module-qtquick-extras (>=5.15.2), - qml-module-qtquick-layouts (>=5.15.2), - qml-module-qtquick-localstorage (>=5.15.2), - qml-module-qtquick-window2 (>=5.15.2), - qml-module-qtquick2 (>=5.15.2), - qml-module-qtqml-models2 (>=5.15.2), - qml-module-qtqml (>=5.15.2), - qml-module-qt-labs-qmlmodels (>=5.15.2) -Description: A fast, secure and easy to use VPN. Built by the makers of Firefox. - Read more on https://vpn.mozilla.org - - diff --git a/linux/debian/rules.qt6 b/linux/debian/rules similarity index 100% rename from linux/debian/rules.qt6 rename to linux/debian/rules diff --git a/linux/debian/rules.beineri b/linux/debian/rules.beineri deleted file mode 100755 index c889c9efdc7..00000000000 --- a/linux/debian/rules.beineri +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/make -f - -export DH_VERBOSE=1 -export QTDIR := /opt/qt515 -export PATH := $(QTDIR)/bin:$(PATH) -export LD_LIBRARY_PATH := $(QTDIR)/lib:$(LD_LIBRARY_PATH) - -DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) -DEB_VERSION ?= $(shell dpkg-parsechangelog -SVersion) - -GOLANG_NATIVE_VERSION := $(shell dpkg-query --showformat='${Version}' --show golang 2>/dev/null || echo 0) -ifneq (ok,$(dpkg --compare-versions $(GOLANG_NATIVE_VERSION) ge 2:1.13 && echo ok)) - export GODIR := /usr/lib/go-1.13 - export PATH := $(GODIR)/bin:$(PATH) -endif - -%: - dh $@ --with=systemd --warn-missing - -override_dh_auto_configure: - python3 scripts/utils/import_languages.py - qmake CONFIG-=debug CONFIG+=release CONFIG-=debug_and_release QT+=svg BUILD_ID=$(DEB_VERSION) - -override_dh_installdocs: - -override_dh_installinfo: - -override_dh_installsystemd: - dh_installsystemd debian/mozillavpn/lib/systemd/system/mozillavpn.service - -override_dh_systemd_start: - dh_systemd_start debian/mozillavpn/lib/systemd/system/mozillavpn.service - -override_dh_systemd_enable: - dh_systemd_enable debian/mozillavpn/lib/systemd/system/mozillavpn.service - diff --git a/linux/debian/rules.qt5 b/linux/debian/rules.qt5 deleted file mode 100755 index 9f46611918e..00000000000 --- a/linux/debian/rules.qt5 +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/make -f - -export DH_VERBOSE=1 - -DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) -DEB_VERSION ?= $(shell dpkg-parsechangelog -SVersion) - -GOLANG_NATIVE_VERSION := $(shell dpkg-query --showformat='${Version}' --show golang 2>/dev/null || echo 0) -ifneq (ok,$(dpkg --compare-versions $(GOLANG_NATIVE_VERSION) ge 2:1.13 && echo ok)) - export GODIR := /usr/lib/go-1.13 - export PATH := $(GODIR)/bin:$(PATH) -endif - -%: - dh $@ --with=systemd --warn-missing - -override_dh_auto_configure: - python3 scripts/utils/import_languages.py - qmake CONFIG-=debug CONFIG+=release CONFIG-=debug_and_release BUILD_ID=$(DEB_VERSION) - -override_dh_installdocs: - -override_dh_installinfo: - -override_dh_installsystemd: - dh_installsystemd debian/mozillavpn/lib/systemd/system/mozillavpn.service - -override_dh_systemd_start: - dh_systemd_start debian/mozillavpn/lib/systemd/system/mozillavpn.service - -override_dh_systemd_enable: - dh_systemd_enable debian/mozillavpn/lib/systemd/system/mozillavpn.service - diff --git a/nebula/nebula.cpp b/nebula/nebula.cpp index 9d9cb715940..d68e293138b 100644 --- a/nebula/nebula.cpp +++ b/nebula/nebula.cpp @@ -11,12 +11,8 @@ void Nebula::Initialize(QQmlEngine* engine) { Q_INIT_RESOURCE(components); Q_INIT_RESOURCE(themes); Q_INIT_RESOURCE(nebula_resources); -# if QT_VERSION >= 0x060000 Q_INIT_RESOURCE(compatQt6); Q_INIT_RESOURCE(resourcesQt6); -# else - Q_INIT_RESOURCE(compatQt5); -# endif #endif engine->addImportPath(QRC_ROOT); diff --git a/nebula/nebula.pri b/nebula/nebula.pri index 6362b428ae2..95a88bcb018 100644 --- a/nebula/nebula.pri +++ b/nebula/nebula.pri @@ -19,9 +19,5 @@ RESOURCES += $$PWD/ui/nebula_resources.qrc QML_IMPORT_PATH += $$PWD/ui -versionAtLeast(QT_VERSION, 6.0.0) { - RESOURCES += $$PWD/ui/compatQt6.qrc - RESOURCES += $$PWD/ui/resourcesQt6.qrc -} else { - RESOURCES += $$PWD/ui/compatQt5.qrc -} +RESOURCES += $$PWD/ui/compatQt6.qrc +RESOURCES += $$PWD/ui/resourcesQt6.qrc diff --git a/nebula/ui/compat/qt5/VPNAnimatedRingsShader.qml b/nebula/ui/compat/qt5/VPNAnimatedRingsShader.qml deleted file mode 100644 index 3e732fd26d9..00000000000 --- a/nebula/ui/compat/qt5/VPNAnimatedRingsShader.qml +++ /dev/null @@ -1,66 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import QtQuick 2.0 - -ShaderEffect { - fragmentShader: " - #ifdef GL_ES - precision mediump float; - #endif - varying mediump vec2 qt_TexCoord0; - uniform mediump float animationProgress; - uniform mediump float animationOpacity; - - float drawCircle(float distance, float radius) { - float antialias = 0.005; - - return smoothstep(radius, radius - antialias, distance); - } - - float composeRing(float distance, float strokeWidth, float radius) { - float circle1 = drawCircle(distance, radius); - float circle2 = drawCircle(distance, radius - strokeWidth); - - return circle1 - circle2; - } - - float calcRingRadius(float minRadius, float maxRadius, float currentRadius, float offset) { - return mod(maxRadius * offset + currentRadius, maxRadius) + minRadius; - } - - void main() { - // Center coordinate - vec2 center = vec2(0.5, 0.275); - float centerDistance = length(qt_TexCoord0 - center); - - // Ring properties - float strokeWidth = 0.015; - float minRadius = 0.0; - float maxRadius = 0.5; - vec4 color = vec4(1.0, 1.0, 1.0, 1.0) * animationOpacity; - - // Rings - float ringRadius1 = calcRingRadius(minRadius, maxRadius, animationProgress, 0.0); - float ring1 = composeRing(centerDistance, strokeWidth, ringRadius1); - - float ringRadius2 = calcRingRadius(minRadius, maxRadius, animationProgress, 0.33 * animationOpacity); - float ring2 = composeRing(centerDistance, strokeWidth, ringRadius2); - - float ringRadius3 = calcRingRadius(minRadius, maxRadius, animationProgress, 0.66 * animationOpacity); - float ring3 = composeRing(centerDistance, strokeWidth, ringRadius3); - - // Radial gradient - float gradientWidth = 5.0; - float gradientBlur = 0.8; - float gradientOffset = 0.28; - float gradientMask = 1.0 - max(0.0, 0.25 - pow(max(0.0, abs(centerDistance - gradientOffset) * gradientWidth), gradientWidth * gradientBlur)); - - // Output rings - float rings = ring1 + ring2 + ring3; - gl_FragColor = color * rings - gradientMask; - } - " -} - diff --git a/nebula/ui/compat/qt5/VPNColorOverlay.qml b/nebula/ui/compat/qt5/VPNColorOverlay.qml deleted file mode 100644 index b66126fd26c..00000000000 --- a/nebula/ui/compat/qt5/VPNColorOverlay.qml +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import QtQuick 2.0 -import QtGraphicalEffects 1.0 - -ColorOverlay { -} diff --git a/nebula/ui/compat/qt5/VPNDropShadow.qml b/nebula/ui/compat/qt5/VPNDropShadow.qml deleted file mode 100644 index dd7e9b5b7b0..00000000000 --- a/nebula/ui/compat/qt5/VPNDropShadow.qml +++ /dev/null @@ -1,10 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import QtQuick 2.0 -import QtGraphicalEffects 1.0 - -DropShadow { - samples: 33 -} diff --git a/nebula/ui/compat/qt5/VPNLinearGradient.qml b/nebula/ui/compat/qt5/VPNLinearGradient.qml deleted file mode 100644 index 2961b3ab0d9..00000000000 --- a/nebula/ui/compat/qt5/VPNLinearGradient.qml +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import QtQuick 2.0 -import QtGraphicalEffects 1.0 - -LinearGradient { -} diff --git a/nebula/ui/compat/qt5/VPNOpacityMask.qml b/nebula/ui/compat/qt5/VPNOpacityMask.qml deleted file mode 100644 index 21dff5653d3..00000000000 --- a/nebula/ui/compat/qt5/VPNOpacityMask.qml +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import QtQuick 2.0 -import QtGraphicalEffects 1.0 - -OpacityMask { -} diff --git a/nebula/ui/compat/qt5/VPNRadialGradient.qml b/nebula/ui/compat/qt5/VPNRadialGradient.qml deleted file mode 100644 index 43a5cf124de..00000000000 --- a/nebula/ui/compat/qt5/VPNRadialGradient.qml +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import QtQuick 2.0 -import QtGraphicalEffects 1.0 - -RadialGradient { -} diff --git a/nebula/ui/compat/qt5/VPNRectangularGlow.qml b/nebula/ui/compat/qt5/VPNRectangularGlow.qml deleted file mode 100644 index 640b38dab35..00000000000 --- a/nebula/ui/compat/qt5/VPNRectangularGlow.qml +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import QtQuick 2.0 -import QtGraphicalEffects 1.0 - -RectangularGlow { -} diff --git a/nebula/ui/compat/qt5/qmldir b/nebula/ui/compat/qt5/qmldir deleted file mode 100644 index 9ea8685cb55..00000000000 --- a/nebula/ui/compat/qt5/qmldir +++ /dev/null @@ -1,7 +0,0 @@ -VPNAnimatedRingsShader 0.1 VPNAnimatedRingsShader.qml -VPNColorOverlay 0.1 VPNColorOverlay.qml -VPNDropShadow 0.1 VPNDropShadow.qml -VPNLinearGradient 0.1 VPNLinearGradient.qml -VPNOpacityMask 0.1 VPNOpacityMask.qml -VPNRadialGradient 0.1 VPNRadialGradient.qml -VPNRectangularGlow 0.1 VPNRectangularGlow.qml diff --git a/nebula/ui/compatQt5.qrc b/nebula/ui/compatQt5.qrc deleted file mode 100644 index 530780b2811..00000000000 --- a/nebula/ui/compatQt5.qrc +++ /dev/null @@ -1,12 +0,0 @@ - - - compat/qt5/qmldir - compat/qt5/VPNAnimatedRingsShader.qml - compat/qt5/VPNColorOverlay.qml - compat/qt5/VPNDropShadow.qml - compat/qt5/VPNLinearGradient.qml - compat/qt5/VPNOpacityMask.qml - compat/qt5/VPNRadialGradient.qml - compat/qt5/VPNRectangularGlow.qml - - diff --git a/scripts/README.md b/scripts/README.md index 1dcee6c17ee..c4bf386c2a8 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -54,7 +54,6 @@ TODO: - ./utils/generate_strings.py - process the string.yaml file and generate resources - ./utils/import_languages.py - process languages and import them - ./utils/inspector.py - send commands to the VPN client inspector -- ./utils/qt5_compile.sh - compile qt5 for linux and macos - ./utils/qt6_compile.sh - compile qt6 for linux and macos # Clang-format utils diff --git a/scripts/linux/script.sh b/scripts/linux/script.sh index a6434d1f426..54e81f9e72c 100755 --- a/scripts/linux/script.sh +++ b/scripts/linux/script.sh @@ -9,7 +9,6 @@ REVISION=1 RELEASE= GITREF= -QTVERSION="qt6" SOURCEONLY=N PPA_URL= DPKG_SIGN="--no-sign" @@ -27,9 +26,6 @@ helpFunction() { print N " -r, --release DIST Build packages for distribution DIST" print N " -g, --gitref REF Generated version suffix from REF" print N " -v, --version REV Set package revision to REV" - print N " --beineri Build using Stephan Binner's Qt5.15 PPA" - print N " --qt5 Build using Qt5 packages" - print N " --qt6 Build using Qt6 packages (default)" print N " --source Build source packages only (no binary)" print N " --ppa URL Upload source packages to PPA at URL (implies: --source)" print N "" @@ -66,18 +62,6 @@ while [[ $# -gt 0 ]]; do shift shift ;; - --beineri) - QTVERSION="beineri" - shift - ;; - --qt5) - QTVERSION="qt5" - shift - ;; - --qt6) - QTVERSION="qt6" - shift - ;; --source) RELEASE="bionic focal jammy fedora" SOURCEONLY=Y @@ -208,11 +192,6 @@ build_deb_source() { rm -rf $WORKDIR/debian || die "Failed" cp -r ../linux/debian $WORKDIR || die "Failed" - mv $WORKDIR/debian/rules.$QTVERSION $WORKDIR/debian/rules - mv $WORKDIR/debian/control.$QTVERSION $WORKDIR/debian/control - rm $WORKDIR/debian/control.* - rm $WORKDIR/debian/rules.* - mv $WORKDIR/debian/changelog.template $WORKDIR/debian/changelog || die "Failed" sed -i -e "s/SHORTVERSION/$SHORTVERSION/g" $WORKDIR/debian/changelog || die "Failed" sed -i -e "s/VERSION/$buildrev/g" $WORKDIR/debian/changelog || die "Failed" diff --git a/scripts/utils/import_languages.py b/scripts/utils/import_languages.py index 4a6b2e5b7cf..0c5ac0ee9ac 100755 --- a/scripts/utils/import_languages.py +++ b/scripts/utils/import_languages.py @@ -52,10 +52,6 @@ def qtquery(qmake, propname): qtbinpath = qtquery('qmake', 'QT_INSTALL_BINS') if qtbinpath is None: qtbinpath = qtquery('qmake6', 'QT_INSTALL_BINS') -if qtbinpath is None: - qtbinpath = qtquery('qmake5', 'QT_INSTALL_BINS') -if qtbinpath is None: - qtbinpath = qtquery('qmake-qt5', 'QT_INSTALL_BINS') if qtbinpath is None: print('Unable to locate qmake tool.') sys.exit(1) diff --git a/scripts/utils/qt5_compile.sh b/scripts/utils/qt5_compile.sh deleted file mode 100755 index 35af03c246f..00000000000 --- a/scripts/utils/qt5_compile.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/bash - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -. $(dirname $0)/commons.sh - -POSITIONAL=() -JOBS=8 - -helpFunction() { - print G "Usage:" - print N "\t$0 [-j|--jobs ] [anything else will be use as argument for the QT configure script]" - print N "" - exit 0 -} - -print N "This script compiles Qt5 statically" -print N "" - -while [[ $# -gt 0 ]]; do - key="$1" - - case $key in - -j | --jobs) - JOBS="$2" - shift - shift - ;; - -h | --help) - helpFunction - ;; - *) - POSITIONAL+=("$1") - shift - ;; - esac -done - -set -- "${POSITIONAL[@]}" # restore positional parameters - -if [[ $# -lt 2 ]]; then - helpFunction -fi - -[ -d "$1" ] || die "Unable to find the QT source folder." - -cd "$1" || die "Unable to enter into the QT source folder" - -shift - -PREFIX=$1 -shift - -printn Y "Cleaning the folder... " -make distclean -j $JOBS &>/dev/null; -print G "done." - -LINUX=" - -platform linux-clang \ - -egl \ - -opengl es2 \ - -no-linuxfb \ - -bundled-xcb-xinput \ - -xcb \ -" - -MACOS=" - -debug-and-release \ - -appstore-compliant \ - -no-feature-qdbus \ - -no-speechd -" - -if [[ "$OSTYPE" == "linux-gnu"* ]]; then - print N "Configure for linux" - PLATFORM=$LINUX -elif [[ "$OSTYPE" == "darwin"* ]]; then - print N "Configure for darwin" - PLATFORM=$MACOS -else - die "Unsupported platform (yet?)" -fi - -print Y "Wait..." -./configure \ - $* \ - --prefix=$PREFIX \ - --recheck-all \ - -opensource \ - -confirm-license \ - -static \ - -strip \ - -silent \ - -no-compile-examples \ - -nomake tests \ - -make libs \ - -no-sql-psql \ - -sql-sqlite \ - -skip qt3d \ - -skip webengine \ - -skip qtmultimedia \ - -skip qtserialport \ - -skip qtsensors \ - -skip qtgamepad \ - -skip qtwebchannel \ - -skip qtandroidextras \ - -feature-imageformat_png \ - -qt-doubleconversion \ - -qt-libpng \ - -qt-zlib \ - -qt-pcre \ - -qt-freetype \ - $PLATFORM || die "Configuration error." - -print Y "Compiling..." -make -j $JOBS || die "Make failed" - -print Y "Installing..." -make -j $JOBS install || die "Make install failed" - -print G "All done!" diff --git a/src/appimageprovider.h b/src/appimageprovider.h index 76a06097637..47d53a862bc 100644 --- a/src/appimageprovider.h +++ b/src/appimageprovider.h @@ -8,25 +8,12 @@ #include #include -// Helper class to support Qt5 and Qt6 -class AppImageProvider : public QQuickImageProvider -#if QT_VERSION < 0x060000 - , - public QObject -#endif -{ +class AppImageProvider : public QQuickImageProvider { public: AppImageProvider(QObject* parent, QQmlImageProviderBase::ImageType type, QQmlImageProviderBase::Flags flags = Flags()) - : QQuickImageProvider(type, flags) -#if QT_VERSION < 0x060000 - , - QObject(parent) -#endif - { -#if QT_VERSION >= 0x060000 + : QQuickImageProvider(type, flags) { setParent(parent); -#endif } virtual ~AppImageProvider() = default; diff --git a/src/mozillavpn.cpp b/src/mozillavpn.cpp index 23986e8db52..3f7924d92f0 100644 --- a/src/mozillavpn.cpp +++ b/src/mozillavpn.cpp @@ -1610,9 +1610,6 @@ QString MozillaVPN::devVersion() { // static QString MozillaVPN::graphicsApi() { -#if QT_VERSION < 0x060000 - return "qt5-angle"; -#else QQuickWindow* window = qobject_cast(QmlEngineHolder::instance()->window()); Q_ASSERT(window); @@ -1634,7 +1631,6 @@ QString MozillaVPN::graphicsApi() { default: return "unknown"; } -#endif } void MozillaVPN::requestDeleteAccount() { diff --git a/src/platforms/dummy/dummyappimageprovider.cpp b/src/platforms/dummy/dummyappimageprovider.cpp deleted file mode 100644 index 52ee8aa9fcd..00000000000 --- a/src/platforms/dummy/dummyappimageprovider.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "dummyappimageprovider.h" -#include "logger.h" -#include "leakdetector.h" - -namespace { -Logger logger(LOG_CONTROLLER, "DummyAppImageProvider"); -} - -DummyAppImageProvider::DummyAppImageProvider(QObject* parent) - : QQuickImageProvider(QQuickImageProvider::Pixmap), QObject(parent) { - MVPN_COUNT_CTOR(DummyAppImageProvider); -} - -DummyAppImageProvider::~DummyAppImageProvider() { - MVPN_COUNT_DTOR(DummyAppImageProvider); -} - -// Returns an example image for any provided APPID (a red square) -QPixmap DummyAppImageProvider::requestPixmap(const QString& id, QSize* size, - const QSize& requestedSize) { - logger.debug() << "Request Image for " << id; - int width = 50; - int height = 50; - - if (size) *size = QSize(width, height); - QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width, - requestedSize.height() > 0 ? requestedSize.height() : height); - pixmap.fill(QColor("red").rgba()); - return pixmap; -} diff --git a/src/platforms/dummy/dummyappimageprovider.h b/src/platforms/dummy/dummyappimageprovider.h deleted file mode 100644 index b0d7dd25b23..00000000000 --- a/src/platforms/dummy/dummyappimageprovider.h +++ /dev/null @@ -1,19 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef DUMMYAPPIMAGEPROVIDER_H -#define DUMMYAPPIMAGEPROVIDER_H - -#include -#include - -class DummyAppImageProvider : public QQuickImageProvider, public QObject { - public: - DummyAppImageProvider(QObject* parent); - ~DummyAppImageProvider(); - QPixmap requestPixmap(const QString& id, QSize* size, - const QSize& requestedSize) override; -}; - -#endif // DUMMYAPPIMAGEPROVIDER_H diff --git a/taskcluster/docker/lint/Dockerfile b/taskcluster/docker/lint/Dockerfile index 01a018acd20..0915f3f2a75 100644 --- a/taskcluster/docker/lint/Dockerfile +++ b/taskcluster/docker/lint/Dockerfile @@ -1,11 +1,9 @@ FROM $DOCKER_IMAGE_PARENT -# Add external PPA, latest version of QT is 5.12.x for Ubuntu 20.04 RUN apt-get update && \ apt-get install --yes software-properties-common && \ apt-get update && \ - add-apt-repository ppa:beineri/opt-qt-5.15.2-focal -y && \ - apt-get install --yes git qt515tools clang-format-11 openjdk-11-jdk python3-lxml && \ + apt-get install --yes git clang-format-11 openjdk-11-jdk python3-lxml && \ apt-get remove --yes software-properties-common && \ apt-get clean From b22992f8e5d959fcdeda493fa7fed62bc99e24dc Mon Sep 17 00:00:00 2001 From: Owen Kirby Date: Fri, 14 Oct 2022 15:00:41 -0700 Subject: [PATCH 41/85] MSI: Use afterInstallValidate schedule during upgrades (#4624) --- windows/installer/MozillaVPN.wxs | 2 +- windows/installer/MozillaVPN_cmake.wxs | 2 +- windows/installer/MozillaVPN_prod.wxs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/windows/installer/MozillaVPN.wxs b/windows/installer/MozillaVPN.wxs index 0e0c1521389..705717edda3 100644 --- a/windows/installer/MozillaVPN.wxs +++ b/windows/installer/MozillaVPN.wxs @@ -54,7 +54,7 @@ AllowDowngrades="no" AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of [ProductName] is already installed." - Schedule="afterInstallExecute" /> + Schedule="afterInstallValidate" /> \n') @@ -163,7 +163,7 @@ def qtquery(qmake, propname): qrcfile.write(' \n') qrcfile.write('\n') -# Step 4 +# Step 5 title("Generate the Js/C++ string definitions...") try: subprocess.call([sys.executable, os.path.join('scripts', 'utils', 'generate_strings.py'), @@ -174,6 +174,7 @@ def qtquery(qmake, propname): print(e) exit(1) +# Step 6 # Build a dummy project to glob together everything that might contain strings. title("Scanning for new strings...") def scan_sources(projfile, dirpath): @@ -193,7 +194,7 @@ def scan_sources(projfile, dirpath): scan_sources(dummyproj, '../../src') scan_sources(dummyproj, '../../nebula') -# Step 5 +# Step 7 title("Generate translation resources...") for l10n_file in l10n_files: os.system(f"{lconvert} -if xlf -i {l10n_file['xliff']} -o {l10n_file['ts']}") From 6bc69d5d526bf44cd90ff555a21dfee2d3547ac2 Mon Sep 17 00:00:00 2001 From: Florian Zia Date: Fri, 28 Oct 2022 14:11:14 +0200 Subject: [PATCH 76/85] Improve text input a11y for screen readers (#4738) * chore: Improve text input screen reader accessibility * fix: Narrate chars entered in text fields * chore: Fix typo * fix: Fix screen reader accessibility and clean up * chore: Advise screen readers to not read password inputs when masked --- .../ui/components/forms/VPNPasswordInput.qml | 8 ++ nebula/ui/components/forms/VPNSearchBar.qml | 35 +++++--- nebula/ui/components/forms/VPNTextArea.qml | 86 ++++++++++++------- nebula/ui/components/forms/VPNTextField.qml | 55 ++++++++---- 4 files changed, 121 insertions(+), 63 deletions(-) diff --git a/nebula/ui/components/forms/VPNPasswordInput.qml b/nebula/ui/components/forms/VPNPasswordInput.qml index c24a9524ec4..da0df946a84 100644 --- a/nebula/ui/components/forms/VPNPasswordInput.qml +++ b/nebula/ui/components/forms/VPNPasswordInput.qml @@ -15,6 +15,14 @@ VPNTextField { property alias placeholder: passwordInput._placeholderText id: passwordInput + + Accessible.ignored: charactersMasked + Accessible.passwordEdit: charactersMasked + // In order for screen readers to respect the `Accessible.ignored` property + // `Accessible.role` has to be set to `EditableText`. For more infos see + // QTBUG-82433: https://bugreports.qt.io/browse/QTBUG-82433. + Accessible.role: Accessible.EditableText + echoMode: charactersMasked ? TextInput.Password : TextInput.Normal hasError: !isValid height: VPNTheme.theme.rowHeight diff --git a/nebula/ui/components/forms/VPNSearchBar.qml b/nebula/ui/components/forms/VPNSearchBar.qml index 9eec8cf8054..3bf922280f3 100644 --- a/nebula/ui/components/forms/VPNSearchBar.qml +++ b/nebula/ui/components/forms/VPNSearchBar.qml @@ -16,34 +16,41 @@ ColumnLayout { property var _sortProxyCallback: () => {} property var _editCallback: () => {} property alias _filterProxySource: model.source - property bool _searchBarHasError: false property alias _searchBarPlaceholderText: searchBar._placeholderText + property bool _searchBarHasError: false spacing: VPNTheme.theme.windowMargin / 2 VPNTextField { - // TODO Add strings for Accessible.description, Accessible.name - id: searchBar - background: VPNInputBackground {} - leftInset: 48 - leftPadding: 48 - onActiveFocusChanged: if (focus && vpnFlickable.ensureVisible) vpnFlickable.ensureVisible(searchBar) + Accessible.editable: false + Accessible.searchEdit: true Layout.fillWidth: true + + _accessibleName: _placeholderText + background: VPNInputBackground {} + leftInset: VPNTheme.theme.windowMargin * 3 + leftPadding: VPNTheme.theme.windowMargin * 3 + + onActiveFocusChanged: if (focus && vpnFlickable.ensureVisible) { + vpnFlickable.ensureVisible(searchBar); + } + onLengthChanged: text => model.invalidate() onTextChanged: { - hasError = _searchBarHasError + hasError = _searchBarHasError; if (focus) { _editCallback(); } } - onLengthChanged: text => model.invalidate() VPNIcon { + anchors { + left: parent.left + leftMargin: VPNTheme.theme.hSpacing + verticalCenter: parent.verticalCenter + } source: "qrc:/nebula/resources/search.svg" - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: 20 sourceSize.height: VPNTheme.theme.windowMargin sourceSize.width: VPNTheme.theme.windowMargin opacity: parent.focus ? 1 : 0.8 @@ -71,7 +78,7 @@ ColumnLayout { } function getProxyModel() { - return model + return model; } function getSearchBarText() { @@ -79,6 +86,6 @@ ColumnLayout { } function clearText() { - searchBar.text = "" + searchBar.text = ""; } } diff --git a/nebula/ui/components/forms/VPNTextArea.qml b/nebula/ui/components/forms/VPNTextArea.qml index 1abb7e81a75..18dc55729a4 100644 --- a/nebula/ui/components/forms/VPNTextArea.qml +++ b/nebula/ui/components/forms/VPNTextArea.qml @@ -17,20 +17,22 @@ Item { id: root - Layout.preferredHeight: VPNTheme.theme.rowHeight * 3 - Layout.preferredWidth: parent.width Layout.maximumHeight: VPNTheme.theme.rowHeight * 3 Layout.minimumHeight: VPNTheme.theme.rowHeight * 3 + Layout.preferredHeight: VPNTheme.theme.rowHeight * 3 + Layout.preferredWidth: parent.width Flickable { id: flickable anchors.fill: parent - contentWidth: width contentHeight: textArea.implicitHeight + contentWidth: width ScrollBar.vertical: ScrollBar { - policy: flickable.contentHeight > root.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff + policy: flickable.contentHeight > root.height + ? ScrollBar.AlwaysOn + : ScrollBar.AlwaysOff Accessible.ignored: true } @@ -42,36 +44,52 @@ Item { property bool showInteractionStates: true id: textArea + + Accessible.focused: textArea.focus + background: VPNInputBackground { + itemToFocus: textArea + z: -1 + } + bottomPadding: VPNTheme.theme.windowMargin clip: true - textFormat: Text.PlainText - font.pixelSize: VPNTheme.theme.fontSizeSmall - font.family: VPNTheme.theme.fontInterFamily color: VPNTheme.colors.input.default.text - wrapMode: Text.WrapAtWordBoundaryOrAnywhere + cursorDelegate: VPNCursorDelegate {} + enabled: root.enabled + font.family: VPNTheme.theme.fontInterFamily + font.pixelSize: VPNTheme.theme.fontSizeSmall + inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhSensitiveData leftPadding: VPNTheme.theme.windowMargin rightPadding: VPNTheme.theme.windowMargin - bottomPadding: VPNTheme.theme.windowMargin - topPadding: VPNTheme.theme.windowMargin - Keys.onTabPressed: nextItemInFocusChain().forceActiveFocus(Qt.TabFocusReason) - onTextChanged: handleOnTextChanged(text) selectByMouse: true selectionColor: VPNTheme.theme.input.highlight - inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhSensitiveData - enabled: root.enabled - background: VPNInputBackground { - itemToFocus: textArea - z: -1 - } + textFormat: Text.PlainText + topPadding: VPNTheme.theme.windowMargin + wrapMode: Text.WrapAtWordBoundaryOrAnywhere - cursorDelegate: VPNCursorDelegate {} + Keys.onTabPressed: nextItemInFocusChain().forceActiveFocus(Qt.TabFocusReason) + onTextChanged: { + handleOnTextChanged(textArea.text); + + // This is a workaround to make VoiceOver on macOS work. + // After gaining initial focus or typing in TextArea the screen reader + // fails to narrate any accessible content and action. After regaining + // active focus the screen reader keeps working as expected. + textArea.focus = false; + textArea.forceActiveFocus(); + } VPNTextBlock { id: formattedPlaceholderText - anchors.fill: textArea - anchors.leftMargin: VPNTheme.theme.windowMargin - anchors.rightMargin: VPNTheme.theme.windowMargin - anchors.topMargin: VPNTheme.theme.windowMargin - color: textAreaStates.state === "emptyHovered" ? VPNTheme.colors.input.hover.placeholder : VPNTheme.colors.input.default.placeholder + + anchors { + fill: textArea + leftMargin: VPNTheme.theme.windowMargin + rightMargin: VPNTheme.theme.windowMargin + topMargin: VPNTheme.theme.windowMargin + } + color: textAreaStates.state === "emptyHovered" + ? VPNTheme.colors.input.hover.placeholder + : VPNTheme.colors.input.default.placeholder visible: textArea.text.length < 1 PropertyAnimation on opacity { @@ -99,7 +117,11 @@ Item { // Remember cursor position const prevCursorPosition = textArea.cursorPosition - textInputLength; // Strip overflowing chars - const strippedString = removeCharsInRange(text, prevCursorPosition, prevCursorPosition + textInputLength); + const strippedString = removeCharsInRange( + text, + prevCursorPosition, + prevCursorPosition + textInputLength + ); textArea.text = strippedString; // Restore previous cursor position textArea.cursorPosition = prevCursorPosition; @@ -109,13 +131,15 @@ Item { } Text { - anchors.top: parent.bottom - anchors.topMargin: 10 - text: textArea.length + " / " + textArea.maxCharacterCount - font.pixelSize: 13 - anchors.rightMargin: 8 - anchors.right: parent.right + anchors { + top: parent.bottom + topMargin: VPNTheme.theme.listSpacing * 1.25 + right: parent.right + rightMargin: VPNTheme.theme.listSpacing + } color: VPNTheme.theme.fontColor + font.pixelSize: VPNTheme.theme.fontSizeSmall + text: textArea.length + " / " + textArea.maxCharacterCount } } diff --git a/nebula/ui/components/forms/VPNTextField.qml b/nebula/ui/components/forms/VPNTextField.qml index 05f5bcdea0f..ef057d85279 100644 --- a/nebula/ui/components/forms/VPNTextField.qml +++ b/nebula/ui/components/forms/VPNTextField.qml @@ -10,50 +10,69 @@ import Mozilla.VPN 1.0 import components 0.1 TextField { - // TODO Add strings for Accessible.description, Accessible.name property bool hasError: false property bool showInteractionStates: true property bool forceBlurOnOutsidePress: true property alias _placeholderText: centeredPlaceholderText.text + property string _accessibleName: _placeholderText + property string _accessibleDescription: "" id: textField + Accessible.name: _accessibleName + Accessible.description: _accessibleDescription + Accessible.focused: textField.focus + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: VPNTheme.theme.rowHeight + background: VPNInputBackground { id: textFieldBackground } - - font.pixelSize: VPNTheme.theme.fontSizeSmall - font.family: VPNTheme.theme.fontInterFamily + bottomPadding: VPNTheme.theme.windowMargin / 2 color: VPNTheme.colors.input.default.text + cursorDelegate: VPNCursorDelegate {} echoMode: TextInput.Normal + focus: true + font.family: VPNTheme.theme.fontInterFamily + font.pixelSize: VPNTheme.theme.fontSizeSmall inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhSensitiveData - onActiveFocusChanged: if (focus && typeof(vpnFlickable) !== "undefined" && vpnFlickable.ensureVisible) vpnFlickable.ensureVisible(textField) - selectByMouse: true - Layout.preferredHeight: VPNTheme.theme.rowHeight - Layout.alignment: Qt.AlignVCenter - verticalAlignment: TextInput.AlignVCenter - placeholderTextColor: VPNTheme.colors.grey40 leftPadding: VPNTheme.theme.windowMargin + placeholderTextColor: VPNTheme.colors.grey40 rightPadding: VPNTheme.theme.windowMargin + selectByMouse: true topPadding: VPNTheme.theme.windowMargin / 2 - bottomPadding: VPNTheme.theme.windowMargin / 2 - focus: true - cursorDelegate: VPNCursorDelegate {} + verticalAlignment: TextInput.AlignVCenter + + onActiveFocusChanged: if (focus && typeof(vpnFlickable) !== "undefined" && vpnFlickable.ensureVisible) { + vpnFlickable.ensureVisible(textField); + } + // This is a workaround to make VoiceOver on macOS work. + // After gaining initial focus or typing in TextField the screen reader + // fails to narrate any accessible content and action. After regaining + // active focus the screen reader keeps working as expected. + onTextChanged: { + textField.focus = false; + textField.forceActiveFocus(); + } Text { id: centeredPlaceholderText + + Accessible.ignored: true + + color: textField.placeholderTextColor + elide: Text.ElideRight + font: textField.font + height: VPNTheme.theme.rowHeight verticalAlignment: Text.AlignVCenter + visible: !textField.length && !textField.preeditText width: textField.width - (textField.leftPadding + textField.rightPadding) - height: VPNTheme.theme.rowHeight - elide: Text.ElideRight x: textField.leftPadding - visible: !textField.length && !textField.preeditText - font: textField.font - color: textField.placeholderTextColor } VPNInputStates { id: textFieldState + itemToTarget: textField } From 39e3a7268f384da3cc4981229d3b3c2734d413b8 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 28 Oct 2022 14:52:58 +0200 Subject: [PATCH 77/85] Non default auth-in-app flows should not go back to StateStart because it's not supported by the front-end code - VPN-3092 (#4748) --- src/authenticationinapp/authenticationinappsession.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/authenticationinapp/authenticationinappsession.cpp b/src/authenticationinapp/authenticationinappsession.cpp index fce90a57c76..b479d4ffc7e 100644 --- a/src/authenticationinapp/authenticationinappsession.cpp +++ b/src/authenticationinapp/authenticationinappsession.cpp @@ -749,7 +749,14 @@ void AuthenticationInAppSession::processErrorObject(const QJsonObject& obj) { } case 114: // Client has sent too many requests - aia->requestState(AuthenticationInApp::StateStart, this); + if (m_typeAuthentication == TypeDefault) { + aia->requestState(AuthenticationInApp::StateStart, this); + } else { + // For non-default authentication flows, we go back to the password + // request, because the email request step is implicit. + aia->requestState(AuthenticationInApp::StateSignIn, this); + } + aia->requestErrorPropagation(this, AuthenticationInApp::ErrorTooManyRequests, obj["retryAfter"].toInt()); From 46996ef8eda2dd0072e8e780dfee8e8dffa511bb Mon Sep 17 00:00:00 2001 From: Matt Lichtenstein Date: Fri, 28 Oct 2022 10:32:07 -0400 Subject: [PATCH 78/85] VPN-927: Center selected server in server list on init (#4710) --- nebula/ui/components/VPNRecentConnections.qml | 123 +++++++++--------- 1 file changed, 60 insertions(+), 63 deletions(-) diff --git a/nebula/ui/components/VPNRecentConnections.qml b/nebula/ui/components/VPNRecentConnections.qml index b0904363469..709d5b683e3 100644 --- a/nebula/ui/components/VPNRecentConnections.qml +++ b/nebula/ui/components/VPNRecentConnections.qml @@ -13,6 +13,57 @@ ColumnLayout { property bool hasVisibleConnections: false property bool showMultiHopRecentConnections: true property real numVisibleConnections: recentConnectionsRepeater.count + property var recentConnectionsModel: getRecentConnectionsModel() + + function getRecentConnectionsModel() { + const maxNumVisibleConnections = 2 + const recentConnections = [] + for (let i=1; i "); + const isMultiHop = servers.length > 1; + + if (isMultiHop !== showMultiHopRecentConnections) { + return recentConnections; + } + + const connection = []; + + for(let x = 0; x < servers.length; x++) { + let index = servers[x].lastIndexOf(","); + if (index <= 0) { + console.log("Unable to parse server from " + servers[x]); + continue; + } + let countryCode = servers[x].slice(index+1).trim(); + let serverCityName = servers[x].slice(0, index).trim(); + + connection.push({ + countryCode: countryCode, + serverCityName: serverCityName, + localizedCityName: VPNLocalizer.localizedCityName(countryCode, serverCityName) + }); + } + + const [{ localizedCityName: firstCityLocalizedName }, secondServer] = connection; + const accessibleLabel = secondServer + ? VPNl18n.MultiHopFeatureAccessibleNameRecentConnection + .arg(firstCityLocalizedName) + .arg(secondServer.localizedCityName) + : firstCityLocalizedName; + + recentConnections.push({ + isMultiHop, + connection, + accessibleLabel + }); + } + return recentConnections + } function focusItemAt(idx) { if (!visible) { @@ -26,7 +77,7 @@ ColumnLayout { id: root spacing: VPNTheme.theme.windowMargin / 2 - visible: repeaterModel.count > 0 + visible: root.recentConnectionsModel.length > 0 function popStack() { stackview.pop() @@ -38,7 +89,7 @@ ColumnLayout { Layout.leftMargin: VPNTheme.theme.windowMargin Layout.minimumHeight: VPNTheme.theme.vSpacing verticalAlignment: Text.AlignVCenter - visible: repeaterModel.count > 0 + visible: root.recentConnectionsModel.length > 0 } @@ -48,69 +99,15 @@ ColumnLayout { spacing: VPNTheme.theme.windowMargin / 2 Layout.fillWidth: true - ListModel { - property real maxNumVisibleConnections: 2 - id: repeaterModel - - Component.onCompleted: { - // don't show the first/current entry - for (let i=1; i "); - const isMultiHop = servers.length > 1; - - if (isMultiHop !== showMultiHopRecentConnections) { - return; - } - - const connection = []; - - for(let x = 0; x < servers.length; x++) { - let index = servers[x].lastIndexOf(","); - if (index <= 0) { - console.log("Unable to parse server from " + servers[x]); - continue; - } - let countryCode = servers[x].slice(index+1).trim(); - let serverCityName = servers[x].slice(0, index).trim(); - - connection.push({ - countryCode: countryCode, - serverCityName: serverCityName, - localizedCityName: VPNLocalizer.localizedCityName(countryCode, serverCityName) - }); - } - - const [{ localizedCityName: firstCityLocalizedName }, secondServer] = connection; - const accessibleLabel = secondServer - ? VPNl18n.MultiHopFeatureAccessibleNameRecentConnection - .arg(firstCityLocalizedName) - .arg(secondServer.localizedCityName) - : firstCityLocalizedName; - - repeaterModel.append({ - isMultiHop, - connection, - accessibleLabel - }); - } - } - } - Repeater { property real maxVisibleConnections: 2 property real visibleConnections: 0 id: recentConnectionsRepeater - model: repeaterModel + model: root.recentConnectionsModel delegate: VPNClickableRow { id: del - accessibleName: accessibleLabel + accessibleName: modelData.accessibleLabel Layout.fillWidth: true Layout.preferredHeight: VPNTheme.theme.rowHeight @@ -126,11 +123,11 @@ ColumnLayout { let args = []; popStack(); - if (isMultiHop) { - return VPNController.changeServer(connection.get(1).countryCode, connection.get(1).serverCityName, connection.get(0).countryCode, connection.get(0).serverCityName) + if (modelData.isMultiHop) { + return VPNController.changeServer(modelData.connection[1].countryCode, modelData.connection[1].serverCityName, modelData.connection[0].countryCode, modelData.connection[0].serverCityName) } - return VPNController.changeServer(connection.get(0).countryCode, connection.get(0).serverCityName) + return VPNController.changeServer(modelData.connection[0].countryCode, modelData.connection[0].serverCityName) } @@ -145,7 +142,7 @@ ColumnLayout { id: serverLabel Layout.fillWidth: true Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - serversList: connection + serversList: modelData.connection } } } @@ -157,7 +154,7 @@ ColumnLayout { Layout.preferredHeight: 1 Layout.alignment: Qt.AlignHCenter color: VPNTheme.colors.grey10 - visible: repeaterModel.count > 0 + visible: root.recentConnectionsModel.length > 0 } } From f1122cd91322a88ed4dab229005f0e9a838a8cc1 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 28 Oct 2022 16:49:07 +0200 Subject: [PATCH 79/85] Add `set -e` to all the bash scripts - VPN-3081 (#4749) --- scripts/README.md | 2 -- scripts/linux/script.sh | 2 ++ scripts/macos/scope_only_change.sh | 34 ------------------------------ scripts/tests/functional_tests.sh | 1 - scripts/utils/commons.sh | 1 - 5 files changed, 2 insertions(+), 38 deletions(-) delete mode 100644 scripts/macos/scope_only_change.sh diff --git a/scripts/README.md b/scripts/README.md index c4bf386c2a8..03fbc817a6b 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -32,10 +32,8 @@ TODO: unify build.sh and script.sh (or remove build.sh) - ./macos/utils/xcode_patcher.rb - tool to patch xcode project - ./macos/utils/commons.sh - common functions for cross-platform scrips - ./macos/import_pkg_resources.py - configure resources for the PKG generation -- ./macos/scope_only_change.sh - runs tests when needed TODO: -1. scope_only_change.sh should be croll-platform! Do we actually use it? 2. remove/merge/move macos_build.sh # Windows-specific scripts diff --git a/scripts/linux/script.sh b/scripts/linux/script.sh index db039e67ff0..97a75c0b653 100755 --- a/scripts/linux/script.sh +++ b/scripts/linux/script.sh @@ -4,6 +4,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +set -e + . $(dirname $0)/../utils/commons.sh REVISION=1 diff --git a/scripts/macos/scope_only_change.sh b/scripts/macos/scope_only_change.sh deleted file mode 100644 index f585ca44fd8..00000000000 --- a/scripts/macos/scope_only_change.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -lottie="$(git diff lottie/ | wc -l)" -qml_src="$(git diff src/ui | wc -l)" -qml_neb="$(git diff nebula/ui | wc -l)" -cpp="$(git diff src/ | wc -l)" -changeCount=$(($lottie + $qml_neb + $qml_src + $cpp)) - -if [ $lottie -gt 0 ]; then - echo "number of changes in lottie code: $lottie" - echo "running lottie unit tests" - ./scripts/tests/lottie_tests.sh -fi - -if [ $cpp -gt 0 ]; then - echo "number of changes in Main C++ code: $cpp" - echo "running unit tests" - ./scripts/tests/lottie_tests.sh -fi - -if [[ $qml_src -gt 0 || $qml_neb -gt 0 ]]; then - echo "number of changes in qml src code: $qml_src" - echo "number of changes in qml nebula code: $qml_neb" - echo "run qml tests" - ./scripts/tests/qml_tests.sh -fi - -if [ $changeCount -lt 1 ]; then - echo "There are no changes in the src, nebula or qml ui" -fi diff --git a/scripts/tests/functional_tests.sh b/scripts/tests/functional_tests.sh index 5525d44c2b9..27d52302f6f 100755 --- a/scripts/tests/functional_tests.sh +++ b/scripts/tests/functional_tests.sh @@ -30,4 +30,3 @@ else runTest "$i" done fi - diff --git a/scripts/utils/commons.sh b/scripts/utils/commons.sh index 1803bde1ed4..d8935100ca3 100755 --- a/scripts/utils/commons.sh +++ b/scripts/utils/commons.sh @@ -52,4 +52,3 @@ die() { exit 1 } - From e6c45e88407d3f4d61a2f473154bebc789e02bcf Mon Sep 17 00:00:00 2001 From: Florian Zia Date: Fri, 28 Oct 2022 21:52:54 +0200 Subject: [PATCH 80/85] chore: Add theme for red text link buttons (#4752) --- nebula/ui/components/VPNCancelButton.qml | 2 +- nebula/ui/components/VPNSignOut.qml | 2 +- nebula/ui/themes/themes.js | 9 +++++++++ src/ui/deleteAccount/ViewDeleteAccountRequest.qml | 2 +- .../ViewSubscriptionManagement.qml | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/nebula/ui/components/VPNCancelButton.qml b/nebula/ui/components/VPNCancelButton.qml index 1f09d276acc..e8aa9b52d4d 100644 --- a/nebula/ui/components/VPNCancelButton.qml +++ b/nebula/ui/components/VPNCancelButton.qml @@ -12,5 +12,5 @@ import components 0.1 VPNLinkButton { labelText: VPNl18n.InAppSupportWorkflowSupportSecondaryActionText // "Cancel" fontName: VPNTheme.theme.fontBoldFamily - linkColor: VPNTheme.theme.redButton + linkColor: VPNTheme.theme.redLinkButton } diff --git a/nebula/ui/components/VPNSignOut.qml b/nebula/ui/components/VPNSignOut.qml index e03afc5f429..af0bff7c0b5 100644 --- a/nebula/ui/components/VPNSignOut.qml +++ b/nebula/ui/components/VPNSignOut.qml @@ -11,7 +11,7 @@ VPNFooterLink { //% "Sign out" labelText: qsTrId("vpn.main.signOut2") fontName: VPNTheme.theme.fontBoldFamily - linkColor: VPNTheme.theme.redButton + linkColor: VPNTheme.theme.redLinkButton onClicked: () => { VPNController.logout(); } diff --git a/nebula/ui/themes/themes.js b/nebula/ui/themes/themes.js index df754e81444..c142e0467d7 100644 --- a/nebula/ui/themes/themes.js +++ b/nebula/ui/themes/themes.js @@ -203,6 +203,15 @@ theme.redButton = { 'focusBorder': theme.redPressed, }; +theme.redLinkButton = { + 'defaultColor': theme.redHovered, + 'buttonHovered': theme.redPressed, + 'buttonPressed': theme.redPressed, + 'buttonDisabled': theme.redDisabled, + 'focusOutline': theme.redfocusOutline, + 'focusBorder': theme.redPressed, +}; + theme.removeDeviceBtn = { 'defaultColor': theme.bgColorTransparent, 'buttonHovered': '#FFDFE7', diff --git a/src/ui/deleteAccount/ViewDeleteAccountRequest.qml b/src/ui/deleteAccount/ViewDeleteAccountRequest.qml index 7a57121389d..e89ea691cd6 100644 --- a/src/ui/deleteAccount/ViewDeleteAccountRequest.qml +++ b/src/ui/deleteAccount/ViewDeleteAccountRequest.qml @@ -102,7 +102,7 @@ VPNInAppAuthenticationBase { fontName: VPNTheme.theme.fontBoldFamily // Cancel labelText: VPNl18n.InAppSupportWorkflowSupportSecondaryActionText - linkColor: VPNTheme.theme.redButton + linkColor: VPNTheme.theme.redLinkButton onClicked: { cancelAuthenticationFlow(); } diff --git a/src/ui/screens/settings/ViewSubscriptionManagement/ViewSubscriptionManagement.qml b/src/ui/screens/settings/ViewSubscriptionManagement/ViewSubscriptionManagement.qml index a1480cb15b4..d94df165438 100644 --- a/src/ui/screens/settings/ViewSubscriptionManagement/ViewSubscriptionManagement.qml +++ b/src/ui/screens/settings/ViewSubscriptionManagement/ViewSubscriptionManagement.qml @@ -107,7 +107,7 @@ VPNViewBase { objectName: "accountDeletionButton" fontName: VPNTheme.theme.fontBoldFamily labelText: VPNl18n.DeleteAccountButtonLabel - linkColor: VPNTheme.theme.redButton + linkColor: VPNTheme.theme.redLinkButton visible: VPNFeatureList.get("accountDeletion").isSupported onClicked: { From 1f0c7f504ac2b1c21028f1bb99aa85f08ef541c2 Mon Sep 17 00:00:00 2001 From: Florian Zia Date: Fri, 28 Oct 2022 21:53:16 +0200 Subject: [PATCH 81/85] Fix user feedback icon ui states (#4684) --- .../GiveFeedbackRadioDelegate.qml | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/ui/screens/getHelp/giveFeedback/GiveFeedbackRadioDelegate.qml b/src/ui/screens/getHelp/giveFeedback/GiveFeedbackRadioDelegate.qml index d99b62f7f0f..2615d8c4d76 100644 --- a/src/ui/screens/getHelp/giveFeedback/GiveFeedbackRadioDelegate.qml +++ b/src/ui/screens/getHelp/giveFeedback/GiveFeedbackRadioDelegate.qml @@ -14,7 +14,7 @@ import compat 0.1 RadioDelegate { property var value property alias iconSource: img.source - property var heightWidth: 30 + property var iconSize: 30 property var uiState: VPNTheme.theme.uiState id: radio @@ -23,18 +23,31 @@ RadioDelegate { implicitWidth: VPNTheme.theme.rowHeight activeFocusOnTab: true focus: true + Component.onCompleted: { state = uiState.stateDefault } - indicator: VPNIcon { - id: img + indicator: Item { anchors.centerIn: parent - antialiasing: true - sourceSize.height: heightWidth - sourceSize.width: heightWidth - } + height: iconSize + width: iconSize + VPNIcon { + id: img + antialiasing: true + sourceSize.height: parent.height + sourceSize.width: parent.width + } + + VPNColorOverlay { + anchors.fill: parent + source: img + color: VPNTheme.colors.blue + visible: radio.checked || radio.state === uiState.stateHovered + || radio.state === uiState.statePressed + } + } Keys.onPressed: event => { if (event.key === Qt.Key_Return || event.key === Qt.Key_Space) @@ -46,28 +59,27 @@ RadioDelegate { radio.clicked(); } - background: VPNFocusOutline { - opacity: radio.checked || radio.activeFocus ? 1 : 0 - color: VPNTheme.theme.transparent - border.width: 4 - border.color: VPNTheme.theme.blueFocusOutline - anchors.margins: 2 - radius: height + anchors.margins: VPNTheme.theme.focusBorderWidth + + border.color: VPNTheme.theme.blueFocusOutline + border.width: VPNTheme.theme.focusBorderWidth * 2 + color: VPNTheme.theme.transparent + opacity: radio.checked || radio.activeFocus ? 1 : 0 + radius: height - Behavior on opacity { - PropertyAnimation { - duration: 100 - } + Behavior on opacity { + PropertyAnimation { + duration: 100 } } + } VPNMouseArea { id: mouseArea - onPressedChanged: if (pressed) radio.forceActiveFocus() onMouseAreaClicked: function() { + radio.forceActiveFocus(); radio.checked = !radio.checked; } } - } From 40710b0033115dca4025a7576eafae8d10c70163 Mon Sep 17 00:00:00 2001 From: Julien Cristau Date: Fri, 28 Oct 2022 23:57:46 +0200 Subject: [PATCH 82/85] Use the production balrog server (and a test channel) in testing mode (#4741) Instead of using the staging balrog instance, always use the production instance, so that staging is no longer on the critical path for releases. https://mozilla-hub.atlassian.net/browse/RELENG-797 --- src/constants.h | 10 ++++------ src/update/balrog.cpp | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/constants.h b/src/constants.h index 42d16e7ef05..4df80d65869 100644 --- a/src/constants.h +++ b/src/constants.h @@ -120,12 +120,10 @@ PRODBETAEXPR(const char*, fxaUrl, "https://accounts.firefox.com", PRODBETAEXPR( const char*, balrogUrl, "https://aus5.mozilla.org/json/1/FirefoxVPN/%1/%2/release/update.json", - "https://stage.balrog.nonprod.cloudops.mozgcp.net/json/1/FirefoxVPN/%1/%2/" - "release-cdntest/update.json"); -PRODBETAEXPR( - const char*, balrogRootCertFingerprint, - "97e8ba9cf12fb3de53cc42a4e6577ed64df493c247b414fea036818d3823560e", - "3c01446abe9036cea9a09acaa3a520ac628f20a7ae32ce861cb2efb70fa0c745"); + "https://aus5.mozilla.org/json/1/FirefoxVPN/%1/%2/release-cdntest/" + "update.json"); +constexpr const char* AUTOGRAPH_ROOT_CERT_FINGERPRINT = + "97e8ba9cf12fb3de53cc42a4e6577ed64df493c247b414fea036818d3823560e"; PRODBETAEXPR(const char*, relayUrl, "https://relay.firefox.com", "https://stage.fxprivaterelay.nonprod.cloudops.mozgcp.net"); diff --git a/src/update/balrog.cpp b/src/update/balrog.cpp index eb57b074e16..490184461e4 100644 --- a/src/update/balrog.cpp +++ b/src/update/balrog.cpp @@ -234,7 +234,7 @@ bool Balrog::validateSignature(const QByteArray& x5uData, QByteArray updateDataCopy = updateData; GoString updateDataGo{updateDataCopy.constData(), updateDataCopy.length()}; - QByteArray rootHashCopy = Constants::balrogRootCertFingerprint(); + QByteArray rootHashCopy = Constants::AUTOGRAPH_ROOT_CERT_FINGERPRINT; rootHashCopy = rootHashCopy.toUpper(); GoString rootHashGo{rootHashCopy.constData(), rootHashCopy.length()}; From ea5f67ae7932f22a8c5a631ba93f7378221e3f63 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 31 Oct 2022 12:06:23 +0100 Subject: [PATCH 83/85] Better logout procedure - VPN-3037 (#4751) Running the removal-device together with the reset() operation means that, if something goes wrong, at the next execution we show the initial screen immediately. --- src/mozillavpn.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/mozillavpn.cpp b/src/mozillavpn.cpp index fb25ce1fe25..88ba2590d1d 100644 --- a/src/mozillavpn.cpp +++ b/src/mozillavpn.cpp @@ -859,8 +859,18 @@ void MozillaVPN::logout() { } if (m_private->m_deviceModel.hasCurrentDevice(keys())) { - TaskScheduler::scheduleTask(new TaskRemoveDevice(keys()->publicKey())); + TaskScheduler::scheduleTask(new TaskGroup( + {new TaskRemoveDevice(keys()->publicKey()), + // Immediately after the scheduling of the device removal, we want to + // delete the session token, so that, in case the app is terminated, at + // the next execution we go back to the init screen. + new TaskFunction([this]() { reset(false); })})); + + // In case the app is closed even before scheduling the previous TaskGroup, + // removing the key we will enforce a new authentication at the first + // TaskAccount execution. m_private->m_keys.forgetKeys(); + return; } TaskScheduler::scheduleTask(new TaskFunction([this]() { reset(false); })); From 0ebce4053e693f1cfbe4da47040c86ccea0029e1 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 31 Oct 2022 14:39:56 +0100 Subject: [PATCH 84/85] Server label updated (#4762) --- translations/servers.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/translations/servers.json b/translations/servers.json index b02da9ae050..38cdbbe41a7 100644 --- a/translations/servers.json +++ b/translations/servers.json @@ -233,10 +233,10 @@ "en": "São Paulo", "en_CA": "São Paulo", "en_GB": "São Paulo", - "es_AR": "San Pablo", - "es_CL": "San Pablo", - "es_ES": "San Pablo", - "es_MX": "San Pablo", + "es_AR": "São Paulo", + "es_CL": "São Paulo", + "es_ES": "São Paulo", + "es_MX": "São Paulo", "fi": "São Paulo", "fr": "São Paulo", "fy_NL": "São Paulo", @@ -969,7 +969,7 @@ "countryCode": "it", "languages": { "co": "Italia", - "cy": "Yr Eidal", + "cy": "yr Eidal", "de": "Italien", "dsb": "Italska", "el": "Ιταλία", @@ -1396,7 +1396,7 @@ "ru": "Окленд", "sq": "Okland", "uk": "Окленд", - "zh_CN": "奧克蘭都會區", + "zh_CN": "奧克蘭", "zh_TW": "奧克蘭" }, "wikiDataID": "Q37100" From 88dbef3da80b672d1367c24d95b019ce5ba4961a Mon Sep 17 00:00:00 2001 From: Sebastian Streich Date: Mon, 31 Oct 2022 14:41:00 +0100 Subject: [PATCH 85/85] Taskcluster: Check compat with "next" QT (#4745) * WIP: check compat with next QT * fix task name * Move reminders forward, nothing changed --- src/commands/commandui.cpp | 4 ++-- src/connectionbenchmark/benchmarktasktransfer.cpp | 2 +- taskcluster/ci/build/android.yml | 13 +++++++++++++ taskcluster/ci/docker-image/kind.yml | 7 +++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/commands/commandui.cpp b/src/commands/commandui.cpp index eb11d69eaea..013aaf14e00 100644 --- a/src/commands/commandui.cpp +++ b/src/commands/commandui.cpp @@ -199,8 +199,8 @@ int CommandUI::run(QStringList& tokens) { // https://bugreports.qt.io/browse/QTBUG-82617 // Currently there is a crash happening on exit with Huawei devices. // Until this is fixed, setting this variable is the "official" workaround. - // We certainly should look at this once 6.4 is out. -# if QT_VERSION >= 0x060400 + // We certainly should look at this once 6.6 is out. +# if QT_VERSION >= 0x060600 # error We have forgotten to remove this Huawei hack! # endif if (AndroidUtils::GetManufacturer() == "Huawei") { diff --git a/src/connectionbenchmark/benchmarktasktransfer.cpp b/src/connectionbenchmark/benchmarktasktransfer.cpp index 9df5188947b..05063cff5bc 100644 --- a/src/connectionbenchmark/benchmarktasktransfer.cpp +++ b/src/connectionbenchmark/benchmarktasktransfer.cpp @@ -53,7 +53,7 @@ void BenchmarkTaskTransfer::handleState(BenchmarkTask::State state) { m_dnsLookup.lookup(); #endif -#if QT_VERSION >= 0x060400 +#if QT_VERSION >= 0x060500 # error Check if QT added support for QDnsLookup::lookup() on Android #endif diff --git a/taskcluster/ci/build/android.yml b/taskcluster/ci/build/android.yml index 47e1f4fbf04..0d9f8288b6a 100644 --- a/taskcluster/ci/build/android.yml +++ b/taskcluster/ci/build/android.yml @@ -17,6 +17,19 @@ task-defaults: use-caches: true cwd: '{checkout}' +android-qt-next/debug: + description: "Android Next QT Build (arm64-v8a)" + treeherder: + platform: android/arm64-v8a + symbol: NEXT + worker: + docker-image: {in-tree: android-qt-next} + run: + command: ./taskcluster/scripts/build/android_build_debug.sh arm64-v8a + release-artifacts: + # APK Artifacts expects file to be in /builds/worker/artifacts/ + - mozillavpn-arm64-v8a-debug.apk + # Debug Builds: android-arm64/debug: description: "Android Debug (arm64-v8a)" diff --git a/taskcluster/ci/docker-image/kind.yml b/taskcluster/ci/docker-image/kind.yml index 6b8a0733b3d..4d01ea46c67 100644 --- a/taskcluster/ci/docker-image/kind.yml +++ b/taskcluster/ci/docker-image/kind.yml @@ -62,3 +62,10 @@ tasks: args: ANDROID_ARCH: android_x86_64 QT_VERSION: 6.2.4 + android-qt-next: + parent: base + symbol: I(android_arm64_v8a_next) + definition: android-qt6-build + args: + ANDROID_ARCH: android_arm64_v8a + QT_VERSION: 6.4.0