From 1e97d3195d366a15a086ca451d082d59972105ba Mon Sep 17 00:00:00 2001
From: Nicolas Werner <nicolas.werner@hotmail.de>
Date: Sat, 23 Jan 2021 20:06:24 +0100
Subject: [PATCH] Store error codes in olm_exceptions

---
 include/mtxclient/crypto/client.hpp | 90 +++++++++++++++++++----------
 lib/crypto/client.cpp               | 34 +++++++++++
 2 files changed, 93 insertions(+), 31 deletions(-)

diff --git a/include/mtxclient/crypto/client.hpp b/include/mtxclient/crypto/client.hpp
index 3813f1f6c..fb7ede0dd 100644
--- a/include/mtxclient/crypto/client.hpp
+++ b/include/mtxclient/crypto/client.hpp
@@ -31,51 +31,79 @@ namespace crypto {
 //! Data representation used to interact with libolm.
 using BinaryBuf = std::vector<uint8_t>;
 
+enum class OlmErrorCode {
+	UNKNOWN_ERROR = - 1,
+	SUCCESS,
+	NOT_ENOUGH_RANDOM,
+	OUTPUT_BUFFER_TOO_SMALL,
+	BAD_MESSAGE_VERSION,
+	BAD_MESSAGE_FORMAT,
+	BAD_MESSAGE_MAC,
+	BAD_MESSAGE_KEY_ID,
+	INVALID_BASE64,
+	BAD_ACCOUNT_KEY,
+	UNKNOWN_PICKLE_VERSION,
+	CORRUPTED_PICKLE,
+	BAD_SESSION_KEY,
+	UNKNOWN_MESSAGE_INDEX,
+	BAD_LEGACY_ACCOUNT_PICKLE,
+	BAD_SIGNATURE,
+	OLM_INPUT_BUFFER_TOO_SMALL,
+	OLM_SAS_THEIR_KEY_NOT_SET
+};
+
 //! Errors returned by the olm library
 class olm_exception : public std::exception
 {
-public:
-        olm_exception(std::string func, OlmSession *s)
-          : msg_(func + ": " + std::string(olm_session_last_error(s)))
-        {}
+	public:
+		olm_exception(std::string func, OlmSession *s)
+			: olm_exception(std::move(func), std::string(olm_session_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmAccount *acc)
-          : msg_(func + ": " + std::string(olm_account_last_error(acc)))
-        {}
+		olm_exception(std::string func, OlmAccount *acc)
+			: olm_exception(std::move(func), std::string(olm_account_last_error(acc)))
+		{}
 
-        olm_exception(std::string func, OlmUtility *util)
-          : msg_(func + ": " + std::string(olm_utility_last_error(util)))
-        {}
+		olm_exception(std::string func, OlmUtility *util)
+			: olm_exception(std::move(func), std::string(olm_utility_last_error(util)))
+		{}
 
-        olm_exception(std::string func, OlmPkDecryption *s)
-          : msg_(func + ": " + std::string(olm_pk_decryption_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmPkDecryption *s)
+			: olm_exception(std::move(func), std::string(olm_pk_decryption_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmPkSigning *s)
-          : msg_(func + ": " + std::string(olm_pk_signing_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmPkSigning *s)
+			: olm_exception(std::move(func), std::string(olm_pk_signing_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmOutboundGroupSession *s)
-          : msg_(func + ": " + std::string(olm_outbound_group_session_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmOutboundGroupSession *s)
+			: olm_exception(std::move(func), std::string(olm_outbound_group_session_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmInboundGroupSession *s)
-          : msg_(func + ": " + std::string(olm_inbound_group_session_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmInboundGroupSession *s)
+			: olm_exception(std::move(func), std::string(olm_inbound_group_session_last_error(s)))
+		{}
 
-        olm_exception(std::string func, OlmSAS *s)
-          : msg_(func + ":" + std::string(olm_sas_last_error(s)))
-        {}
+		olm_exception(std::string func, OlmSAS *s)
+			: olm_exception(std::move(func), std::string(olm_sas_last_error(s)))
+		{}
 
-        olm_exception(std::string msg)
-          : msg_(msg)
-        {}
+                //! Returns a description of the olm error.
+                const char *what() const noexcept override { return msg_.c_str(); }
 
-        //! Returns a description of the olm error.
-        const char *what() const noexcept override { return msg_.c_str(); }
+                //! Returns an error code reconstructed from the error string returned by olm
+                OlmErrorCode error_code() const noexcept { return ec_; }
+
+        private:
+                olm_exception(std::string &&func, std::string error_string)
+                  : msg_(func + ": " + error_string)
+                  , ec_(ec_from_string(error_string))
+                {}
+
+		OlmErrorCode ec_from_string(std::string_view);
 
-private:
         std::string msg_;
+	OlmErrorCode ec_ = OlmErrorCode::UNKNOWN_ERROR;
 };
 
 //! Serialize olm objects into strings encrypted using key to persist them on non volatile storage.
diff --git a/lib/crypto/client.cpp b/lib/crypto/client.cpp
index feb8574d9..73e3ea78d 100644
--- a/lib/crypto/client.cpp
+++ b/lib/crypto/client.cpp
@@ -14,6 +14,40 @@ using namespace mtx::crypto;
 
 static constexpr auto pwhash_SALTBYTES = 16u;
 
+using namespace std::string_view_literals;
+
+static const std::array olmErrorStrings{
+  "SUCCESS"sv,
+  "NOT_ENOUGH_RANDOM"sv,
+  "OUTPUT_BUFFER_TOO_SMALL"sv,
+  "BAD_MESSAGE_VERSION"sv,
+  "BAD_MESSAGE_FORMAT"sv,
+  "BAD_MESSAGE_MAC"sv,
+  "BAD_MESSAGE_KEY_ID"sv,
+  "INVALID_BASE64"sv,
+  "BAD_ACCOUNT_KEY"sv,
+  "UNKNOWN_PICKLE_VERSION"sv,
+  "CORRUPTED_PICKLE"sv,
+  "BAD_SESSION_KEY"sv,
+  "UNKNOWN_MESSAGE_INDEX"sv,
+  "BAD_LEGACY_ACCOUNT_PICKLE"sv,
+  "BAD_SIGNATURE"sv,
+  "OLM_INPUT_BUFFER_TOO_SMALL"sv,
+  "OLM_SAS_THEIR_KEY_NOT_SET"sv,
+
+};
+
+OlmErrorCode
+olm_exception::ec_from_string(std::string_view error)
+{
+        for (size_t i = 0; i < olmErrorStrings.size(); i++) {
+                if (olmErrorStrings[i] == error)
+                        return static_cast<OlmErrorCode>(i);
+        }
+
+        return OlmErrorCode::UNKNOWN_ERROR;
+}
+
 void
 OlmClient::create_new_account()
 {
-- 
GitLab