aboutsummaryrefslogtreecommitdiff
path: root/src/client/QXmppAtmTrustMemoryStorage.cpp
blob: 04c8c74752acf4e8a2477c730a3c160719b4699f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#include "QXmppAtmTrustMemoryStorage.h"

#include "QXmppFutureUtils_p.h"
#include "QXmppTrustMessageKeyOwner.h"

#include <QMultiHash>

using namespace QXmpp::Private;

///
/// \class QXmppAtmTrustMemoryStorage
///
/// \brief The QXmppAtmTrustMemoryStorage class stores trust data for
/// \xep{0450, Automatic Trust Management (ATM)} in the memory.
///
/// \warning THIS API IS NOT FINALIZED YET!
///
/// \since QXmpp 1.5
///

struct UnprocessedKey
{
    QByteArray id;
    QString ownerJid;
    QByteArray senderKeyId;
    bool trust;
};

class QXmppAtmTrustMemoryStoragePrivate
{
public:
    // encryption protocols mapped to trust message data received from endpoints
    // with unauthenticated keys
    QMultiHash<QString, UnprocessedKey> keys;
};

///
/// Constructs an ATM trust memory storage.
///
QXmppAtmTrustMemoryStorage::QXmppAtmTrustMemoryStorage()
    : d(new QXmppAtmTrustMemoryStoragePrivate)
{
}

QXmppAtmTrustMemoryStorage::~QXmppAtmTrustMemoryStorage() = default;

/// \cond
QXmppTask<void> QXmppAtmTrustMemoryStorage::addKeysForPostponedTrustDecisions(const QString &encryption, const QByteArray &senderKeyId, const QList<QXmppTrustMessageKeyOwner> &keyOwners)
{
    const auto addKeys = [&](const QXmppTrustMessageKeyOwner &keyOwner, bool trust, const QList<QByteArray> &keyIds) {
        for (const auto &keyId : keyIds) {
            auto isKeyFound = false;

            for (auto itr = d->keys.find(encryption); itr != d->keys.end() && itr.key() == encryption; ++itr) {
                auto &key = itr.value();
                if (key.id == keyId && key.ownerJid == keyOwner.jid() && key.senderKeyId == senderKeyId) {
                    // Update the stored trust if it differs from the new one.
                    if (key.trust != trust) {
                        key.trust = trust;
                    }

                    isKeyFound = true;
                    break;
                }
            }

            // Create a new entry and store it if there is no such entry yet.
            if (!isKeyFound) {
                UnprocessedKey key;
                key.id = keyId;
                key.ownerJid = keyOwner.jid();
                key.senderKeyId = senderKeyId;
                key.trust = trust;
                d->keys.insert(encryption, key);
            }
        }
    };

    for (const auto &keyOwner : keyOwners) {
        addKeys(keyOwner, true, keyOwner.trustedKeys());
        addKeys(keyOwner, false, keyOwner.distrustedKeys());
    }

    return makeReadyTask();
}

QXmppTask<void> QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &keyIdsForAuthentication, const QList<QByteArray> &keyIdsForDistrusting)
{
    for (auto itr = d->keys.find(encryption);
         itr != d->keys.end() && itr.key() == encryption;) {
        const auto &key = itr.value();
        if ((key.trust && keyIdsForAuthentication.contains(key.id)) ||
            (!key.trust && keyIdsForDistrusting.contains(key.id))) {
            itr = d->keys.erase(itr);
        } else {
            ++itr;
        }
    }

    return makeReadyTask();
}

QXmppTask<void> QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds)
{
    for (auto itr = d->keys.find(encryption);
         itr != d->keys.end() && itr.key() == encryption;) {
        if (senderKeyIds.contains(itr.value().senderKeyId)) {
            itr = d->keys.erase(itr);
        } else {
            ++itr;
        }
    }

    return makeReadyTask();
}

QXmppTask<void> QXmppAtmTrustMemoryStorage::removeKeysForPostponedTrustDecisions(const QString &encryption)
{
    d->keys.remove(encryption);
    return makeReadyTask();
}

QXmppTask<QHash<bool, QMultiHash<QString, QByteArray>>> QXmppAtmTrustMemoryStorage::keysForPostponedTrustDecisions(const QString &encryption, const QList<QByteArray> &senderKeyIds)
{
    QHash<bool, QMultiHash<QString, QByteArray>> keys;

    const auto storedKeys = d->keys.values(encryption);
    for (const auto &key : storedKeys) {
        if (senderKeyIds.contains(key.senderKeyId) || senderKeyIds.isEmpty()) {
            keys[key.trust].insert(key.ownerJid, key.id);
        }
    }

    return makeReadyTask(std::move(keys));
}

QXmppTask<void> QXmppAtmTrustMemoryStorage::resetAll(const QString &encryption)
{
    QXmppTrustMemoryStorage::resetAll(encryption);
    d->keys.remove(encryption);
    return makeReadyTask();
}
/// \endcond