zrtp authentication token

This commit is contained in:
Gaelle Braud 2024-01-18 11:33:15 +01:00
parent 92f7d05b18
commit c33b35724a
18 changed files with 420 additions and 110 deletions

View file

@ -20,7 +20,6 @@
#include "CallCore.hpp"
#include "core/App.hpp"
#include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp"
@ -51,11 +50,11 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
mPeerAddress = Utils::coreStringToAppString(mCallModel->getRemoteAddress()->asString());
mStatus = LinphoneEnums::fromLinphone(call->getCallLog()->getStatus());
mTransferState = LinphoneEnums::fromLinphone(call->getTransferState());
auto encryption = LinphoneEnums::fromLinphone(call->getCurrentParams()->getMediaEncryption());
mEncryption = LinphoneEnums::fromLinphone(call->getParams()->getMediaEncryption());
auto tokenVerified = mCallModel->getAuthenticationTokenVerified();
mPeerSecured = (encryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
encryption == LinphoneEnums::MediaEncryption::Srtp ||
encryption == LinphoneEnums::MediaEncryption::Dtls;
mIsSecured = (mEncryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
mEncryption == LinphoneEnums::MediaEncryption::Srtp ||
mEncryption == LinphoneEnums::MediaEncryption::Dtls;
mPaused = mState == LinphoneEnums::CallState::Pausing || mState == LinphoneEnums::CallState::Paused ||
mState == LinphoneEnums::CallState::PausedByRemote;
mRecording = call->getParams() && call->getParams()->isRecording();
@ -70,75 +69,82 @@ CallCore::~CallCore() {
}
void CallCore::setSelf(QSharedPointer<CallCore> me) {
mAccountModelConnection = QSharedPointer<SafeConnection<CallCore, CallModel>>(
mCallModelConnection = QSharedPointer<SafeConnection<CallCore, CallModel>>(
new SafeConnection<CallCore, CallModel>(me, mCallModel), &QObject::deleteLater);
mAccountModelConnection->makeConnectToCore(&CallCore::lSetMicrophoneMuted, [this](bool isMuted) {
mAccountModelConnection->invokeToModel([this, isMuted]() { mCallModel->setMicrophoneMuted(isMuted); });
mCallModelConnection->makeConnectToCore(&CallCore::lSetMicrophoneMuted, [this](bool isMuted) {
mCallModelConnection->invokeToModel([this, isMuted]() { mCallModel->setMicrophoneMuted(isMuted); });
});
mAccountModelConnection->makeConnectToModel(&CallModel::microphoneMutedChanged, [this](bool isMuted) {
mAccountModelConnection->invokeToCore([this, isMuted]() { setMicrophoneMuted(isMuted); });
mCallModelConnection->makeConnectToModel(&CallModel::microphoneMutedChanged, [this](bool isMuted) {
mCallModelConnection->invokeToCore([this, isMuted]() { setMicrophoneMuted(isMuted); });
});
mAccountModelConnection->makeConnectToModel(&CallModel::remoteVideoEnabledChanged, [this](bool enabled) {
mAccountModelConnection->invokeToCore([this, enabled]() { setRemoteVideoEnabled(enabled); });
mCallModelConnection->makeConnectToModel(&CallModel::remoteVideoEnabledChanged, [this](bool enabled) {
mCallModelConnection->invokeToCore([this, enabled]() { setRemoteVideoEnabled(enabled); });
});
mAccountModelConnection->makeConnectToCore(&CallCore::lSetSpeakerMuted, [this](bool isMuted) {
mAccountModelConnection->invokeToModel([this, isMuted]() { mCallModel->setSpeakerMuted(isMuted); });
mCallModelConnection->makeConnectToCore(&CallCore::lSetSpeakerMuted, [this](bool isMuted) {
mCallModelConnection->invokeToModel([this, isMuted]() { mCallModel->setSpeakerMuted(isMuted); });
});
mAccountModelConnection->makeConnectToModel(&CallModel::speakerMutedChanged, [this](bool isMuted) {
mAccountModelConnection->invokeToCore([this, isMuted]() { setSpeakerMuted(isMuted); });
mCallModelConnection->makeConnectToModel(&CallModel::speakerMutedChanged, [this](bool isMuted) {
mCallModelConnection->invokeToCore([this, isMuted]() { setSpeakerMuted(isMuted); });
});
mAccountModelConnection->makeConnectToCore(&CallCore::lSetCameraEnabled, [this](bool enabled) {
mAccountModelConnection->invokeToModel([this, enabled]() { mCallModel->setCameraEnabled(enabled); });
mCallModelConnection->makeConnectToCore(&CallCore::lSetCameraEnabled, [this](bool enabled) {
mCallModelConnection->invokeToModel([this, enabled]() { mCallModel->setCameraEnabled(enabled); });
});
mAccountModelConnection->makeConnectToCore(&CallCore::lStartRecording, [this]() {
mAccountModelConnection->invokeToModel([this]() { mCallModel->startRecording(); });
mCallModelConnection->makeConnectToCore(&CallCore::lStartRecording, [this]() {
mCallModelConnection->invokeToModel([this]() { mCallModel->startRecording(); });
});
mAccountModelConnection->makeConnectToCore(&CallCore::lStopRecording, [this]() {
mAccountModelConnection->invokeToModel([this]() { mCallModel->stopRecording(); });
mCallModelConnection->makeConnectToCore(&CallCore::lStopRecording, [this]() {
mCallModelConnection->invokeToModel([this]() { mCallModel->stopRecording(); });
});
mAccountModelConnection->makeConnectToModel(&CallModel::recordingChanged, [this](bool recording) {
mAccountModelConnection->invokeToCore([this, recording]() { setRecording(recording); });
mCallModelConnection->makeConnectToModel(&CallModel::recordingChanged, [this](bool recording) {
mCallModelConnection->invokeToCore([this, recording]() { setRecording(recording); });
});
mAccountModelConnection->makeConnectToModel(
mCallModelConnection->makeConnectToCore(&CallCore::lVerifyAuthenticationToken, [this](bool verified) {
mCallModelConnection->invokeToModel(
[this, verified]() { mCallModel->setAuthenticationTokenVerified(verified); });
});
mCallModelConnection->makeConnectToModel(&CallModel::authenticationTokenVerifiedChanged, [this](bool verified) {
mCallModelConnection->invokeToCore([this, verified]() { setIsSecured(verified); });
});
mCallModelConnection->makeConnectToModel(
&CallModel::remoteRecording, [this](const std::shared_ptr<linphone::Call> &call, bool recording) {
mAccountModelConnection->invokeToCore([this, recording]() { setRemoteRecording(recording); });
mCallModelConnection->invokeToCore([this, recording]() { setRemoteRecording(recording); });
});
mAccountModelConnection->makeConnectToModel(&CallModel::cameraEnabledChanged, [this](bool enabled) {
mAccountModelConnection->invokeToCore([this, enabled]() { setCameraEnabled(enabled); });
mCallModelConnection->makeConnectToModel(&CallModel::cameraEnabledChanged, [this](bool enabled) {
mCallModelConnection->invokeToCore([this, enabled]() { setCameraEnabled(enabled); });
});
mAccountModelConnection->makeConnectToModel(&CallModel::durationChanged, [this](int duration) {
mAccountModelConnection->invokeToCore([this, duration]() { setDuration(duration); });
mCallModelConnection->makeConnectToModel(&CallModel::durationChanged, [this](int duration) {
mCallModelConnection->invokeToCore([this, duration]() { setDuration(duration); });
});
mAccountModelConnection->makeConnectToModel(
mCallModelConnection->makeConnectToModel(
&CallModel::stateChanged, [this](linphone::Call::State state, const std::string &message) {
mAccountModelConnection->invokeToCore([this, state, message]() {
mCallModelConnection->invokeToCore([this, state, message]() {
setState(LinphoneEnums::fromLinphone(state), Utils::coreStringToAppString(message));
});
});
mAccountModelConnection->makeConnectToModel(&CallModel::statusChanged, [this](linphone::Call::Status status) {
mAccountModelConnection->invokeToCore([this, status]() { setStatus(LinphoneEnums::fromLinphone(status)); });
mCallModelConnection->makeConnectToModel(&CallModel::statusChanged, [this](linphone::Call::Status status) {
mCallModelConnection->invokeToCore([this, status]() { setStatus(LinphoneEnums::fromLinphone(status)); });
});
mAccountModelConnection->makeConnectToModel(&CallModel::stateChanged,
[this](linphone::Call::State state, const std::string &message) {
mAccountModelConnection->invokeToCore([this, state]() {
setRecordable(state == linphone::Call::State::StreamsRunning);
});
});
mAccountModelConnection->makeConnectToCore(&CallCore::lSetPaused, [this](bool paused) {
mAccountModelConnection->invokeToModel([this, paused]() { mCallModel->setPaused(paused); });
mCallModelConnection->makeConnectToModel(&CallModel::stateChanged,
[this](linphone::Call::State state, const std::string &message) {
mCallModelConnection->invokeToCore([this, state]() {
setRecordable(state == linphone::Call::State::StreamsRunning);
});
});
mCallModelConnection->makeConnectToCore(&CallCore::lSetPaused, [this](bool paused) {
mCallModelConnection->invokeToModel([this, paused]() { mCallModel->setPaused(paused); });
});
mAccountModelConnection->makeConnectToModel(&CallModel::pausedChanged, [this](bool paused) {
mAccountModelConnection->invokeToCore([this, paused]() { setPaused(paused); });
mCallModelConnection->makeConnectToModel(&CallModel::pausedChanged, [this](bool paused) {
mCallModelConnection->invokeToCore([this, paused]() { setPaused(paused); });
});
mAccountModelConnection->makeConnectToCore(&CallCore::lTransferCall, [this](const QString &address) {
mAccountModelConnection->invokeToModel(
mCallModelConnection->makeConnectToCore(&CallCore::lTransferCall, [this](const QString &address) {
mCallModelConnection->invokeToModel(
[this, address]() { mCallModel->transferTo(ToolModel::interpretUrl(address)); });
});
mAccountModelConnection->makeConnectToModel(
mCallModelConnection->makeConnectToModel(
&CallModel::transferStateChanged,
[this](const std::shared_ptr<linphone::Call> &call, linphone::Call::State state) {
mAccountModelConnection->invokeToCore([this, state]() {
mCallModelConnection->invokeToCore([this, state]() {
QString message;
if (state == linphone::Call::State::Error) {
message = "L'appel n'a pas pu être transféré.";
@ -146,27 +152,35 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
setTransferState(LinphoneEnums::fromLinphone(state), message);
});
});
mAccountModelConnection->makeConnectToModel(
mCallModelConnection->makeConnectToModel(
&CallModel::encryptionChanged,
[this](const std::shared_ptr<linphone::Call> &call, bool on, const std::string &authenticationToken) {
auto encryption = LinphoneEnums::fromLinphone(call->getCurrentParams()->getMediaEncryption());
auto tokenVerified = mCallModel->getAuthenticationTokenVerified();
mAccountModelConnection->invokeToCore([this, call, encryption, tokenVerified]() {
setPeerSecured((encryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
encryption == LinphoneEnums::MediaEncryption::Srtp ||
encryption == LinphoneEnums::MediaEncryption::Dtls);
auto token = Utils::coreStringToAppString(mCallModel->getAuthenticationToken());
mCallModelConnection->invokeToCore([this, call, encryption, tokenVerified, token]() {
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);
});
});
mAccountModelConnection->makeConnectToCore(&CallCore::lAccept, [this](bool withVideo) {
mAccountModelConnection->invokeToModel([this, withVideo]() { mCallModel->accept(withVideo); });
mCallModelConnection->makeConnectToCore(&CallCore::lAccept, [this](bool withVideo) {
mCallModelConnection->invokeToModel([this, withVideo]() { mCallModel->accept(withVideo); });
});
mAccountModelConnection->makeConnectToCore(
&CallCore::lDecline, [this]() { mAccountModelConnection->invokeToModel([this]() { mCallModel->decline(); }); });
mAccountModelConnection->makeConnectToCore(&CallCore::lTerminate, [this]() {
mAccountModelConnection->invokeToModel([this]() { mCallModel->terminate(); });
mCallModelConnection->makeConnectToCore(
&CallCore::lDecline, [this]() { mCallModelConnection->invokeToModel([this]() { mCallModel->decline(); }); });
mCallModelConnection->makeConnectToCore(&CallCore::lTerminate, [this]() {
mCallModelConnection->invokeToModel([this]() { mCallModel->terminate(); });
});
mAccountModelConnection->makeConnectToCore(&CallCore::lTerminateAllCalls, [this]() {
mAccountModelConnection->invokeToModel([this]() { mCallModel->terminateAllCalls(); });
mCallModelConnection->makeConnectToCore(&CallCore::lTerminateAllCalls, [this]() {
mCallModelConnection->invokeToModel([this]() { mCallModel->terminateAllCalls(); });
});
}
@ -276,13 +290,47 @@ void CallCore::setPaused(bool paused) {
}
}
bool CallCore::getPeerSecured() const {
return mPeerSecured;
bool CallCore::isSecured() const {
return mIsSecured;
}
void CallCore::setPeerSecured(bool secured) {
if (mPeerSecured != secured) {
mPeerSecured = secured;
emit peerSecuredChanged();
void CallCore::setIsSecured(bool secured) {
if (mIsSecured != secured) {
mIsSecured = secured;
emit securityUpdated();
}
}
QString CallCore::getLocalSas() {
return mLocalSas;
}
QString CallCore::getRemoteSas() {
return mRemoteSas;
}
void CallCore::setLocalSas(const QString &sas) {
if (mLocalSas != sas) {
mLocalSas = sas;
emit localSasChanged();
}
}
void CallCore::setRemoteSas(const QString &sas) {
if (mRemoteSas != sas) {
mRemoteSas = sas;
emit remoteSasChanged();
}
}
LinphoneEnums::MediaEncryption CallCore::getEncryption() const {
return mEncryption;
}
void CallCore::setEncryption(LinphoneEnums::MediaEncryption encryption) {
if (mEncryption != encryption) {
mEncryption = encryption;
emit securityUpdated();
}
}

View file

@ -42,7 +42,10 @@ class CallCore : public QObject, public AbstractObject {
Q_PROPERTY(bool cameraEnabled READ getCameraEnabled WRITE lSetCameraEnabled NOTIFY cameraEnabledChanged)
Q_PROPERTY(bool paused READ getPaused WRITE lSetPaused NOTIFY pausedChanged)
Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT)
Q_PROPERTY(bool peerSecured READ getPeerSecured WRITE setPeerSecured NOTIFY peerSecuredChanged)
Q_PROPERTY(bool isSecured READ isSecured 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(
bool remoteVideoEnabled READ getRemoteVideoEnabled WRITE setRemoteVideoEnabled NOTIFY remoteVideoEnabledChanged)
Q_PROPERTY(bool recording READ getRecording WRITE setRecording NOTIFY recordingChanged)
@ -86,8 +89,16 @@ public:
bool getPaused() const;
void setPaused(bool paused);
bool getPeerSecured() const;
void setPeerSecured(bool secured);
bool isSecured() const;
void setIsSecured(bool secured);
QString getLocalSas();
void setLocalSas(const QString &sas);
QString getRemoteSas();
void setRemoteSas(const QString &sas);
LinphoneEnums::MediaEncryption getEncryption() const;
void setEncryption(LinphoneEnums::MediaEncryption encryption);
bool getRemoteVideoEnabled() const;
void setRemoteVideoEnabled(bool enabled);
@ -118,7 +129,9 @@ signals:
void cameraEnabledChanged();
void pausedChanged();
void transferStateChanged();
void peerSecuredChanged();
void securityUpdated();
void localSasChanged();
void remoteSasChanged();
void remoteVideoEnabledChanged(bool remoteVideoEnabled);
void recordingChanged();
void remoteRecordingChanged();
@ -136,6 +149,7 @@ signals:
void lTransferCall(const QString &dest);
void lStartRecording();
void lStopRecording();
void lVerifyAuthenticationToken(bool verified);
/* TODO
Q_INVOKABLE void acceptWithVideo();
@ -161,9 +175,10 @@ private:
LinphoneEnums::CallState mState;
LinphoneEnums::CallState mTransferState;
LinphoneEnums::CallDir mDir;
LinphoneEnums::MediaEncryption mEncryption;
QString mLastErrorMessage;
QString mPeerAddress;
bool mPeerSecured;
bool mIsSecured;
int mDuration = 0;
bool mSpeakerMuted;
bool mMicrophoneMuted;
@ -173,7 +188,9 @@ private:
bool mRecording = false;
bool mRemoteRecording = false;
bool mRecordable = false;
QSharedPointer<SafeConnection<CallCore, CallModel>> mAccountModelConnection;
QString mLocalSas;
QString mRemoteSas;
QSharedPointer<SafeConnection<CallCore, CallModel>> mCallModelConnection;
DECLARE_ABSTRACT_OBJECT
};

View file

@ -66,6 +66,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
"data/image/heart.svg"
"data/image/heart-fill.svg"
"data/image/record-fill.svg"
"data/image/media_encryption_zrtp_pq.svg"
data/shaders/roundEffect.vert.qsb
data/shaders/roundEffect.frag.qsb

View file

@ -136,6 +136,7 @@ void CallModel::stopRecording() {
}
void CallModel::setRecordFile(const std::string &path) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
auto params = core->createCallParams(mMonitor);
params->setRecordFile(path);
@ -143,6 +144,7 @@ void CallModel::setRecordFile(const std::string &path) {
}
std::string CallModel::getRecordFile() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return mMonitor->getParams()->getRecordFile();
}
@ -151,11 +153,23 @@ std::shared_ptr<const linphone::Address> CallModel::getRemoteAddress() {
return mMonitor->getRemoteAddress();
}
bool CallModel::getAuthenticationTokenVerified() {
bool CallModel::getAuthenticationTokenVerified() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return mMonitor->getAuthenticationTokenVerified();
}
void CallModel::setAuthenticationTokenVerified(bool verified) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->setAuthenticationTokenVerified(verified);
emit authenticationTokenVerifiedChanged(verified);
}
std::string CallModel::getAuthenticationToken() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto token = mMonitor->getAuthenticationToken();
return token;
}
void CallModel::onDtmfReceived(const std::shared_ptr<linphone::Call> &call, int dtmf) {
emit dtmfReceived(call, dtmf);
}

View file

@ -53,7 +53,9 @@ public:
std::string getRecordFile() const;
std::shared_ptr<const linphone::Address> getRemoteAddress();
bool getAuthenticationTokenVerified();
bool getAuthenticationTokenVerified() const;
void setAuthenticationTokenVerified(bool verified);
std::string getAuthenticationToken() const;
signals:
void microphoneMutedChanged(bool isMuted);
@ -63,6 +65,7 @@ signals:
void pausedChanged(bool paused);
void remoteVideoEnabledChanged(bool remoteVideoEnabled);
void recordingChanged(bool recording);
void authenticationTokenVerifiedChanged(bool verified);
private:
QTimer mDurationTimer;

View file

@ -75,7 +75,8 @@ QString ToolModel::getDisplayName(QString address) {
QSharedPointer<CallCore> ToolModel::createCall(const QString &sipAddress,
const QString &prepareTransfertAddress,
const QHash<QString, QString> &headers) {
const QHash<QString, QString> &headers,
linphone::MediaEncryption mediaEncryption) {
bool waitRegistrationForCall = true; // getSettingsModel()->getWaitRegistrationForCall()
std::shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
@ -88,6 +89,7 @@ QSharedPointer<CallCore> ToolModel::createCall(const QString &sipAddress,
std::shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(false);
params->setMediaEncryption(mediaEncryption);
if (Utils::coreStringToAppString(params->getRecordFile()).isEmpty()) {
params->setRecordFile(

View file

@ -41,7 +41,8 @@ public:
static QSharedPointer<CallCore> createCall(const QString &sipAddress,
const QString &prepareTransfertAddress = "",
const QHash<QString, QString> &headers = {});
const QHash<QString, QString> &headers = {},
linphone::MediaEncryption = linphone::MediaEncryption::None);
private:
DECLARE_ABSTRACT_OBJECT

View file

@ -312,7 +312,6 @@ Q_DECLARE_METATYPE(LinphoneEnums::ConferenceInfoState)
Q_DECLARE_METATYPE(LinphoneEnums::ConferenceSchedulerState)
Q_DECLARE_METATYPE(LinphoneEnums::EventLogType)
Q_DECLARE_METATYPE(LinphoneEnums::FriendCapability)
Q_DECLARE_METATYPE(LinphoneEnums::MediaEncryption)
Q_DECLARE_METATYPE(LinphoneEnums::ParticipantDeviceState)
Q_DECLARE_METATYPE(LinphoneEnums::RecorderState)
Q_DECLARE_METATYPE(LinphoneEnums::TunnelMode)

View file

@ -28,6 +28,7 @@
#include "tool/providers/AvatarProvider.hpp"
#include <QImageReader>
#include <QQuickWindow>
#include <QRandomGenerator>
// =============================================================================
@ -261,3 +262,29 @@ QString Utils::generateSavedFilename(const QString &from, const QString &to) {
.arg(escape(from))
.arg(escape(to));
}
QStringList Utils::generateSecurityLettersArray(int arraySize, int correctIndex, QString correctCode) {
QStringList vec;
const QString possibleCharacters(tr("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"));
const int n = 2;
for (int i = 0; i < arraySize; ++i) {
QString randomString;
if (i == correctIndex) randomString = correctCode;
else {
do {
randomString.clear();
for (int j = 0; j < n; ++j) {
int index = rand() % possibleCharacters.length();
QChar nextChar = possibleCharacters.at(index);
randomString.append(nextChar);
}
} while (vec.contains(randomString) || randomString == correctCode);
}
vec.append(randomString);
}
return vec;
}
int Utils::getRandomIndex(int size) {
return QRandomGenerator::global()->bounded(size);
}

View file

@ -69,7 +69,9 @@ public:
Q_INVOKABLE static QString formatElapsedTime(int seconds,
bool dotsSeparator = true); // Return the elapsed time formated
Q_INVOKABLE static QString formatDate(const QDateTime &date, bool includeTime = true); // Return the date formated
Q_INVOKABLE static QString formatDateElapsedTime(const QDateTime &date); // Return the date formated
Q_INVOKABLE static QString formatDateElapsedTime(const QDateTime &date);
Q_INVOKABLE static QStringList generateSecurityLettersArray(int arraySize, int correctIndex, QString correctCode);
Q_INVOKABLE static int getRandomIndex(int size);
static QString generateSavedFilename(const QString &from, const QString &to);
static inline QString coreStringToAppString(const std::string &str) {

View file

@ -18,6 +18,15 @@ Window {
Connections {
target: call.core
onRemoteVideoEnabledChanged: console.log("remote video enabled", call.core.remoteVideoEnabled)
onSecurityUpdated: {
if (call.core.isSecured) {
zrtpValidation.close()
}
else if(call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) {
zrtpValidation.open()
// mainWindow.attachVirtualWindow(Utils.buildLinphoneDialogUri('ZrtpTokenAuthenticationDialog'), {call:callModel})
}
}
}
onCallChanged: {
@ -29,7 +38,12 @@ Window {
property var callState: call.core.state
onCallStateChanged: {
console.log("State:", callState)
if (callState === LinphoneEnums.CallState.Error || callState === LinphoneEnums.CallState.End) {
if (callState === LinphoneEnums.CallState.Connected) {
if(!call.core.isSecured && call.core.encryption === LinphoneEnums.MediaEncryption.Zrtp) {
zrtpValidation.open()
}
}
else if (callState === LinphoneEnums.CallState.Error || callState === LinphoneEnums.CallState.End) {
endCall(call)
}
}
@ -122,6 +136,10 @@ Window {
colorizationColor: disabledIcon && bottomButton.checked ? DefaultStyle.main2_0 : DefaultStyle.grey_0
}
}
ZrtpTokenAuthenticationDialog {
id: zrtpValidation
call: mainWindow.call
}
Popup {
id: waitingPopup
visible: mainWindow.call.core.transferState === LinphoneEnums.CallState.OutgoingInit
@ -259,8 +277,7 @@ Window {
bottomPadding: 8 * DefaultStyle.dp
leftPadding: 10 * DefaultStyle.dp
rightPadding: 10 * DefaultStyle.dp
visible: mainWindow.call.core.peerSecured
onVisibleChanged: console.log("peer secured", mainWindow.call.core.peerSecured)
visible: mainWindow.call.core.isSecured
background: Rectangle {
anchors.fill: parent
border.color: DefaultStyle.info_500_main
@ -483,8 +500,6 @@ Window {
Control.StackView.onActivated: rightPanelTitle.text = qsTr("Liste d'appel")
// width: callList.width
// height: callList.height
onHeightChanged: console.log("control height changed", height)
// padding: 15 * DefaultStyle.dp
topPadding: 15 * DefaultStyle.dp
bottomPadding: 15 * DefaultStyle.dp

View file

@ -45,6 +45,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Item/TextInput.qml
view/Item/ToolTip.qml
view/Item/VerticalTabBar.qml
view/Item/ZrtpTokenAuthenticationDialog.qml
view/Item/Form/LoginForm.qml

View file

@ -6,9 +6,12 @@ import Linphone
Control.Button {
id: mainItem
property int capitalization
property color color: DefaultStyle.main1_500_main
property color pressedColor: DefaultStyle.main1_500_main_darker
property bool inversedColors: false
property int textSize: 18 * DefaultStyle.dp
property int textWeight: 600 * DefaultStyle.dp
property bool underline: false
property bool shadowEnabled: false
hoverEnabled: true
@ -26,10 +29,10 @@ Control.Button {
? DefaultStyle.grey_100
: DefaultStyle.grey_0
: mainItem.pressed
? DefaultStyle.main1_500_main_darker
: DefaultStyle.main1_500_main
? mainItem.pressedColor
: mainItem.color
radius: 48 * DefaultStyle.dp
border.color: inversedColors ? DefaultStyle.main1_500_main : DefaultStyle.grey_0
border.color: inversedColors ? mainItem.color : DefaultStyle.grey_0
MouseArea {
anchors.fill: parent
@ -49,16 +52,18 @@ Control.Button {
}
contentItem: Text {
id: contentText
horizontalAlignment: Text.AlignHCenter
anchors.centerIn: parent
wrapMode: Text.WordWrap
text: mainItem.text
color: inversedColors ? DefaultStyle.main1_500_main : DefaultStyle.grey_0
color: inversedColors ? mainItem.color : DefaultStyle.grey_0
font {
pixelSize: mainItem.textSize
weight: mainItem.textWeight
family: DefaultStyle.defaultFont
capitalization: mainItem.capitalization
underline: mainItem.underline
}
}
}

View file

@ -12,9 +12,11 @@ Popup {
rightPadding: 10 * DefaultStyle.dp
leftPadding: 10 * DefaultStyle.dp
topPadding: 10 * DefaultStyle.dp
bottomPadding: 10 * DefaultStyle.dp + buttonsLayout.height
bottomPadding: 10 * DefaultStyle.dp
property int radius: 16 * DefaultStyle.dp
property color underlineColor: DefaultStyle.main1_500_main
property alias buttons: buttonsLayout.data
property alias content: contentLayout.data
property string text
signal accepted()
signal rejected()
@ -24,14 +26,17 @@ Popup {
Rectangle {
visible: mainItem.underlineColor != undefined
width: mainItem.width
height: mainItem.height + 2 * DefaultStyle.dp
x: backgroundItem.x
y: backgroundItem.y
height: backgroundItem.height + 2 * DefaultStyle.dp
color: mainItem.underlineColor
radius: mainItem.radius
}
Rectangle{
Rectangle {
id: backgroundItem
anchors.fill: parent
width: mainItem.width
height: mainItem.height
height: mainItem.implicitHeight
radius: mainItem.radius
color: DefaultStyle.grey_0
border.color: DefaultStyle.grey_0
@ -44,13 +49,39 @@ Popup {
shadowBlur: 1.0
shadowOpacity: 0.1
}
}
contentItem: ColumnLayout {
spacing: 20 * DefaultStyle.dp
ColumnLayout {
id: contentLayout
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
}
Text {
id: defaultText
visible: text.length != 0
width: parent.width
Layout.preferredWidth: 278 * DefaultStyle.dp
text: mainItem.text
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
}
RowLayout {
id: buttonsLayout
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: 10 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
spacing: 10 * DefaultStyle.dp
// Default buttons only visible if no other children
// have been set
Button {
visible: mainItem.buttons.length === 2
text: qsTr("Oui")
onClicked: {
mainItem.accepted()
@ -58,6 +89,7 @@ Popup {
}
}
Button {
visible: mainItem.buttons.length === 2
text: qsTr("Non")
onClicked: {
mainItem.rejected()
@ -66,16 +98,4 @@ Popup {
}
}
}
contentItem: Text {
width: parent.width
Layout.preferredWidth: 278 * DefaultStyle.dp
text: mainItem.text
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
}
}

View file

@ -0,0 +1,155 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import Linphone
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
onCallChanged: if(!call) close()
Connections {
target: call.core
onStatusChanged: if (status === CallModel.CallStatusEnded) close()
}
buttons: ColumnLayout {
spacing: 15 * DefaultStyle.dp
Button {
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()
}
}
Button {
text: qsTr("Letters doesn't match")
color: DefaultStyle.danger_500main
inversedColors: true
Layout.alignment: Qt.AlignHCenter
width: 330 * DefaultStyle.dp
onClicked: {
if(mainItem.call) mainItem.call.core.lVerifyAuthenticationToken(false)
mainItem.close()
}
}
}
content: ColumnLayout {
spacing: 32 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
ColumnLayout {
spacing: 10 * DefaultStyle.dp
Text {
Layout.preferredWidth: 330 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter
text: qsTr("Vérifier l'appareil")
horizontalAlignment: Text.AlignLeft
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
Text {
Layout.preferredWidth: 330 * DefaultStyle.dp
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
}
}
GridLayout {
id: securityGridView
// Layout.fillWidth: true
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 {
target: mainItem.call.core
// 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
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
}
}
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()
}
}
}
}
MultiEffect {
source: code
anchors.fill: code
shadowEnabled: true
shadowOpacity: 0.1
shadowBlur: 1.0
}
}
}
}
}
}

View file

@ -23,7 +23,6 @@ AbstractMainPage {
listStackView.push(newCallItem)
}
Dialog {
id: deleteHistoryPopup
width: 278 * DefaultStyle.dp

View file

@ -66,4 +66,5 @@ QtObject {
property string heart: "image://internal/heart.svg"
property string heartFill: "image://internal/heart-fill.svg"
property string recordFill: "image://internal/record-fill.svg"
property string mediaEncryptionZrtpPq: "image://internal/media_encryption_zrtp_pq.svg"
}