diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-08-25 19:58:48 +0200 |
---|---|---|
committer | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-08-25 19:59:29 +0200 |
commit | 6404b8cd4d57468b810538da04f8017fb13ccc37 (patch) | |
tree | a7ea65d971b24791368d9eae5b1db92551ef0ea8 /lib | |
parent | 376da43a29f3ebad807da2761e7a0c0b105587ec (diff) | |
download | libquotient-6404b8cd4d57468b810538da04f8017fb13ccc37.tar.gz libquotient-6404b8cd4d57468b810538da04f8017fb13ccc37.zip |
Refactor the code handling emoji
- Use a dedicated structure, EmojiEntry, instead of QVariantMap
(it's Q_GADGET, should be readable from QML just fine)
- While we're at it, QVector is better than QList in Qt 5.15
- Remove language from the session state - it's used in a single method
- Modernise handleKey() code
Diffstat (limited to 'lib')
-rw-r--r-- | lib/keyverificationsession.cpp | 128 | ||||
-rw-r--r-- | lib/keyverificationsession.h | 19 |
2 files changed, 91 insertions, 56 deletions
diff --git a/lib/keyverificationsession.cpp b/lib/keyverificationsession.cpp index caf5071a..2c468c3e 100644 --- a/lib/keyverificationsession.cpp +++ b/lib/keyverificationsession.cpp @@ -110,9 +110,6 @@ void KeyVerificationSession::init(milliseconds timeout) auto randomSize = olm_create_sas_random_length(m_sas); auto random = getRandom(randomSize); olm_create_sas(m_sas, random.data(), randomSize); - - m_language = QLocale::system().uiLanguages()[0]; - m_language = m_language.left(m_language.indexOf('-')); } KeyVerificationSession::~KeyVerificationSession() @@ -121,18 +118,57 @@ KeyVerificationSession::~KeyVerificationSession() delete[] reinterpret_cast<std::byte*>(m_sas); } +struct EmojiStoreEntry : EmojiEntry { + QHash<QString, QString> translatedDescriptions; + + explicit EmojiStoreEntry(const QJsonObject& json) + : EmojiEntry{ fromJson<QString>(json["emoji"]), + fromJson<QString>(json["description"]) } + , translatedDescriptions{ fromJson<QHash<QString, QString>>( + json["translated_descriptions"]) } + {} +}; + +using EmojiStore = QVector<EmojiStoreEntry>; + +EmojiStore loadEmojiStore() +{ + QFile dataFile(":/sas-emoji.json"); + dataFile.open(QFile::ReadOnly); + return fromJson<EmojiStore>( + QJsonDocument::fromJson(dataFile.readAll()).array()); +} + +EmojiEntry emojiForCode(int code, const QString& language) +{ + static const EmojiStore emojiStore = loadEmojiStore(); + const auto& entry = emojiStore[code]; + if (!language.isEmpty()) + if (const auto translatedDescription = + emojiStore[code].translatedDescriptions.value(language); + !translatedDescription.isNull()) + return { entry.emoji, translatedDescription }; + + return SLICE(entry, EmojiEntry); +} + void KeyVerificationSession::handleKey(const KeyVerificationKeyEvent& event) { if (state() != WAITINGFORKEY && state() != WAITINGFORVERIFICATION) { cancelVerification(UNEXPECTED_MESSAGE); return; } - olm_sas_set_their_key(m_sas, event.key().toLatin1().data(), event.key().toLatin1().size()); + auto eventKey = event.key().toLatin1(); + olm_sas_set_their_key(m_sas, eventKey.data(), eventKey.size()); if (startSentByUs) { - auto commitment = QString(QCryptographicHash::hash((event.key() % m_startEvent).toLatin1(), QCryptographicHash::Sha256).toBase64()); - commitment = commitment.left(commitment.indexOf('=')); - if (commitment != m_commitment) { + const auto paddedCommitment = + QCryptographicHash::hash((eventKey % m_startEvent).toLatin1(), + QCryptographicHash::Sha256) + .toBase64(); + const QLatin1String unpaddedCommitment(paddedCommitment.constData(), + paddedCommitment.indexOf('=')); + if (unpaddedCommitment != m_commitment) { qCWarning(E2EE) << "Commitment mismatch; aborting verification"; cancelVerification(MISMATCHED_COMMITMENT); return; @@ -142,34 +178,40 @@ void KeyVerificationSession::handleKey(const KeyVerificationKeyEvent& event) } setState(WAITINGFORVERIFICATION); - QByteArray keyBytes(olm_sas_pubkey_length(m_sas), '\0'); - olm_sas_get_pubkey(m_sas, keyBytes.data(), keyBytes.size()); - QString key = QString(keyBytes); - - QByteArray output(6, '\0'); - QString infoTemplate = startSentByUs ? "MATRIX_KEY_VERIFICATION_SAS|%1|%2|%3|%4|%5|%6|%7"_ls : "MATRIX_KEY_VERIFICATION_SAS|%4|%5|%6|%1|%2|%3|%7"_ls; - - auto info = infoTemplate.arg(m_connection->userId()).arg(m_connection->deviceId()).arg(key).arg(m_remoteUserId).arg(m_remoteDeviceId).arg(event.key()).arg(m_transactionId); - olm_sas_generate_bytes(m_sas, info.toLatin1().data(), info.toLatin1().size(), output.data(), output.size()); - - QVector<uint8_t> code(7, 0); - const auto& data = (uint8_t *) output.data(); - - code[0] = data[0] >> 2; - code[1] = (data[0] << 4 & 0x3f) | data[1] >> 4; - code[2] = (data[1] << 2 & 0x3f) | data[2] >> 6; - code[3] = data[2] & 0x3f; - code[4] = data[3] >> 2; - code[5] = (data[3] << 4 & 0x3f) | data[4] >> 4; - code[6] = (data[4] << 2 & 0x3f) | data[5] >> 6; - - for (const auto& c : code) { - auto [emoji, description] = emojiForCode(c); - QVariantMap map; - map["emoji"] = emoji; - map["description"] = description; - m_sasEmojis += map; - } + std::string key(olm_sas_pubkey_length(m_sas), '\0'); + olm_sas_get_pubkey(m_sas, key.data(), key.size()); + + std::array<std::byte, 6> output{}; + const auto infoTemplate = + startSentByUs ? "MATRIX_KEY_VERIFICATION_SAS|%1|%2|%3|%4|%5|%6|%7"_ls + : "MATRIX_KEY_VERIFICATION_SAS|%4|%5|%6|%1|%2|%3|%7"_ls; + + const auto info = infoTemplate + .arg(m_connection->userId(), m_connection->deviceId(), + key.data(), m_remoteUserId, m_remoteDeviceId, + eventKey, m_transactionId) + .toLatin1(); + olm_sas_generate_bytes(m_sas, info.data(), info.size(), output.data(), + output.size()); + + static constexpr auto x3f = std::byte{ 0x3f }; + const std::array<std::byte, 7> code{ + output[0] >> 2, + (output[0] << 4 & x3f) | output[1] >> 4, + (output[1] << 2 & x3f) | output[2] >> 6, + output[2] & x3f, + output[3] >> 2, + (output[3] << 4 & x3f) | output[4] >> 4, + (output[4] << 2 & x3f) | output[5] >> 6 + }; + + const auto uiLanguages = QLocale().uiLanguages(); + const auto preferredLanguage = uiLanguages.isEmpty() + ? QString() + : uiLanguages.front().section('-', 0, 0); + for (const auto& c : code) + m_sasEmojis += emojiForCode(std::to_integer<int>(c), preferredLanguage); + emit sasEmojisChanged(); emit keyReceived(); } @@ -369,21 +411,7 @@ void KeyVerificationSession::handleCancel(const KeyVerificationCancelEvent& even setState(CANCELED); } -std::pair<QString, QString> KeyVerificationSession::emojiForCode(int code) -{ - static QJsonArray data; - if (data.isEmpty()) { - QFile dataFile(":/sas-emoji.json"); - dataFile.open(QFile::ReadOnly); - data = QJsonDocument::fromJson(dataFile.readAll()).array(); - } - if (data[code].toObject()["translated_descriptions"].toObject().contains(m_language)) { - return {data[code].toObject()["emoji"].toString(), data[code].toObject()["translated_descriptions"].toObject()[m_language].toString()}; - } - return {data[code].toObject()["emoji"].toString(), data[code].toObject()["description"].toString()}; -} - -QList<QVariantMap> KeyVerificationSession::sasEmojis() const +QVector<EmojiEntry> KeyVerificationSession::sasEmojis() const { return m_sasEmojis; } diff --git a/lib/keyverificationsession.h b/lib/keyverificationsession.h index 73c9384e..aa0295cb 100644 --- a/lib/keyverificationsession.h +++ b/lib/keyverificationsession.h @@ -12,6 +12,15 @@ struct OlmSAS; namespace Quotient { class Connection; +struct QUOTIENT_API EmojiEntry { + QString emoji; + QString description; + + Q_GADGET + Q_PROPERTY(QString emoji MEMBER emoji CONSTANT) + Q_PROPERTY(QString description MEMBER description CONSTANT) +}; + /** A key verification session. Listen for incoming sessions by connecting to Connection::newKeyVerificationSession. Start a new session using Connection::startKeyVerificationSession. The object is delete after finished is emitted. @@ -67,7 +76,7 @@ public: Q_ENUM(Error) Q_PROPERTY(QString remoteDeviceId MEMBER m_remoteDeviceId CONSTANT) - Q_PROPERTY(QList<QVariantMap> sasEmojis READ sasEmojis NOTIFY sasEmojisChanged) + Q_PROPERTY(QVector<EmojiEntry> sasEmojis READ sasEmojis NOTIFY sasEmojisChanged) Q_PROPERTY(State state READ state NOTIFY stateChanged) Q_PROPERTY(Error error READ error NOTIFY errorChanged) @@ -79,7 +88,7 @@ public: ~KeyVerificationSession() override; Q_DISABLE_COPY_MOVE(KeyVerificationSession) - QList<QVariantMap> sasEmojis() const; + QVector<EmojiEntry> sasEmojis() const; State state() const; Error error() const; @@ -107,13 +116,12 @@ private: const QString m_transactionId; Connection* m_connection; OlmSAS* m_sas = nullptr; - QList<QVariantMap> m_sasEmojis; + QVector<EmojiEntry> m_sasEmojis; bool startSentByUs = false; State m_state = INCOMING; Error m_error = NONE; QString m_startEvent; QString m_commitment; - QString m_language; bool macReceived = false; bool m_encrypted; QStringList m_remoteSupportedMethods; @@ -133,8 +141,7 @@ private: QByteArray macInfo(bool verifying, const QString& key = "KEY_IDS"_ls); QString calculateMac(const QString& input, bool verifying, const QString& keyId= "KEY_IDS"_ls); - - std::pair<QString, QString> emojiForCode(int code); }; } // namespace Quotient +Q_DECLARE_METATYPE(Quotient::EmojiEntry) |