140 lines
5.8 KiB
C++
140 lines
5.8 KiB
C++
#include "eetv4client.h"
|
|
#include "eetv4signer.h"
|
|
|
|
#include <QFile>
|
|
#include <QProcess>
|
|
#include <QSslCertificate>
|
|
#include <QSslKey>
|
|
#include <QSslServer>
|
|
#include <QTemporaryDir>
|
|
#include <QtTest>
|
|
|
|
namespace
|
|
{
|
|
class MockEetServer : public QSslServer
|
|
{
|
|
public:
|
|
explicit MockEetServer(const QByteArray &response)
|
|
: m_response(response)
|
|
{
|
|
connect(this, &QSslServer::pendingConnectionAvailable, this, [this] {
|
|
QSslSocket *socket = qobject_cast<QSslSocket *>(nextPendingConnection());
|
|
if (socket == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
connect(socket, &QSslSocket::readyRead, this, [this, socket] {
|
|
const QByteArray request = socket->readAll();
|
|
const qsizetype bodyStart = request.indexOf("\r\n\r\n");
|
|
const QByteArray soap = bodyStart < 0 ? QByteArray()
|
|
: request.mid(bodyStart + 4);
|
|
QString verificationError;
|
|
m_requestVerified = !soap.isEmpty() &&
|
|
EetV4Signer::verifySoap(soap, &verificationError);
|
|
const QByteArray http =
|
|
"HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\n"
|
|
"Content-Length: " + QByteArray::number(m_response.size()) +
|
|
"\r\nConnection: close\r\n\r\n" + m_response;
|
|
socket->write(http);
|
|
socket->disconnectFromHost();
|
|
});
|
|
});
|
|
}
|
|
|
|
bool requestVerified() const
|
|
{
|
|
return m_requestVerified;
|
|
}
|
|
|
|
private:
|
|
QByteArray m_response;
|
|
bool m_requestVerified{false};
|
|
};
|
|
}
|
|
|
|
class EetV4ClientIntegrationTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private slots:
|
|
void sendsSignedSaleAndParsesPok();
|
|
};
|
|
|
|
void EetV4ClientIntegrationTest::sendsSignedSaleAndParsesPok()
|
|
{
|
|
QTemporaryDir directory;
|
|
QVERIFY(directory.isValid());
|
|
const QString keyPath = directory.filePath(QStringLiteral("key.pem"));
|
|
const QString certPath = directory.filePath(QStringLiteral("certificate.pem"));
|
|
const QString p12Path = directory.filePath(QStringLiteral("certificate.p12"));
|
|
auto runOpenSsl = [](const QStringList &arguments) {
|
|
QProcess process;
|
|
process.start(QStringLiteral("openssl"), arguments);
|
|
QVERIFY2(process.waitForFinished(30000), qPrintable(process.errorString()));
|
|
QVERIFY2(process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0,
|
|
process.readAllStandardError().constData());
|
|
};
|
|
runOpenSsl({QStringLiteral("req"), QStringLiteral("-x509"), QStringLiteral("-newkey"),
|
|
QStringLiteral("rsa:2048"), QStringLiteral("-nodes"), QStringLiteral("-subj"),
|
|
QStringLiteral("/CN=localhost"), QStringLiteral("-keyout"), keyPath,
|
|
QStringLiteral("-out"), certPath, QStringLiteral("-days"), QStringLiteral("1")});
|
|
runOpenSsl({QStringLiteral("pkcs12"), QStringLiteral("-export"), QStringLiteral("-out"),
|
|
p12Path, QStringLiteral("-inkey"), keyPath, QStringLiteral("-in"), certPath,
|
|
QStringLiteral("-passout"), QStringLiteral("pass:test")});
|
|
|
|
const QByteArray unsignedResponse =
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
|
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
|
|
" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/"
|
|
"oasis-200401-wss-wssecurity-secext-1.0.xsd\""
|
|
" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/"
|
|
"oasis-200401-wss-wssecurity-utility-1.0.xsd\">"
|
|
"<soap:Header/><soap:Body wsu:Id=\"response-body\">"
|
|
"<Odpoved xmlns=\"http://fs.gov.cz/eet/schema/v4\">"
|
|
"<Hlavicka uuid_zpravy=\"123e4567-e89b-42d3-a456-426614174000\" "
|
|
"dat_prij=\"2026-10-13T20:00:00+02:00\"/>"
|
|
"<Potvrzeni pok=\"123e4567-e89b-42d3-a456-426614174000-01\"/>"
|
|
"</Odpoved></soap:Body></soap:Envelope>";
|
|
QString signingError;
|
|
const QByteArray signedResponse = EetV4Signer::signSoap(
|
|
unsignedResponse, p12Path, QByteArrayLiteral("test"), &signingError);
|
|
QVERIFY2(!signedResponse.isEmpty(), qPrintable(signingError));
|
|
|
|
MockEetServer server(signedResponse);
|
|
QSslConfiguration serverSsl = QSslConfiguration::defaultConfiguration();
|
|
QFile keyFile(keyPath);
|
|
QFile certificateFile(certPath);
|
|
QVERIFY(keyFile.open(QIODevice::ReadOnly));
|
|
QVERIFY(certificateFile.open(QIODevice::ReadOnly));
|
|
serverSsl.setPrivateKey(QSslKey(keyFile.readAll(), QSsl::Rsa, QSsl::Pem));
|
|
serverSsl.setLocalCertificate(QSslCertificate(certificateFile.readAll(), QSsl::Pem));
|
|
server.setSslConfiguration(serverSsl);
|
|
QVERIFY(server.listen(QHostAddress::LocalHost));
|
|
|
|
QSslConfiguration clientSsl = QSslConfiguration::defaultConfiguration();
|
|
clientSsl.setCaCertificates({serverSsl.localCertificate()});
|
|
EetV4Client client({
|
|
QUrl(QStringLiteral("https://localhost:%1/eet").arg(server.serverPort())),
|
|
5000, clientSsl
|
|
});
|
|
EetV4SaleRequest request;
|
|
request.sentAt = QDateTime::currentDateTime().toOffsetFromUtc(0);
|
|
request.saleAt = request.sentAt;
|
|
request.taxpayerEic = QStringLiteral("CZ123456789");
|
|
request.unitId = 1;
|
|
request.cashRegisterId = QStringLiteral("KASA1");
|
|
request.receiptNumber = QStringLiteral("TEST-1");
|
|
QVERIFY(EetV4Amount::fromString(QStringLiteral("100.00"), &request.totalSale));
|
|
|
|
EetV4Response response;
|
|
QString error;
|
|
QVERIFY2(client.sendSale(request, p12Path, QByteArrayLiteral("test"), &response, &error),
|
|
qPrintable(error));
|
|
QVERIFY(server.requestVerified());
|
|
QVERIFY(response.isSuccess());
|
|
QCOMPARE(response.pok, QStringLiteral("123e4567-e89b-42d3-a456-426614174000-01"));
|
|
}
|
|
|
|
QTEST_MAIN(EetV4ClientIntegrationTest)
|
|
#include "eetv4client_integration_test.moc"
|