diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0655b48..454802a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,241 +1,242 @@ set(KDE_INSTALL_INCLUDEDIR_PIM ${KDE_INSTALL_INCLUDEDIR}/KPim) add_subdirectory(cli) if (TARGET Qt5::Network) add_subdirectory(knowledgedb-generator) endif() +add_subdirectory(vdv/certs) configure_file(config-kitinerary.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kitinerary.h) set(kitinerary_lib_srcs datatypes/action.cpp datatypes/brand.cpp datatypes/bustrip.cpp datatypes/creativework.cpp datatypes/event.cpp datatypes/flight.cpp datatypes/organization.cpp datatypes/person.cpp datatypes/place.cpp datatypes/reservation.cpp datatypes/taxi.cpp datatypes/ticket.cpp datatypes/traintrip.cpp datatypes/rentalcar.cpp datatypes/visit.cpp generic/genericpdfextractor.cpp generic/genericpkpassextractor.cpp generic/genericuic918extractor.cpp generic/structureddataextractor.cpp jsapi/barcode.cpp jsapi/bitarray.cpp jsapi/context.cpp jsapi/jsonld.cpp knowledgedb/alphaid.cpp knowledgedb/airportdb.cpp knowledgedb/countrydb.cpp knowledgedb/iatacode.cpp knowledgedb/knowledgedb.cpp knowledgedb/timezonedb.cpp knowledgedb/trainstationdb.cpp pdf/pdfdocument.cpp pdf/pdfextractoroutputdevice.cpp pdf/pdfimage.cpp pdf/pdfvectorpicture.cpp pdf/popplerglobalparams.cpp pdf/popplerutils.cpp uic9183/rct2ticket.cpp uic9183/uic9183block.cpp uic9183/uic9183parser.cpp uic9183/uic9183ticketlayout.cpp uic9183/vendor0080block.cpp vdv/iso9796_2decoder.cpp vdv/vdvcertificate.cpp vdv/vdvticket.cpp vdv/vdvticketparser.cpp vdv/certs/vdv-certs.qrc barcodedecoder.cpp calendarhandler.cpp documentutil.cpp extractor.cpp extractorengine.cpp extractorfilter.cpp extractorinput.cpp extractorpostprocessor.cpp extractorrepository.cpp extractorutil.cpp extractorvalidator.cpp file.cpp flightpostprocessor.cpp htmldocument.cpp iatabcbpparser.cpp jsonlddocument.cpp jsonldimportfilter.cpp locationutil.cpp mergeutil.cpp qimagepurebinarizer.cpp sortutil.cpp stringutil.cpp ) qt5_add_resources(kitinerary_lib_srcs extractors/extractors.qrc) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER logging.h IDENTIFIER KItinerary::Log CATEGORY_NAME org.kde.kitinerary) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER compare-logging.h IDENTIFIER KItinerary::CompareLog CATEGORY_NAME org.kde.kitinerary.comparator) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER validator-logging.h IDENTIFIER KItinerary::ValidatorLog CATEGORY_NAME org.kde.kitinerary.extractorValidator) add_library(KPimItinerary ${kitinerary_lib_srcs}) add_library(KPim::Itinerary ALIAS KPimItinerary) generate_export_header(KPimItinerary BASE_NAME KItinerary) set_target_properties(KPimItinerary PROPERTIES VERSION ${KITINERARY_VERSION_STRING} SOVERSION ${KITINERARY_SOVERSION} EXPORT_NAME Itinerary ) target_include_directories(KPimItinerary INTERFACE "$") target_include_directories(KPimItinerary PUBLIC "$") target_link_libraries(KPimItinerary PUBLIC Qt5::Core KF5::Mime PRIVATE Qt5::Qml KF5::Archive KF5::I18n KF5::Contacts KPim::PkPass ${ZLIB_LIBRARIES} ) if (HAVE_POPPLER) target_link_libraries(KPimItinerary PRIVATE Poppler::Core) endif() if (HAVE_ZXING) target_link_libraries(KPimItinerary PRIVATE ZXing::Core) endif() if (HAVE_KCAL) target_link_libraries(KPimItinerary PUBLIC KF5::CalendarCore) endif() if (HAVE_LIBXML2) target_compile_definitions(KPimItinerary PRIVATE ${LIBXML2_DEFINITIONS}) target_include_directories(KPimItinerary PRIVATE ${LIBXML2_INCLUDE_DIR}) target_link_libraries(KPimItinerary PRIVATE ${LIBXML2_LIBRARIES}) endif() if (HAVE_PHONENUMBER) target_link_libraries(KPimItinerary PRIVATE PhoneNumber::PhoneNumber) endif() if (HAVE_OPENSSL_RSA) target_link_libraries(KPimItinerary PRIVATE OpenSSL::Crypto) endif() ecm_generate_headers(KItinerary_FORWARDING_HEADERS HEADER_NAMES BarcodeDecoder CalendarHandler DocumentUtil Extractor ExtractorEngine ExtractorFilter ExtractorInput ExtractorPostprocessor ExtractorRepository File HtmlDocument IataBcbpParser JsonLdDocument LocationUtil MergeUtil SortUtil PREFIX KItinerary REQUIRED_HEADERS KItinerary_HEADERS ) ecm_generate_headers(KItinerary_KnowledgeDb_FORWARDING_HEADERS HEADER_NAMES AlphaId CountryDb KnowledgeDb PREFIX KItinerary REQUIRED_HEADERS KItinerary_KnowledgeDb_HEADERS RELATIVE knowledgedb ) ecm_generate_headers(KItinerary_Datatypes_FORWARDING_HEADERS HEADER_NAMES Action Brand BusTrip CreativeWork Datatypes Event Flight Organization Reservation RentalCar Person Place Taxi Ticket TrainTrip Visit PREFIX KItinerary REQUIRED_HEADERS KItinerary_Datatypes_HEADERS RELATIVE datatypes ) ecm_generate_headers(KItinerary_Pdf_FORWARDING_HEADERS HEADER_NAMES PdfDocument PdfImage PREFIX KItinerary REQUIRED_HEADERS KItinerary_Pdf_HEADERS RELATIVE pdf ) ecm_generate_headers(KItinerary_Uic9183_FORWARDING_HEADERS HEADER_NAMES Rct2Ticket Uic9183Block Uic9183Parser Uic9183TicketLayout Vendor0080Block PREFIX KItinerary REQUIRED_HEADERS KItinerary_Uic9183_HEADERS RELATIVE uic9183 ) ecm_generate_headers(KItinerary_Vdv_FORWARDING_HEADERS HEADER_NAMES VdvTicket VdvTicketParser PREFIX KItinerary REQUIRED_HEADERS KItinerary_Vdv_HEADERS RELATIVE vdv ) install(TARGETS KPimItinerary EXPORT KPimItineraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${KItinerary_FORWARDING_HEADERS} ${KItinerary_KnowledgeDb_FORWARDING_HEADERS} ${KItinerary_Datatypes_FORWARDING_HEADERS} ${KItinerary_Pdf_FORWARDING_HEADERS} ${KItinerary_Uic9183_FORWARDING_HEADERS} ${KItinerary_Vdv_FORWARDING_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_PIM}/KItinerary ) install(FILES ${KItinerary_HEADERS} ${KItinerary_AirportDb_HEADERS} ${KItinerary_Datatypes_HEADERS} ${KItinerary_KnowledgeDb_HEADERS} ${KItinerary_Pdf_HEADERS} ${KItinerary_Uic9183_HEADERS} ${KItinerary_Vdv_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kitinerary_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_PIM}/kitinerary ) if (NOT ANDROID) install(FILES application-vnd-kde-itinerary.xml DESTINATION ${XDG_MIME_INSTALL_DIR}) update_xdg_mimetypes(${XDG_MIME_INSTALL_DIR}) endif() diff --git a/src/vdv/certs/CMakeLists.txt b/src/vdv/certs/CMakeLists.txt new file mode 100644 index 0000000..0e57afd --- /dev/null +++ b/src/vdv/certs/CMakeLists.txt @@ -0,0 +1,12 @@ +if (NOT HAVE_OPENSSL_RSA) + return() +endif() + +add_executable(vdv-cert-downloader + cert-downloader.cpp + ../vdvcertificate.cpp + ../iso9796_2decoder.cpp +) + +target_include_directories(vdv-cert-downloader PRIVATE ${CMAKE_BINARY_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/..) +target_link_libraries(vdv-cert-downloader PRIVATE Qt5::Core OpenSSL::Crypto) diff --git a/src/vdv/certs/cert-downloader.cpp b/src/vdv/certs/cert-downloader.cpp new file mode 100644 index 0000000..4f92244 --- /dev/null +++ b/src/vdv/certs/cert-downloader.cpp @@ -0,0 +1,122 @@ +/* + Copyright (C) 2019 Volker Krause + + This program 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 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 Library 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 . +*/ + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace KItinerary; + +static std::vector listCerts() +{ + QProcess proc; + proc.setProgram(QStringLiteral("kioclient5")); + proc.setArguments({QStringLiteral("ls"), QStringLiteral("ldap://ldap-vdv-ion.telesec.de:389/ou=VDV%20KA,o=VDV%20Kernapplikations%20GmbH,c=de")}); + proc.start(); + proc.waitForFinished(); + + std::vector certs; + for (const auto &line : proc.readAllStandardOutput().split('\n')) { + if (line.size() <= 5) { + continue; + } + certs.push_back(QString::fromUtf8(line.left(line.size() - 5))); + } + return certs; +} + +static void downloadCert(const QString &certName) +{ + QProcess proc; + proc.setProgram(QStringLiteral("kioclient5")); + proc.setArguments({QStringLiteral("cat"), QStringLiteral("ldap://ldap-vdv-ion.telesec.de:389/cn=") + certName + QStringLiteral(",ou=VDV%20KA,o=VDV%20Kernapplikations%20GmbH,c=de")}); + proc.start(); + proc.waitForFinished(); + + // primitive LDIF parser, would be nicer with something like KLDAP + const auto certLdif = QString::fromUtf8(proc.readAllStandardOutput()); + QRegularExpression regExp(QStringLiteral("cACertificate:: ([\\w\\W]*?)\n[^ ]")); + const auto match = regExp.match(certLdif); + const auto certData = match.captured(1).remove(QLatin1Char('\n')).remove(QLatin1Char(' ')).toUtf8(); + + QFile f(certName + QLatin1String(".vdv-cert")); + f.open(QFile::WriteOnly); + f.write(QByteArray::fromBase64(certData)); +} + +static void writeQrc(const std::vector &certNames) +{ + QFile qrc(QStringLiteral("vdv-certs.qrc")); + qrc.open(QFile::WriteOnly); + qrc.write("\n \n"); + for (const auto &certName : certNames) { + qrc.write(" "); + qrc.write(certName.toUtf8()); + qrc.write(".vdv-cert\n"); + } + qrc.write(" \n\n"); +} + +static void decodeCert(const QString &certName) +{ + QFile f(certName + QLatin1String(".vdv-cert")); + f.open(QFile::ReadOnly); + VdvCertificate cert(f.readAll()); + if (cert.needsCaKey()) { + qDebug() << certName << "needs decoding"; + // TODO + } else { + qDebug() << certName << "is already decoded"; + } +} + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + // (1) list all certificates + auto certNames = listCerts(); + + // (2) load all certificates we don't have yet + for (const auto &certName : certNames) { + qDebug() << "checking certificate" << certName; + if (QFile::exists(certName + QLatin1String(".vdv-cert"))) { + continue; + } + downloadCert(certName); + } + + // (3) decode certificates (avoids runtime cost and shrinks the file size) + for (const auto &certName : certNames) { + decodeCert(certName); + } + + // (4) discard old sub-CA certificates we don't need + // TODO + + // (5) write qrc file + std::sort(certNames.begin(), certNames.end()); + writeQrc(certNames); + + return 0; +}