diff --git a/src/kleo/checksumdefinition.cpp b/src/kleo/checksumdefinition.cpp index d75a0a849..adb9f0cc6 100644 --- a/src/kleo/checksumdefinition.cpp +++ b/src/kleo/checksumdefinition.cpp @@ -1,430 +1,429 @@ /* -*- mode: c++; c-basic-offset:4 -*- checksumdefinition.cpp This file is part of libkleopatra, the KDE keymanagement library SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include "checksumdefinition.h" #include "kleoexception.h" #include "libkleo_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef stdin #undef stdin // pah.. #endif using namespace Kleo; static QMutex installPathMutex; Q_GLOBAL_STATIC(QString, _installPath) QString ChecksumDefinition::installPath() { const QMutexLocker locker(&installPathMutex); QString *const ip = _installPath(); if (ip->isEmpty()) { if (QCoreApplication::instance()) { *ip = QCoreApplication::applicationDirPath(); } else { qCWarning(LIBKLEO_LOG) << "checksumdefinition.cpp: installPath() called before QCoreApplication was constructed"; } } return *ip; } void ChecksumDefinition::setInstallPath(const QString &ip) { const QMutexLocker locker(&installPathMutex); *_installPath() = ip; } // Checksum Definition #N groups static const QLatin1String ID_ENTRY("id"); static const QLatin1String NAME_ENTRY("Name"); static const QLatin1String CREATE_COMMAND_ENTRY("create-command"); static const QLatin1String VERIFY_COMMAND_ENTRY("verify-command"); static const QLatin1String FILE_PATTERNS_ENTRY("file-patterns"); static const QLatin1String OUTPUT_FILE_ENTRY("output-file"); static const QLatin1String FILE_PLACEHOLDER("%f"); static const QLatin1String INSTALLPATH_PLACEHOLDER("%I"); static const QLatin1String NULL_SEPARATED_STDIN_INDICATOR("0|"); static const QLatin1Char NEWLINE_SEPARATED_STDIN_INDICATOR('|'); // ChecksumOperations group static const QLatin1String CHECKSUM_DEFINITION_ID_ENTRY("checksum-definition-id"); namespace { class ChecksumDefinitionError : public Kleo::Exception { const QString m_id; public: ChecksumDefinitionError(const QString &id, const QString &message) : Kleo::Exception(GPG_ERR_INV_PARAMETER, i18n("Error in checksum definition %1: %2", id, message), MessageOnly) , m_id(id) { } ~ChecksumDefinitionError() throw() override { } const QString &checksumDefinitionId() const { return m_id; } }; } static QString try_extensions(const QString &path) { static const char exts[][4] = { "", "exe", "bat", "bin", "cmd", }; static const size_t numExts = sizeof exts / sizeof *exts; for (unsigned int i = 0; i < numExts; ++i) { const QFileInfo fi(path + QLatin1Char('.') + QLatin1String(exts[i])); if (fi.exists()) { return fi.filePath(); } } return QString(); } static void parse_command(QString cmdline, const QString &id, const QString &whichCommand, QString *command, QStringList *prefix, QStringList *suffix, ChecksumDefinition::ArgumentPassingMethod *method) { Q_ASSERT(prefix); Q_ASSERT(suffix); Q_ASSERT(method); KShell::Errors errors; QStringList l; if (cmdline.startsWith(NULL_SEPARATED_STDIN_INDICATOR)) { *method = ChecksumDefinition::NullSeparatedInputFile; cmdline.remove(0, 2); } else if (cmdline.startsWith(NEWLINE_SEPARATED_STDIN_INDICATOR)) { *method = ChecksumDefinition::NewlineSeparatedInputFile; cmdline.remove(0, 1); } else { *method = ChecksumDefinition::CommandLine; } if (*method != ChecksumDefinition::CommandLine && cmdline.contains(FILE_PLACEHOLDER)) { throw ChecksumDefinitionError(id, i18n("Cannot use both %f and | in '%1'", whichCommand)); } cmdline .replace(FILE_PLACEHOLDER, QLatin1String("__files_go_here__")) // .replace(INSTALLPATH_PLACEHOLDER, QStringLiteral("__path_goes_here__")); l = KShell::splitArgs(cmdline, KShell::AbortOnMeta | KShell::TildeExpand, &errors); l = l.replaceInStrings(QStringLiteral("__files_go_here__"), FILE_PLACEHOLDER); if (l.indexOf(QRegExp(QLatin1String(".*__path_goes_here__.*"))) >= 0) { l = l.replaceInStrings(QStringLiteral("__path_goes_here__"), ChecksumDefinition::installPath()); } if (errors == KShell::BadQuoting) { throw ChecksumDefinitionError(id, i18n("Quoting error in '%1' entry", whichCommand)); } if (errors == KShell::FoundMeta) { throw ChecksumDefinitionError(id, i18n("'%1' too complex (would need shell)", whichCommand)); } qCDebug(LIBKLEO_LOG) << "ChecksumDefinition[" << id << ']' << l; if (l.empty()) { throw ChecksumDefinitionError(id, i18n("'%1' entry is empty/missing", whichCommand)); } const QFileInfo fi1(l.front()); if (fi1.isAbsolute()) { *command = try_extensions(l.front()); } else { *command = QStandardPaths::findExecutable(fi1.fileName()); } if (command->isEmpty()) { throw ChecksumDefinitionError(id, i18n("'%1' empty or not found", whichCommand)); } const int idx1 = l.indexOf(FILE_PLACEHOLDER); if (idx1 < 0) { // none -> append *prefix = l.mid(1); } else { *prefix = l.mid(1, idx1 - 1); *suffix = l.mid(idx1 + 1); } switch (*method) { case ChecksumDefinition::CommandLine: qCDebug(LIBKLEO_LOG) << "ChecksumDefinition[" << id << ']' << *command << *prefix << FILE_PLACEHOLDER << *suffix; break; case ChecksumDefinition::NewlineSeparatedInputFile: qCDebug(LIBKLEO_LOG) << "ChecksumDefinition[" << id << ']' << "find | " << *command << *prefix; break; case ChecksumDefinition::NullSeparatedInputFile: qCDebug(LIBKLEO_LOG) << "ChecksumDefinition[" << id << ']' << "find -print0 | " << *command << *prefix; break; case ChecksumDefinition::NumArgumentPassingMethods: Q_ASSERT(!"Should not happen"); break; } } namespace { class KConfigBasedChecksumDefinition : public ChecksumDefinition { public: explicit KConfigBasedChecksumDefinition(const KConfigGroup &group) : ChecksumDefinition(group.readEntryUntranslated(ID_ENTRY), group.readEntry(NAME_ENTRY), group.readEntry(OUTPUT_FILE_ENTRY), group.readEntry(FILE_PATTERNS_ENTRY, QStringList())) { if (id().isEmpty()) { throw ChecksumDefinitionError(group.name(), i18n("'id' entry is empty/missing")); } if (outputFileName().isEmpty()) { throw ChecksumDefinitionError(id(), i18n("'output-file' entry is empty/missing")); } if (patterns().empty()) { throw ChecksumDefinitionError(id(), i18n("'file-patterns' entry is empty/missing")); } // create-command ArgumentPassingMethod method; parse_command(group.readEntry(CREATE_COMMAND_ENTRY), id(), CREATE_COMMAND_ENTRY, &m_createCommand, &m_createPrefixArguments, &m_createPostfixArguments, &method); setCreateCommandArgumentPassingMethod(method); // verify-command parse_command(group.readEntry(VERIFY_COMMAND_ENTRY), id(), VERIFY_COMMAND_ENTRY, &m_verifyCommand, &m_verifyPrefixArguments, &m_verifyPostfixArguments, &method); setVerifyCommandArgumentPassingMethod(method); } private: QString doGetCreateCommand() const override { return m_createCommand; } QStringList doGetCreateArguments(const QStringList &files) const override { return m_createPrefixArguments + files + m_createPostfixArguments; } QString doGetVerifyCommand() const override { return m_verifyCommand; } QStringList doGetVerifyArguments(const QStringList &files) const override { return m_verifyPrefixArguments + files + m_verifyPostfixArguments; } private: QString m_createCommand, m_verifyCommand; QStringList m_createPrefixArguments, m_createPostfixArguments; QStringList m_verifyPrefixArguments, m_verifyPostfixArguments; }; } ChecksumDefinition::ChecksumDefinition(const QString &id, const QString &label, const QString &outputFileName, const QStringList &patterns) : m_id(id) , m_label(label.isEmpty() ? id : label) , m_outputFileName(outputFileName) , m_patterns(patterns) , m_createMethod(CommandLine) , m_verifyMethod(CommandLine) { } ChecksumDefinition::~ChecksumDefinition() { } QString ChecksumDefinition::createCommand() const { return doGetCreateCommand(); } QString ChecksumDefinition::verifyCommand() const { return doGetVerifyCommand(); } #if 0 QStringList ChecksumDefinition::createCommandArguments(const QStringList &files) const { return doGetCreateArguments(files); } QStringList ChecksumDefinition::verifyCommandArguments(const QStringList &files) const { return doGetVerifyArguments(files); } #endif static QByteArray make_input(const QStringList &files, char sep) { QByteArray result; for (const QString &file : files) { result += QFile::encodeName(file); result += sep; } return result; } static bool start_command(QProcess *p, const char *functionName, const QString &cmd, const QStringList &args, const QStringList &files, ChecksumDefinition::ArgumentPassingMethod method) { if (!p) { qCWarning(LIBKLEO_LOG) << functionName << ": process == NULL"; return false; } switch (method) { case ChecksumDefinition::NumArgumentPassingMethods: Q_ASSERT(!"Should not happen"); case ChecksumDefinition::CommandLine: qCDebug(LIBKLEO_LOG) << "Starting: " << cmd << " " << args.join(QLatin1Char(' ')); p->start(cmd, args, QIODevice::ReadOnly); return true; case ChecksumDefinition::NewlineSeparatedInputFile: case ChecksumDefinition::NullSeparatedInputFile: qCDebug(LIBKLEO_LOG) << "Starting: " << cmd << " " << args.join(QLatin1Char(' ')); p->start(cmd, args, QIODevice::ReadWrite); if (!p->waitForStarted()) { return false; } const char sep = method == ChecksumDefinition::NewlineSeparatedInputFile ? '\n' : '\0'; const QByteArray stdin = make_input(files, sep); if (p->write(stdin) != stdin.size()) { return false; } p->closeWriteChannel(); return true; } return false; // make compiler happy } bool ChecksumDefinition::startCreateCommand(QProcess *p, const QStringList &files) const { return start_command(p, Q_FUNC_INFO, doGetCreateCommand(), m_createMethod == CommandLine ? doGetCreateArguments(files) : doGetCreateArguments(QStringList()), files, m_createMethod); } bool ChecksumDefinition::startVerifyCommand(QProcess *p, const QStringList &files) const { return start_command(p, Q_FUNC_INFO, doGetVerifyCommand(), m_verifyMethod == CommandLine ? doGetVerifyArguments(files) : doGetVerifyArguments(QStringList()), files, m_verifyMethod); } // static -std::vector> ChecksumDefinition::getChecksumDefinitions() +std::vector ChecksumDefinition::getChecksumDefinitions() { QStringList errors; return getChecksumDefinitions(errors); } // static -std::vector> ChecksumDefinition::getChecksumDefinitions(QStringList &errors) +std::vector ChecksumDefinition::getChecksumDefinitions(QStringList &errors) { - std::vector> result; + std::vector result; KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("libkleopatrarc")); const QStringList groups = config->groupList().filter(QRegularExpression(QStringLiteral("^Checksum Definition #"))); result.reserve(groups.size()); for (const QString &group : groups) { try { - const std::shared_ptr ad(new KConfigBasedChecksumDefinition(KConfigGroup(config, group))); + const ChecksumDefinition::Ptr ad(new KConfigBasedChecksumDefinition(KConfigGroup(config, group))); result.push_back(ad); } catch (const std::exception &e) { qDebug() << e.what(); errors.push_back(QString::fromLocal8Bit(e.what())); } catch (...) { errors.push_back(i18n("Caught unknown exception in group %1", group)); } } return result; } // static -std::shared_ptr -ChecksumDefinition::getDefaultChecksumDefinition(const std::vector> &checksumDefinitions) +ChecksumDefinition::Ptr ChecksumDefinition::getDefaultChecksumDefinition(const std::vector &checksumDefinitions) { const KConfigGroup group(KSharedConfig::openConfig(), "ChecksumOperations"); const QString checksumDefinitionId = group.readEntry(CHECKSUM_DEFINITION_ID_ENTRY, QStringLiteral("sha256sum")); if (!checksumDefinitionId.isEmpty()) { - for (const std::shared_ptr &cd : checksumDefinitions) { + for (const ChecksumDefinition::Ptr &cd : checksumDefinitions) { if (cd && cd->id() == checksumDefinitionId) { return cd; } } } if (!checksumDefinitions.empty()) { return checksumDefinitions.front(); } else { - return std::shared_ptr(); + return ChecksumDefinition::Ptr(); } } // static -void ChecksumDefinition::setDefaultChecksumDefinition(const std::shared_ptr &checksumDefinition) +void ChecksumDefinition::setDefaultChecksumDefinition(const ChecksumDefinition::Ptr &checksumDefinition) { if (!checksumDefinition) { return; } KConfigGroup group(KSharedConfig::openConfig(), "ChecksumOperations"); group.writeEntry(CHECKSUM_DEFINITION_ID_ENTRY, checksumDefinition->id()); group.sync(); } diff --git a/src/kleo/checksumdefinition.h b/src/kleo/checksumdefinition.h index fef9b374a..02443cc64 100644 --- a/src/kleo/checksumdefinition.h +++ b/src/kleo/checksumdefinition.h @@ -1,108 +1,110 @@ /* -*- mode: c++; c-basic-offset:4 -*- checksumdefinition.h This file is part of libkleopatra, the KDE keymanagement library SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "kleo_export.h" #include #include #include #include class QProcess; namespace Kleo { class KLEO_EXPORT ChecksumDefinition { protected: ChecksumDefinition(const QString &id, const QString &label, const QString &outputFileName, const QStringList &extensions); public: + using Ptr = std::shared_ptr; + virtual ~ChecksumDefinition(); enum ArgumentPassingMethod { CommandLine, NewlineSeparatedInputFile, NullSeparatedInputFile, NumArgumentPassingMethods }; QString id() const { return m_id; } QString label() const { return m_label; } const QStringList &patterns() const { return m_patterns; } QString outputFileName() const { return m_outputFileName; } QString createCommand() const; ArgumentPassingMethod createCommandArgumentPassingMethod() const { return m_createMethod; } QString verifyCommand() const; ArgumentPassingMethod verifyCommandArgumentPassingMethod() const { return m_verifyMethod; } bool startCreateCommand(QProcess *process, const QStringList &files) const; bool startVerifyCommand(QProcess *process, const QStringList &files) const; static QString installPath(); static void setInstallPath(const QString &ip); - static std::vector> getChecksumDefinitions(); - static std::vector> getChecksumDefinitions(QStringList &errors); + static std::vector getChecksumDefinitions(); + static std::vector getChecksumDefinitions(QStringList &errors); - static std::shared_ptr getDefaultChecksumDefinition(const std::vector> &available); - static void setDefaultChecksumDefinition(const std::shared_ptr &checksumDefinition); + static Ptr getDefaultChecksumDefinition(const std::vector &available); + static void setDefaultChecksumDefinition(const Ptr &checksumDefinition); protected: void setCreateCommandArgumentPassingMethod(ArgumentPassingMethod method) { m_createMethod = method; } void setVerifyCommandArgumentPassingMethod(ArgumentPassingMethod method) { m_verifyMethod = method; } private: virtual QString doGetCreateCommand() const = 0; virtual QString doGetVerifyCommand() const = 0; virtual QStringList doGetCreateArguments(const QStringList &files) const = 0; virtual QStringList doGetVerifyArguments(const QStringList &files) const = 0; private: const QString m_id; const QString m_label; const QString m_outputFileName; const QStringList m_patterns; ArgumentPassingMethod m_createMethod = CommandLine; ArgumentPassingMethod m_verifyMethod = CommandLine; }; } diff --git a/src/utils/classify.cpp b/src/utils/classify.cpp index da6b93cc5..dd0a05ed7 100644 --- a/src/utils/classify.cpp +++ b/src/utils/classify.cpp @@ -1,421 +1,421 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/classify.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include "classify.h" #include "kleo/checksumdefinition.h" #include "libkleo_debug.h" #include "utils/algorithm.h" #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo::Class; namespace { const unsigned int ExamineContentHint = 0x8000; static const struct _classification { char extension[4]; unsigned int classification; } classifications[] = { // ordered by extension {"arl", Kleo::Class::CMS | Binary | CertificateRevocationList}, {"asc", Kleo::Class::OpenPGP | Ascii | OpaqueSignature | DetachedSignature | CipherText | AnyCertStoreType | ExamineContentHint}, {"cer", Kleo::Class::CMS | Binary | Certificate}, {"crl", Kleo::Class::CMS | Binary | CertificateRevocationList}, {"crt", Kleo::Class::CMS | Binary | Certificate}, {"der", Kleo::Class::CMS | Binary | Certificate | CertificateRevocationList}, {"gpg", Kleo::Class::OpenPGP | Binary | OpaqueSignature | CipherText | AnyCertStoreType | ExamineContentHint}, {"p10", Kleo::Class::CMS | Ascii | CertificateRequest}, {"p12", Kleo::Class::CMS | Binary | ExportedPSM}, {"p7c", Kleo::Class::CMS | Binary | Certificate}, {"p7m", Kleo::Class::CMS | AnyFormat | CipherText}, {"p7s", Kleo::Class::CMS | AnyFormat | AnySignature}, {"pem", Kleo::Class::CMS | Ascii | AnyType | ExamineContentHint}, {"pfx", Kleo::Class::CMS | Binary | Certificate}, {"pgp", Kleo::Class::OpenPGP | Binary | OpaqueSignature | CipherText | AnyCertStoreType | ExamineContentHint}, {"sig", Kleo::Class::OpenPGP | AnyFormat | DetachedSignature}, }; static const QMap gpgmeTypeMap{ // clang-format off {GpgME::Data::PGPSigned, Kleo::Class::OpenPGP | OpaqueSignature }, /* PGPOther might be just an unencrypted unsigned pgp message. Decrypt * would yield the plaintext anyway so for us this is CipherText. */ {GpgME::Data::PGPOther, Kleo::Class::OpenPGP | CipherText }, {GpgME::Data::PGPKey, Kleo::Class::OpenPGP | Certificate }, {GpgME::Data::CMSSigned, Kleo::Class::CMS | AnySignature }, {GpgME::Data::CMSEncrypted, Kleo::Class::CMS | CipherText }, /* See PGPOther */ {GpgME::Data::CMSOther, Kleo::Class::CMS | CipherText }, {GpgME::Data::X509Cert, Kleo::Class::CMS | Certificate }, {GpgME::Data::PKCS12, Kleo::Class::CMS | Binary | ExportedPSM }, {GpgME::Data::PGPEncrypted, Kleo::Class::OpenPGP | CipherText }, {GpgME::Data::PGPSignature, Kleo::Class::OpenPGP | DetachedSignature}, // clang-format on }; static const unsigned int defaultClassification = NoClass; template class Op> struct ByExtension { using result_type = bool; template bool operator()(const T &lhs, const T &rhs) const { return Op()(qstricmp(lhs.extension, rhs.extension), 0); } template bool operator()(const T &lhs, const char *rhs) const { return Op()(qstricmp(lhs.extension, rhs), 0); } template bool operator()(const char *lhs, const T &rhs) const { return Op()(qstricmp(lhs, rhs.extension), 0); } bool operator()(const char *lhs, const char *rhs) const { return Op()(qstricmp(lhs, rhs), 0); } }; static const struct _content_classification { char content[28]; unsigned int classification; } content_classifications[] = { // clang-format off {"CERTIFICATE", Certificate }, {"ENCRYPTED MESSAGE", CipherText }, {"MESSAGE", OpaqueSignature | CipherText }, {"PKCS12", ExportedPSM }, {"PRIVATE KEY BLOCK", ExportedPSM }, {"PUBLIC KEY BLOCK", Certificate }, {"SIGNATURE", DetachedSignature }, {"SIGNED MESSAGE", ClearsignedMessage | DetachedSignature}, // clang-format on }; template class Op> struct ByContent { using result_type = bool; const unsigned int N; explicit ByContent(unsigned int n) : N(n) { } template bool operator()(const T &lhs, const T &rhs) const { return Op()(qstrncmp(lhs.content, rhs.content, N), 0); } template bool operator()(const T &lhs, const char *rhs) const { return Op()(qstrncmp(lhs.content, rhs, N), 0); } template bool operator()(const char *lhs, const T &rhs) const { return Op()(qstrncmp(lhs, rhs.content, N), 0); } bool operator()(const char *lhs, const char *rhs) const { return Op()(qstrncmp(lhs, rhs, N), 0); } }; } unsigned int Kleo::classify(const QStringList &fileNames) { if (fileNames.empty()) { return 0; } unsigned int result = classify(fileNames.front()); for (const QString &fileName : fileNames) { result &= classify(fileName); } return result; } static unsigned int classifyExtension(const QFileInfo &fi) { const _classification *const it = Kleo::binary_find(std::begin(classifications), std::end(classifications), fi.suffix().toLatin1().constData(), ByExtension()); if (it != std::end(classifications)) { if (!(it->classification & ExamineContentHint)) { return it->classification; } } return it == std::end(classifications) ? defaultClassification : it->classification; } unsigned int Kleo::classify(const QString &filename) { Q_ASSERT(std::is_sorted(std::begin(classifications), std::end(classifications), ByExtension())); const QFileInfo fi(filename); if (!fi.exists()) { return 0; } QFile file(filename); /* The least reliable but always available classification */ const unsigned int extClass = classifyExtension(fi); if (!GpgME::hasFeature(0, GpgME::BinaryAndFineGrainedIdentify) && !(extClass & ExamineContentHint)) { /* GpgME's identify and our internal Classify were so incomplete * before BinaryAndFineGrainedIdentify that we are better of * to just use the file extension if ExamineContentHint is not set. */ qCDebug(LIBKLEO_LOG) << "Classified based only on extension."; return extClass; } if (!file.open(QIODevice::ReadOnly)) { qCDebug(LIBKLEO_LOG) << "Failed to open file: " << filename << " for classification."; return extClass; } /* More reliable */ const unsigned int contentClass = classifyContent(file.read(4096)); if (contentClass != defaultClassification) { qCDebug(LIBKLEO_LOG) << "Classified based on content as:" << contentClass; return contentClass; } /* Probably some X509 Stuff that GpgME in it's wisdom does not handle. Again * file extension is probably more reliable as the last resort. */ qCDebug(LIBKLEO_LOG) << "No classification based on content."; return extClass; } static unsigned int classifyContentInteral(const QByteArray &data) { Q_ASSERT(std::is_sorted(std::begin(content_classifications), std::end(content_classifications), ByContent(100))); static const char beginString[] = "-----BEGIN "; static const QByteArrayMatcher beginMatcher(beginString); int pos = beginMatcher.indexIn(data); if (pos < 0) { return defaultClassification; } pos += sizeof beginString - 1; const bool pgp = qstrncmp(data.data() + pos, "PGP ", 4) == 0; if (pgp) { pos += 4; } const int epos = data.indexOf("-----\n", pos); if (epos < 0) { return defaultClassification; } const _content_classification *const cit = Kleo::binary_find(std::begin(content_classifications), std::end(content_classifications), data.data() + pos, ByContent(epos - pos)); if (cit != std::end(content_classifications)) { return cit->classification | (pgp ? Kleo::Class::OpenPGP : Kleo::Class::CMS); } return defaultClassification; } unsigned int Kleo::classifyContent(const QByteArray &data) { /* As of Version 1.6.0 GpgME does not distinguish between detached * signatures and signatures. So we prefer kleo's classification and * only use gpgme as fallback. * With newer versions we have a better identify that really inspects * the PGP Packages. Which is by far the most reliable classification. * So this is already used for the default classification. File extensions * and our classifyinternal is only used as a fallback. */ if (!GpgME::hasFeature(0, GpgME::BinaryAndFineGrainedIdentify)) { unsigned int ourClassification = classifyContentInteral(data); if (ourClassification != defaultClassification) { return ourClassification; } } QGpgME::QByteArrayDataProvider dp(data); GpgME::Data gpgmeData(&dp); GpgME::Data::Type type = gpgmeData.type(); return gpgmeTypeMap.value(type, defaultClassification); } QString Kleo::printableClassification(unsigned int classification) { QStringList parts; if (classification & Kleo::Class::CMS) { parts.push_back(QStringLiteral("CMS")); } if (classification & Kleo::Class::OpenPGP) { parts.push_back(QStringLiteral("OpenPGP")); } if (classification & Kleo::Class::Binary) { parts.push_back(QStringLiteral("Binary")); } if (classification & Kleo::Class::Ascii) { parts.push_back(QStringLiteral("Ascii")); } if (classification & Kleo::Class::DetachedSignature) { parts.push_back(QStringLiteral("DetachedSignature")); } if (classification & Kleo::Class::OpaqueSignature) { parts.push_back(QStringLiteral("OpaqueSignature")); } if (classification & Kleo::Class::ClearsignedMessage) { parts.push_back(QStringLiteral("ClearsignedMessage")); } if (classification & Kleo::Class::CipherText) { parts.push_back(QStringLiteral("CipherText")); } if (classification & Kleo::Class::Certificate) { parts.push_back(QStringLiteral("Certificate")); } if (classification & Kleo::Class::ExportedPSM) { parts.push_back(QStringLiteral("ExportedPSM")); } if (classification & Kleo::Class::CertificateRequest) { parts.push_back(QStringLiteral("CertificateRequest")); } return parts.join(QLatin1String(", ")); } static QString chopped(QString s, unsigned int n) { s.chop(n); return s; } /*! \return the data file that corresponds to the signature file \a signatureFileName, or QString(), if no such file can be found. */ QString Kleo::findSignedData(const QString &signatureFileName) { if (!mayBeDetachedSignature(signatureFileName)) { return QString(); } const QString baseName = chopped(signatureFileName, 4); return QFile::exists(baseName) ? baseName : QString(); } /*! \return all (existing) candidate signature files for \a signedDataFileName Note that there can very well be more than one such file, e.g. if the same data file was signed by both CMS and OpenPGP certificates. */ QStringList Kleo::findSignatures(const QString &signedDataFileName) { QStringList result; for (unsigned int i = 0, end = sizeof(classifications) / sizeof(_classification); i < end; ++i) { if (classifications[i].classification & DetachedSignature) { const QString candidate = signedDataFileName + QLatin1Char('.') + QLatin1String(classifications[i].extension); if (QFile::exists(candidate)) { result.push_back(candidate); } } } return result; } /*! \return the (likely) output filename for \a inputFileName, or "inputFileName.out" if none can be determined. */ QString Kleo::outputFileName(const QString &inputFileName) { const QFileInfo fi(inputFileName); if (!std::binary_search(std::begin(classifications), std::end(classifications), fi.suffix().toLatin1().constData(), ByExtension())) { return inputFileName + QLatin1String(".out"); } else { return chopped(inputFileName, 4); } } /*! \return the commonly used extension for files of type \a classification, or NULL if none such exists. */ const char *Kleo::outputFileExtension(unsigned int classification, bool usePGPFileExt) { if (usePGPFileExt && (classification & Class::OpenPGP) && (classification & Class::Binary)) { return "pgp"; } for (unsigned int i = 0; i < sizeof classifications / sizeof *classifications; ++i) { if ((classifications[i].classification & classification) == classification) { return classifications[i].extension; } } return nullptr; } bool Kleo::isFingerprint(const QString &fpr) { static QRegularExpression fprRegex(QStringLiteral("[0-9a-fA-F]{40}")); return fprRegex.match(fpr).hasMatch(); } bool Kleo::isChecksumFile(const QString &file) { static bool initialized; static QList patterns; const QFileInfo fi(file); if (!fi.exists()) { return false; } if (!initialized) { const auto getChecksumDefinitions = ChecksumDefinition::getChecksumDefinitions(); - for (const std::shared_ptr &cd : getChecksumDefinitions) { + for (const ChecksumDefinition::Ptr &cd : getChecksumDefinitions) { if (cd) { const auto patternsList = cd->patterns(); for (const QString &pattern : patternsList) { #ifdef Q_OS_WIN patterns << QRegExp(pattern, Qt::CaseInsensitive); #else patterns << QRegExp(pattern, Qt::CaseSensitive); #endif } } } initialized = true; } const QString fileName = fi.fileName(); for (const QRegExp &pattern : std::as_const(patterns)) { if (pattern.exactMatch(fileName)) { return true; } } return false; }