keepassxc/src/keeshare/ShareImport.cpp
Jonathan White 31db3c325d Fix compiling with minizip-ng
* minizip-ng has slightly different defines and function names than the original minizip. These changes adapt the existing code to use the minizip-ng versions if necessary.
2022-04-03 13:28:39 -04:00

101 lines
3.6 KiB
C++

/*
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ShareImport.h"
#include "core/Merger.h"
#include "format/KeePass2Reader.h"
#include "keeshare/KeeShare.h"
#include "keys/PasswordKey.h"
#include <QBuffer>
#include <minizip/unzip.h>
namespace
{
QByteArray readZipFile(void* uf)
{
QByteArray data;
int bytes, bytesRead = 0;
unzOpenCurrentFile(uf);
do {
data.resize(data.size() + 8192);
bytes = unzReadCurrentFile(uf, data.data() + bytesRead, 8192);
if (bytes > 0) {
bytesRead += bytes;
}
} while (bytes > 0);
unzCloseCurrentFile(uf);
data.truncate(bytesRead);
return data;
}
} // namespace
ShareObserver::Result ShareImport::containerInto(const QString& resolvedPath,
const KeeShareSettings::Reference& reference,
Group* targetGroup)
{
QByteArray dbData;
auto uf = unzOpen64(resolvedPath.toLatin1().constData());
if (uf) {
// Open zip share, extract database portion, ignore signature file
char zipFileName[256];
auto err = unzGoToFirstFile(uf);
while (err == UNZ_OK) {
unzGetCurrentFileInfo64(uf, nullptr, zipFileName, sizeof(zipFileName), nullptr, 0, nullptr, 0);
if (QString(zipFileName).compare(KeeShare::containerFileName()) == 0) {
dbData = readZipFile(uf);
}
err = unzGoToNextFile(uf);
}
unzClose(uf);
} else {
// Open KDBX file directly
QFile file(resolvedPath);
if (!file.open(QIODevice::ReadOnly)) {
qCritical("Unable to open file %s.", qPrintable(reference.path));
return {reference.path, ShareObserver::Result::Error, file.errorString()};
}
dbData = file.readAll();
file.close();
}
QBuffer buffer(&dbData);
buffer.open(QIODevice::ReadOnly);
KeePass2Reader reader;
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create(reference.password));
auto sourceDb = QSharedPointer<Database>::create();
if (!reader.readDatabase(&buffer, key, sourceDb.data())) {
qCritical("Error while parsing the database: %s", qPrintable(reader.errorString()));
return {reference.path, ShareObserver::Result::Error, reader.errorString()};
}
qDebug("Synchronize %s %s with %s",
qPrintable(reference.path),
qPrintable(targetGroup->name()),
qPrintable(sourceDb->rootGroup()->name()));
Merger merger(sourceDb->rootGroup(), targetGroup);
merger.setForcedMergeMode(Group::Synchronize);
auto changelist = merger.merge();
if (!changelist.isEmpty()) {
return {reference.path, ShareObserver::Result::Success, ShareImport::tr("Successful import")};
}
return {};
}