[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [trojita] /: Crypto: gracefully handle unavailable data
From:       Thomas_Lübking <thomas.luebking () gmail ! com>
Date:       2016-06-20 18:53:56
Message-ID: E1bF4Ka-0008Q5-FY () code ! kde ! org
[Download RAW message or body]

Git commit a80757e6e55bbdfd1617462636ff851a47c3c801 by Thomas Lübking, on behalf of \
Jan Kundrát. Committed on 18/06/2016 at 08:05.
Pushed by gerrit into branch 'master'.

Crypto: gracefully handle unavailable data

The crypto code should be transparent for network failures, that is, it
should act as if the signature/encryption was not available for some
reason, and should just use the underlying data in whatever form it's
currently available.

Change-Id: I61816d306b17fbcbfc63d04188cd563426606ffb

M  +14   -0    src/Cryptography/GpgMe++.cpp
M  +94   -0    tests/Cryptography/test_Cryptography_PGP.cpp
M  +2    -0    tests/Cryptography/test_Cryptography_PGP.h

http://commits.kde.org/trojita/a80757e6e55bbdfd1617462636ff851a47c3c801

diff --git a/src/Cryptography/GpgMe++.cpp b/src/Cryptography/GpgMe++.cpp
index 414dcb6..4285799 100644
--- a/src/Cryptography/GpgMe++.cpp
+++ b/src/Cryptography/GpgMe++.cpp
@@ -630,6 +630,13 @@ void GpgMeSigned::handleDataChanged(const QModelIndex &topLeft, \
const QModelInde  Q_ASSERT(m_plaintextPart.isValid());
     Q_ASSERT(m_plaintextMimePart.isValid());
     Q_ASSERT(m_signaturePart.isValid());
+    if (m_plaintextPart.data(RoleIsUnavailable).toBool() || \
m_plaintextMimePart.data(RoleIsUnavailable).toBool() +            || \
m_signaturePart.data(RoleIsUnavailable).toBool() || \
m_enclosingMessage.data(RoleIsUnavailable).toBool()) { +        \
forwardFailure(tr("Data Unavailable"), +                       tr("Some data are not \
available, perhaps due to an offline network connection"), +                       \
QStringLiteral("state-offline")); +        return;
+    }
     if (!m_plaintextPart.data(RoleIsFetched).toBool() || \
                !m_plaintextMimePart.data(RoleIsFetched).toBool() ||
             !m_signaturePart.data(RoleIsFetched).toBool() || \
!m_enclosingMessage.data(RoleMessageEnvelope).isValid()) {  return;
@@ -766,6 +773,13 @@ void GpgMeEncrypted::handleDataChanged(const QModelIndex \
&topLeft, const QModelI  }
     Q_ASSERT(m_versionPart.isValid());
     Q_ASSERT(m_encPart.isValid());
+    if (m_versionPart.data(RoleIsUnavailable).toBool() || \
m_encPart.data(RoleIsUnavailable).toBool() +            || \
m_enclosingMessage.data(RoleIsUnavailable).toBool()) { +        \
forwardFailure(tr("Data Unavailable"), +                       tr("Cannot decrypt. \
Some data are not available, perhaps due to an offline network connection."), +       \
QStringLiteral("state-offline")); +        return;
+    }
     if (!m_versionPart.data(RoleIsFetched).toBool() || \
!m_encPart.data(RoleIsFetched).toBool()  || \
!m_enclosingMessage.data(RoleMessageEnvelope).isValid()) {  return;
diff --git a/tests/Cryptography/test_Cryptography_PGP.cpp \
b/tests/Cryptography/test_Cryptography_PGP.cpp index 99694c5..c2b4eb7 100644
--- a/tests/Cryptography/test_Cryptography_PGP.cpp
+++ b/tests/Cryptography/test_Cryptography_PGP.cpp
@@ -478,4 +478,98 @@ void CryptographyPGPTest::testMalformed_data()
 
 }
 
+/** @short Check operation when some data are not available */
+void CryptographyPGPTest::testOffline()
+{
+    QFETCH(QByteArray, bodystructure);
+    QFETCH(QByteArray, fetchRegex);
+
+    model->setProperty("trojita-imap-delayed-fetch-part", 0);
+    helperSyncBNoMessages();
+    cServer("* 1 EXISTS\r\n");
+    cClient(t.mk("UID FETCH 1:* (FLAGS)\r\n"));
+    cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t.last("OK fetched\r\n"));
+    QCOMPARE(model->rowCount(msgListB), 1);
+    QModelIndex msg = msgListB.child(0, 0);
+    QVERIFY(msg.isValid());
+    QCOMPARE(model->rowCount(msg), 0);
+    cClient(t.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS ")\r\n"));
+    cServer(helperCreateTrivialEnvelope(1, 333, QStringLiteral("subj"), \
QStringLiteral("foo@example.org"), bodystructure) +            + t.last("OK \
fetched\r\n")); +    cEmpty();
+    QVERIFY(model->rowCount(msg) > 0);
+    Cryptography::MessageModel msgModel(0, msg);
+#ifdef TROJITA_HAVE_CRYPTO_MESSAGES
+#  ifdef TROJITA_HAVE_GPGMEPP
+    msgModel.registerPartHandler(std::make_shared<Cryptography::GpgMeReplacer>());
+#  endif
+#endif
+    QModelIndex mappedMsg = msgModel.index(0,0);
+    QVERIFY(mappedMsg.isValid());
+    QVERIFY(msgModel.rowCount(mappedMsg) > 0);
+
+    QModelIndex data = mappedMsg.child(0, 0);
+    QVERIFY(data.isValid());
+#ifdef TROJITA_HAVE_CRYPTO_MESSAGES
+    QCOMPARE(msgModel.rowCount(mappedMsg), 1);
+    QCOMPARE(msgModel.rowCount(data), 0);
+    QCOMPARE(data.data(Imap::Mailbox::RoleIsFetched).toBool(), false);
+
+    cClientRegExp(t.mk(fetchRegex));
+    auto fetchResp = t.last("NO offline\r\n");
+    LibMailboxSync::setModelNetworkPolicy(model, Imap::Mailbox::NETWORK_OFFLINE);
+    cClient(t.mk("LOGOUT\r\n"));
+    cServer(fetchResp + t.last("OK logout\r\n"));
+
+    QSignalSpy qcaErrorSpy(&msgModel, SIGNAL(error(const QModelIndex \
&,QString,QString))); +
+    int i = 0;
+    while (data.isValid() && \
data.data(Imap::Mailbox::RolePartCryptoNotFinishedYet).toBool() && \
qcaErrorSpy.empty() && i++ < 1000) { +        QTest::qWait(10);
+    }
+    // allow for event processing, so that the model can retrieve the results
+    QCoreApplication::processEvents();
+
+    QCOMPARE(data.data(Imap::Mailbox::RolePartCryptoNotFinishedYet), \
QVariant(false)); +    QCOMPARE(data.data(Imap::Mailbox::RolePartCryptoTLDR), \
QVariant(QStringLiteral("Data Unavailable"))); +    QCOMPARE(msgModel.rowCount(data), \
2); +
+    if (!qcaErrorSpy.isEmpty()) {
+        qDebug() << "Unexpected failure in crypto";
+        for (int i = 0; i < qcaErrorSpy.size(); ++i) {
+            qDebug() << qcaErrorSpy[i][1].toString();
+            qDebug() << qcaErrorSpy[i][2].toString();
+        }
+    }
+
+    // We're offline, we cannot call cEmpty(), that would assert-crash due to no \
active parsers +    //cEmpty();
+
+    QVERIFY(errorSpy->empty());
+#else
+    QCOMPARE(msgModel.rowCount(data), 2);
+    QCOMPARE(data.data(Imap::Mailbox::RoleIsFetched).toBool(), true);
+    cEmpty();
+
+    QSKIP("Some tests were skipped because this build doesn't have GpgME++ \
support"); +#endif
+}
+
+void CryptographyPGPTest::testOffline_data()
+{
+    QTest::addColumn<QByteArray>("bodystructure");
+    QTest::addColumn<QByteArray>("fetchRegex");
+
+    QTest::newRow("signed")
+            << QByteArray("(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \
\"7bit\" 423 14 NIL NIL NIL NIL)" +            "(\"application\" \"pgp-signature\" \
NIL NIL NIL \"7bit\" 851 NIL NIL NIL NIL)" +            " \"signed\" (\"boundary\" \
\"=-=-=\" \"micalg\" \"pgp-sha256\" \"protocol\" \"application/pgp-signature\")" +    \
" NIL NIL NIL") +            << QByteArray("UID FETCH 333 \
\\((BODY\\.PEEK\\[(2|1|1\\.MIME)\\] ?){3}\\)"); +
+    QTest::newRow("encrypted")
+            << bsEncrypted
+            << QByteArray("UID FETCH 333 \\((BODY\\.PEEK\\[(1|2)\\] ?){2}\\)");
+}
+
 QTEST_GUILESS_MAIN(CryptographyPGPTest)
diff --git a/tests/Cryptography/test_Cryptography_PGP.h \
b/tests/Cryptography/test_Cryptography_PGP.h index 9cf3946..5eff0d5 100644
--- a/tests/Cryptography/test_Cryptography_PGP.h
+++ b/tests/Cryptography/test_Cryptography_PGP.h
@@ -40,6 +40,8 @@ private Q_SLOTS:
     void testVerification_data();
     void testMalformed();
     void testMalformed_data();
+    void testOffline();
+    void testOffline_data();
 };
 
 Q_DECLARE_METATYPE(CryptographyPGPTest::pathList)


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic