From a9737131cf31864fe2aaa19adbb7215287e352e9 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 11 May 2022 14:57:04 -0400 Subject: [PATCH] Remove webview auth code for iOS and Android (#3502) * Remove iOS webview auth code * Remove android webview auth code --- .../firefox/vpn/qt/PackageManagerHelper.java | 65 ----- .../mozilla/firefox/vpn/qt/VPNWebView.java | 166 ------------ src/authenticationlistener.cpp | 13 +- src/commands/commandui.cpp | 3 - src/mozillavpn.h | 4 - .../android/androidauthenticationlistener.cpp | 54 ---- .../android/androidauthenticationlistener.h | 23 -- .../android/androidauthenticationview.qml | 105 -------- src/platforms/android/androidutils.cpp | 58 ---- src/platforms/android/androidutils.h | 19 -- src/platforms/android/androidwebview.cpp | 251 ------------------ src/platforms/android/androidwebview.h | 63 ----- src/platforms/ios/iosauthenticationlistener.h | 24 -- .../ios/iosauthenticationlistener.mm | 153 ----------- src/qmake/platforms/android.pri | 6 - src/qmake/platforms/ios.pri | 5 - src/ui/main.qml | 8 - src/ui/ui.qrc | 1 - 18 files changed, 4 insertions(+), 1017 deletions(-) delete mode 100644 android/src/org/mozilla/firefox/vpn/qt/VPNWebView.java delete mode 100644 src/platforms/android/androidauthenticationlistener.cpp delete mode 100644 src/platforms/android/androidauthenticationlistener.h delete mode 100644 src/platforms/android/androidauthenticationview.qml delete mode 100644 src/platforms/android/androidwebview.cpp delete mode 100644 src/platforms/android/androidwebview.h delete mode 100644 src/platforms/ios/iosauthenticationlistener.h delete mode 100644 src/platforms/ios/iosauthenticationlistener.mm diff --git a/android/src/org/mozilla/firefox/vpn/qt/PackageManagerHelper.java b/android/src/org/mozilla/firefox/vpn/qt/PackageManagerHelper.java index 07ad228d83..e71a463fcd 100644 --- a/android/src/org/mozilla/firefox/vpn/qt/PackageManagerHelper.java +++ b/android/src/org/mozilla/firefox/vpn/qt/PackageManagerHelper.java @@ -18,7 +18,6 @@ import android.net.Uri; import android.os.Build; import android.util.Log; -import android.webkit.WebView; import org.json.JSONException; import org.json.JSONObject; @@ -31,10 +30,6 @@ // Gets used by /platforms/android/androidAppListProvider.cpp public class PackageManagerHelper { final static String TAG = "PackageManagerHelper"; - final static int MIN_CHROME_VERSION = 65; - - final static List CHROME_BROWSERS = Arrays.asList( - new String[] {"com.google.android.webview", "com.android.webview", "com.google.chrome"}); private static String getAllAppNames(Context ctx) { JSONObject output = new JSONObject(); @@ -126,64 +121,4 @@ private static List getBrowserIDs(PackageManager pm) { } return browsers; } - - // Gets called in AndroidAuthenticationListener; - public static boolean isWebViewSupported(Context ctx) { - Log.v(TAG, "Checking if installed Webview is compatible with FxA"); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - // The default Webview is able do to FXA - return true; - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - PackageInfo pi = WebView.getCurrentWebViewPackage(); - if (CHROME_BROWSERS.contains(pi.packageName)) { - return isSupportedChromeBrowser(pi); - } - return isNotAncientBrowser(pi); - } - - // Before O the webview is hardcoded, but we dont know which package it is. - // Check if com.google.android.webview is installed - PackageManager pm = ctx.getPackageManager(); - try { - PackageInfo pi = pm.getPackageInfo("com.google.android.webview", 0); - return isSupportedChromeBrowser(pi); - } catch (PackageManager.NameNotFoundException e) { - } - // Otherwise check com.android.webview - try { - PackageInfo pi = pm.getPackageInfo("com.android.webview", 0); - return isSupportedChromeBrowser(pi); - } catch (PackageManager.NameNotFoundException e) { - } - Log.e(TAG, "Android System WebView is not found"); - // Giving up :( - return false; - } - - private static boolean isSupportedChromeBrowser(PackageInfo pi) { - Log.d(TAG, "Checking Chrome Based Browser: " + pi.packageName); - Log.d(TAG, "version name: " + pi.versionName); - Log.d(TAG, "version code: " + pi.versionCode); - try { - String versionCode = pi.versionName.split(Pattern.quote(" "))[0]; - String majorVersion = versionCode.split(Pattern.quote("."))[0]; - int version = Integer.parseInt(majorVersion); - return version >= MIN_CHROME_VERSION; - } catch (Exception e) { - Log.e(TAG, "Failed to check Chrome Version Code " + pi.versionName); - return false; - } - } - - private static boolean isNotAncientBrowser(PackageInfo pi) { - // Not a google chrome - So the version name is worthless - // Lets just make sure the WebView - // used is not ancient ==> Was updated in at least the last 365 days - Log.d(TAG, "Checking Chrome Based Browser: " + pi.packageName); - Log.d(TAG, "version name: " + pi.versionName); - Log.d(TAG, "version code: " + pi.versionCode); - double oneYearInMillis = 31536000000L; - return pi.lastUpdateTime > (System.currentTimeMillis() - oneYearInMillis); - } } diff --git a/android/src/org/mozilla/firefox/vpn/qt/VPNWebView.java b/android/src/org/mozilla/firefox/vpn/qt/VPNWebView.java deleted file mode 100644 index 4bbbf046d0..0000000000 --- a/android/src/org/mozilla/firefox/vpn/qt/VPNWebView.java +++ /dev/null @@ -1,166 +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/. */ - -package org.mozilla.firefox.vpn.qt; - -import android.app.Activity; -import android.graphics.Bitmap; -import android.os.RemoteException; -import android.view.Window; -import android.view.WindowManager; -import android.webkit.WebSettings; -import android.webkit.WebSettings.PluginState; -import android.webkit.WebStorage; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import android.webkit.CookieManager; - -import android.util.Log; - -import com.android.installreferrer.api.InstallReferrerClient; -import com.android.installreferrer.api.InstallReferrerStateListener; -import com.android.installreferrer.api.ReferrerDetails; - -import java.lang.Runnable; -import java.lang.String; -import java.util.concurrent.Semaphore; - -public class VPNWebView -{ - private static final String TAG = "VPNWebView"; - - private final Activity m_activity; - private WebView m_webView = null; - private InstallReferrerClient m_referrer; - - private native void nativeOnPageStarted(String url, Bitmap icon); - private native void nativeOnError(int errorCode, String description, String url); - - private class VPNWebViewClient extends WebViewClient - { - VPNWebViewClient() { super(); } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) - { - return false; - } - - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - // While the login view is open, disable the ability to do screenshots. - m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); - - super.onPageStarted(view, url, favicon); - nativeOnPageStarted(url, favicon); - } - - @Override - public void onReceivedError(WebView view, - int errorCode, - String description, - String url) - { - super.onReceivedError(view, errorCode, description, url); - nativeOnError(errorCode, description, url); - } - } - - public VPNWebView(final Activity activity, final String userAgent) - { - Log.v(TAG, "created - userAgent: " + userAgent); - - m_activity = activity; - - m_referrer = InstallReferrerClient.newBuilder(activity).build(); - final Semaphore sem = new Semaphore(0); - m_activity.runOnUiThread(new Runnable() { - @Override - public void run() { - m_webView = new WebView(m_activity); - WebSettings webSettings = m_webView.getSettings(); - - Log.e(TAG, "UA" + webSettings.getUserAgentString()); - - webSettings.setAllowFileAccess(false); - webSettings.setDatabaseEnabled(true); - webSettings.setDomStorageEnabled(true); - webSettings.setJavaScriptEnabled(true); - webSettings.setGeolocationEnabled(false); - webSettings.setBuiltInZoomControls(false); - webSettings.setPluginState(PluginState.ON); - - m_webView.getSettings().setUserAgentString(userAgent); - - m_webView.setWebViewClient((WebViewClient)new VPNWebViewClient()); - sem.release(); - } - }); - - try { - sem.acquire(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void setUrl(final String url) - { - Log.v(TAG, "load url: " + url); - - // Try to Get a Referrer and then Load the URL with it - m_referrer.startConnection(new InstallReferrerStateListener() { - @Override - public void onInstallReferrerSetupFinished(int responseCode) { - String referrerValue =""; - if( responseCode == InstallReferrerClient.InstallReferrerResponse.OK){ - try { - ReferrerDetails response = m_referrer.getInstallReferrer(); - referrerValue = "&" + response.getInstallReferrer(); - Log.v(TAG, "Recived - referrer: " + referrerValue); - - } catch (RemoteException e) { - Log.v(TAG, "Failed - referrer - " + e.toString()); - } - }else{ - Log.v(TAG, "Failed - referrer not available "); - } - m_referrer.endConnection(); - - // We now have a referrer - Load the URI - final String refUrl = url + referrerValue; - nativeOnPageStarted(refUrl, null); - m_activity.runOnUiThread(new Runnable() { - @Override - public void run() { m_webView.loadUrl(refUrl); } - }); - } - @Override - public void onInstallReferrerServiceDisconnected() {} - }); - } - - public WebView getWebView() - { - return m_webView; - } - - public void destroy() - { - Log.v(TAG, "bye!"); - m_activity.runOnUiThread(new Runnable() { - @Override - public void run() { - m_webView.destroy(); - m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); - } - }); - } - public void clearStorage(){ - m_webView.clearCache(true); - CookieManager.getInstance().removeAllCookies(null); - CookieManager.getInstance().flush(); - WebStorage.getInstance().deleteAllData(); - } -} diff --git a/src/authenticationlistener.cpp b/src/authenticationlistener.cpp index a9b6098f53..c396f85d62 100644 --- a/src/authenticationlistener.cpp +++ b/src/authenticationlistener.cpp @@ -10,11 +10,7 @@ #include "networkmanager.h" #include "networkrequest.h" -#if defined(MVPN_ANDROID) -# include "platforms/android/androidauthenticationlistener.h" -#elif defined(MVPN_IOS) -# include "platforms/ios/iosauthenticationlistener.h" -#elif defined(MVPN_MACOS) +#if defined(MVPN_MACOS) # include "platforms/macos/macosauthenticationlistener.h" #elif defined(MVPN_WASM) # include "platforms/wasm/wasmauthenticationlistener.h" @@ -35,10 +31,9 @@ AuthenticationListener* AuthenticationListener::create( QObject* parent, MozillaVPN::AuthenticationType authenticationType) { switch (authenticationType) { case MozillaVPN::AuthenticationInBrowser: -#if defined(MVPN_ANDROID) - return new AndroidAuthenticationListener(parent); -#elif defined(MVPN_IOS) - return new IOSAuthenticationListener(parent); +#if defined(MVPN_ANDROID) or defined(MVPN_IOS) + logger.error() << "Something went totally wrong"; + Q_ASSERT(false); #elif defined(MVPN_MACOS) return new MacosAuthenticationListener(parent); #elif defined(MVPN_WASM) diff --git a/src/commands/commandui.cpp b/src/commands/commandui.cpp index e3f8b716f5..6e8e60e03e 100644 --- a/src/commands/commandui.cpp +++ b/src/commands/commandui.cpp @@ -51,7 +51,6 @@ #ifdef MVPN_ANDROID # include "platforms/android/androidutils.h" -# include "platforms/android/androidwebview.h" #endif #ifndef Q_OS_WIN @@ -437,8 +436,6 @@ int CommandUI::run(QStringList& tokens) { QQmlEngine::setObjectOwnership(obj, QQmlEngine::CppOwnership); return obj; }); - - qmlRegisterType("Mozilla.VPN", 1, 0, "VPNAndroidWebView"); #endif if (FeatureInAppPurchase::instance()->isSupported()) { diff --git a/src/mozillavpn.h b/src/mozillavpn.h index 23d62e5ae7..ed43b86fad 100644 --- a/src/mozillavpn.h +++ b/src/mozillavpn.h @@ -414,10 +414,6 @@ class MozillaVPN final : public QObject { void aboutToQuit(); - // This is used only on android but, if we use #ifdef MVPN_ANDROID, qml engine - // complains... - void loadAndroidAuthenticationView(); - void logsReady(const QString& logs); void currentViewChanged(); diff --git a/src/platforms/android/androidauthenticationlistener.cpp b/src/platforms/android/androidauthenticationlistener.cpp deleted file mode 100644 index bb79d29a33..0000000000 --- a/src/platforms/android/androidauthenticationlistener.cpp +++ /dev/null @@ -1,54 +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 "androidauthenticationlistener.h" -#include "leakdetector.h" -#include "logger.h" -#include "mozillavpn.h" -#include "platforms/android/androidutils.h" -#include "tasks/authenticate/desktopauthenticationlistener.h" -#include -#include -#include - -namespace { -Logger logger(LOG_ANDROID, "AndroidAuthenticationListener"); -} - -AndroidAuthenticationListener::AndroidAuthenticationListener(QObject* parent) - : AuthenticationListener(parent) { - MVPN_COUNT_CTOR(AndroidAuthenticationListener); - logger.debug() << "Android authentication listener"; -} - -AndroidAuthenticationListener::~AndroidAuthenticationListener() { - MVPN_COUNT_DTOR(AndroidAuthenticationListener); -} - -void AndroidAuthenticationListener::start(Task* task, - const QString& codeChallenge, - const QString& codeChallengeMethod, - const QString& emailAddress) { - logger.debug() << "Authenticationlistener initialize"; - - QUrl url(createAuthenticationUrl(codeChallenge, codeChallengeMethod, - emailAddress)); - - QJniObject activity = AndroidUtils::getActivity(); - jboolean supported = QJniObject::callStaticMethod( - "org/mozilla/firefox/vpn/qt/PackageManagerHelper", "isWebViewSupported", - "(Landroid/content/Context;)Z", activity.object()); - if (supported) { - AndroidUtils::instance()->startAuthentication(this, url); - return; - } - DesktopAuthenticationListener* legacyAuth; - legacyAuth = new DesktopAuthenticationListener(this); - legacyAuth->start(task, codeChallenge, codeChallengeMethod, emailAddress); - - connect(legacyAuth, &AuthenticationListener::completed, this, - &AndroidAuthenticationListener::completed); - connect(legacyAuth, &AuthenticationListener::failed, this, - &AndroidAuthenticationListener::failed); -} diff --git a/src/platforms/android/androidauthenticationlistener.h b/src/platforms/android/androidauthenticationlistener.h deleted file mode 100644 index 0754975682..0000000000 --- a/src/platforms/android/androidauthenticationlistener.h +++ /dev/null @@ -1,23 +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 ANDROIDAUTHENTICATIONLISTENER_H -#define ANDROIDAUTHENTICATIONLISTENER_H - -#include "authenticationlistener.h" -#include - -class AndroidAuthenticationListener final : public AuthenticationListener { - Q_DISABLE_COPY_MOVE(AndroidAuthenticationListener) - - public: - AndroidAuthenticationListener(QObject* parent); - ~AndroidAuthenticationListener(); - - void start(Task* task, const QString& codeChallenge, - const QString& codeChallengeMethod, - const QString& emailAddress) override; -}; - -#endif // ANDROIDAUTHENTICATIONLISTENER_H diff --git a/src/platforms/android/androidauthenticationview.qml b/src/platforms/android/androidauthenticationview.qml deleted file mode 100644 index 32eee14f6b..0000000000 --- a/src/platforms/android/androidauthenticationview.qml +++ /dev/null @@ -1,105 +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 QtQuick.Controls 2.15 -import QtWebView 1.15 - -import Mozilla.VPN 1.0 -import components 0.1 - -Item { - Item { - id: menuBar - - width: parent.width - height: 56 - // Ensure that menu is on top of possible scrollable - // content. - z: 1 - - Rectangle { - id: menuBackground - color: VPNTheme.theme.bgColor - y: 0 - width: parent.width - height: 55 - } - - VPNIconButton { - id: iconButton - - onClicked: { - VPNAndroidUtils.abortAuthentication(); - authWebview.clearStorage(); - mainStackView.pop(StackView.Immediate); - } - - anchors.top: parent.top - anchors.left: parent.left - anchors.topMargin: VPNTheme.theme.windowMargin / 2 - anchors.leftMargin: VPNTheme.theme.windowMargin / 2 - - accessibleName: qsTrId("vpn.main.back") - - Image { - id: backImage - - source: "qrc:/nebula/resources/close-dark.svg" - sourceSize.width: VPNTheme.theme.iconSize - fillMode: Image.PreserveAspectFit - anchors.centerIn: iconButton - } - } - - VPNBoldLabel { - id: title - - anchors.top: menuBar.top - anchors.centerIn: menuBar - - //% "Authentication" - text: qsTrId("vpn.android.authentication") - } - - Rectangle { - color: "#0C0C0D0A" - y: 55 - width: parent.width - height: 1 - } - } - - VPNAndroidWebView { - id: authWebview - url: VPNAndroidUtils.url - - height: parent.height - menuBar.height - width: parent.width - y: menuBar.height - - onPageStarted: { - if (VPNAndroidUtils.maybeCompleteAuthentication(url)) { - mainStackView.pop(StackView.Immediate); - } - } - - onFailure: { - VPNAndroidUtils.abortAuthentication(); - mainStackView.pop(StackView.Immediate) - } - } - - Component.onCompleted: VPNCloseEventHandler.addView(menuBar) - - Connections { - target: VPNCloseEventHandler - function onGoBack(item) { - if (item === menuBar) { - VPNAndroidUtils.abortAuthentication(); - mainStackView.pop(StackView.Immediate); - } - } - } -} diff --git a/src/platforms/android/androidutils.cpp b/src/platforms/android/androidutils.cpp index dbde14d05b..ebebe63775 100644 --- a/src/platforms/android/androidutils.cpp +++ b/src/platforms/android/androidutils.cpp @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "androidutils.h" -#include "androidauthenticationlistener.h" #include "constants.h" #include "leakdetector.h" #include "logger.h" @@ -81,63 +80,6 @@ AndroidUtils::~AndroidUtils() { s_instance = nullptr; } -void AndroidUtils::startAuthentication(AuthenticationListener* listener, - const QUrl& url) { - logger.debug() << "Open the authentication view"; - - Q_ASSERT(!m_listener); - m_listener = listener; - - connect(listener, &QObject::destroyed, this, &AndroidUtils::resetListener); - - m_url = url; - emit urlChanged(); - - emit MozillaVPN::instance()->loadAndroidAuthenticationView(); -} - -bool AndroidUtils::maybeCompleteAuthentication(const QString& url) { - logger.debug() << "Maybe complete authentication"; - - Q_ASSERT(m_listener); - - QString apiUrl = NetworkRequest::apiBaseUrl(); - if (!url.startsWith(apiUrl)) { - return false; - } - - QUrl loadingUrl(url); - if (loadingUrl.path() == "/vpn/client/login/success") { - QUrlQuery query(loadingUrl.query()); - if (!query.hasQueryItem("code")) { - emit m_listener->failed(ErrorHandler::RemoteServiceError); - m_listener = nullptr; - return true; - } - - QString code = query.queryItemValue("code"); - emit m_listener->completed(code); - m_listener = nullptr; - return true; - } - - if (loadingUrl.path() == "/vpn/client/login/error") { - emit m_listener->failed(ErrorHandler::AuthenticationError); - m_listener = nullptr; - return true; - } - - return false; -} - -void AndroidUtils::abortAuthentication() { - logger.warning() << "Aborting authentication"; - - Q_ASSERT(m_listener); - emit m_listener->abortedByUser(); - m_listener = nullptr; -} - // static void AndroidUtils::dispatchToMainThread(std::function callback) { QTimer* timer = new QTimer(); diff --git a/src/platforms/android/androidutils.h b/src/platforms/android/androidutils.h index 654b2f2d27..8c5b4afc83 100644 --- a/src/platforms/android/androidutils.h +++ b/src/platforms/android/androidutils.h @@ -19,8 +19,6 @@ class AndroidUtils final : public QObject { Q_OBJECT Q_DISABLE_COPY_MOVE(AndroidUtils) - Q_PROPERTY(QUrl url READ url NOTIFY urlChanged) - public: static QString GetDeviceName(); @@ -33,14 +31,6 @@ class AndroidUtils final : public QObject { static AndroidUtils* instance(); - void startAuthentication(AuthenticationListener* listener, const QUrl& url); - - const QUrl& url() const { return m_url; } - - Q_INVOKABLE void abortAuthentication(); - - Q_INVOKABLE bool maybeCompleteAuthentication(const QString& url); - Q_INVOKABLE void openNotificationSettings(); static void dispatchToMainThread(std::function callback); @@ -57,18 +47,9 @@ class AndroidUtils final : public QObject { static void runOnAndroidThreadSync(const std::function runnable); - signals: - void urlChanged(); - private: AndroidUtils(QObject* parent); ~AndroidUtils(); - - void resetListener() { m_listener = nullptr; } - - private: - QUrl m_url; - AuthenticationListener* m_listener = nullptr; }; #endif // ANDROIDUTILS_H diff --git a/src/platforms/android/androidwebview.cpp b/src/platforms/android/androidwebview.cpp deleted file mode 100644 index 04599d2040..0000000000 --- a/src/platforms/android/androidwebview.cpp +++ /dev/null @@ -1,251 +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 "androidwebview.h" -#include "androidutils.h" -#include "errorhandler.h" -#include "leakdetector.h" -#include "logger.h" -#include "mozillavpn.h" -#include "networkmanager.h" - -#include -#include -#include -#include -#include -#include - -namespace { -Logger logger(LOG_ANDROID, "AndroidWebView"); -bool s_methodsInitialized = false; -AndroidWebView* s_instance = nullptr; -constexpr auto WEBVIEW_CLASS = "org/mozilla/firefox/vpn/qt/VPNWebView"; -} // namespace - -// static -void AndroidWebView::onPageStarted(JNIEnv* env, jobject thiz, jstring url, - jobject icon) { - Q_UNUSED(thiz); - Q_UNUSED(icon); - - QString pageUrl = AndroidUtils::getQStringFromJString(env, url); - logger.debug() << "Page started:" << pageUrl; - - AndroidUtils::dispatchToMainThread([pageUrl] { - Q_ASSERT(s_instance); - emit s_instance->pageStarted(pageUrl); - }); -} - -// static -void AndroidWebView::onError(JNIEnv* env, jobject thiz, jint errorCode, - jstring description, jstring url) { - Q_UNUSED(thiz); - Q_UNUSED(errorCode); - Q_UNUSED(url); - - QString errorDescription = - AndroidUtils::getQStringFromJString(env, description); - logger.error() << "Network failure:" << errorDescription; - - AndroidUtils::dispatchToMainThread([errorDescription] { - Q_ASSERT(s_instance); - s_instance->propagateError(ErrorHandler::NoConnectionError); - }); -} - -AndroidWebView::AndroidWebView(QQuickItem* parent) : QQuickItem(parent) { - MVPN_COUNT_CTOR(AndroidWebView); - - logger.debug() << "AndroidWebView created"; - - // We do not support multiple android webviews. No needs for now. - Q_ASSERT(!s_instance); - s_instance = this; - - if (!s_methodsInitialized) { - s_methodsInitialized = true; - - QJniEnvironment env; - jclass javaClass = env.findClass(WEBVIEW_CLASS); - if (!javaClass) { - propagateError(ErrorHandler::RemoteServiceError); - return; - } - - JNINativeMethod methods[]{ - {"nativeOnPageStarted", - "(Ljava/lang/String;Landroid/graphics/Bitmap;)V", - reinterpret_cast(onPageStarted)}, - {"nativeOnError", "(ILjava/lang/String;Ljava/lang/String;)V", - reinterpret_cast(onError)}, - }; - - env->RegisterNatives(javaClass, methods, - sizeof(methods) / sizeof(methods[0])); - } - - QString userAgentStr = NetworkManager::userAgent(); - QJniObject userAgent = QJniObject::fromString(userAgentStr); - Q_ASSERT(userAgent.isValid()); - - QJniObject activity = AndroidUtils::getActivity(); - Q_ASSERT(activity.isValid()); - - m_object = - QJniObject(WEBVIEW_CLASS, "(Landroid/app/Activity;Ljava/lang/String;)V", - activity.object(), userAgent.object()); - - if (!m_object.isValid()) { - propagateError(ErrorHandler::UnrecoverableError); - return; - } - - m_webView = - m_object.callObjectMethod("getWebView", "()Landroid/webkit/WebView;"); - if (!m_webView.isValid()) { - propagateError(ErrorHandler::UnrecoverableError); - return; - } - - m_window = QWindow::fromWinId(reinterpret_cast(m_webView.object())); - - connect(this, &QQuickItem::windowChanged, this, - &AndroidWebView::onWindowChanged); - connect(this, &QQuickItem::visibleChanged, this, - &AndroidWebView::onVisibleChanged); -} - -AndroidWebView::~AndroidWebView() { - MVPN_COUNT_DTOR(AndroidWebView); - - logger.debug() << "AndroidWebView destroyed"; - - Q_ASSERT(s_instance == this); - s_instance = nullptr; - - if (m_window) { - m_window->setVisible(false); - m_window->setParent(0); - delete m_window; - } - - if (m_object.isValid()) { - m_object.callMethod("destroy"); - } -} - -QUrl AndroidWebView::url() const { - if (!m_object.isValid()) { - logger.warning() << "Invalid object. Returning an empty URL"; - return QUrl(); - } - - return QUrl::fromUserInput( - m_object.callObjectMethod("getUrl").toString()); -} - -void AndroidWebView::setUrl(const QUrl& url) { - QUrl::FormattingOptions options = QUrl::RemoveQuery | QUrl::RemoveUserInfo; - logger.debug() << "Set URL:" << url.toString(options); - - if (!m_object.isValid()) { - logger.error() << "Invalid object. Failed the loading."; - return; - } - - QJniObject urlString = QJniObject::fromString(url.toString()); - m_object.callMethod("setUrl", "(Ljava/lang/String;)V", - urlString.object()); - emit urlChanged(); -} - -void AndroidWebView::componentComplete() { - if (m_window) { - m_window->setVisibility(QWindow::Windowed); - } -} - -void AndroidWebView::updatePolish() { - QSize itemSize = QSize(width(), height()); - if (!itemSize.isValid()) { - return; - } - - QQuickWindow* w = window(); - if (!w) { - return; - } - - QRect itemGeometry = mapRectToScene(QRect(QPoint(0, 0), itemSize)).toRect(); - - const QPoint& tl = w->mapToGlobal(itemGeometry.topLeft()); - QWindow* rw = QQuickRenderControl::renderWindowFor(w); - - m_window->setGeometry(rw ? QRect(rw->mapFromGlobal(tl), itemSize) - : itemGeometry); - m_window->setVisible(isVisible()); -} - -void AndroidWebView::geometryChange(const QRectF& newGeometry, - const QRectF& oldGeometry) { - QQuickItem::geometryChange(newGeometry, oldGeometry); - if (newGeometry.isValid()) { - polish(); - } -} - -void AndroidWebView::propagateError(ErrorHandler::ErrorType error) { - MozillaVPN::instance()->errorHandle(error); - emit failure(); -} - -void AndroidWebView::onWindowChanged(QQuickWindow* window) { - logger.debug() << "window changed"; - - QQuickWindow* oldParent = qobject_cast(m_window->parent()); - if (oldParent) { - oldParent->disconnect(this); - } - - if (!window) { - m_window->setParent(nullptr); - return; - } - - // Check if there's an actual native window available. - QWindow* rw = QQuickRenderControl::renderWindowFor(window); - if (!rw) { - rw = window; - } - - connect(rw, &QWindow::widthChanged, this, &AndroidWebView::polish); - connect(rw, &QWindow::heightChanged, this, &AndroidWebView::polish); - connect(rw, &QWindow::xChanged, this, &AndroidWebView::polish); - connect(rw, &QWindow::yChanged, this, &AndroidWebView::polish); - connect(rw, &QWindow::visibleChanged, this, - [this](bool visible) { m_window->setVisible(visible); }); - connect(window, &QQuickWindow::sceneGraphInitialized, this, - &AndroidWebView::polish); - connect(window, &QQuickWindow::sceneGraphInvalidated, this, - &AndroidWebView::invalidateSceneGraph); - m_window->setParent(rw); -} - -void AndroidWebView::onVisibleChanged() { - logger.debug() << "visible changed"; - m_window->setVisible(isVisible()); -} - -void AndroidWebView::invalidateSceneGraph() { - if (m_window) { - m_window->setVisible(false); - } -} - -void AndroidWebView::clearStorage() { - AndroidUtils::runOnAndroidThreadSync( - [this]() { m_object.callMethod("clearStorage", "()V"); }); -} diff --git a/src/platforms/android/androidwebview.h b/src/platforms/android/androidwebview.h deleted file mode 100644 index 7c9aee352e..0000000000 --- a/src/platforms/android/androidwebview.h +++ /dev/null @@ -1,63 +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 ANDROIDWEBVIEW_H -#define ANDROIDWEBVIEW_H - -#include "errorhandler.h" - -#include -#include - -#include -#include -#include -#include - -class AndroidWebView : public QQuickItem { - Q_OBJECT - Q_DISABLE_COPY_MOVE(AndroidWebView) - - Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) - QML_ELEMENT - - public: - AndroidWebView(QQuickItem* parent = 0); - virtual ~AndroidWebView(); - - QUrl url() const; - void setUrl(const QUrl& url); - Q_INVOKABLE void clearStorage(); - - protected: - void componentComplete() override; - void updatePolish() override; - void geometryChange(const QRectF& newGeometry, - const QRectF& oldGeometry) override; - - signals: - void urlChanged(); - void pageStarted(const QString& url); - void failure(); - - private slots: - void onWindowChanged(QQuickWindow* window); - void onVisibleChanged(); - void invalidateSceneGraph(); - - private: - static void onPageStarted(JNIEnv* env, jobject thiz, jstring url, - jobject icon); - static void onError(JNIEnv* env, jobject thiz, jint errorCode, - jstring description, jstring url); - void propagateError(ErrorHandler::ErrorType error); - - private: - QWindow* m_window = nullptr; - - QJniObject m_object; - QJniObject m_webView; -}; - -#endif // ANDROIDWEBVIEW_H diff --git a/src/platforms/ios/iosauthenticationlistener.h b/src/platforms/ios/iosauthenticationlistener.h deleted file mode 100644 index d042a4182e..0000000000 --- a/src/platforms/ios/iosauthenticationlistener.h +++ /dev/null @@ -1,24 +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 IOSAUTHENTICATIONLISTENER_H -#define IOSAUTHENTICATIONLISTENER_H - -#include "authenticationlistener.h" - -#include - -class IOSAuthenticationListener final : public AuthenticationListener { - Q_DISABLE_COPY_MOVE(IOSAuthenticationListener) - - public: - IOSAuthenticationListener(QObject* parent); - ~IOSAuthenticationListener(); - - void start(Task* task, const QString& codeChallenge, - const QString& codeChallengeMethod, - const QString& emailAddress) override; -}; - -#endif // IOSAUTHENTICATIONLISTENER_H diff --git a/src/platforms/ios/iosauthenticationlistener.mm b/src/platforms/ios/iosauthenticationlistener.mm deleted file mode 100644 index afe80e688c..0000000000 --- a/src/platforms/ios/iosauthenticationlistener.mm +++ /dev/null @@ -1,153 +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 "iosauthenticationlistener.h" -#include "leakdetector.h" -#include "logger.h" -#include "mozillavpn.h" -#include "qmlengineholder.h" - -#include -#include -#include -#include -#include -#include -#include - -#import -#import - -namespace { - -Logger logger({LOG_IOS, LOG_MAIN}, "IOSAuthenticationListener"); - -ASWebAuthenticationSession* s_session = nullptr; - -} // namespace - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 -@interface ContextProvider : NSObject { - UIView* m_view; -} -@end - -@implementation ContextProvider - -- (id)initWithUIView:(UIView*)uiView { - self = [super init]; - if (self) { - m_view = uiView; - } - return self; -} - -# pragma mark - ASWebAuthenticationPresentationContextProviding -- (nonnull ASPresentationAnchor)presentationAnchorForWebAuthenticationSession: - (nonnull ASWebAuthenticationSession*)s_session API_AVAILABLE(ios(13.0)) { - return m_view.window; -} - -@end -#endif - -IOSAuthenticationListener::IOSAuthenticationListener(QObject* parent) - : AuthenticationListener(parent) { - MVPN_COUNT_CTOR(IOSAuthenticationListener); -} - -IOSAuthenticationListener::~IOSAuthenticationListener() { - MVPN_COUNT_DTOR(IOSAuthenticationListener); - - if (s_session) { - logger.info() << "Canceling the session"; - [s_session cancel]; - - [s_session dealloc]; - s_session = nullptr; - } -} - -void IOSAuthenticationListener::start(Task* task, const QString& codeChallenge, - const QString& codeChallengeMethod, - const QString& emailAddress) { - logger.debug() << "IOSAuthenticationListener initialize"; - - Q_UNUSED(task); - - QUrl url(createAuthenticationUrl(codeChallenge, codeChallengeMethod, emailAddress)); - QUrlQuery query(url.query()); - query.addQueryItem("platform", "ios"); - url.setQuery(query); - -#ifdef MVPN_DEBUG - logger.debug() << "Authentication URL:" << url.toString(); -#endif - - if (s_session) { - [s_session dealloc]; - s_session = nullptr; - } - - s_session = [[ASWebAuthenticationSession alloc] - initWithURL:url.toNSURL() - callbackURLScheme:@"mozilla-vpn" - completionHandler:^(NSURL* _Nullable callbackURL, NSError* _Nullable error) { - if (!s_session) { - logger.info() << "The operation has been aborted in the meantime."; - return; - } - - [s_session dealloc]; - s_session = nullptr; - - if (error) { - logger.error() << "Authentication failed:" - << QString::fromNSString([error localizedDescription]); - logger.error() << "Code:" << [error code]; - logger.error() << "Suggestion:" - << QString::fromNSString([error localizedRecoverySuggestion]); - logger.error() << "Reason:" << QString::fromNSString([error localizedFailureReason]); - - if ([error code] == ASWebAuthenticationSessionErrorCodeCanceledLogin) { - emit abortedByUser(); - } else { - emit failed(ErrorHandler::RemoteServiceError); - } - - return; - } - - QUrl callbackUrl = QUrl::fromNSURL(callbackURL); - logger.debug() << "Authentication completed"; - - Q_ASSERT(callbackUrl.hasQuery()); - - QUrlQuery callbackUrlQuery(callbackUrl.query()); - Q_ASSERT(callbackUrlQuery.hasQueryItem("code")); - QString code = callbackUrlQuery.queryItemValue("code"); - emit completed(code); - }]; - -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 - QObject* rootObject = QmlEngineHolder::instance()->engine()->rootObjects().first(); - QWindow* window = qobject_cast(rootObject); - Q_ASSERT(window); - - UIView* view = static_cast( - QGuiApplication::platformNativeInterface()->nativeResourceForWindow("uiview", window)); - - if (@available(iOS 13, *)) { - s_session.presentationContextProvider = [[ContextProvider alloc] initWithUIView:view]; - } -#endif - - if (![s_session start]) { - [s_session dealloc]; - s_session = nullptr; - - logger.error() << "Authentication failed: session doesn't start."; - emit failed(ErrorHandler::RemoteServiceError); - } -} diff --git a/src/qmake/platforms/android.pri b/src/qmake/platforms/android.pri index 6cf9784ebf..3d94e24966 100644 --- a/src/qmake/platforms/android.pri +++ b/src/qmake/platforms/android.pri @@ -60,34 +60,28 @@ DEFINES += MVPN_ANDROID INCLUDEPATH += platforms/android SOURCES += \ - platforms/android/androidauthenticationlistener.cpp \ platforms/android/androidcontroller.cpp \ platforms/android/androidiaphandler.cpp \ platforms/android/androidnotificationhandler.cpp \ platforms/android/androidutils.cpp \ - platforms/android/androidwebview.cpp \ platforms/android/androidvpnactivity.cpp \ platforms/android/androiddatamigration.cpp \ platforms/android/androidappimageprovider.cpp \ platforms/android/androidapplistprovider.cpp \ platforms/android/androidsharedprefs.cpp \ - tasks/authenticate/desktopauthenticationlistener.cpp \ tasks/purchase/taskpurchase.cpp HEADERS += \ - platforms/android/androidauthenticationlistener.h \ platforms/android/androidcontroller.h \ platforms/android/androidiaphandler.h \ platforms/android/androidnotificationhandler.h \ platforms/android/androidutils.h \ - platforms/android/androidwebview.h \ platforms/android/androidvpnactivity.h \ platforms/android/androiddatamigration.h\ platforms/android/androidappimageprovider.h \ platforms/android/androidapplistprovider.h \ platforms/android/androidsharedprefs.h \ platforms/android/androidjnicompat.h \ - tasks/authenticate/desktopauthenticationlistener.h \ tasks/purchase/taskpurchase.h diff --git a/src/qmake/platforms/ios.pri b/src/qmake/platforms/ios.pri index c7fdb2ed2f..a668767224 100644 --- a/src/qmake/platforms/ios.pri +++ b/src/qmake/platforms/ios.pri @@ -47,9 +47,6 @@ QT -= networkauth CONFIG += c++1z -# For the authentication -LIBS += -framework AuthenticationServices - # For notifications LIBS += -framework UIKit LIBS += -framework Foundation @@ -64,7 +61,6 @@ SOURCES += \ OBJECTIVE_SOURCES += \ platforms/ios/iosiaphandler.mm \ - platforms/ios/iosauthenticationlistener.mm \ platforms/ios/ioscontroller.mm \ platforms/ios/iosdatamigration.mm \ platforms/ios/iosglue.mm \ @@ -79,7 +75,6 @@ HEADERS += \ OBJECTIVE_HEADERS += \ platforms/ios/iosiaphandler.h \ - platforms/ios/iosauthenticationlistener.h \ platforms/ios/ioscontroller.h \ platforms/ios/iosdatamigration.h \ platforms/ios/iosnotificationhandler.h \ diff --git a/src/ui/main.qml b/src/ui/main.qml index 0e935f4f6b..629f2fce8c 100644 --- a/src/ui/main.qml +++ b/src/ui/main.qml @@ -289,14 +289,6 @@ Window { mainStackView.push("qrc:/ui/views/ViewLogs.qml"); } - function onLoadAndroidAuthenticationView() { - if (Qt.platform.os !== "android") { - console.log("Unexpected android authentication view request!"); - } - - mainStackView.push("qrc:/ui/platforms/android/androidauthenticationview.qml", StackView.Immediate) - } - function onInitializeGlean() { if (VPN.debugMode) { console.debug("Initializing glean with debug mode"); diff --git a/src/ui/ui.qrc b/src/ui/ui.qrc index 565c8019e5..b2c1306fb5 100644 --- a/src/ui/ui.qrc +++ b/src/ui/ui.qrc @@ -1,6 +1,5 @@ - ../platforms/android/androidauthenticationview.qml authenticationInApp/ViewAuthenticationFallbackInBrowser.qml authenticationInApp/ViewAuthenticationInApp.qml authenticationInApp/ViewAuthenticationInitializing.qml