2
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation, either version 2 or (at your option)
7
* version 3 of the License.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
#include "ShareImport.h"
18
#include "core/Merger.h"
19
#include "format/KeePass2Reader.h"
20
#include "keeshare/KeeShare.h"
21
#include "keys/PasswordKey.h"
24
#include <minizip/unzip.h>
28
QByteArray readZipFile(void* uf)
31
int bytes, bytesRead = 0;
32
unzOpenCurrentFile(uf);
34
data.resize(data.size() + 8192);
35
bytes = unzReadCurrentFile(uf, data.data() + bytesRead, 8192);
40
unzCloseCurrentFile(uf);
41
data.truncate(bytesRead);
46
ShareObserver::Result ShareImport::containerInto(const QString& resolvedPath,
47
const KeeShareSettings::Reference& reference,
52
auto uf = unzOpen64(resolvedPath.toLatin1().constData());
54
// Open zip share, extract database portion, ignore signature file
55
char zipFileName[256];
56
auto err = unzGoToFirstFile(uf);
57
while (err == UNZ_OK) {
58
unzGetCurrentFileInfo64(uf, nullptr, zipFileName, sizeof(zipFileName), nullptr, 0, nullptr, 0);
59
if (QString(zipFileName).compare(KeeShare::containerFileName()) == 0) {
60
dbData = readZipFile(uf);
62
err = unzGoToNextFile(uf);
66
// Open KDBX file directly
67
QFile file(resolvedPath);
68
if (!file.open(QIODevice::ReadOnly)) {
69
qCritical("Unable to open file %s.", qPrintable(reference.path));
70
return {reference.path, ShareObserver::Result::Error, file.errorString()};
72
dbData = file.readAll();
76
QBuffer buffer(&dbData);
77
buffer.open(QIODevice::ReadOnly);
79
KeePass2Reader reader;
80
auto key = QSharedPointer<CompositeKey>::create();
81
key->addKey(QSharedPointer<PasswordKey>::create(reference.password));
82
auto sourceDb = QSharedPointer<Database>::create();
83
sourceDb->setEmitModified(false);
84
if (!reader.readDatabase(&buffer, key, sourceDb.data())) {
85
qCritical("Error while parsing the database: %s", qPrintable(reader.errorString()));
86
return {reference.path, ShareObserver::Result::Error, reader.errorString()};
88
sourceDb->setEmitModified(true);
90
qDebug("Synchronize %s %s with %s",
91
qPrintable(reference.path),
92
qPrintable(targetGroup->name()),
93
qPrintable(sourceDb->rootGroup()->name()));
95
Merger merger(sourceDb->rootGroup(), targetGroup);
96
merger.setForcedMergeMode(Group::Synchronize);
97
merger.setSkipDatabaseCustomData(true);
98
auto changelist = merger.merge();
99
if (!changelist.isEmpty()) {
100
return {reference.path, ShareObserver::Result::Success, ShareImport::tr("Successful import")};