diff --git a/CHANGELOG.md b/CHANGELOG.md index f36d20ba3..073020b3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - File viewer in chats (Image/Animated Image/Video/Texts) with the option to export the file. - Accept/decline CLI commands. - Colored Emojis with its own font family. +- OAuth2 connection to retrieve remote provisioning (Experimental and not usable without configuration). ## 5.0.11 - undefined diff --git a/CMakeLists.txt b/CMakeLists.txt index 236f8dc29..b3c983d4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ endif() #------------------------------------------------------------------------------- option(ENABLE_APP_LICENSE "Enable the license in packages." YES) +option(ENABLE_APP_OAUTH2 "Build with OAuth2 support for remote provisioning." OFF) #Experimental. option(ENABLE_APP_PACKAGING "Enable packaging" NO) option(ENABLE_APP_PACKAGE_ROOTCA "Embed the rootca file into the package" YES) option(ENABLE_APP_WEBVIEW "Enable webviews." NO) #Webview is not fully supported because of deployments. Used for subscription. @@ -141,6 +142,7 @@ option(LIBSECRET_SUPPORT "Build with libsecret support" OFF) #Need libsecret-dev set(APP_OPTIONS "-DENABLE_UPDATE_CHECK=${ENABLE_UPDATE_CHECK}") list(APPEND APP_OPTIONS "-DENABLE_APP_LICENSE=${ENABLE_APP_LICENSE}") +list(APPEND APP_OPTIONS "-DENABLE_APP_OAUTH2=${ENABLE_APP_OAUTH2}") list(APPEND APP_OPTIONS "-DENABLE_APP_PACKAGING=${ENABLE_APP_PACKAGING}") list(APPEND APP_OPTIONS "-DENABLE_APP_PACKAGE_ROOTCA=${ENABLE_APP_PACKAGE_ROOTCA}") list(APPEND APP_OPTIONS "-DENABLE_APP_WEBVIEW=${ENABLE_APP_WEBVIEW}") @@ -157,6 +159,7 @@ endif() list(APPEND APP_OPTIONS "-DENABLE_LDAP=${ENABLE_LDAP}") list(APPEND APP_OPTIONS "-DENABLE_NON_FREE_CODECS=${ENABLE_NON_FREE_CODECS}") list(APPEND APP_OPTIONS "-DENABLE_OPENH264=${ENABLE_OPENH264}") +list(APPEND APP_OPTIONS "-DENABLE_OPENH264=${ENABLE_OPENH264}") list(APPEND APP_OPTIONS "-DENABLE_QT_KEYCHAIN=${ENABLE_QT_KEYCHAIN}") list(APPEND APP_OPTIONS "-DENABLE_OPENSSL_EXPORT=${ENABLE_OPENSSL_EXPORT}") list(APPEND APP_OPTIONS "-DENABLE_QRCODE=${ENABLE_QRCODE}") diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt index 15c764637..c1f9247d6 100644 --- a/linphone-app/CMakeLists.txt +++ b/linphone-app/CMakeLists.txt @@ -134,6 +134,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)#useful for config.h set(QT5_PACKAGES Core Gui Quick Widgets QuickControls2 Svg LinguistTools Concurrent Network Test Qml) +if(ENABLE_APP_OAUTH2) + list(APPEND QT5_PACKAGES NetworkAuth) + add_definitions(-DENABLE_OAUTH2) +endif() if(ENABLE_APP_WEBVIEW) list(APPEND QT5_PACKAGES WebView WebEngine WebEngineCore) add_definitions(-DENABLE_WEBVIEW) @@ -429,10 +433,12 @@ set(HEADERS src/utils/Utils.hpp src/utils/plugins/PluginsManager.hpp ) + set(PLUGIN_HEADERS include/LinphoneApp/PluginDataAPI.hpp include/LinphoneApp/PluginNetworkHelper.hpp include/LinphoneApp/LinphonePlugin.hpp) + list(APPEND SOURCES include/LinphoneApp/PluginExample.json) set(MAIN_FILE src/app/main.cpp) @@ -483,6 +489,12 @@ if(ENABLE_QT_KEYCHAIN) list(APPEND SOURCES src/components/vfs/VfsUtils.cpp) endif() +if(ENABLE_APP_OAUTH2) + list(APPEND HEADERS src/components/authentication/OAuth2Model.hpp) + list(APPEND SOURCES src/components/authentication/OAuth2Model.cpp) +endif() + + set(QRC_RESOURCES resources.qrc) if(ENABLE_APP_WEBVIEW) set(QRC_WEBVIEW_RESOURCES webview_resources.qrc) diff --git a/linphone-app/src/components/assistant/AssistantModel.cpp b/linphone-app/src/components/assistant/AssistantModel.cpp index 05a387262..af83b7bd4 100644 --- a/linphone-app/src/components/assistant/AssistantModel.cpp +++ b/linphone-app/src/components/assistant/AssistantModel.cpp @@ -28,6 +28,10 @@ #include "AssistantModel.hpp" +#ifdef ENABLE_OAUTH2 +#include "components/authentication/OAuth2Model.hpp" +#endif + #ifdef ENABLE_QRCODE #include #endif @@ -166,6 +170,11 @@ AssistantModel::AssistantModel (QObject *parent) : QObject(parent) { AssistantModel::~AssistantModel(){ setIsReadingQRCode(false); +#ifdef ENABLE_OAUTH2 + if(oAuth2Model) + oAuth2Model->deleteLater(); + oAuth2Model = nullptr; +#endif } // ----------------------------------------------------------------------------- @@ -365,6 +374,28 @@ void AssistantModel::attachAccount(const QString& token){ #endif } +bool AssistantModel::isOAuth2Available(){ +#ifdef ENABLE_OAUTH2 + return OAuth2Model::isAvailable(); +#else + return false; +#endif +} + +void AssistantModel::requestOauth2(){ +#ifdef ENABLE_OAUTH2 + if(isOAuth2Available()){ + if(oAuth2Model) + oAuth2Model->deleteLater(); + oAuth2Model = new OAuth2Model(); + connect(oAuth2Model, &OAuth2Model::requestFailed, this, &AssistantModel::oauth2RequestFailed); + connect(oAuth2Model, &OAuth2Model::statusChanged, this, &AssistantModel::oauth2StatusChanged); + connect(oAuth2Model, &OAuth2Model::authenticated, this, &AssistantModel::oauth2AuthenticationGranted); + oAuth2Model->grant(); + } +#endif +} + // ----------------------------------------------------------------------------- QString AssistantModel::getEmail () const { diff --git a/linphone-app/src/components/assistant/AssistantModel.hpp b/linphone-app/src/components/assistant/AssistantModel.hpp index a124f963e..5c8c709b7 100644 --- a/linphone-app/src/components/assistant/AssistantModel.hpp +++ b/linphone-app/src/components/assistant/AssistantModel.hpp @@ -25,6 +25,9 @@ #include // ============================================================================= +#ifdef ENABLE_OAUTH2 +class OAuth2Model; +#endif class AssistantModel : public QObject { class Handlers; @@ -57,9 +60,12 @@ public: Q_INVOKABLE void generateQRCode(); Q_INVOKABLE void requestQRCode(); Q_INVOKABLE void readQRCode(); + Q_INVOKABLE void requestOauth2(); Q_INVOKABLE void attachAccount(const QString& token); + Q_INVOKABLE static bool isOAuth2Available(); + void checkLinkingAccount(); public slots: @@ -80,6 +86,10 @@ signals: void createStatusChanged (const QString &error); void loginStatusChanged (const QString &error); void recoverStatusChanged (const QString &error); + void oauth2RequestFailed(const QString& error); + + void oauth2StatusChanged(const QString& status); + void oauth2AuthenticationGranted(); void configFilenameChanged (const QString &configFilename); @@ -132,6 +142,9 @@ private: std::shared_ptr mAccountCreator; std::shared_ptr mHandlers; +#ifdef ENABLE_OAUTH2 + OAuth2Model * oAuth2Model = nullptr; +#endif }; #endif // ASSISTANT_MODEL_H_ diff --git a/linphone-app/src/components/authentication/OAuth2Model.cpp b/linphone-app/src/components/authentication/OAuth2Model.cpp new file mode 100644 index 000000000..f1706e603 --- /dev/null +++ b/linphone-app/src/components/authentication/OAuth2Model.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010-2023 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "OAuth2Model.hpp" + +#include +#include + +#include "components/core/CoreManager.hpp" +#include "components/settings/SettingsModel.hpp" +#include "utils/Utils.hpp" + +// ============================================================================= +// Goal : override the default redirect url which is "http://localhost:0" +class OAuthHttpServerReplyHandler : public QOAuthHttpServerReplyHandler{ +public: + OAuthHttpServerReplyHandler(const int& port, QObject * parent = nullptr ) : QOAuthHttpServerReplyHandler(port, parent){ + } + QString callback() const override{ + QString uri = CoreManager::getInstance()->getSettingsModel()->getOAuth2RedirectUri(); + if( uri!= "") + return uri; + else + return QOAuthHttpServerReplyHandler::callback();// Return default + } +}; + +OAuth2Model::OAuth2Model (QObject *parent){ + QUrl url(CoreManager::getInstance()->getSettingsModel()->getOAuth2RedirectUri()); + auto replyHandler = new OAuthHttpServerReplyHandler(url.port(0), this); + oauth2.setReplyHandler(replyHandler); + oauth2.setAuthorizationUrl(QUrl(CoreManager::getInstance()->getSettingsModel()->getOAuth2AuthorizationUrl())); + oauth2.setAccessTokenUrl(QUrl(CoreManager::getInstance()->getSettingsModel()->getOAuth2AccessTokenUrl())); + oauth2.setNetworkAccessManager(new QNetworkAccessManager(&oauth2)); + oauth2.setClientIdentifier(CoreManager::getInstance()->getSettingsModel()->getOAuth2Identifier()); + oauth2.setClientIdentifierSharedKey(CoreManager::getInstance()->getSettingsModel()->getOAuth2Password()); + oauth2.setScope(CoreManager::getInstance()->getSettingsModel()->getOAuth2Scope()); + + connect(oauth2.networkAccessManager(), &QNetworkAccessManager::authenticationRequired, [=](QNetworkReply *reply, QAuthenticator *authenticator){ + qWarning() << "authenticationRequired received but not implemented"; + }); + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::statusChanged, [=](QAbstractOAuth::Status status) { + qWarning() << (int)status; + switch(status){ + case QAbstractOAuth::Status::Granted : { + emit statusChanged("Authentication granted"); + emit authenticated(); + break; + } + case QAbstractOAuth::Status::NotAuthenticated : { + emit statusChanged("Not authenticated"); + break; + } + case QAbstractOAuth::Status::RefreshingToken : { + emit statusChanged("Refreshing token"); + break; + } + case QAbstractOAuth::Status::TemporaryCredentialsReceived : { + emit statusChanged("Temporary credentials received"); + break; + } + default:{} + } + }); + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::requestFailed, [=](QAbstractOAuth::Error error){ + qWarning() << (int)error; + switch(error){ + case QAbstractOAuth::Error::NetworkError : emit requestFailed("Network error"); break; + case QAbstractOAuth::Error::ServerError : emit requestFailed("Server error"); break; + case QAbstractOAuth::Error::OAuthTokenNotFoundError : emit requestFailed("OAuth token not found"); break; + case QAbstractOAuth::Error::OAuthTokenSecretNotFoundError : emit requestFailed("OAuth token secret not found"); break; + case QAbstractOAuth::Error::OAuthCallbackNotVerified: emit requestFailed("OAuth callback not verified"); break; + default:{ + } + } + }); + + // in case we want to add parameters. + oauth2.setModifyParametersFunction([&](QAbstractOAuth::Stage stage, QVariantMap *parameters) { + qWarning() << (int)stage; + switch(stage){ + case QAbstractOAuth::Stage::RequestingAccessToken : { + emit statusChanged("Requesting access token"); + break; + } + case QAbstractOAuth::Stage::RefreshingAccessToken : { + emit statusChanged("Refreshing access token"); + break; + } + case QAbstractOAuth::Stage::RequestingAuthorization : { + emit statusChanged("Requesting authorization"); + break; + } + case QAbstractOAuth::Stage::RequestingTemporaryCredentials : { + emit statusChanged("Requesting temporary credentials"); + break; + } + default:{} + } + }); + + // + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, [this](const QUrl & url){ + qDebug() << "Browser authentication url : " << url; + emit statusChanged("Requesting authorization from browser"); + QDesktopServices::openUrl(url); + }); + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::finished, [this](QNetworkReply * reply){ + qDebug() << "Finished " << reply->errorString(); + connect(reply, &QNetworkReply::errorOccurred, [this, reply](QNetworkReply::NetworkError error){ + qDebug() << reply->errorString(); + + }); + }); + connect(this, &OAuth2Model::authenticated, this, &OAuth2Model::getRemoteProvisioning); +} + +bool OAuth2Model::isAvailable(){ + return !CoreManager::getInstance()->getSettingsModel()->getOAuth2AuthorizationUrl().isEmpty() + && !CoreManager::getInstance()->getSettingsModel()->getOAuth2AccessTokenUrl().isEmpty(); +} + +void OAuth2Model::grant(){ + oauth2.grant(); +} + +void OAuth2Model::getRemoteProvisioning() { + qDebug() << "getRemoteProvisioning " << oauth2.extraTokens() << oauth2.token(); + QString basicAuthentication(CoreManager::getInstance()->getSettingsModel()->getOAuth2RemoteProvisioningBasicAuth()); + QUrl url(CoreManager::getInstance()->getSettingsModel()->getRemoteProvisioningRootUrl()); + std::vector > headers; + auto header = CoreManager::getInstance()->getSettingsModel()->getOAuth2RemoteProvisioningHeader(); + if( !header.isEmpty()) + headers.push_back(std::pair(Utils::appStringToCoreString(header), Utils::appStringToCoreString(oauth2.token()))); + headers.push_back(std::pair("accept", "application/xml")); + if(!basicAuthentication.isEmpty()){ + headers.push_back(std::pair("authorization", Utils::appStringToCoreString("Basic "+basicAuthentication))); + } + CoreManager::getInstance()->getCore()->clearProvisioningHeaders(); + for(int i = 0 ; i < headers.size() ; ++i) + CoreManager::getInstance()->getCore()->addProvisioningHeader(headers[i].first, headers[i].second); + CoreManager::getInstance()->getSettingsModel()->setRemoteProvisioning(url.toString()); +} diff --git a/linphone-app/src/components/authentication/OAuth2Model.hpp b/linphone-app/src/components/authentication/OAuth2Model.hpp new file mode 100644 index 000000000..d55748f3f --- /dev/null +++ b/linphone-app/src/components/authentication/OAuth2Model.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010-2023 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef O_AUTH_2_MODEL_H_ +#define O_AUTH_2_MODEL_H_ + +#include + +#include +#include +// ============================================================================= + + +class OAuth2Model : public QObject { + Q_OBJECT + +public: + OAuth2Model (QObject *parent = Q_NULLPTR); + + void grant(); //Start authentication + void getRemoteProvisioning(); + + static bool isAvailable(); + +signals: + void authenticated(); + void requestFailed(const QString& error); + void statusChanged(const QString& status); + void remoteProvisioningReceived(const QString& url); + +private: + QOAuth2AuthorizationCodeFlow oauth2; +}; + +#endif diff --git a/linphone-app/src/components/settings/SettingsModel.cpp b/linphone-app/src/components/settings/SettingsModel.cpp index 9f906f68a..3419f49a3 100644 --- a/linphone-app/src/components/settings/SettingsModel.cpp +++ b/linphone-app/src/components/settings/SettingsModel.cpp @@ -32,6 +32,7 @@ #include "app/logger/Logger.hpp" #include "app/paths/Paths.hpp" +#include "components/assistant/AssistantModel.hpp" #include "components/core/CoreManager.hpp" #include "components/tunnel/TunnelModel.hpp" #include "include/LinphoneApp/PluginNetworkHelper.hpp" @@ -1756,6 +1757,58 @@ bool SettingsModel::isLdapAvailable(){ return CoreManager::getInstance()->getCore()->ldapAvailable(); } +bool SettingsModel::isOAuth2Available(){ + return AssistantModel::isOAuth2Available(); +} + +QString SettingsModel::getOAuth2AuthorizationUrl()const{ + return Utils::coreStringToAppString( + mConfig->getString(UiSection, "oauth2_authorization_url", Constants::OAuth2AuthorizationUrl) + ); +} + +QString SettingsModel::getOAuth2AccessTokenUrl()const{ + return Utils::coreStringToAppString( + mConfig->getString(UiSection, "oauth2_access_token_url", Constants::OAuth2AccessTokenUrl) + ); +} + +QString SettingsModel::getOAuth2RedirectUri()const{ + return Utils::coreStringToAppString( + mConfig->getString(UiSection, "oauth2_redirect_uri", Constants::OAuth2RedirectUri) + ); +} + +QString SettingsModel::getOAuth2Identifier()const{ + return Utils::coreStringToAppString( + mConfig->getString(UiSection, "oauth2_identifier", Constants::OAuth2Identifier) + ); +} + +QString SettingsModel::getOAuth2Password()const{ + return Utils::coreStringToAppString( + mConfig->getString(UiSection, "oauth2_password", Constants::OAuth2Password) + ); +} + +QString SettingsModel::getOAuth2Scope()const{ + return Utils::coreStringToAppString( + mConfig->getString(UiSection, "oauth2_scope", Constants::OAuth2Scope) + ); +} + +QString SettingsModel::getOAuth2RemoteProvisioningBasicAuth()const{ + return Utils::coreStringToAppString( + mConfig->getString(UiSection, "oauth2_remote_provisioning_basic_auth", Constants::RemoteProvisioningBasicAuth) + ); +} + +QString SettingsModel::getOAuth2RemoteProvisioningHeader()const{ + return Utils::coreStringToAppString( + mConfig->getString(UiSection, "oauth2_remote_provisioning_header", Constants::DefaultOAuth2RemoteProvisioningHeader) + ); +} + // --------------------------------------------------------------------------- QString SettingsModel::getLogsFolder (const shared_ptr &config) { diff --git a/linphone-app/src/components/settings/SettingsModel.hpp b/linphone-app/src/components/settings/SettingsModel.hpp index 40b8ba162..6159c7437 100644 --- a/linphone-app/src/components/settings/SettingsModel.hpp +++ b/linphone-app/src/components/settings/SettingsModel.hpp @@ -630,6 +630,17 @@ public: Q_INVOKABLE bool isLdapAvailable(); +// OAuth 2 + Q_INVOKABLE bool isOAuth2Available(); + QString getOAuth2AuthorizationUrl()const; + QString getOAuth2AccessTokenUrl()const; + QString getOAuth2RedirectUri()const; + QString getOAuth2Identifier()const; + QString getOAuth2Password()const; + QString getOAuth2Scope()const; + QString getOAuth2RemoteProvisioningBasicAuth()const; + QString getOAuth2RemoteProvisioningHeader()const; + // --------------------------------------------------------------------------- static QString getLogsFolder (const std::shared_ptr &config); diff --git a/linphone-app/src/utils/Constants.cpp b/linphone-app/src/utils/Constants.cpp index 70c285385..bb22d44b1 100644 --- a/linphone-app/src/utils/Constants.cpp +++ b/linphone-app/src/utils/Constants.cpp @@ -76,6 +76,17 @@ constexpr char Constants::DefaultAssistantRegistrationUrl[]; constexpr char Constants::DefaultAssistantLoginUrl[]; constexpr char Constants::DefaultAssistantLogoutUrl[]; +constexpr char Constants::RemoteProvisioningBasicAuth[]; +constexpr char Constants::OAuth2AuthorizationUrl[]; +constexpr char Constants::OAuth2AccessTokenUrl[]; +constexpr char Constants::OAuth2RedirectUri[]; +constexpr char Constants::OAuth2Identifier[]; +constexpr char Constants::OAuth2Password[]; +constexpr char Constants::OAuth2Scope[]; +constexpr char Constants::DefaultOAuth2RemoteProvisioningHeader[]; + + + #if defined(Q_OS_LINUX) || defined(Q_OS_WIN) constexpr char Constants::H264Description[]; #endif // if defined(Q_OS_LINUX) || defined(Q_OS_WIN) diff --git a/linphone-app/src/utils/Constants.hpp b/linphone-app/src/utils/Constants.hpp index 482bb90ec..ba11d5e9d 100644 --- a/linphone-app/src/utils/Constants.hpp +++ b/linphone-app/src/utils/Constants.hpp @@ -67,8 +67,18 @@ public: static constexpr char DefaultRlsUri[] = "sips:rls@sip.linphone.org"; static constexpr char DefaultLogsEmail[] = "linphone-desktop@belledonne-communications.com"; - static constexpr char DefaultFlexiAPIURL[] = "http://fs-test-sandbox.linphone.org/flexiapi/api/";// Need "/" at the end - static constexpr char RemoteProvisioningURL[] = "http://fs-test-sandbox.linphone.org/flexiapi/provisioning"; + static constexpr char DefaultFlexiAPIURL[] = "https://subscribe.linphone.org/api/";// Need "/" at the end + static constexpr char RemoteProvisioningURL[] = "https://subscribe.linphone.org/api/provisioning"; + static constexpr char RemoteProvisioningBasicAuth[] = ""; +// OAuth2 settings + static constexpr char OAuth2AuthorizationUrl[] = ""; + static constexpr char OAuth2AccessTokenUrl[] = ""; + static constexpr char OAuth2RedirectUri[] = ""; + static constexpr char OAuth2Identifier[] = ""; + static constexpr char OAuth2Password[] = ""; + static constexpr char OAuth2Scope[] = ""; + static constexpr char DefaultOAuth2RemoteProvisioningHeader[] = "x-linphone-oauth2-token"; + Q_PROPERTY(QString PasswordRecoveryUrl MEMBER PasswordRecoveryUrl CONSTANT) Q_PROPERTY(QString CguUrl MEMBER CguUrl CONSTANT) diff --git a/linphone-app/ui/modules/Linphone/Blocks/RequestBlock.qml b/linphone-app/ui/modules/Linphone/Blocks/RequestBlock.qml index 988b44dee..88226834a 100644 --- a/linphone-app/ui/modules/Linphone/Blocks/RequestBlock.qml +++ b/linphone-app/ui/modules/Linphone/Blocks/RequestBlock.qml @@ -1,6 +1,7 @@ import QtQuick 2.7 import Common 1.0 +import Common.Styles 1.0 import Linphone.Styles 1.0 // ============================================================================= @@ -50,7 +51,7 @@ Column { padding: RequestBlockStyle.error.padding wrapMode: Text.WordWrap - visible: !block.loading && errorBlock.text != '' + visible: errorBlock.text != '' } BusyIndicator { @@ -58,7 +59,7 @@ Column { anchors { horizontalCenter: parent.horizontalCenter } - + color: BusyIndicatorStyle.alternateColor.color height: visible ? RequestBlockStyle.loadingIndicator.height : 0 width: RequestBlockStyle.loadingIndicator.width diff --git a/linphone-app/ui/views/App/Main/Assistant/FetchRemoteConfiguration.qml b/linphone-app/ui/views/App/Main/Assistant/FetchRemoteConfiguration.qml index 360bef520..8e4ff1088 100644 --- a/linphone-app/ui/views/App/Main/Assistant/FetchRemoteConfiguration.qml +++ b/linphone-app/ui/views/App/Main/Assistant/FetchRemoteConfiguration.qml @@ -44,6 +44,9 @@ Item{ target: assistantModel onNewQRCodeReceived: {assistantModel.qrcode = 'image://qrcode/'+code; requestBlock.stop('')} onNewQRCodeNotReceived: requestBlock.stop(message) + onOauth2StatusChanged: requestBlock.setText(status) + onOauth2RequestFailed: requestBlock.stop(error) + onOauth2AuthenticationGranted: requestBlock.stop('') onProvisioningTokenReceived: {url.text = token SettingsModel.remoteProvisioning = url.text assistantModel.qrcode = '' @@ -116,8 +119,27 @@ Item{ id: requestBlock action: (function () { }) - Layout.preferredWidth: parent.width - + Layout.fillWidth: true + } + Text{ + Layout.topMargin: 15 + Layout.alignment: Qt.AlignCenter + visible: oAuth2Button.visible + font.pointSize: FetchRemoteConfigurationStyle.fieldTitles.pointSize + font.weight: Font.Bold + font.capitalization: Font.Capitalize + color: FetchRemoteConfigurationStyle.fieldTitles.colorModel.color + //: 'or' : conjunction to choose between options. + text: qsTr('or') + } + TextButtonB { + id: oAuth2Button + Layout.margins: 15 + Layout.alignment: Qt.AlignCenter + text: 'OAuth2' + visible: assistantModel.isOAuth2Available() + onClicked: {requestBlock.execute(); assistantModel.requestOauth2()} + capitalization: Font.AllUppercase } Text{ Layout.topMargin: 15 @@ -192,6 +214,7 @@ Item{ capitalization: Font.AllUppercase } } + //------------------------------------------------------------------ // Developer Section //------------------------------------------------------------------ diff --git a/linphone-sdk b/linphone-sdk index acfe74e4f..05d1ffdf5 160000 --- a/linphone-sdk +++ b/linphone-sdk @@ -1 +1 @@ -Subproject commit acfe74e4f769606b7f09819430c79836362cf19c +Subproject commit 05d1ffdf582f459e801cf726837fb091cba595e0