diff --git a/messageviewer/src/CMakeLists.txt b/messageviewer/src/CMakeLists.txt index f87467a7..e0533fd2 100644 --- a/messageviewer/src/CMakeLists.txt +++ b/messageviewer/src/CMakeLists.txt @@ -1,575 +1,576 @@ add_definitions(-DTRANSLATION_DOMAIN=\"libmessageviewer\") add_subdirectory(messagepartthemes/grantlee) # KCFG files: # The main messageviewer.kcfg is configured by CMake and put in the build directory. if(KDEPIM_ENTERPRISE_BUILD) set(LEGACY_MANGLE_FROM_TO_HEADERS true) set(LEGACY_BODY_INVITES true) set(EXCHANGE_COMPATIBLE_INVITATIONS true) else() set(LEGACY_MANGLE_FROM_TO_HEADERS false) set(LEGACY_BODY_INVITES false) set(EXCHANGE_COMPATIBLE_INVITATIONS false) endif() configure_file(settings/messageviewer.kcfg.cmake ${CMAKE_CURRENT_BINARY_DIR}/messageviewer.kcfg) include(CheckIncludeFiles) find_package(Inotify) set_package_properties(Inotify PROPERTIES PURPOSE "Filesystem alteration notifications using inotify") if(Inotify_FOUND) set(HAVE_SYS_INOTIFY_H 1) else() set(HAVE_SYS_INOTIFY_H 0) endif() find_package(Qca-qt5 2.1.0 CONFIG REQUIRED) set_package_properties(Qca-qt5 PROPERTIES DESCRIPTION "Qt Cryptographic Architecture" URL "https:/download.kde.org/stable/qca-qt5" TYPE REQUIRED PURPOSE "Needed for dkim support.") if (${Qca-qt5_FOUND}) set(USE_DKIM_CHECKER 1) endif() configure_file(config-messageviewer.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-messageviewer.h) # target_include_directories does not handle empty include paths include_directories(${GPGME_INCLUDES}) if(BUILD_TESTING) add_subdirectory(header/autotests) add_subdirectory(scamdetection/autotests) add_subdirectory(scamdetection/tests) add_subdirectory(viewerplugins/tests/) add_subdirectory(htmlwriter/autotests) add_subdirectory(viewer/webengine/tests) add_subdirectory(messagepartthemes/default/autotests) add_subdirectory(widgets/autotests/) add_subdirectory(utils/autotests) endif() add_subdirectory(pics) add_subdirectory(kconf_update) add_subdirectory(about) add_subdirectory(messageviewerheaderplugins) if (${Qca-qt5_FOUND}) if (BUILD_TESTING) add_subdirectory(dkim-verify/autotests) add_subdirectory(dkim-verify/tests) endif() set(dkim_verify_SRCS dkim-verify/dkiminfo.cpp dkim-verify/dkimmanagerkey.cpp dkim-verify/dkimmanagerkeywidget.cpp dkim-verify/dkimmanagerkeydialog.cpp dkim-verify/dkimdownloadkeyjob.cpp dkim-verify/dkimchecksignaturejob.cpp dkim-verify/dkimcheckauthenticationstatusjob.cpp dkim-verify/dkimauthenticationstatusinfo.cpp dkim-verify/dkimutil.cpp dkim-verify/dkimkeyrecord.cpp dkim-verify/dkimmanager.cpp dkim-verify/dkimresultattribute.cpp dkim-verify/dkimwidgetinfo.cpp dkim-verify/dkimstoreresultjob.cpp dkim-verify/dkimheaderparser.cpp dkim-verify/dkimcheckpolicy.cpp dkim-verify/dmarcrecordjob.cpp dkim-verify/dmarcinfo.cpp dkim-verify/dmarcpolicyjob.cpp dkim-verify/dkimcheckpolicyjob.cpp dkim-verify/dkimrule.cpp dkim-verify/dkimmanagerrules.cpp dkim-verify/dkimgeneraterulejob.cpp dkim-verify/dkimauthenticationstatusinfoutil.cpp ) endif() if(DEBUG_SIGNATURE) add_definitions(-DDEBUG_SIGNATURE) endif() if (MESSAGEVIEWER_EXPERIMENTAL_CONVERSATIONVIEW) set(libmessageviewer_conversationviewer_SRCS conversationview/conversationviewwidget.cpp ) if (BUILD_TESTING) add_subdirectory(conversationview/autotests) add_subdirectory(conversationview/tests) endif() endif() set(libmessageviewer_mailviewer_SRCS viewer/webengine/mailwebengineview.cpp viewer/webengine/mailwebenginepage.cpp viewer/webengine/loadexternalreferencesurlinterceptor/loadexternalreferencesurlinterceptor.cpp viewer/webengine/cidreferencesurlinterceptor/cidreferencesurlinterceptor.cpp viewer/webengine/blockexternalresourcesurlinterceptor/blockexternalresourcesurlinterceptor.cpp viewer/webengine/blockmailtrackingurlinterceptor/blockmailtrackingurlinterceptor.cpp ) set(libmessageviewer_viewer_SRCS viewer/attachmentstrategy.cpp viewer/csshelper.cpp viewer/csshelperbase.cpp viewer/editorwatcher.cpp viewer/objecttreeemptysource.cpp viewer/objecttreeviewersource.cpp viewer/viewer.cpp viewer/viewer_p.cpp viewer/messagedisplayformatattribute.cpp viewer/urlhandlermanager.cpp viewer/mimeparttree/mimeparttreeview.cpp viewer/mimeparttree/mimetreemodel.cpp ) set(libmessageviewer_widgets_SRCS widgets/attachmentdialog.cpp widgets/configurewidget.cpp widgets/printingsettings.cpp widgets/htmlstatusbar.cpp widgets/vcardviewer.cpp widgets/invitationsettings.cpp widgets/openattachmentfolderwidget.cpp widgets/mailsourceviewtextbrowserwidget.cpp widgets/submittedformwarningwidget.cpp widgets/mailtrackingwarningwidget.cpp widgets/mailtrackingdetailsdialog.cpp widgets/shownextmessagewidget.cpp ) set(libmessageviewer_widgets_webengine_SRCS widgets/mailsourcewebengineviewer.cpp ) set(libmessageviewer_header_SRCS header/contactdisplaymessagememento.cpp header/headerstrategy.cpp header/richheaderstrategy.cpp header/headerstyle.cpp header/grantleeheaderstyle.cpp header/plainheaderstyle.cpp header/headerstyle_util.cpp header/grantleeheaderformatter.cpp header/grantleeheaderteststyle.cpp header/kxface.cpp header/headerstyleplugin.cpp header/headerstylepluginmanager.cpp header/headerstyleinterface.cpp header/headerstylemenumanager.cpp ) set(libmessageviewer_scamdetection_SRCS scamdetection/scamdetectionwarningwidget.cpp scamdetection/scamdetectiondetailsdialog.cpp scamdetection/scamattribute.cpp scamdetection/scamcheckshorturl.cpp scamdetection/scamexpandurljob.cpp scamdetection/scamcheckshorturlmanager.cpp ) set(libmessageviewer_scamdetection_webengine_SRCS scamdetection/scamdetectionwebengine.cpp ) set(libmessageviewer_findbar_SRCS findbar/findbarsourceview.cpp ) set(libmessageviewer_utils_SRCS utils/iconnamecache.cpp utils/markmessagereadhandler.cpp utils/messageviewerutil.cpp utils/mimetype.cpp ) set(libmessageviewer_htmlwriter_SRCS htmlwriter/webengineparthtmlwriter.cpp htmlwriter/webengineembedpart.cpp htmlwriter/bufferedhtmlwriter.cpp htmlwriter/filehtmlwriter.cpp ) set(libmessageviewer_antispam_SRCS antispam/spamheaderanalyzer.cpp antispam/antispamconfig.cpp ) set(libmessageviewer_job_SRCS job/modifymessagedisplayformatjob.cpp ) set(libmessageviewer_viewerplugins_SRCS viewerplugins/viewerpluginmanager.cpp viewerplugins/viewerplugin.cpp viewerplugins/viewerplugininterface.cpp viewerplugins/viewerplugintoolmanager.cpp ) set(libmessageviewer_configureplugins_SRCS messageviewerconfigureplugins/messageviewerconfiguresettingsplugin.cpp messageviewerconfigureplugins/messageviewerconfiguresettingspluginmanager.cpp messageviewerconfigureplugins/messageviewerconfiguresettingspluginwidget.cpp ) set(libmessageviewer_messagepartthemes_default_SRCS messagepartthemes/default/converthtmltoplaintext.cpp messagepartthemes/default/defaultrenderer.cpp messagepartthemes/default/htmlblock.cpp messagepartthemes/default/messagepartrenderermanager.cpp messagepartthemes/default/plugins/attachmentmessagepartrenderer.cpp messagepartthemes/default/plugins/messagepartrenderer.cpp messagepartthemes/default/plugins/textmessagepartrenderer.cpp messagepartthemes/default/plugins/quotehtml.cpp messagepartthemes/default/messagepartrenderbase.cpp messagepartthemes/default/messagepartrenderplugin.cpp messagepartthemes/default/messagepartrendererfactory.cpp ) set(libmessageviewer_interfaces_SRCS interfaces/htmlwriter.cpp ) set(libmessageviewer_SRCS ${libmessageviewer_conversationviewer_SRCS} ${dkim_verify_SRCS} ${libmessageviewer_messagepartthemes_default_SRCS} ${libmessageviewer_htmlwriter_SRCS} ${libmessageviewer_messagepartthemes_SRCS} ${libmessageviewer_scamdetection_webengine_SRCS} ${libmessageviewer_widgets_webengine_SRCS} ${libmessageviewer_viewer_SRCS} ${libmessageviewer_widgets_SRCS} ${libmessageviewer_header_SRCS} ${libmessageviewer_scamdetection_SRCS} ${libmessageviewer_findbar_SRCS} ${libmessageviewer_utils_SRCS} ${libmessageviewer_antispam_SRCS} ${libmessageviewer_job_SRCS} ${libmessageviewer_viewerplugins_SRCS} settings/messageviewersettings.cpp ${libmessageviewer_mailviewer_SRCS} ${libmessageviewer_interfaces_SRCS} ${libmessageviewer_configureplugins_SRCS} ) qt5_add_resources(libmessageviewer_SRCS messagepartthemes.qrc) ecm_qt_declare_logging_category(libmessageviewer_SRCS HEADER messageviewer_debug.h IDENTIFIER MESSAGEVIEWER_LOG CATEGORY_NAME org.kde.pim.messageviewer) ecm_qt_declare_logging_category(libmessageviewer_SRCS HEADER messageviewer_dkimcheckerdebug.h IDENTIFIER MESSAGEVIEWER_DKIMCHECKER_LOG CATEGORY_NAME org.kde.pim.messageviewer_dkimchecker) kconfig_add_kcfg_files(libmessageviewer_SRCS settings/globalsettings_messageviewer.kcfgc ) ki18n_wrap_ui(libmessageviewer_SRCS ui/settings.ui ui/invitationsettings.ui ui/printingsettings.ui ) add_library(KF5MessageViewer ${libmessageviewer_SRCS}) generate_export_header(KF5MessageViewer BASE_NAME messageviewer) add_library(KF5::MessageViewer ALIAS KF5MessageViewer) target_include_directories(KF5MessageViewer INTERFACE "$;${Inotify_INCLUDE_DIRS}") if (${Qca-qt5_FOUND}) set(OPTIONAL_PRIVATE qca-qt5) endif() target_link_libraries(KF5MessageViewer PUBLIC KF5::MessageCore KF5::PimCommon KF5::AkonadiCore KF5::AkonadiMime KF5::Contacts KF5::Libkleo KF5::MimeTreeParser PRIVATE KF5::SyntaxHighlighting KF5::ItemViews Qt5::Network KF5::WebEngineViewer KF5::LibkdepimAkonadi KF5::GrantleeTheme KF5::KaddressbookGrantlee KF5::MailTransportAkonadi KF5::Mime KF5::Mbox KF5::PimTextEdit KF5::Gravatar KF5::IconThemes KF5::I18n KF5::KIOFileWidgets KF5::KIOWidgets KF5::XmlGui Grantlee5::TextDocument Grantlee5::Templates Qt5::PrintSupport QGpgme ${Inotify_LIBRARIES} ${OPTIONAL_PRIVATE} ) set_target_properties(KF5MessageViewer PROPERTIES VERSION ${MESSAGEVIEWER_VERSION_STRING} SOVERSION ${MESSAGEVIEWER_SOVERSION} EXPORT_NAME MessageViewer ) install(TARGETS KF5MessageViewer EXPORT KF5MessageViewerTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} ${LIBRARY_NAMELINK} ) ecm_generate_headers(MessageViewer_Camelblockmailtrackingurlinterceptor_HEADERS HEADER_NAMES BlockMailTrackingUrlInterceptor REQUIRED_HEADERS MessageViewer_blockmailtrackingurlinterceptor_HEADERS PREFIX MessageViewer RELATIVE viewer/webengine/blockmailtrackingurlinterceptor ) ecm_generate_headers(MessageViewer_Camelcasewebengine_HEADERS HEADER_NAMES MailWebEnginePage MailWebEngineView REQUIRED_HEADERS MessageViewer_webengine_HEADERS PREFIX MessageViewer RELATIVE viewer/webengine ) ecm_generate_headers(MessageViewer_Camelcasescam_HEADERS HEADER_NAMES ScamExpandUrlJob ScamCheckShortUrlManager ScamCheckShortUrl REQUIRED_HEADERS MessageViewer_scam_HEADERS PREFIX MessageViewer RELATIVE scamdetection ) if (${Qca-qt5_FOUND}) ecm_generate_headers(MessageViewer_Cameldkimverify_HEADERS HEADER_NAMES DKIMManagerKey DKIMCheckSignatureJob DKIMManager DKIMManagerKeyWidget DKIMManagerKeyDialog DKIMKeyRecord DKIMInfo DKIMWidgetInfo DKIMCheckPolicy DKIMManagerRules DKIMRule + DKIMHeaderParser REQUIRED_HEADERS MessageViewer_dkimverify_HEADERS PREFIX MessageViewer RELATIVE dkim-verify ) endif() ecm_generate_headers(MessageViewer_Camelcaseviewer_HEADERS HEADER_NAMES AttachmentStrategy Viewer CSSHelperBase CSSHelper ObjectTreeEmptySource EditorWatcher Stl_Util REQUIRED_HEADERS MessageViewer_viewer_HEADERS PREFIX MessageViewer RELATIVE viewer ) ecm_generate_headers(MessageViewer_Camelcasewidgets_HEADERS HEADER_NAMES InvitationSettings PrintingSettings ConfigureWidget REQUIRED_HEADERS MessageViewer_widgets_HEADERS PREFIX MessageViewer RELATIVE widgets ) ecm_generate_headers(MessageViewer_Camelcaseutils_HEADERS HEADER_NAMES IconNameCache MarkMessageReadHandler MessageViewerUtil MimeType REQUIRED_HEADERS MessageViewer_utils_HEADERS PREFIX MessageViewer RELATIVE utils ) ecm_generate_headers(MessageViewer_Camelcaseantispam_HEADERS HEADER_NAMES SpamHeaderAnalyzer REQUIRED_HEADERS MessageViewer_antispam_HEADERS PREFIX MessageViewer RELATIVE antispam ) ecm_generate_headers(MessageViewer_Camelcaseinterfaces_HEADERS HEADER_NAMES HtmlWriter BodyPartURLHandler URLHandler REQUIRED_HEADERS MessageViewer_interfaces_HEADERS PREFIX MessageViewer RELATIVE interfaces ) ecm_generate_headers(MessageViewer_Camelcasehtmlwriter_HEADERS HEADER_NAMES BufferedHtmlWriter FileHtmlWriter REQUIRED_HEADERS MessageViewer_htmlwriter_HEADERS PREFIX MessageViewer RELATIVE htmlwriter ) ecm_generate_headers(MessageViewer_Camelcasesettings_HEADERS HEADER_NAMES MessageViewerSettings REQUIRED_HEADERS MessageViewer_settings_HEADERS PREFIX MessageViewer RELATIVE settings ) ecm_generate_headers(MessageViewer_CamelcaseConfigurePlugins_HEADERS HEADER_NAMES MessageViewerConfigureSettingsPluginManager MessageViewerConfigureSettingsPlugin MessageViewerConfigureSettingsPluginWidget REQUIRED_HEADERS MessageViewer_ConfigurePlugins_HEADERS PREFIX MessageViewer RELATIVE messageviewerconfigureplugins ) ecm_generate_headers(MessageViewer_Camelcaseheader_HEADERS HEADER_NAMES HeaderStrategy GrantleeHeaderTestStyle GrantleeHeaderStyle HeaderStyle KXFace HeaderStyle_Util HeaderStylePlugin HeaderStyleInterface PlainHeaderStyle RichHeaderStrategy HeaderStylePluginManager HeaderStyleMenuManager REQUIRED_HEADERS MessageViewer_header_HEADERS PREFIX MessageViewer RELATIVE header ) ecm_generate_headers(MessageViewer_Camelcaseviewerplugin_HEADERS HEADER_NAMES ViewerPluginManager ViewerPlugin ViewerPluginInterface ViewerPluginToolManager REQUIRED_HEADERS MessageViewer_viewerplugin_HEADERS PREFIX MessageViewer RELATIVE viewerplugins ) ecm_generate_headers(MessageViewer_Camelcaserenderer_HEADERS HEADER_NAMES HtmlBlock MessagePartRendererBase MessagePartRendererManager MessagePartRenderPlugin REQUIRED_HEADERS MessageViewer_renderer_HEADERS PREFIX MessageViewer RELATIVE messagepartthemes/default ) ecm_generate_pri_file(BASE_NAME MessageViewer LIB_NAME KF5MessageViewer DEPS "PimCommon MessageCore AkonadiCore AkonadiMime Contacts Libkleo MimeTreeParser" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/MessageViewer ) if (${Qca-qt5_FOUND}) install(FILES ${MessageViewer_Cameldkimverify_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/MessageViewer COMPONENT Devel ) install(FILES ${MessageViewer_dkimverify_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/messageviewer COMPONENT Devel ) endif() install(FILES ${MessageViewer_CamelcaseConfigurePlugins_HEADERS} ${MessageViewer_Camelcasewebengine_HEADERS} ${MessageViewer_Camelcaseheader_HEADERS} ${MessageViewer_Camelcaseviewerplugin_HEADERS} ${MessageViewer_Camelcasesettings_HEADERS} ${MessageViewer_Camelcaseutils_HEADERS} ${MessageViewer_Camelcaseinterfaces_HEADERS} ${MessageViewer_Camelcasehtmlwriter_HEADERS} ${MessageViewer_Camelcaseviewer_HEADERS} ${MessageViewer_Camelcasewidgets_HEADERS} ${MessageViewer_Camelcaseantispam_HEADERS} ${MessageViewer_Camelfindbar_HEADERS} ${MessageViewer_Camelcasescam_HEADERS} ${MessageViewer_Camelcaserenderer_HEADERS} ${MessageViewer_Camelblockmailtrackingurlinterceptor_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/MessageViewer COMPONENT Devel ) install(FILES ${MessageViewer_ConfigurePlugins_HEADERS} ${MessageViewer_webengine_HEADERS} ${MessageViewer_scam_HEADERS} ${MessageViewer_viewerplugin_HEADERS} ${MessageViewer_settings_HEADERS} ${MessageViewer_header_HEADERS} ${MessageViewer_utils_HEADERS} ${MessageViewer_interfaces_HEADERS} ${MessageViewer_htmlwriter_HEADERS} ${MessageViewer_HEADERS} ${MessageViewer_viewer_HEADERS} ${MessageViewer_widgets_HEADERS} ${MessageViewer_antispam_HEADERS} ${MessageViewer_findbar_HEADERS} ${MessageViewer_renderer_HEADERS} ${MessageViewer_blockmailtrackingurlinterceptor_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/messageviewer_export.h ${CMAKE_CURRENT_BINARY_DIR}/globalsettings_messageviewer.h ${CMAKE_CURRENT_BINARY_DIR}/messageviewer_debug.h ${CMAKE_CURRENT_BINARY_DIR}/config-messageviewer.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/messageviewer COMPONENT Devel ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) install(FILES header/data/messageviewer_header_themes.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR} ) install(FILES notify/messageviewer.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR} ) install(FILES scamdetection/data/longurlServices.json DESTINATION ${KDE_INSTALL_DATADIR}/messageviewer ) diff --git a/messageviewer/src/dkim-verify/dkimchecksignaturejob.cpp b/messageviewer/src/dkim-verify/dkimchecksignaturejob.cpp index ad6e1eb5..2ae43f2b 100644 --- a/messageviewer/src/dkim-verify/dkimchecksignaturejob.cpp +++ b/messageviewer/src/dkim-verify/dkimchecksignaturejob.cpp @@ -1,676 +1,676 @@ /* Copyright (C) 2018-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dkimchecksignaturejob.h" #include "dkimdownloadkeyjob.h" #include "dkimmanagerkey.h" #include "dkiminfo.h" #include "dkimutil.h" #include "dkimkeyrecord.h" #include "messageviewer_dkimcheckerdebug.h" -#include "dkimheaderparser.h" #include #include #include #include #include //see https://tools.ietf.org/html/rfc6376 //#define DEBUG_SIGNATURE_DKIM 1 using namespace MessageViewer; DKIMCheckSignatureJob::DKIMCheckSignatureJob(QObject *parent) : QObject(parent) { } DKIMCheckSignatureJob::~DKIMCheckSignatureJob() { } MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult DKIMCheckSignatureJob::createCheckResult() { MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult result; result.error = mError; result.warning = mWarning; result.status = mStatus; result.item = mMessageItem; result.signedBy = mDkimInfo.domain(); result.fromEmail = mFromEmail; return result; } QString DKIMCheckSignatureJob::bodyCanonizationResult() const { return mBodyCanonizationResult; } QString DKIMCheckSignatureJob::headerCanonizationResult() const { return mHeaderCanonizationResult; } void DKIMCheckSignatureJob::start() { if (mMessageItem.isValid() && !mMessage) { if (mMessageItem.hasPayload()) { mMessage = mMessageItem.payload(); } } else if (mMessage) { //Nothing } else { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Item has not a message"; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } if (auto hrd = mMessage->headerByType("DKIM-Signature")) { mDkimValue = hrd->asUnicodeString(); } //Store mFromEmail before looking at mDkimValue value. Otherwise we can return a from empty if (auto hrd = mMessage->from(false)) { mFromEmail = KEmailAddress::extractEmailAddress(hrd->asUnicodeString()); } if (mDkimValue.isEmpty()) { mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::EmailNotSigned; Q_EMIT result(createCheckResult()); deleteLater(); return; } qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << "mFromEmail " << mFromEmail; if (!mDkimInfo.parseDKIM(mDkimValue)) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Impossible to parse header" << mDkimValue; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } const MessageViewer::DKIMCheckSignatureJob::DKIMStatus status = checkSignature(mDkimInfo); if (status != MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Valid) { mStatus = status; Q_EMIT result(createCheckResult()); deleteLater(); return; } //ComputeBodyHash now. switch (mDkimInfo.bodyCanonization()) { case MessageViewer::DKIMInfo::CanonicalizationType::Unknown: mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidBodyCanonicalization; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; case MessageViewer::DKIMInfo::CanonicalizationType::Simple: mBodyCanonizationResult = bodyCanonizationSimple(); break; case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed: mBodyCanonizationResult = bodyCanonizationRelaxed(); break; } //qDebug() << " bodyCanonizationResult "<< mBodyCanonizationResult << " algorithm " << mDkimInfo.hashingAlgorithm() << mDkimInfo.bodyHash(); if (mDkimInfo.bodyLengthCount() != -1) { //Verify it. if (mDkimInfo.bodyLengthCount() < mBodyCanonizationResult.length()) { // length tag exceeds body size mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::SignatureTooLarge; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } else if (mDkimInfo.bodyLengthCount() > mBodyCanonizationResult.length()) { mWarning = MessageViewer::DKIMCheckSignatureJob::DKIMWarning::SignatureTooSmall; } // truncated body to the length specified in the "l=" tag mBodyCanonizationResult = mBodyCanonizationResult.left(mDkimInfo.bodyLengthCount()); } if (mBodyCanonizationResult.startsWith(QLatin1String("\r\n"))) { //Remove it from start mBodyCanonizationResult = mBodyCanonizationResult.right(mBodyCanonizationResult.length() -2); } #ifdef DEBUG_SIGNATURE_DKIM QFile caFile(QStringLiteral("/tmp/bodycanon-kmail.txt")); caFile.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream outStream(&caFile); outStream << mBodyCanonizationResult; caFile.close(); #endif QByteArray resultHash; switch (mDkimInfo.hashingAlgorithm()) { case DKIMInfo::HashingAlgorithmType::Sha1: resultHash = MessageViewer::DKIMUtil::generateHash(mBodyCanonizationResult.toLatin1(), QCryptographicHash::Sha1); break; case DKIMInfo::HashingAlgorithmType::Sha256: resultHash = MessageViewer::DKIMUtil::generateHash(mBodyCanonizationResult.toLatin1(), QCryptographicHash::Sha256); break; case DKIMInfo::HashingAlgorithmType::Any: case DKIMInfo::HashingAlgorithmType::Unknown: mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InsupportedHashAlgorithm; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } // compare body hash qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "resultHash " << resultHash << "mDkimInfo.bodyHash()" << mDkimInfo.bodyHash(); if (resultHash != mDkimInfo.bodyHash().toLatin1()) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << " Corrupted body hash"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::CorruptedBodyHash; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } if (mDkimInfo.headerCanonization() == MessageViewer::DKIMInfo::CanonicalizationType::Unknown) { mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidHeaderCanonicalization; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } + //Parse message header + mHeaderParser.setHead(mMessage->head()); + mHeaderParser.parse(); + computeHeaderCanonization(true); if (mPolicy.saveKey() == MessageViewer::MessageViewerSettings::EnumSaveKey::Save) { const QString keyValue = MessageViewer::DKIMManagerKey::self()->keyValue(mDkimInfo.selector(), mDkimInfo.domain()); //qDebug() << " mDkimInfo.selector() " << mDkimInfo.selector() << "mDkimInfo.domain() " << mDkimInfo.domain() << keyValue; if (keyValue.isEmpty()) { downloadKey(mDkimInfo); } else { parseDKIMKeyRecord(keyValue, mDkimInfo.domain(), mDkimInfo.selector(), false); } } else { downloadKey(mDkimInfo); } } void DKIMCheckSignatureJob::computeHeaderCanonization(bool removeQuoteOnContentType) { //Compute Hash Header switch (mDkimInfo.headerCanonization()) { case MessageViewer::DKIMInfo::CanonicalizationType::Unknown: return; case MessageViewer::DKIMInfo::CanonicalizationType::Simple: mHeaderCanonizationResult = headerCanonizationSimple(); break; case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed: mHeaderCanonizationResult = headerCanonizationRelaxed(removeQuoteOnContentType); break; } // In hash step 2, the Signer/Verifier MUST pass the following to the // hash algorithm in the indicated order. // 1. The header fields specified by the "h=" tag, in the order // specified in that tag, and canonicalized using the header // canonicalization algorithm specified in the "c=" tag. Each // header field MUST be terminated with a single CRLF. // 2. The DKIM-Signature header field that exists (verifying) or will // be inserted (signing) in the message, with the value of the "b=" // tag (including all surrounding whitespace) deleted (i.e., treated // as the empty string), canonicalized using the header // canonicalization algorithm specified in the "c=" tag, and without // a trailing CRLF. // add DKIM-Signature header to the hash input // with the value of the "b=" tag (including all surrounding whitespace) deleted //Add dkim-signature as lowercase QString dkimValue = mDkimValue; dkimValue = dkimValue.left(dkimValue.indexOf(QLatin1String("b=")) + 2); switch (mDkimInfo.headerCanonization()) { case MessageViewer::DKIMInfo::CanonicalizationType::Unknown: return; case MessageViewer::DKIMInfo::CanonicalizationType::Simple: mHeaderCanonizationResult += QLatin1String("\r\n") + MessageViewer::DKIMUtil::headerCanonizationSimple(QLatin1String("dkim-signature"), dkimValue); break; case MessageViewer::DKIMInfo::CanonicalizationType::Relaxed: mHeaderCanonizationResult += QLatin1String("\r\n") + MessageViewer::DKIMUtil::headerCanonizationRelaxed(QLatin1String("dkim-signature"), dkimValue, removeQuoteOnContentType); break; } #ifdef DEBUG_SIGNATURE_DKIM QFile headerFile(QStringLiteral("/tmp/headercanon-kmail-%1.txt").arg(removeQuoteOnContentType ? QLatin1String("removequote") : QLatin1String("withquote"))); headerFile.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream outHeaderStream(&headerFile); outHeaderStream << mHeaderCanonizationResult; headerFile.close(); #endif } QString DKIMCheckSignatureJob::bodyCanonizationSimple() const { /* * canonicalize the body using the simple algorithm * specified in Section 3.4.3 of RFC 6376 */ // The "simple" body canonicalization algorithm ignores all empty lines // at the end of the message body. An empty line is a line of zero // length after removal of the line terminator. If there is no body or // no trailing CRLF on the message body, a CRLF is added. It makes no // other changes to the message body. In more formal terms, the // "simple" body canonicalization algorithm converts "*CRLF" at the end // of the body to a single "CRLF". // Note that a completely empty or missing body is canonicalized as a // single "CRLF"; that is, the canonicalized length will be 2 octets. return MessageViewer::DKIMUtil::bodyCanonizationSimple(QString::fromLatin1(mMessage->encodedBody())); } QString DKIMCheckSignatureJob::bodyCanonizationRelaxed() const { /* * canonicalize the body using the relaxed algorithm * specified in Section 3.4.4 of RFC 6376 */ /* a. Reduce whitespace: * Ignore all whitespace at the end of lines. Implementations MUST NOT remove the CRLF at the end of the line. * Reduce all sequences of WSP within a line to a single SP character. b. Ignore all empty lines at the end of the message body. "Empty line" is defined in Section 3.4.3. If the body is non-empty but does not end with a CRLF, a CRLF is added. (For email, this is only possible when using extensions to SMTP or non-SMTP transport mechanisms.) */ const QString returnValue = MessageViewer::DKIMUtil::bodyCanonizationRelaxed(QString::fromLatin1(mMessage->encodedBody())); return returnValue; } QString DKIMCheckSignatureJob::headerCanonizationSimple() const { QString headers; - DKIMHeaderParser parser; - parser.setHead(mMessage->head()); - parser.parse(); + + DKIMHeaderParser parser = mHeaderParser; for (const QString &header : mDkimInfo.listSignedHeader()) { const QString str = parser.headerType(header.toLower()); if (!str.isEmpty()) { if (!headers.isEmpty()) { headers += QLatin1String("\r\n"); } headers += MessageViewer::DKIMUtil::headerCanonizationSimple(header, str); } } return headers; } QString DKIMCheckSignatureJob::headerCanonizationRelaxed(bool removeQuoteOnContentType) const { // The "relaxed" header canonicalization algorithm MUST apply the // following steps in order: // o Convert all header field names (not the header field values) to // lowercase. For example, convert "SUBJect: AbC" to "subject: AbC". // o Unfold all header field continuation lines as described in // [RFC5322]; in particular, lines with terminators embedded in // continued header field values (that is, CRLF sequences followed by // WSP) MUST be interpreted without the CRLF. Implementations MUST // NOT remove the CRLF at the end of the header field value. // o Convert all sequences of one or more WSP characters to a single SP // character. WSP characters here include those before and after a // line folding boundary. // o Delete all WSP characters at the end of each unfolded header field // value. // o Delete any WSP characters remaining before and after the colon // separating the header field name from the header field value. The // colon separator MUST be retained. QString headers; - DKIMHeaderParser parser; - parser.setHead(mMessage->head()); - parser.parse(); + DKIMHeaderParser parser = mHeaderParser; for (const QString &header : mDkimInfo.listSignedHeader()) { const QString str = parser.headerType(header.toLower()); if (!str.isEmpty()) { if (!headers.isEmpty()) { headers += QLatin1String("\r\n"); } headers += MessageViewer::DKIMUtil::headerCanonizationRelaxed(header, str, removeQuoteOnContentType); } } return headers; } void DKIMCheckSignatureJob::downloadKey(const DKIMInfo &info) { DKIMDownloadKeyJob *job = new DKIMDownloadKeyJob(this); job->setDomainName(info.domain()); job->setSelectorName(info.selector()); connect(job, &DKIMDownloadKeyJob::error, this, [this](const QString &errorString) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Impossible to start downloadkey: error returned: " << errorString; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToDownloadKey; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); }); connect(job, &DKIMDownloadKeyJob::success, this, &DKIMCheckSignatureJob::slotDownloadKeyDone); if (!job->start()) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Impossible to start downloadkey"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::ImpossibleToDownloadKey; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); } } void DKIMCheckSignatureJob::slotDownloadKeyDone(const QList &lst, const QString &domain, const QString &selector) { QByteArray ba; if (lst.count() != 1) { for (const QByteArray &b : lst) { ba += b; } qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Key result has more that 1 element" << lst; } else { ba = lst.at(0); } parseDKIMKeyRecord(QString::fromLocal8Bit(ba), domain, selector, true); } void DKIMCheckSignatureJob::parseDKIMKeyRecord(const QString &str, const QString &domain, const QString &selector, bool storeKeyValue) { qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << "void DKIMCheckSignatureJob::parseDKIMKeyRecord(const QString &str, const QString &domain, const QString &selector, bool storeKeyValue) key:" << str; if (!mDkimKeyRecord.parseKey(str)) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Impossible to parse key record " << str; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } if (mDkimKeyRecord.keyType() != QLatin1String("rsa")) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "mDkimKeyRecord key type is unknown " << mDkimKeyRecord.keyType() << " str " << str; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } // if s flag is set in DKIM key record // AUID must be from the same domain as SDID (and not a subdomain) if (mDkimKeyRecord.flags().contains(QLatin1String("s"))) { // s Any DKIM-Signature header fields using the "i=" tag MUST have // the same domain value on the right-hand side of the "@" in the // "i=" tag and the value of the "d=" tag. That is, the "i=" // domain MUST NOT be a subdomain of "d=". Use of this flag is // RECOMMENDED unless subdomaining is required. if (mDkimInfo.iDomain() != mDkimInfo.domain()) { mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::DomainI; Q_EMIT result(createCheckResult()); deleteLater(); return; } } // check that the testing flag is not set if (mDkimKeyRecord.flags().contains(QLatin1String("y"))) { if (!mPolicy.verifySignatureWhenOnlyTest()) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Testing mode!"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::TestKeyMode; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } } if (mDkimKeyRecord.publicKey().isEmpty()) { // empty value means that this public key has been revoked qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "mDkimKeyRecord public key is empty. It was revoked "; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::PublicKeyWasRevoked; mStatus = MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; Q_EMIT result(createCheckResult()); deleteLater(); return; } if (storeKeyValue) { Q_EMIT storeKey(str, domain, selector); } verifyRSASignature(); } void DKIMCheckSignatureJob::verifyRSASignature() { QCA::ConvertResult conversionResult; //qDebug() << "mDkimKeyRecord.publicKey() " < currentDate) { mWarning = DKIMCheckSignatureJob::DKIMWarning::SignatureCreatedInFuture; } if (info.signature().isEmpty()) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Signature doesn't exist"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::MissingSignature; return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; } if (!info.listSignedHeader().contains(QLatin1String("from"), Qt::CaseInsensitive)) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "From is not include in headers list"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::MissingFrom; return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; } if (info.domain().isEmpty()) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Domain is not defined."; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::DomainNotExist; return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; } if (info.query() != QLatin1String("dns/txt")) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Query is incorrect: " << info.query(); mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidQueryMethod; return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; } if ((info.hashingAlgorithm() == MessageViewer::DKIMInfo::HashingAlgorithmType::Any) || (info.hashingAlgorithm() == MessageViewer::DKIMInfo::HashingAlgorithmType::Unknown)) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "body header algorithm is empty"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidBodyHashAlgorithm; return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; } if (info.signingAlgorithm().isEmpty()) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "signature algorithm is empty"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::InvalidSignAlgorithm; return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; } if (info.hashingAlgorithm() == DKIMInfo::HashingAlgorithmType::Sha1) { if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Nothing) { //nothing } else if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Warning) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "hash algorithm is not secure sha1 : Error"; mWarning = MessageViewer::DKIMCheckSignatureJob::DKIMWarning::HashAlgorithmUnsafe; } else if (mPolicy.rsaSha1Policy() == MessageViewer::MessageViewerSettings::EnumPolicyRsaSha1::Error) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "hash algorithm is not secure sha1: Error"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::HashAlgorithmUnsafeSha1; return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; } } //qDebug() << "info.agentOrUserIdentifier() " << info.agentOrUserIdentifier() << " info.iDomain() " << info.iDomain(); if (!info.agentOrUserIdentifier().endsWith(info.iDomain())) { qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "AUID is not in a subdomain of SDID"; mError = MessageViewer::DKIMCheckSignatureJob::DKIMError::IDomainError; return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Invalid; } //Add more test //TODO check if info is valid return MessageViewer::DKIMCheckSignatureJob::DKIMStatus::Valid; } DKIMCheckSignatureJob::DKIMError DKIMCheckSignatureJob::error() const { return mError; } DKIMCheckSignatureJob::DKIMStatus DKIMCheckSignatureJob::status() const { return mStatus; } void DKIMCheckSignatureJob::setStatus(const DKIMCheckSignatureJob::DKIMStatus &status) { mStatus = status; } QString DKIMCheckSignatureJob::dkimValue() const { return mDkimValue; } bool DKIMCheckSignatureJob::CheckSignatureResult::isValid() const { return status != DKIMCheckSignatureJob::DKIMStatus::Unknown; } bool DKIMCheckSignatureJob::CheckSignatureResult::operator==(const DKIMCheckSignatureJob::CheckSignatureResult &other) const { return error == other.error && warning == other.warning && status == other.status && item == other.item && fromEmail == other.fromEmail; } bool DKIMCheckSignatureJob::CheckSignatureResult::operator!=(const DKIMCheckSignatureJob::CheckSignatureResult &other) const { return !CheckSignatureResult::operator==(other); } diff --git a/messageviewer/src/dkim-verify/dkimchecksignaturejob.h b/messageviewer/src/dkim-verify/dkimchecksignaturejob.h index 546f6cc0..9d0a61ca 100644 --- a/messageviewer/src/dkim-verify/dkimchecksignaturejob.h +++ b/messageviewer/src/dkim-verify/dkimchecksignaturejob.h @@ -1,157 +1,159 @@ /* Copyright (C) 2018-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DKIMCHECKSIGNATUREJOB_H #define DKIMCHECKSIGNATUREJOB_H #include #include "messageviewer_export.h" #include #include #include +#include #include #include namespace MessageViewer { /** * @brief The DKIMCheckSignatureJob class * @author Laurent Montel */ class MESSAGEVIEWER_EXPORT DKIMCheckSignatureJob : public QObject { Q_OBJECT public: enum class DKIMStatus : int { Unknown = 0, Valid = 1, Invalid = 2, EmailNotSigned = 3, NeedToBeSigned = 4 }; Q_ENUM(DKIMStatus) enum class DKIMError : int { Any = 0, CorruptedBodyHash = 1, DomainNotExist = 2, MissingFrom = 3, MissingSignature = 4, InvalidQueryMethod = 5, InvalidHeaderCanonicalization = 6, InvalidBodyCanonicalization = 7, InvalidBodyHashAlgorithm = 8, InvalidSignAlgorithm = 9, PublicKeyWasRevoked = 10, SignatureTooLarge = 11, InsupportedHashAlgorithm = 12, PublicKeyTooSmall = 13, ImpossibleToVerifySignature = 14, DomainI = 15, TestKeyMode = 16, ImpossibleToDownloadKey = 17, HashAlgorithmUnsafeSha1 = 18, IDomainError = 19, PublicKeyConversionError = 20, }; Q_ENUM(DKIMError) enum class DKIMWarning : int { Any = 0, SignatureExpired = 1, SignatureCreatedInFuture = 2, SignatureTooSmall = 3, HashAlgorithmUnsafe = 4, }; Q_ENUM(DKIMWarning) struct CheckSignatureResult { Q_REQUIRED_RESULT bool isValid() const; Q_REQUIRED_RESULT bool operator==(const CheckSignatureResult &other) const; Q_REQUIRED_RESULT bool operator!=(const CheckSignatureResult &other) const; DKIMCheckSignatureJob::DKIMError error = DKIMCheckSignatureJob::DKIMError::Any; DKIMCheckSignatureJob::DKIMWarning warning = DKIMCheckSignatureJob::DKIMWarning::Any; DKIMCheckSignatureJob::DKIMStatus status = DKIMCheckSignatureJob::DKIMStatus::Unknown; Akonadi::Item item; QString signedBy; QString fromEmail; }; explicit DKIMCheckSignatureJob(QObject *parent = nullptr); ~DKIMCheckSignatureJob(); void start(); Q_REQUIRED_RESULT QString dkimValue() const; Q_REQUIRED_RESULT DKIMCheckSignatureJob::DKIMStatus status() const; void setStatus(const DKIMCheckSignatureJob::DKIMStatus &status); Q_REQUIRED_RESULT MessageViewer::DKIMCheckSignatureJob::DKIMStatus checkSignature(const MessageViewer::DKIMInfo &info); Q_REQUIRED_RESULT DKIMCheckSignatureJob::DKIMError error() const; Q_REQUIRED_RESULT KMime::Message::Ptr message() const; void setMessage(const KMime::Message::Ptr &message); Q_REQUIRED_RESULT DKIMCheckSignatureJob::DKIMWarning warning() const; void setWarning(const DKIMWarning &warning); Q_REQUIRED_RESULT QString headerCanonizationResult() const; Q_REQUIRED_RESULT QString bodyCanonizationResult() const; Q_REQUIRED_RESULT Akonadi::Item item() const; void setItem(const Akonadi::Item &item); Q_REQUIRED_RESULT DKIMCheckPolicy policy() const; void setPolicy(const DKIMCheckPolicy &policy); Q_SIGNALS: void result(const MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult &checkResult); void storeKey(const QString &key, const QString &domain, const QString &selector); private: void downloadKey(const DKIMInfo &info); void slotDownloadKeyDone(const QList &lst, const QString &domain, const QString &selector); void parseDKIMKeyRecord(const QString &str, const QString &domain, const QString &selector, bool storeKeyValue = true); Q_REQUIRED_RESULT QString headerCanonizationSimple() const; Q_REQUIRED_RESULT QString headerCanonizationRelaxed(bool removeQuoteOnContentType) const; Q_REQUIRED_RESULT QString bodyCanonizationRelaxed() const; Q_REQUIRED_RESULT QString bodyCanonizationSimple() const; Q_REQUIRED_RESULT MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult createCheckResult(); void verifyRSASignature(); void computeHeaderCanonization(bool removeQuoteOnContentType); DKIMCheckPolicy mPolicy; + DKIMHeaderParser mHeaderParser; KMime::Message::Ptr mMessage; Akonadi::Item mMessageItem; QString mFromEmail; DKIMInfo mDkimInfo; DKIMKeyRecord mDkimKeyRecord; QString mDkimValue; QString mHeaderCanonizationResult; QString mBodyCanonizationResult; DKIMCheckSignatureJob::DKIMError mError = DKIMCheckSignatureJob::DKIMError::Any; DKIMCheckSignatureJob::DKIMWarning mWarning = DKIMCheckSignatureJob::DKIMWarning::Any; DKIMCheckSignatureJob::DKIMStatus mStatus = DKIMCheckSignatureJob::DKIMStatus::Unknown; }; } Q_DECLARE_METATYPE(MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult) #endif // DKIMCHECKSIGNATUREJOB_H diff --git a/messageviewer/src/dkim-verify/dkimheaderparser.h b/messageviewer/src/dkim-verify/dkimheaderparser.h index 12a22fd2..c3be12c9 100644 --- a/messageviewer/src/dkim-verify/dkimheaderparser.h +++ b/messageviewer/src/dkim-verify/dkimheaderparser.h @@ -1,55 +1,59 @@ /* Copyright (C) 2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DKIMHEADERPARSER_H #define DKIMHEADERPARSER_H -#include "messageviewer_private_export.h" +#include "messageviewer_export.h" #include #include namespace MessageViewer { -class MESSAGEVIEWER_TESTS_EXPORT DKIMHeaderParser +/** + * @brief The DKIMHeaderParser class + * @author Laurent Montel + */ +class MESSAGEVIEWER_EXPORT DKIMHeaderParser { public: DKIMHeaderParser(); ~DKIMHeaderParser(); void parse(); void setHead(const QByteArray &head); Q_REQUIRED_RESULT QByteArray head() const; Q_REQUIRED_RESULT QString headerType(const QString &str); private: struct Header { QString headerName; QString headerValue; QByteArray codec; Q_REQUIRED_RESULT bool isValid() const { return !headerName.isEmpty(); } }; Q_REQUIRED_RESULT int findHeaderLineEnd(const QByteArray &src, int &dataBegin, bool *folded); MessageViewer::DKIMHeaderParser::Header extractHeader(const QByteArray &head, const int headerStart, int &endOfFieldBody); Q_REQUIRED_RESULT QByteArray unfoldHeader(const char *header, size_t headerSize); QByteArray mHead; QList mListHeaders; }; } #endif // DKIMHEADERPARSER_H