diff --git a/Linphone/core/call/CallCore.cpp b/Linphone/core/call/CallCore.cpp index eba1fb375..f41fccca5 100644 --- a/Linphone/core/call/CallCore.cpp +++ b/Linphone/core/call/CallCore.cpp @@ -65,13 +65,10 @@ CallCore::CallCore(const std::shared_ptr &call) : QObject(nullpt mLocalAddress = Utils::coreStringToAppString(call->getCallLog()->getLocalAddress()->asStringUriOnly()); mStatus = LinphoneEnums::fromLinphone(call->getCallLog()->getStatus()); mTransferState = LinphoneEnums::fromLinphone(call->getTransferState()); - auto token = Utils::coreStringToAppString(mCallModel->getAuthenticationToken()); - auto localToken = mDir == LinphoneEnums::CallDir::Incoming ? token.left(2).toUpper() : token.right(2).toUpper(); - auto remoteToken = mDir == LinphoneEnums::CallDir::Outgoing ? token.left(2).toUpper() : token.right(2).toUpper(); + mLocalToken = Utils::coreStringToAppString(mCallModel->getLocalAtuhenticationToken()); + mRemoteTokens = mCallModel->getRemoteAtuhenticationTokens(); mEncryption = LinphoneEnums::fromLinphone(call->getParams()->getMediaEncryption()); auto tokenVerified = call->getAuthenticationTokenVerified(); - mLocalSas = localToken; - mRemoteSas = remoteToken; mIsSecured = (mEncryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) || mEncryption == LinphoneEnums::MediaEncryption::Srtp || mEncryption == LinphoneEnums::MediaEncryption::Dtls; @@ -150,13 +147,21 @@ void CallCore::setSelf(QSharedPointer me) { } }); }); - mCallModelConnection->makeConnectToCore(&CallCore::lVerifyAuthenticationToken, [this](bool verified) { - mCallModelConnection->invokeToModel( - [this, verified]() { mCallModel->setAuthenticationTokenVerified(verified); }); + mCallModelConnection->makeConnectToCore(&CallCore::lCheckAuthenticationTokenSelected, [this](const QString &token) { + mCallModelConnection->invokeToModel([this, token]() { mCallModel->checkAuthenticationToken(token); }); }); - mCallModelConnection->makeConnectToModel(&CallModel::authenticationTokenVerifiedChanged, [this](bool verified) { - mCallModelConnection->invokeToCore([this, verified]() { setIsSecured(verified); }); + mCallModelConnection->makeConnectToCore(&CallCore::lSkipZrtpAuthentication, [this]() { + mCallModelConnection->invokeToModel([this]() { mCallModel->skipZrtpAuthentication(); }); }); + mCallModelConnection->makeConnectToModel(&CallModel::authenticationTokenVerified, + [this](const std::shared_ptr &call, bool verified) { + auto isMismatch = mCallModel->getZrtpCaseMismatch(); + mCallModelConnection->invokeToCore([this, verified, isMismatch]() { + setTokenVerified(verified); + setIsSecured(verified && !isMismatch); + emit tokenVerified(); + }); + }); mCallModelConnection->makeConnectToModel( &CallModel::remoteRecording, [this](const std::shared_ptr &call, bool recording) { mCallModelConnection->invokeToCore([this, recording]() { setRemoteRecording(recording); }); @@ -232,23 +237,22 @@ void CallCore::setSelf(QSharedPointer me) { [this](const std::shared_ptr &call, bool on, const std::string &authenticationToken) { auto encryption = LinphoneEnums::fromLinphone(call->getCurrentParams()->getMediaEncryption()); auto tokenVerified = mCallModel->getAuthenticationTokenVerified(); - auto token = Utils::coreStringToAppString(mCallModel->getAuthenticationToken()); - mCallModelConnection->invokeToCore([this, call, encryption, tokenVerified, token]() { - if (token.size() == 4) { - auto localToken = - mDir == LinphoneEnums::CallDir::Incoming ? token.left(2).toUpper() : token.right(2).toUpper(); - auto remoteToken = - mDir == LinphoneEnums::CallDir::Outgoing ? token.left(2).toUpper() : token.right(2).toUpper(); - setLocalSas(localToken); - setRemoteSas(remoteToken); - } - setEncryption(encryption); - setIsSecured((encryption == LinphoneEnums::MediaEncryption::Zrtp && - tokenVerified)); // || - // encryption == LinphoneEnums::MediaEncryption::Srtp || - // encryption == LinphoneEnums::MediaEncryption::Dtls); - // TODO : change this when api available in sdk - }); + auto isCaseMismatch = mCallModel->getZrtpCaseMismatch(); + auto localToken = Utils::coreStringToAppString(mCallModel->getLocalAtuhenticationToken()); + QStringList remoteTokens = mCallModel->getRemoteAtuhenticationTokens(); + mCallModelConnection->invokeToCore( + [this, call, encryption, tokenVerified, localToken, remoteTokens, isCaseMismatch]() { + setLocalToken(localToken); + setRemoteTokens(remoteTokens); + setEncryption(encryption); + setIsMismatch(isCaseMismatch); + setIsSecured( + (encryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified && !isCaseMismatch)); // || + // encryption == LinphoneEnums::MediaEncryption::Srtp || + // encryption == LinphoneEnums::MediaEncryption::Dtls); + // TODO : change this when api available in sdk + setTokenVerified(tokenVerified); + }); }); mCallModelConnection->makeConnectToCore(&CallCore::lSetSpeakerVolumeGain, [this](float gain) { mCallModelConnection->invokeToModel([this, gain]() { mCallModel->setSpeakerVolumeGain(gain); }); @@ -430,6 +434,17 @@ void CallCore::setPaused(bool paused) { } } +bool CallCore::getTokenVerified() const { + return mTokenVerified; +} + +void CallCore::setTokenVerified(bool verified) { + if (mTokenVerified != verified) { + mTokenVerified = verified; + emit securityUpdated(); + } +} + bool CallCore::isSecured() const { return mIsSecured; } @@ -441,6 +456,17 @@ void CallCore::setIsSecured(bool secured) { } } +bool CallCore::isMismatch() const { + return mIsMismatch; +} + +void CallCore::setIsMismatch(bool mismatch) { + if (mIsMismatch != mismatch) { + mIsMismatch = mismatch; + emit securityUpdated(); + } +} + ConferenceGui *CallCore::getConferenceGui() const { return mConference ? new ConferenceGui(mConference) : nullptr; } @@ -463,25 +489,25 @@ bool CallCore::isConference() const { return mIsConference; } -QString CallCore::getLocalSas() { - return mLocalSas; +QString CallCore::getLocalToken() { + return mLocalToken; } -QString CallCore::getRemoteSas() { - return mRemoteSas; +QStringList CallCore::getRemoteTokens() { + return mRemoteTokens; } -void CallCore::setLocalSas(const QString &sas) { - if (mLocalSas != sas) { - mLocalSas = sas; - emit localSasChanged(); +void CallCore::setLocalToken(const QString &Token) { + if (mLocalToken != Token) { + mLocalToken = Token; + emit localTokenChanged(); } } -void CallCore::setRemoteSas(const QString &sas) { - if (mRemoteSas != sas) { - mRemoteSas = sas; - emit remoteSasChanged(); +void CallCore::setRemoteTokens(const QStringList &token) { + if (mRemoteTokens != token) { + mRemoteTokens = token; + emit remoteTokensChanged(); } } diff --git a/Linphone/core/call/CallCore.hpp b/Linphone/core/call/CallCore.hpp index 817d50170..8fc1d7316 100644 --- a/Linphone/core/call/CallCore.hpp +++ b/Linphone/core/call/CallCore.hpp @@ -45,10 +45,12 @@ class CallCore : public QObject, public AbstractObject { Q_PROPERTY(bool paused READ getPaused WRITE lSetPaused NOTIFY pausedChanged) Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT) Q_PROPERTY(QString localAddress READ getLocalAddress CONSTANT) - Q_PROPERTY(bool isSecured READ isSecured NOTIFY securityUpdated) + Q_PROPERTY(bool tokenVerified READ getTokenVerified WRITE setTokenVerified NOTIFY securityUpdated) + // Q_PROPERTY(bool isSecured READ isSecured WRITE setIsSecured NOTIFY securityUpdated) + Q_PROPERTY(bool isMismatch READ isMismatch WRITE setIsMismatch NOTIFY securityUpdated) Q_PROPERTY(LinphoneEnums::MediaEncryption encryption READ getEncryption NOTIFY securityUpdated) - Q_PROPERTY(QString localSas READ getLocalSas WRITE setLocalSas MEMBER mLocalSas NOTIFY localSasChanged) - Q_PROPERTY(QString remoteSas WRITE setRemoteSas MEMBER mRemoteSas NOTIFY remoteSasChanged) + Q_PROPERTY(QString localToken READ getLocalToken WRITE setLocalToken MEMBER mLocalToken NOTIFY localTokenChanged) + Q_PROPERTY(QStringList remoteTokens WRITE setRemoteTokens MEMBER mRemoteTokens NOTIFY remoteTokensChanged) Q_PROPERTY( bool remoteVideoEnabled READ getRemoteVideoEnabled WRITE setRemoteVideoEnabled NOTIFY remoteVideoEnabledChanged) Q_PROPERTY( @@ -104,19 +106,25 @@ public: bool getPaused() const; void setPaused(bool paused); + bool getTokenVerified() const; + void setTokenVerified(bool verified); + bool isSecured() const; void setIsSecured(bool secured); + bool isMismatch() const; + void setIsMismatch(bool mismatch); + ConferenceGui *getConferenceGui() const; QSharedPointer getConferenceCore() const; void setConference(const QSharedPointer &conference); bool isConference() const; - QString getLocalSas(); - void setLocalSas(const QString &sas); - QString getRemoteSas(); - void setRemoteSas(const QString &sas); + QString getLocalToken(); + void setLocalToken(const QString &token); + QStringList getRemoteTokens(); + void setRemoteTokens(const QStringList &Tokens); LinphoneEnums::MediaEncryption getEncryption() const; void setEncryption(LinphoneEnums::MediaEncryption encryption); @@ -169,8 +177,9 @@ signals: void pausedChanged(); void transferStateChanged(); void securityUpdated(); - void localSasChanged(); - void remoteSasChanged(); + void tokenVerified(); + void localTokenChanged(); + void remoteTokensChanged(); void remoteVideoEnabledChanged(bool remoteVideoEnabled); void localVideoEnabledChanged(); void recordingChanged(); @@ -196,7 +205,8 @@ signals: void lTransferCall(QString &est); void lStartRecording(); void lStopRecording(); - void lVerifyAuthenticationToken(bool verified); + void lCheckAuthenticationTokenSelected(const QString &token); + void lSkipZrtpAuthentication(); void lSetSpeakerVolumeGain(float gain); void lSetMicrophoneVolumeGain(float gain); void lSetInputAudioDevice(QString id); @@ -236,10 +246,12 @@ private: QString mLastErrorMessage; QString mPeerAddress; QString mLocalAddress; - bool mIsSecured; + bool mTokenVerified = false; + bool mIsSecured = false; + bool mIsMismatch = false; int mDuration = 0; - bool mSpeakerMuted; - bool mMicrophoneMuted; + bool mSpeakerMuted = false; + bool mMicrophoneMuted = false; bool mLocalVideoEnabled = false; bool mVideoEnabled = false; bool mPaused = false; @@ -248,8 +260,8 @@ private: bool mRemoteRecording = false; bool mRecordable = false; bool mIsConference = false; - QString mLocalSas; - QString mRemoteSas; + QString mLocalToken; + QStringList mRemoteTokens; float mSpeakerVolumeGain; float mMicrophoneVolume; float mMicrophoneVolumeGain; diff --git a/Linphone/data/image/lock-key.svg b/Linphone/data/image/lock-key.svg new file mode 100644 index 000000000..e033ef858 --- /dev/null +++ b/Linphone/data/image/lock-key.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/lock-simple-open.svg b/Linphone/data/image/lock-simple-open.svg new file mode 100644 index 000000000..203a421a1 --- /dev/null +++ b/Linphone/data/image/lock-simple-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/data/image/shield-warning.svg b/Linphone/data/image/shield-warning.svg new file mode 100644 index 000000000..41c778b3f --- /dev/null +++ b/Linphone/data/image/shield-warning.svg @@ -0,0 +1,3 @@ + + + diff --git a/Linphone/data/image/trusted-white.svg b/Linphone/data/image/trusted-white.svg new file mode 100644 index 000000000..91975350c --- /dev/null +++ b/Linphone/data/image/trusted-white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Linphone/model/call/CallModel.cpp b/Linphone/model/call/CallModel.cpp index 7319cfa65..9109ff0ff 100644 --- a/Linphone/model/call/CallModel.cpp +++ b/Linphone/model/call/CallModel.cpp @@ -270,16 +270,28 @@ bool CallModel::getAuthenticationTokenVerified() const { return mMonitor->getAuthenticationTokenVerified(); } -void CallModel::setAuthenticationTokenVerified(bool verified) { +void CallModel::checkAuthenticationToken(const QString &token) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); - mMonitor->setAuthenticationTokenVerified(verified); - emit authenticationTokenVerifiedChanged(verified); + mMonitor->checkAuthenticationTokenSelected(Utils::appStringToCoreString(token)); } -std::string CallModel::getAuthenticationToken() const { - mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); - auto token = mMonitor->getAuthenticationToken(); - return token; +void CallModel::skipZrtpAuthentication() { + mMonitor->skipZrtpAuthentication(); +} + +std::string CallModel::getLocalAtuhenticationToken() const { + return mMonitor->getLocalAuthenticationToken(); +} + +QStringList CallModel::getRemoteAtuhenticationTokens() const { + QStringList ret; + for (auto &token : mMonitor->getRemoteAuthenticationTokens()) + ret.append(Utils::coreStringToAppString(token)); + return ret; +} + +bool CallModel::getZrtpCaseMismatch() const { + return mMonitor->getZrtpCacheMismatchFlag(); } void CallModel::setConference(const std::shared_ptr &conference) { @@ -459,3 +471,7 @@ void CallModel::onAudioDeviceChanged(const std::shared_ptr &call void CallModel::onRemoteRecording(const std::shared_ptr &call, bool recording) { emit remoteRecording(call, recording); } + +void CallModel::onAuthenticationTokenVerified(const std::shared_ptr &call, bool verified) { + emit authenticationTokenVerified(call, verified); +} diff --git a/Linphone/model/call/CallModel.hpp b/Linphone/model/call/CallModel.hpp index 7faa97aa7..4c6ea38c1 100644 --- a/Linphone/model/call/CallModel.hpp +++ b/Linphone/model/call/CallModel.hpp @@ -66,8 +66,11 @@ public: std::string getRecordFile() const; std::shared_ptr getRemoteAddress(); bool getAuthenticationTokenVerified() const; - void setAuthenticationTokenVerified(bool verified); - std::string getAuthenticationToken() const; + void checkAuthenticationToken(const QString &token); + void skipZrtpAuthentication(); + std::string getLocalAtuhenticationToken() const; + QStringList getRemoteAtuhenticationTokens() const; + bool getZrtpCaseMismatch() const; LinphoneEnums::ConferenceLayout getConferenceVideoLayout() const; void changeConferenceVideoLayout(LinphoneEnums::ConferenceLayout layout); // Make a call request @@ -91,7 +94,6 @@ signals: void remoteVideoEnabledChanged(bool remoteVideoEnabled); void localVideoEnabledChanged(bool enabled); void recordingChanged(bool recording); - void authenticationTokenVerifiedChanged(bool verified); void speakerVolumeGainChanged(float volume); void microphoneVolumeGainChanged(float volume); void inputAudioDeviceChanged(const std::string &id); @@ -143,6 +145,7 @@ private: virtual void onAudioDeviceChanged(const std::shared_ptr &call, const std::shared_ptr &audioDevice) override; virtual void onRemoteRecording(const std::shared_ptr &call, bool recording) override; + virtual void onAuthenticationTokenVerified(const std::shared_ptr &call, bool verified); signals: void dtmfReceived(const std::shared_ptr &call, int dtmf); @@ -170,6 +173,7 @@ signals: void audioDeviceChanged(const std::shared_ptr &call, const std::shared_ptr &audioDevice); void remoteRecording(const std::shared_ptr &call, bool recording); + void authenticationTokenVerified(const std::shared_ptr &call, bool verified); }; #endif diff --git a/Linphone/view/App/CallsWindow.qml b/Linphone/view/App/CallsWindow.qml index 2e6541755..812f0d8da 100644 --- a/Linphone/view/App/CallsWindow.qml +++ b/Linphone/view/App/CallsWindow.qml @@ -31,7 +31,7 @@ AppWindow { middleItemStackView.replace(inCallItem) bottomButtonsLayout.visible = true } - if(!call.core.isSecured && call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) { + if(call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp && (!call.core.tokenVerified || call.core.isMismatch)) { zrtpValidation.open() } } @@ -184,7 +184,7 @@ AppWindow { ZrtpTokenAuthenticationDialog { id: zrtpValidation call: mainWindow.call - modal: false + modal: true } Popup { id: waitingPopup @@ -334,20 +334,60 @@ AppWindow { } RowLayout { spacing: 5 * DefaultStyle.dp - visible: mainWindow.call && mainWindow.call.core.isSecured + visible: mainWindow.callState != LinphoneEnums.CallState.End && mainWindow.callState != LinphoneEnums.CallState.Released + BusyIndicator { + visible: mainWindow.call && mainWindow.callState != LinphoneEnums.CallState.Connected && mainWindow.callState != LinphoneEnums.CallState.StreamsRunning + Layout.preferredWidth: 15 * DefaultStyle.dp + Layout.preferredHeight: 15 * DefaultStyle.dp + indicatorColor: DefaultStyle.grey_0 + } EffectImage { Layout.preferredWidth: 15 * DefaultStyle.dp Layout.preferredHeight: 15 * DefaultStyle.dp - colorizationColor: DefaultStyle.info_500_main - imageSource: AppIcons.lockSimple + colorizationColor: mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp + ? DefaultStyle.info_500_main + : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp + ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified + ? DefaultStyle.warning_600 + : DefaultStyle.info_500_main + : DefaultStyle.grey_0 + visible: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning + imageSource: mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp + ? AppIcons.lockSimple + : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp + ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified + ? AppIcons.warningCircle + : AppIcons.lockKey + : AppIcons.lockSimpleOpen } Text { - text: qsTr("Appel chiffré de bout en bout") - color: DefaultStyle.info_500_main + text: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning + ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp + ? qsTr("Appel chiffré de point à point") + : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp + ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified + ? qsTr("Vérification nécessaire") + : qsTr("Appel chiffré de bout en bout") + : qsTr("Appel non chiffré") + : qsTr("En attente de chiffrement") + color: mainWindow.call && mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning + ? mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Srtp + ? DefaultStyle.info_500_main + : mainWindow.call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp + ? mainWindow.call.core.isMismatch || !mainWindow.call.core.tokenVerified + ? DefaultStyle.warning_600 + : DefaultStyle.info_500_main + : DefaultStyle.grey_0 + : DefaultStyle.grey_0 font { pixelSize: 12 * DefaultStyle.dp weight: 400 * DefaultStyle.dp } + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + } } Item { Layout.fillWidth: true diff --git a/Linphone/view/Item/Form/LoginForm.qml b/Linphone/view/Item/Form/LoginForm.qml index 383133d5e..55c66d646 100644 --- a/Linphone/view/Item/Form/LoginForm.qml +++ b/Linphone/view/Item/Form/LoginForm.qml @@ -152,4 +152,4 @@ ColumnLayout { } } -} +} \ No newline at end of file diff --git a/Linphone/view/Item/ZrtpTokenAuthenticationDialog.qml b/Linphone/view/Item/ZrtpTokenAuthenticationDialog.qml index f9aeafc56..4f3d5acf2 100644 --- a/Linphone/view/Item/ZrtpTokenAuthenticationDialog.qml +++ b/Linphone/view/Item/ZrtpTokenAuthenticationDialog.qml @@ -8,150 +8,311 @@ import UtilsCpp 1.0 // ============================================================================= Dialog { id: mainItem - - property var call - width: 436 * DefaultStyle.dp - height: 549 * DefaultStyle.dp - - rightPadding: 15 * DefaultStyle.dp - leftPadding: 15 * DefaultStyle.dp - topPadding: 40 * DefaultStyle.dp - bottomPadding: 40 * DefaultStyle.dp + rightPadding: 0 * DefaultStyle.dp + leftPadding: 0 * DefaultStyle.dp + topPadding: 85 * DefaultStyle.dp + 23 * DefaultStyle.dp + bottomPadding: 24 * DefaultStyle.dp + modal: true + closePolicy: Popup.NoAutoClose + property var call onCallChanged: if(!call) close() + property bool isTokenVerified: call && call.core.tokenVerified || false + property bool isCaseMismatch: call && call.core.isMismatch || false + property bool securityError: false + property bool firstTry: true Connections { enabled: call != undefined && call != null target: call && call.core onStatusChanged: if (status === CallModel.CallStatusEnded) close() - } - - buttons: Layout.ColumnLayout { - spacing: 15 * DefaultStyle.dp - Button { - Layout.Layout.alignment: Qt.AlignHCenter - background: Item{} - contentItem: Text { - text: qsTr("Skip") - font { - pixelSize: 13 * DefaultStyle.dp - weight: 600 * DefaultStyle.dp - underline: true - } - } - onClicked: { - if(mainItem.call) mainItem.call.core.lVerifyAuthenticationToken(false) - mainItem.close() - } + onSecurityUpdated: { + if (!mainItem.isTokenVerified) { + mainItem.securityError = true + } else close() } - Button { - text: qsTr("Letters doesn't match") - color: DefaultStyle.danger_500main - inversedColors: true - Layout.Layout.alignment: Qt.AlignHCenter - width: 330 * DefaultStyle.dp - onClicked: { - if(mainItem.call) mainItem.call.core.lVerifyAuthenticationToken(false) - mainItem.close() - } + onTokenVerified: { + if (!mainItem.isTokenVerified) { + mainItem.securityError = true + } else close() } } - - content: Layout.ColumnLayout { - spacing: 32 * DefaultStyle.dp - Layout.Layout.alignment: Qt.AlignHCenter - Layout.ColumnLayout { - spacing: 10 * DefaultStyle.dp - Text { - Layout.Layout.preferredWidth: 330 * DefaultStyle.dp - Layout.Layout.alignment: Qt.AlignHCenter - text: qsTr("Vérifier l'appareil") - horizontalAlignment: Text.AlignLeft - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - } - - Text { - Layout.Layout.preferredWidth: 330 * DefaultStyle.dp - Layout.Layout.alignment: Qt.AlignHCenter - - horizontalAlignment: Text.AlignLeft - //: 'To raise the security level, you can check the following codes with your correspondent.' : Explanation to do a security check. - text: qsTr("Dites %1 et cliquez sur les lettres votre interlocuteur vous dit :".arg(mainItem.call && mainItem.call.core.localSas || "")) - - wrapMode: Text.WordWrap - font.pixelSize: 14 * DefaultStyle.dp - } - } - - Layout.GridLayout { - id: securityGridView - // Layout.Layout.fillWidth: true - Layout.Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom - rows: 2 - columns: 2 - rowSpacing: 32 * DefaultStyle.dp - columnSpacing: 32 * DefaultStyle.dp - property var correctIndex - property var modelList - Connections { - enabled: mainItem.call - target: mainItem.call ? mainItem.call.core : null - // this connection is needed to get the remoteSas when available - // due to the asynchronous connection between core and ui - onRemoteSasChanged: { - securityGridView.correctIndex = UtilsCpp.getRandomIndex(4) - securityGridView.modelList = UtilsCpp.generateSecurityLettersArray(4, securityGridView.correctIndex, mainItem.call.core.remoteSas) - } - } - Repeater { - model: securityGridView.modelList + background: Item { + anchors.fill: parent + Rectangle { + id: backgroundItem + anchors.fill: parent + width: mainItem.width + height: mainItem.implicitHeight + color: mainItem.securityError + ? DefaultStyle.danger_500main + : mainItem.isCaseMismatch + ? DefaultStyle.warning_600 + : DefaultStyle.info_500_main + radius: mainItem.radius + Layout.ColumnLayout { + anchors.top: parent.top + anchors.topMargin: 18 * DefaultStyle.dp + anchors.horizontalCenter: parent.horizontalCenter Item { - // implicitWidth: 70 * DefaultStyle.dp - // implicitHeight: 70 * DefaultStyle.dp - width: 70 * DefaultStyle.dp - height: 70 * DefaultStyle.dp - Rectangle { - id: code - anchors.fill: parent - color: DefaultStyle.grey_0 - radius: 71 * DefaultStyle.dp - Text { - anchors.fill: parent - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: modelData - font { - pixelSize: 32 * DefaultStyle.dp - weight: 400 * DefaultStyle.dp - } + // spacing: 14 * DefaultStyle.dp + width: childrenRect.width + height: childrenRect.height + Layout.Layout.fillWidth: true + Image { + id: trustShield + anchors.centerIn: parent + source: AppIcons.trustedWhite + sourceSize.width: 24 * DefaultStyle.dp + sourceSize.height: 24 * DefaultStyle.dp + width: 24 * DefaultStyle.dp + height: 24 * DefaultStyle.dp + } + EffectImage { + anchors.left: trustShield.right + anchors.leftMargin: 14 * DefaultStyle.dp + visible: mainItem.securityError + imageSource: AppIcons.shieldWarning + colorizationColor: DefaultStyle.main2_700 + width: 24 * DefaultStyle.dp + height: 24 * DefaultStyle.dp + } + } + Text { + text: qsTr("Vérification de sécurité") + color: DefaultStyle.grey_0 + Layout.Layout.alignment: Qt.AlignHCenter + font { + pixelSize: 14 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } + } + Item{Layout.Layout.fillHeight: true} + } + Button { + visible: !mainItem.securityError + anchors.top: parent.top + anchors.right: parent.right + anchors.topMargin: 10 * DefaultStyle.dp + anchors.rightMargin: 17 * DefaultStyle.dp + background: Item{} + contentItem: Text { + text: qsTr("Passer") + color: DefaultStyle.grey_0 + font { + pixelSize: 13 * DefaultStyle.dp + weight: 600 * DefaultStyle.dp + underline: true + } + } + onClicked: { + call.core.lSkipZrtpAuthentication() + mainItem.close() + } + } + } + Rectangle { + z: 1 + width: mainItem.width + height: parent.height - 87 * DefaultStyle.dp + x: parent.x + y: parent.y + 85 * DefaultStyle.dp + color: DefaultStyle.grey_0 + radius: mainItem.radius + } + MultiEffect { + anchors.fill: backgroundItem + source: backgroundItem + shadowEnabled: true + shadowColor: DefaultStyle.grey_900 + shadowBlur: 1.0 + shadowOpacity: 0.1 + } + } + + content: [ + Layout.ColumnLayout { + visible: !mainItem.securityError + spacing: 20 * DefaultStyle.dp + Layout.Layout.alignment: Qt.AlignHCenter + Layout.Layout.fillWidth: true + Layout.ColumnLayout { + spacing: 10 * DefaultStyle.dp + Layout.Layout.alignment: Qt.AlignHCenter + Text { + Layout.Layout.preferredWidth: 343 * DefaultStyle.dp + Layout.Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + text: !mainItem.isTokenVerified && mainItem.isCaseMismatch + ? qsTr("Pour garantir le chiffrement, nous avons besoin de réauthentifier l’appareil de votre correspondant. Echangez vos codes :") + : qsTr("Pour garantir le chiffrement, nous avons besoin d’authentifier l’appareil de votre correspondant. Veuillez échanger vos codes : ") + wrapMode: Text.WordWrap + font.pixelSize: 14 * DefaultStyle.dp + } + Layout.ColumnLayout { + spacing: 0 + Layout.Layout.alignment: Qt.AlignHCenter + Text { + text: qsTr("Votre code :") + horizontalAlignment: Text.AlignHCenter + Layout.Layout.alignment: Qt.AlignHCenter + font.pixelSize: 14 * DefaultStyle.dp + } + Text { + text: mainItem.call && mainItem.call.core.localToken || "" + horizontalAlignment: Text.AlignHCenter + Layout.Layout.alignment: Qt.AlignHCenter + font { + pixelSize: 18 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp } - MouseArea { - anchors.fill: parent - onClicked: { - console.log("correct", index == securityGridView.correctIndex, index) - if (index == securityGridView.correctIndex) { - if(mainItem.call) mainItem.call.core.lVerifyAuthenticationToken(true) - } else { - if(mainItem.call) mainItem.call.core.lVerifyAuthenticationToken(false) - mainItem.close() + } + } + } + Rectangle { + color: "transparent" + border.color: DefaultStyle.main2_200 + border.width: Math.max(0.5, 1 * DefaultStyle.dp) + radius: 15 * DefaultStyle.dp + Layout.Layout.preferredWidth: 292 * DefaultStyle.dp + Layout.Layout.preferredHeight: 233 * DefaultStyle.dp + Layout.Layout.alignment: Qt.AlignHCenter + Layout.ColumnLayout { + anchors.fill: parent + anchors.topMargin: 10 * DefaultStyle.dp + Text { + text: qsTr("Code correspondant :") + font.pixelSize: 14 * DefaultStyle.dp + Layout.Layout.alignment: Qt.AlignHCenter + } + Layout.GridLayout { + id: securityGridView + Layout.Layout.alignment: Qt.AlignHCenter + rows: 2 + columns: 2 + rowSpacing: 32 * DefaultStyle.dp + columnSpacing: 32 * DefaultStyle.dp + property var correctIndex + property var modelList + Repeater { + model: mainItem.call && mainItem.call.core.remoteTokens || "" + Item { + width: 70 * DefaultStyle.dp + height: 70 * DefaultStyle.dp + Rectangle { + id: code + anchors.fill: parent + color: DefaultStyle.grey_0 + radius: 71 * DefaultStyle.dp + Text { + anchors.fill: parent + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: modelData + font { + pixelSize: 32 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor + onClicked: { + console.log("check token", modelData) + if(mainItem.call) mainItem.call.core.lCheckAuthenticationTokenSelected(modelData) + } + } + } + MultiEffect { + source: code + anchors.fill: code + shadowEnabled: true + shadowOpacity: 0.1 + shadowBlur: 1.0 } } } } - MultiEffect { - source: code - anchors.fill: code - shadowEnabled: true - shadowOpacity: 0.1 - shadowBlur: 1.0 - } } } + }, + Layout.ColumnLayout { + spacing: 0 + Text { + visible: mainItem.securityError + width: 303 * DefaultStyle.dp + // Layout.Layout.preferredWidth: 343 * DefaultStyle.dp + Layout.Layout.alignment: Qt.AlignHCenter + Layout.Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + text: qsTr("Le code fourni ne correspond pas.") + wrapMode: Text.WordWrap + font.pixelSize: 14 * DefaultStyle.dp + } + Text { + visible: mainItem.securityError + width: 303 * DefaultStyle.dp + // Layout.Layout.preferredWidth: 343 * DefaultStyle.dp + Layout.Layout.alignment: Qt.AlignHCenter + Layout.Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + text: qsTr("La confidentialité de votre appel peut être compromise !") + wrapMode: Text.WordWrap + font.pixelSize: 14 * DefaultStyle.dp + } + } + ] + + buttons: Layout.ColumnLayout { + Layout.Layout.alignment: Qt.AlignHCenter + Button { + Layout.Layout.alignment: Qt.AlignHCenter + text: qsTr("Aucune correspondance") + color: DefaultStyle.danger_500main + inversedColors: true + textSize: 15 * DefaultStyle.dp + visible: !mainItem.securityError + leftPadding: 16 * DefaultStyle.dp + rightPadding: 16 * DefaultStyle.dp + topPadding: 10 * DefaultStyle.dp + bottomPadding: 10 * DefaultStyle.dp + width: 247 * DefaultStyle.dp + onClicked: { + if(mainItem.call) mainItem.call.core.lCheckAuthenticationTokenSelected(" ") + } + } + Button { + Layout.Layout.preferredWidth: 247 * DefaultStyle.dp + visible: mainItem.securityError && mainItem.firstTry + text: qsTr("Réessayer") + color: DefaultStyle.danger_500main + inversedColors: true + leftPadding: 16 * DefaultStyle.dp + rightPadding: 16 * DefaultStyle.dp + topPadding: 10 * DefaultStyle.dp + bottomPadding: 10 * DefaultStyle.dp + onClicked: { + mainItem.firstTry = false + mainItem.securityError = false + } + } + Button { + Layout.Layout.preferredWidth: 247 * DefaultStyle.dp + visible: mainItem.securityError + leftPadding: (247 * DefaultStyle.dp - contentItem.implicitWidth) /2 + rightPadding: (247 * DefaultStyle.dp - contentItem.implicitWidth) /2 + topPadding: 10 * DefaultStyle.dp + bottomPadding: 10 * DefaultStyle.dp + color: DefaultStyle.danger_500main + onClicked: mainItem.call.core.lTerminate() + spacing: 15 * DefaultStyle.dp + icon.source: AppIcons.endCall + contentImageColor: DefaultStyle.grey_0 + text: qsTr("Raccrocher") + textColor: DefaultStyle.grey_0 } } -} +} \ No newline at end of file diff --git a/Linphone/view/Style/AppIcons.qml b/Linphone/view/Style/AppIcons.qml index f3dd2a71e..6f145c47f 100644 --- a/Linphone/view/Style/AppIcons.qml +++ b/Linphone/view/Style/AppIcons.qml @@ -6,6 +6,9 @@ QtObject { property string welcomeLock: "image://internal/secured.svg" property string lock: "image://internal/lock.svg" property string lockSimple: "image://internal/lock-simple.svg" + property string lockSimpleOpen: "image://internal/lock-simple-open.svg" + property string lockKey: "image://internal/lock-key.svg" + property string shieldWarning: "image://internal/shield-warning.svg" property string welcomeOpenSource: "image://internal/open_source.svg" property string splashscreenLogo: "image://internal/splashscreen-logo.svg" property string eyeHide: "image://internal/eye.svg" @@ -60,6 +63,7 @@ QtObject { property string speaker: "image://internal/speaker-high.svg" property string speakerSlash: "image://internal/speaker-slash.svg" property string trusted: "image://internal/trusted.svg" + property string trustedWhite: "image://internal/trusted-white.svg" property string avatar: "image://internal/randomAvatar.png" property string pause: "image://internal/pause.svg" property string play: "image://internal/play.svg"