keepassxc

Форк
0
/
EntryAttributes.cpp 
341 строка · 8.7 Кб
1
/*
2
 *  Copyright (C) 2023 KeePassXC Team <team@keepassxc.org>
3
 *  Copyright (C) 2012 Felix Geyer <debfx@fobos.de>
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation, either version 2 or (at your option)
8
 *  version 3 of the License.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

19
#include "EntryAttributes.h"
20
#include "core/Global.h"
21

22
#include <QRegularExpression>
23
#include <QUuid>
24

25
const QString EntryAttributes::TitleKey = "Title";
26
const QString EntryAttributes::UserNameKey = "UserName";
27
const QString EntryAttributes::PasswordKey = "Password";
28
const QString EntryAttributes::URLKey = "URL";
29
const QString EntryAttributes::NotesKey = "Notes";
30
const QStringList EntryAttributes::DefaultAttributes(QStringList()
31
                                                     << TitleKey << UserNameKey << PasswordKey << URLKey << NotesKey);
32
const QString EntryAttributes::WantedFieldGroupName = "WantedField";
33
const QString EntryAttributes::SearchInGroupName = "SearchIn";
34
const QString EntryAttributes::SearchTextGroupName = "SearchText";
35

36
const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD";
37
const QString EntryAttributes::AdditionalUrlAttribute = "KP2A_URL";
38
const QString EntryAttributes::PasskeyAttribute = "KPEX_PASSKEY";
39

40
EntryAttributes::EntryAttributes(QObject* parent)
41
    : ModifiableObject(parent)
42
{
43
    clear();
44
}
45

46
QList<QString> EntryAttributes::keys() const
47
{
48
    return m_attributes.keys();
49
}
50

51
bool EntryAttributes::hasKey(const QString& key) const
52
{
53
    return m_attributes.contains(key);
54
}
55

56
bool EntryAttributes::hasPasskey() const
57
{
58
    const auto keyList = keys();
59
    for (const auto& key : keyList) {
60
        if (isPasskeyAttribute(key)) {
61
            return true;
62
        }
63
    }
64

65
    return false;
66
}
67

68
QList<QString> EntryAttributes::customKeys() const
69
{
70
    QList<QString> customKeys;
71
    const QList<QString> keyList = keys();
72
    for (const QString& key : keyList) {
73
        if (!isDefaultAttribute(key) && !isPasskeyAttribute(key)) {
74
            customKeys.append(key);
75
        }
76
    }
77
    return customKeys;
78
}
79

80
QString EntryAttributes::value(const QString& key) const
81
{
82
    return m_attributes.value(key);
83
}
84

85
QList<QString> EntryAttributes::values(const QList<QString>& keys) const
86
{
87
    QList<QString> values;
88
    for (const QString& key : keys) {
89
        values.append(m_attributes.value(key));
90
    }
91
    return values;
92
}
93

94
bool EntryAttributes::contains(const QString& key) const
95
{
96
    return m_attributes.contains(key);
97
}
98

99
bool EntryAttributes::containsValue(const QString& value) const
100
{
101
    return asConst(m_attributes).values().contains(value);
102
}
103

104
bool EntryAttributes::isProtected(const QString& key) const
105
{
106
    return m_protectedAttributes.contains(key);
107
}
108

109
bool EntryAttributes::isReference(const QString& key) const
110
{
111
    if (!m_attributes.contains(key)) {
112
        Q_ASSERT(false);
113
        return false;
114
    }
115

116
    const QString data = value(key);
117
    return matchReference(data).hasMatch();
118
}
119

120
void EntryAttributes::set(const QString& key, const QString& value, bool protect)
121
{
122
    bool shouldEmitModified = false;
123

124
    bool addAttribute = !m_attributes.contains(key);
125
    bool changeValue = !addAttribute && (m_attributes.value(key) != value);
126
    bool defaultAttribute = isDefaultAttribute(key);
127

128
    if (addAttribute && !defaultAttribute) {
129
        emit aboutToBeAdded(key);
130
    }
131

132
    if (addAttribute || changeValue) {
133
        m_attributes.insert(key, value);
134
        shouldEmitModified = true;
135
    }
136

137
    if (protect) {
138
        if (!m_protectedAttributes.contains(key)) {
139
            shouldEmitModified = true;
140
        }
141
        m_protectedAttributes.insert(key);
142
    } else if (m_protectedAttributes.remove(key)) {
143
        shouldEmitModified = true;
144
    }
145

146
    if (shouldEmitModified) {
147
        emitModified();
148
    }
149

150
    if (defaultAttribute && changeValue) {
151
        emit defaultKeyModified();
152
    } else if (addAttribute) {
153
        emit added(key);
154
    } else if (shouldEmitModified) {
155
        emit customKeyModified(key);
156
    }
157
}
158

159
void EntryAttributes::remove(const QString& key)
160
{
161
    Q_ASSERT(!isDefaultAttribute(key));
162

163
    if (!m_attributes.contains(key)) {
164
        return;
165
    }
166

167
    emit aboutToBeRemoved(key);
168

169
    m_attributes.remove(key);
170
    m_protectedAttributes.remove(key);
171

172
    emit removed(key);
173
    emitModified();
174
}
175

176
void EntryAttributes::rename(const QString& oldKey, const QString& newKey)
177
{
178
    Q_ASSERT(!isDefaultAttribute(oldKey));
179
    Q_ASSERT(!isDefaultAttribute(newKey));
180

181
    if (!m_attributes.contains(oldKey)) {
182
        Q_ASSERT(false);
183
        return;
184
    }
185

186
    if (m_attributes.contains(newKey)) {
187
        Q_ASSERT(false);
188
        return;
189
    }
190

191
    QString data = value(oldKey);
192
    bool protect = isProtected(oldKey);
193

194
    emit aboutToRename(oldKey, newKey);
195

196
    m_attributes.remove(oldKey);
197
    m_attributes.insert(newKey, data);
198
    if (protect) {
199
        m_protectedAttributes.remove(oldKey);
200
        m_protectedAttributes.insert(newKey);
201
    }
202

203
    emitModified();
204
    emit renamed(oldKey, newKey);
205
}
206

207
void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other)
208
{
209
    if (!areCustomKeysDifferent(other)) {
210
        return;
211
    }
212

213
    emit aboutToBeReset();
214

215
    // remove all non-default keys
216
    const QList<QString> keyList = keys();
217
    for (const QString& key : keyList) {
218
        if (!isDefaultAttribute(key)) {
219
            m_attributes.remove(key);
220
            m_protectedAttributes.remove(key);
221
        }
222
    }
223

224
    const QList<QString> otherKeyList = other->keys();
225
    for (const QString& key : otherKeyList) {
226
        if (!isDefaultAttribute(key)) {
227
            m_attributes.insert(key, other->value(key));
228
            if (other->isProtected(key)) {
229
                m_protectedAttributes.insert(key);
230
            }
231
        }
232
    }
233

234
    emit reset();
235
    emitModified();
236
}
237

238
bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other)
239
{
240
    // check if they are equal ignoring the order of the keys
241
    if (keys().toSet() != other->keys().toSet()) {
242
        return true;
243
    }
244

245
    const QList<QString> keyList = keys();
246
    for (const QString& key : keyList) {
247
        if (isDefaultAttribute(key)) {
248
            continue;
249
        }
250

251
        if (isProtected(key) != other->isProtected(key) || value(key) != other->value(key)) {
252
            return true;
253
        }
254
    }
255

256
    return false;
257
}
258

259
void EntryAttributes::copyDataFrom(const EntryAttributes* other)
260
{
261
    if (*this != *other) {
262
        emit aboutToBeReset();
263

264
        m_attributes = other->m_attributes;
265
        m_protectedAttributes = other->m_protectedAttributes;
266

267
        emit reset();
268
        emitModified();
269
    }
270
}
271

272
QUuid EntryAttributes::referenceUuid(const QString& key) const
273
{
274
    if (!m_attributes.contains(key)) {
275
        Q_ASSERT(false);
276
        return {};
277
    }
278

279
    auto match = matchReference(value(key));
280
    if (match.hasMatch()) {
281
        const QString uuid = match.captured("SearchText");
282
        if (!uuid.isEmpty()) {
283
            return QUuid::fromRfc4122(QByteArray::fromHex(uuid.toLatin1()));
284
        }
285
    }
286

287
    return {};
288
}
289

290
bool EntryAttributes::operator==(const EntryAttributes& other) const
291
{
292
    return (m_attributes == other.m_attributes && m_protectedAttributes == other.m_protectedAttributes);
293
}
294

295
bool EntryAttributes::operator!=(const EntryAttributes& other) const
296
{
297
    return (m_attributes != other.m_attributes || m_protectedAttributes != other.m_protectedAttributes);
298
}
299

300
QRegularExpressionMatch EntryAttributes::matchReference(const QString& text)
301
{
302
    static QRegularExpression referenceRegExp(
303
        "\\{REF:(?<WantedField>[TUPANI])@(?<SearchIn>[TUPANIO]):(?<SearchText>[^}]+)\\}",
304
        QRegularExpression::CaseInsensitiveOption);
305

306
    return referenceRegExp.match(text);
307
}
308

309
void EntryAttributes::clear()
310
{
311
    emit aboutToBeReset();
312

313
    m_attributes.clear();
314
    m_protectedAttributes.clear();
315

316
    for (const QString& key : DefaultAttributes) {
317
        m_attributes.insert(key, "");
318
    }
319

320
    emit reset();
321
    emitModified();
322
}
323

324
int EntryAttributes::attributesSize() const
325
{
326
    int size = 0;
327
    for (auto it = m_attributes.constBegin(); it != m_attributes.constEnd(); ++it) {
328
        size += it.key().toUtf8().size() + it.value().toUtf8().size();
329
    }
330
    return size;
331
}
332

333
bool EntryAttributes::isDefaultAttribute(const QString& key)
334
{
335
    return DefaultAttributes.contains(key);
336
}
337

338
bool EntryAttributes::isPasskeyAttribute(const QString& key)
339
{
340
    return key.startsWith(PasskeyAttribute);
341
}
342

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.