From 1c4976cb0b839614fc32b04e009e5bd4d803945a Mon Sep 17 00:00:00 2001 From: Josef Rokos Date: Tue, 24 Jan 2017 22:27:36 +0100 Subject: [PATCH] Implemented response parsing. --- eetsend/main.cpp | 11 +- libEet/eetrequest.cpp | 15 +- libEet/eetrequest.h | 10 +- libEet/eetresult.cpp | 99 ++++++++++++++ libEet/eetresult.h | 72 ++++++++++ libEet/eetsender.cpp | 219 +++++++++++++++++++++++++++++- libEet/eetsender.h | 22 ++- libEet/eettemplate.cpp | 13 +- libEet/libEet.pro | 8 +- libEet/res/template_body.txt | 18 +-- libEet/res/template_request.txt | 30 ++-- libEet/res/template_signature.txt | 24 ++-- 12 files changed, 481 insertions(+), 60 deletions(-) create mode 100644 libEet/eetresult.cpp create mode 100644 libEet/eetresult.h diff --git a/eetsend/main.cpp b/eetsend/main.cpp index c060e9b..bb178da 100644 --- a/eetsend/main.cpp +++ b/eetsend/main.cpp @@ -11,13 +11,18 @@ int main(int argc, char *argv[]) request.setCelkTrzba(1); request.setCerpZuct(2); request.setCestSluz(3); + request.setDatOdesl(QDateTime::currentDateTime()); + request.setPrvniZaslani(true); request.setIdPokl("id pokladny"); - request.setIdProvoz("id provoz"); - request.setDicPopl("CZ1234567"); + request.setIdProvoz("1"); + request.setDicPopl("CZ1212121218"); + request.setPoradCis("123/5"); + request.setDatTrzby(QDateTime::currentDateTime()); request.setCelkTrzba(100); + request.setRezim(EetRequest::STANDARD); EetSender sender; - sender.setupSigner("/home/pepa/Dokumenty/dev/eet/01000003.p12", "eet"); + sender.setupSigner("/home/pepa/Dokumenty/dev/eet/121212.p12", "eet"); sender.sendRequest(&request); return a.exec(); diff --git a/libEet/eetrequest.cpp b/libEet/eetrequest.cpp index 4145dd8..617fe4b 100644 --- a/libEet/eetrequest.cpp +++ b/libEet/eetrequest.cpp @@ -3,8 +3,6 @@ EetRequest::EetRequest(QObject *parent) : QObject(parent) { m_prvniZaslani = true; - m_produkcni = false; - m_rezim = STANDARD; } @@ -67,19 +65,20 @@ QString EetRequest::uuidZpravyStr() const return ret; } -bool EetRequest::produkcni() const +bool EetRequest::overeni() const { - return m_produkcni; + return m_overeni.isNull() ? false : *m_overeni.data(); } -void EetRequest::setProdukcni(bool produkcni) +void EetRequest::setOvereni(bool overeni) { - m_produkcni = produkcni; + m_overeni = QSharedPointer(new bool); + *m_overeni.data() = overeni; } -QString EetRequest::produkcniStr() const +QString EetRequest::overeniStr() const { - return m_produkcni ? "true" : "false"; + return m_overeni.isNull() ? NULL_VAL : (*m_overeni.data() ? "true" : "false"); } QString EetRequest::dicPopl() const diff --git a/libEet/eetrequest.h b/libEet/eetrequest.h index bff64c6..70d0c03 100644 --- a/libEet/eetrequest.h +++ b/libEet/eetrequest.h @@ -17,7 +17,7 @@ class EETCPPSHARED_EXPORT EetRequest : public QObject Q_PROPERTY(QString dat_odesl READ datOdeslStr) Q_PROPERTY(QString prvni_zaslani READ prvniZaslaniStr) Q_PROPERTY(QString uuid_zpravy READ uuidZpravyStr) - Q_PROPERTY(QString produkcni READ produkcniStr) + Q_PROPERTY(QString overeni READ overeniStr) Q_PROPERTY(QString dic_popl READ dicPopl) Q_PROPERTY(QString dic_poverujiciho READ dicPoverujiciho) Q_PROPERTY(QString id_provoz READ idProvoz) @@ -63,9 +63,9 @@ public: void setUuidZpravy(const QUuid &uuidZpravy); QString uuidZpravyStr() const; - bool produkcni() const; - void setProdukcni(bool produkcni); - QString produkcniStr() const; + bool overeni() const; + void setOvereni(bool overeni); + QString overeniStr() const; QString dicPopl() const; void setDicPopl(const QString &dicPopl); @@ -154,7 +154,7 @@ private: QTimeZone m_datOdeslZone; bool m_prvniZaslani; QUuid m_uuidZpravy; - bool m_produkcni; + QSharedPointer m_overeni; QSharedPointer m_dicPopl; QSharedPointer m_dicPoverujiciho; QString m_idProvoz; diff --git a/libEet/eetresult.cpp b/libEet/eetresult.cpp new file mode 100644 index 0000000..fa987df --- /dev/null +++ b/libEet/eetresult.cpp @@ -0,0 +1,99 @@ +#include "eetresult.h" + +EetResult::EetResult(QObject *parent) : QObject(parent) +{ + m_status = RESPONSE_OK; +} + +EetResult::ResponseStatus EetResult::status() const +{ + return m_status; +} + +void EetResult::setStatus(const EetResult::ResponseStatus &status) +{ + m_status = status; +} + +QString EetResult::fik() const +{ + return m_fik; +} + +void EetResult::setFik(const QString &fik) +{ + m_fik = fik; +} + +EetMessageList EetResult::warnings() const +{ + return m_warnings; +} + +void EetResult::setWarnings(const EetMessageList &warnings) +{ + m_warnings = warnings; +} + +EetMessageList EetResult::errors() const +{ + return m_errors; +} + +void EetResult::setErrors(const EetMessageList &errors) +{ + m_errors = errors; +} + +QUuid EetResult::uuid() const +{ + return m_uuid; +} + +void EetResult::setUuid(const QUuid &uuid) +{ + m_uuid = uuid; +} + +QDateTime EetResult::reciveDate() const +{ + return m_reciveDate; +} + +void EetResult::setReciveDate(const QDateTime &reciveDate) +{ + m_reciveDate = reciveDate; +} + +EetMessage::EetMessage(QObject *parent) + :QObject(parent) +{ + m_code = 0; +} + +EetMessage::EetMessage(int code, const QString &message, QObject *parent) + :QObject(parent) +{ + m_code = code; + m_message = message; +} + +int EetMessage::code() const +{ + return m_code; +} + +void EetMessage::setCode(int code) +{ + m_code = code; +} + +QString EetMessage::message() const +{ + return m_message; +} + +void EetMessage::setMessage(const QString &message) +{ + m_message = message; +} diff --git a/libEet/eetresult.h b/libEet/eetresult.h new file mode 100644 index 0000000..b22cc97 --- /dev/null +++ b/libEet/eetresult.h @@ -0,0 +1,72 @@ +#ifndef EETRESULT_H +#define EETRESULT_H + +#include +#include +#include +#include +#include + +class EetMessage : public QObject +{ + Q_OBJECT +public: + explicit EetMessage(QObject *parent = 0); + EetMessage(int code, const QString &message, QObject *parent = 0); + + int code() const; + void setCode(int code); + + QString message() const; + void setMessage(const QString &message); + +private: + int m_code; + QString m_message; +}; + +typedef QList EetMessageList; + +class EetResult : public QObject +{ + Q_OBJECT +public: + enum ResponseStatus + { + RESPONSE_OK = 0, + DATA_ERROR, + SERVER_ERROR, + SSL_ERROR, + TIMEDOUT + }; + + explicit EetResult(QObject *parent = 0); + + ResponseStatus status() const; + void setStatus(const ResponseStatus &status); + + QString fik() const; + void setFik(const QString &fik); + + EetMessageList warnings() const; + void setWarnings(const EetMessageList &warnings); + + EetMessageList errors() const; + void setErrors(const EetMessageList &errors); + + QUuid uuid() const; + void setUuid(const QUuid &uuid); + + QDateTime reciveDate() const; + void setReciveDate(const QDateTime &reciveDate); + +private: + ResponseStatus m_status; + QUuid m_uuid; + QDateTime m_reciveDate; + QString m_fik; + EetMessageList m_warnings; + EetMessageList m_errors; +}; + +#endif // EETRESULT_H diff --git a/libEet/eetsender.cpp b/libEet/eetsender.cpp index 3f8a19f..66e4cf6 100644 --- a/libEet/eetsender.cpp +++ b/libEet/eetsender.cpp @@ -1,11 +1,35 @@ +#include +#include + #include "eetsender.h" #include "eetsigner.h" #include +#include +#include +#include +#include +#include +#include + +const QString EetSender::ms_nsDef = "declare namespace eet = \"http://fs.mfcr.cz/eet/schema/v3\";\n" + "declare namespace ds = \"http://www.w3.org/2000/09/xmldsig#\";\n" + "declare namespace wsu = \"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";\n" + "declare namespace wsse = \"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\";\n" + "declare namespace senc = \"http://schemas.xmlsoap.org/soap/encoding/\";\n" + "declare namespace senv = \"http://schemas.xmlsoap.org/soap/envelope/\";\n"; EetSender::EetSender(QObject *parent) : QObject(parent) { m_signer = nullptr; + m_resut = nullptr; + m_checkSignature = true; + + m_manager = new QNetworkAccessManager(this); + connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); + connect(m_manager, &QNetworkAccessManager::sslErrors, [this](QNetworkReply *rep, QList errs){ + emit serviceCertError(); + }); } void EetSender::sendRequest(EetRequest *request) @@ -36,7 +60,12 @@ void EetSender::sendRequest(EetRequest *request) QString strRequest = tempRequest.fillTemplate(val); - qDebug() << strRequest; + QNetworkRequest req(QUrl("https://pg.eet.cz/eet/services/EETServiceSOAP/v3")); + m_manager->post(req, strRequest.toUtf8()); + + QFile file("/home/pepa/Dokumenty/dev/eet/req.xml"); + file.open(QIODevice::WriteOnly); + file.write(strRequest.toUtf8()); } void EetSender::setupSigner(const QString &certPath, const QString &passwd) @@ -49,3 +78,191 @@ void EetSender::setupSigner(const QString &certPath, const QString &passwd) m_signer = new EetSigner(this); m_signer->setup(certPath, QCA::SecureArray(passwd.toUtf8())); } + +void EetSender::setCheckSignature(bool checkSignature) +{ + m_checkSignature = checkSignature; +} + +bool EetSender::checkSignature() const +{ + return m_checkSignature; +} + +EetResult *EetSender::resut() const +{ + return m_resut; +} + +bool EetSender::verifySignature(const QByteArray &repData) +{ + QString queryString("//senv:Envelope/senv:Header/wsse:Security/ds:Signature/ds:SignedInfo"); + QString signedInfo, certB64, signatureB64; + QXmlQuery q; + + q.setFocus(QString(repData)); + q.setQuery(ms_nsDef + queryString); + q.evaluateTo(&signedInfo); + + QStringList list = signedInfo.split("\n"); + signedInfo = "\n"; + for (int i = 1; i < list.length(); i++) + { + QString line = list[i]; + line = line.replace(QRegExp("^(\\s+)<([A-Za-z]+)([A-Za-z0-9-\"=/#:\\.\\ ]+)/>"), "\\1<\\2\\3>"); + signedInfo += line + "\n"; + } + + signedInfo = signedInfo.trimmed(); + signedInfo = signedInfo.replace(" ", " "); + + queryString = "//senv:Envelope/senv:Header/wsse:Security/wsse:BinarySecurityToken/text()"; + q.setQuery(ms_nsDef + queryString); + q.evaluateTo(&certB64); + + queryString = "//senv:Envelope/senv:Header/wsse:Security/ds:Signature/ds:SignatureValue/text()"; + q.setQuery(ms_nsDef + queryString); + q.evaluateTo(&signatureB64); + + QCA::ConvertResult res; + QCA::Certificate cert = QCA::Certificate::fromDER(QByteArray::fromBase64(certB64.toUtf8()), &res); + + if (res != QCA::ConvertGood) + { + emit serviceCertError(); + return false; + } + + QCA::PublicKey pubKey = cert.subjectPublicKey(); + + if (!pubKey.canVerify()) + { + emit serviceCertError(); + return false; + } + + bool signValid = pubKey.verifyMessage(QCA::MemoryRegion(signedInfo.toUtf8()), QByteArray::fromBase64(signatureB64.toUtf8()), QCA::EMSA3_SHA256); + + if (!signValid) + { + emit signInvalid(); + return false; + } + + return true; +} + +void EetSender::replyFinished(QNetworkReply *reply) +{ + if (reply->error() != QNetworkReply::NoError) + { + emit sendError(); + reply->deleteLater(); + return; + } + + QByteArray repData = reply->readAll(); + + /*QFile file("/home/pepa/Dokumenty/dev/eet/reply.xml"); + file.open(QIODevice::ReadOnly); + repData = file.readAll();*/ + + if (m_checkSignature && !verifySignature(repData)) + { + return; + } + + QXmlQuery q; + q.setFocus(QString(repData)); + + QString result; + QString queryString("//senv:Envelope/senv:Body/eet:Odpoved/eet:Hlavicka/@uuid_zpravy/data(.)"); + q.setQuery(ms_nsDef + queryString); + q.evaluateTo(&result); + result = result.trimmed(); + + if (m_resut == nullptr) + { + m_resut = new EetResult(this); + } + + m_resut->setUuid(QUuid(result)); + + queryString = "//senv:Envelope/senv:Body/eet:Odpoved/eet:Hlavicka/@dat_prij/data(.)"; + q.setQuery(ms_nsDef + queryString); + q.evaluateTo(&result); + result = result.trimmed(); + m_resut->setReciveDate(QDateTime::fromString(result)); + + queryString = "//senv:Envelope/senv:Body/eet:Odpoved/eet:Potvrzeni/@fik/data(.)"; + q.setQuery(ms_nsDef + queryString); + q.evaluateTo(&result); + result = result.trimmed(); + m_resut->setFik(result); + + QXmlResultItems items; + queryString = "//senv:Envelope/senv:Body/eet:Odpoved/eet:Varovani"; + q.setQuery(ms_nsDef + queryString); + q.evaluateTo(&items); + + EetMessageList warnings; + QXmlItem item = items.next(); + while (!item.isNull()) + { + EetMessage *mesg = new EetMessage(m_resut); + queryString = "./@kod_varov/data(.)"; + q.setQuery(ms_nsDef + queryString); + q.setFocus(item); + q.evaluateTo(&result); + result = result.trimmed(); + + mesg->setCode(result.toInt()); + + queryString = "./text(.)"; + q.setQuery(ms_nsDef + queryString); + q.setFocus(item); + q.evaluateTo(&result); + result = result.trimmed(); + + mesg->setMessage(result); + warnings.append(mesg); + + item = items.next(); + } + + m_resut->setWarnings(warnings); + + queryString = "//senv:Envelope/senv:Body/eet:Odpoved/eet:Chyba"; + q.setQuery(ms_nsDef + queryString); + q.evaluateTo(&items); + + EetMessageList errors; + item = items.next(); + while (!item.isNull()) + { + EetMessage *mesg = new EetMessage(m_resut); + queryString = "./@kod/data(.)"; + q.setQuery(ms_nsDef + queryString); + q.setFocus(item); + q.evaluateTo(&result); + result = result.trimmed(); + + mesg->setCode(result.toInt()); + + queryString = "./text(.)"; + q.setQuery(ms_nsDef + queryString); + q.setFocus(item); + q.evaluateTo(&result); + result = result.trimmed(); + + mesg->setMessage(result); + errors.append(mesg); + + item = items.next(); + } + + m_resut->setErrors(errors); + emit responseRecieved(m_resut); + + reply->deleteLater(); +} diff --git a/libEet/eetsender.h b/libEet/eetsender.h index b202383..81481ec 100644 --- a/libEet/eetsender.h +++ b/libEet/eetsender.h @@ -6,6 +6,10 @@ #include "eetcpp_global.h" #include "eetrequest.h" #include "eettemplate.h" +#include "eetresult.h" + +class QNetworkAccessManager; +class QNetworkReply; class EETCPPSHARED_EXPORT EetSender : public QObject { @@ -16,13 +20,29 @@ public: void sendRequest(EetRequest *request); void setupSigner(const QString &certPath, const QString &passwd); + void setCheckSignature(bool checkSignature); + bool checkSignature() const; + + EetResult *resut() const; + private: + static const QString ms_nsDef; EetSigner *m_signer; + QNetworkAccessManager *m_manager; + bool m_checkSignature; + EetResult *m_resut; + + bool verifySignature(const QByteArray &repData); + +private slots: + void replyFinished(QNetworkReply *reply); signals: void certError(); void sendError(); - void responseRecieved(); + void responseRecieved(EetRequest *result); + void signInvalid(); + void serviceCertError(); public slots: }; diff --git a/libEet/eettemplate.cpp b/libEet/eettemplate.cpp index 0c795c4..2734d90 100644 --- a/libEet/eettemplate.cpp +++ b/libEet/eettemplate.cpp @@ -70,8 +70,15 @@ QString EetTemplate::fillTemplateInternal(EetRequest *request, QMap 0 && c == ' ' && m_template[i - 1] == ' ')) + { + continue; + } + else + { + ret += c; + continue; + } } int p = m_template.indexOf("}", i + 2); @@ -111,7 +118,7 @@ QString EetTemplate::fillTemplateInternal(EetRequest *request, QMap"), "\">"); } QString EetTemplate::getPkpString(EetRequest *request) diff --git a/libEet/libEet.pro b/libEet/libEet.pro index 09e3445..2546763 100644 --- a/libEet/libEet.pro +++ b/libEet/libEet.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += network xml +QT += network xml xmlpatterns QT -= gui @@ -19,14 +19,16 @@ SOURCES += eetcpp.cpp \ eetrequest.cpp \ eettemplate.cpp \ eetsender.cpp \ - eetsigner.cpp + eetsigner.cpp \ + eetresult.cpp HEADERS += eetcpp.h\ eetcpp_global.h \ eetrequest.h \ eettemplate.h \ eetsender.h \ - eetsigner.h + eetsigner.h \ + eetresult.h unix { target.path = /usr/lib diff --git a/libEet/res/template_body.txt b/libEet/res/template_body.txt index aee8361..173611c 100644 --- a/libEet/res/template_body.txt +++ b/libEet/res/template_body.txt @@ -1,10 +1,10 @@ - - - - - ${pkp} - ${bkp} - - - \ No newline at end of file + + + + +${pkp} +${bkp} + + + \ No newline at end of file diff --git a/libEet/res/template_request.txt b/libEet/res/template_request.txt index e1597f2..ee786ec 100644 --- a/libEet/res/template_request.txt +++ b/libEet/res/template_request.txt @@ -10,20 +10,20 @@ ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="TheCert">${certb64} - - - - - - - - - - - ${digest} - - - ${signature} + + + + + + + + + + +${digest} + + + ${signature} @@ -32,5 +32,5 @@ - ${soap:Body} +${soap:Body} diff --git a/libEet/res/template_signature.txt b/libEet/res/template_signature.txt index a4ecfe4..1d1880d 100644 --- a/libEet/res/template_signature.txt +++ b/libEet/res/template_signature.txt @@ -1,13 +1,13 @@ - - - - - - - - - - ${digest} - - \ No newline at end of file + + + + + + + + + +${digest} + + \ No newline at end of file