KItinerary

online-ticket-dump.cpp
1/*
2 SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
3 SPDX-License-Identifier: LGPL-2.0-or-later
4*/
5
6#include <kitinerary_version.h>
7
8#include <KItinerary/ExtractorEngine>
9#include <KItinerary/ExtractorResult>
10#include <KItinerary/HttpResponse>
11
12#include <QCommandLineParser>
13#include <QCoreApplication>
14#include <QDateTime>
15#include <QFile>
16#include <QJsonDocument>
17#include <QJsonObject>
18#include <QNetworkAccessManager>
19#include <QNetworkReply>
20
21#include <iostream>
22
23using namespace KItinerary;
24
25static void harPostRequest(const QNetworkRequest &req, const QByteArray &postData, QJsonObject &harEntry)
26{
27 QJsonArray headers;
28 const auto rawHeaders = req.rawHeaderList();
29 for (const auto &h : rawHeaders) {
30 headers.push_back(QJsonObject({
33 }));
34 }
35
36 harEntry.insert(
37 QLatin1StringView("request"),
39 {QLatin1StringView("method"), QLatin1String("POST")},
40 {QLatin1StringView("url"), req.url().toString()},
41 {QLatin1StringView("headers"), headers},
42 {QLatin1StringView("postData"),
44 {QLatin1StringView("text"), QString::fromUtf8(postData)},
45 })},
46 }));
47}
48
49static void harResponse(const HttpResponse &response, QJsonObject &harEntry)
50{
51 harEntry.insert(
52 QLatin1StringView("response"),
54 {{QLatin1StringView("content"),
56 {QLatin1StringView("text"),
57 QString::fromUtf8(response.content().toBase64())},
58 {QLatin1StringView("encoding"), QLatin1String("base64")},
59 })}}));
60}
61
62int main(int argc, char **argv)
63{
64 QCoreApplication::setApplicationName(QStringLiteral("online-ticket-dump"));
65 QCoreApplication::setApplicationVersion(QStringLiteral(KITINERARY_VERSION_STRING));
66 QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
67 QCoreApplication::setOrganizationName(QStringLiteral("KDE"));
68 QCoreApplication app(argc, argv);
69
70 QCommandLineParser parser;
71 parser.setApplicationDescription(QStringLiteral("Dump online ticket data."));
72 parser.addHelpOption();
73 parser.addVersionOption();
74 QCommandLineOption nameOpt(QStringLiteral("name"), QStringLiteral("Passenger last name."), QStringLiteral("name"));
75 parser.addOption(nameOpt);
76 QCommandLineOption refOpt(QStringLiteral("ref"), QStringLiteral("Ticket reference number."), QStringLiteral("ref"));
77 parser.addOption(refOpt);
78 QCommandLineOption kwidOpt(QStringLiteral("kwid"), QStringLiteral("DB kwid UUID."), QStringLiteral("ref"));
79 parser.addOption(kwidOpt);
80 QCommandLineOption sourceOpt(QStringLiteral("source"), QStringLiteral("Ticket provider (db or sncf)."), QStringLiteral("provider"));
81 parser.addOption(sourceOpt);
82 QCommandLineOption harOpt(QStringLiteral("har"), QStringLiteral("File to write HTTP communication to."), QStringLiteral("file"));
83 parser.addOption(harOpt);
84 parser.process(app);
85
86 if (!parser.isSet(nameOpt) || !parser.isSet(refOpt) || !parser.isSet(sourceOpt)) {
87 parser.showHelp(1);
88 }
89
92 QNetworkReply *reply = nullptr;
93
94 QJsonObject harEntry{
95 {QLatin1StringView("startDateTime"),
97 if (parser.value(sourceOpt) == QLatin1StringView("db")) {
99 QUrl(QStringLiteral("https://fahrkarten.bahn.de/mobile/dbc/xs.go?")));
101 QByteArray("application/x-www-form-urlencoded"));
102 QByteArray postData(
103 "<rqorderdetails version=\"1.0\"><rqheader v=\"23080000\" os=\"KCI\" "
104 "app=\"KCI-Webservice\"/><rqorder on=\"" +
105 parser.value(refOpt).toUtf8() +
106 (parser.isSet(kwidOpt)
107 ? QByteArray("\" kwid=\"" + parser.value(kwidOpt).toUtf8())
108 : QByteArray()) +
109 "\"/><authname tln=\"" + parser.value(nameOpt).toUtf8() +
110 "\"/></rqorderdetails>");
111 reply = nam.post(req, postData);
112 harPostRequest(req, postData, harEntry);
113 } else if (parser.value(sourceOpt) == QLatin1StringView("sncf")) {
114 // based on https://www.sncf-connect.com/app/trips/search and stripped to
115 // the bare minimum that works
116 QNetworkRequest req(QUrl(QStringLiteral(
117 "https://www.sncf-connect.com/bff/api/v1/trips/trips-by-criteria")));
119 QByteArray("application/json"));
121 QByteArray("Mozilla/5.0 (X11; Linux x86_64; rv:109.0) "
122 "Gecko/20100101 Firefox/111.0"));
123 req.setRawHeader("Accept", "application/json, text/plain, */*");
124 req.setRawHeader("x-bff-key", "ah1MPO-izehIHD-QZZ9y88n-kku876");
125 QByteArray postData("{\"reference\":\"" + parser.value(refOpt).toUtf8() +
126 "\",\"name\":\"" + parser.value(nameOpt).toUtf8() +
127 "\"}");
128 reply = nam.post(req, postData);
129 harPostRequest(req, postData, harEntry);
130 }
131
132 if (!reply) {
133 parser.showHelp(1);
134 }
135
136 QObject::connect(reply, &QNetworkReply::finished, &app, [&app, &parser, &harOpt, &harEntry, reply]() {
137 reply->deleteLater();
138 const auto response = HttpResponse::fromNetworkReply(reply);
139 ExtractorEngine engine;
140 engine.setContent(response, u"internal/http-response");
141 qDebug().noquote() << QJsonDocument(engine.extract()).toJson();
142
143 if (const auto harPath = parser.value(harOpt); !harPath.isEmpty()) {
144 QFile f(harPath);
145 if (!f.open(QFile::WriteOnly)) {
146 qWarning() << f.errorString();
147 }
148
149 harResponse(response, harEntry);
150 QJsonObject har({
151 {QLatin1StringView("log"),
153 {{QLatin1StringView("entries"), QJsonArray({harEntry})}})},
154 });
155 f.write(QJsonDocument(har).toJson());
156 }
157
158 app.quit();
159 });
160
161 return app.exec();
162}
Semantic data extraction engine.
void setContent(const QVariant &data, QStringView mimeType)
Already decoded data to extract from.
QJsonArray extract()
Perform the actual extraction, and return the JSON-LD data that has been found.
Container for an HTTP response to be passed into the extractor engine.
static HttpResponse fromNetworkReply(QNetworkReply *reply)
Create a HttpResponse object from an active QNetworkReply.
Classes for reservation/travel data models, data extraction and data augmentation.
Definition berelement.h:17
QByteArray toBase64(Base64Options options) const const
QCommandLineOption addHelpOption()
bool addOption(const QCommandLineOption &option)
QCommandLineOption addVersionOption()
bool isSet(const QCommandLineOption &option) const const
void process(const QCoreApplication &app)
void setApplicationDescription(const QString &description)
void showHelp(int exitCode)
QString value(const QCommandLineOption &option) const const
void setApplicationName(const QString &application)
void setApplicationVersion(const QString &version)
void setOrganizationDomain(const QString &orgDomain)
void setOrganizationName(const QString &orgName)
QDateTime currentDateTime()
QString toString(QStringView format, QCalendar cal) const const
void push_back(const QJsonValue &value)
QByteArray toJson(JsonFormat format) const const
iterator insert(QLatin1StringView key, const QJsonValue &value)
QNetworkReply * post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
void setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
QByteArray rawHeader(const QByteArray &headerName) const const
QList< QByteArray > rawHeaderList() const const
void setHeader(KnownHeaders header, const QVariant &value)
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
QUrl url() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
QString fromUtf8(QByteArrayView str)
QByteArray toUtf8() const const
ISODateWithMs
QString toString(FormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:45:33 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.