From 8ede4f21d6b81263b15487509e37e6df4553c18f Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Mon, 26 Feb 2018 17:27:04 +0100
Subject: Ignore invalid vCard avatar update notifications

Test-Information:

Tests pass on macOS 10.13.3 with clang-trunk and ASAN.

Change-Id: Ice68e93341693349ed5d95dfc062c0a7b07dc673

diff --git a/Swift/Controllers/Storages/AvatarFileStorage.cpp b/Swift/Controllers/Storages/AvatarFileStorage.cpp
index a103920..9d9b9ea 100644
--- a/Swift/Controllers/Storages/AvatarFileStorage.cpp
+++ b/Swift/Controllers/Storages/AvatarFileStorage.cpp
@@ -1,16 +1,15 @@
 /*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
 
 #include <Swift/Controllers/Storages/AvatarFileStorage.h>
 
-#include <iostream>
-
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
 
+#include <Swiften/Base/Log.h>
 #include <Swiften/Base/String.h>
 #include <Swiften/Crypto/CryptoProvider.h>
 #include <Swiften/StringCodecs/Hexify.h>
@@ -31,13 +30,13 @@ AvatarFileStorage::AvatarFileStorage(const boost::filesystem::path& avatarsDir,
                         jidAvatars.insert(std::make_pair(jid, r.first));
                     }
                     else if (!r.first.empty() || !r.second.empty()) {
-                        std::cerr << "Invalid entry in avatars file: " << r.second << std::endl;
+                        SWIFT_LOG(error) << "Invalid entry in avatars file: " << r.second << std::endl;
                     }
                 }
             }
         }
         catch (...) {
-            std::cerr << "Error reading avatars file" << std::endl;
+            SWIFT_LOG(error) << "Error reading avatars file" << std::endl;
         }
     }
 }
@@ -55,12 +54,17 @@ void AvatarFileStorage::addAvatar(const std::string& hash, const ByteArray& avat
             boost::filesystem::create_directories(avatarPath.parent_path());
         }
         catch (const boost::filesystem::filesystem_error& e) {
-            std::cerr << "ERROR: " << e.what() << std::endl;
+            SWIFT_LOG(error) << "filesystem error: " << e.what() << std::endl;
         }
     }
-    boost::filesystem::ofstream file(avatarPath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out);
-    file.write(reinterpret_cast<const char*>(vecptr(avatar)), static_cast<std::streamsize>(avatar.size()));
-    file.close();
+
+    try {
+        boost::filesystem::ofstream file(avatarPath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out);
+        file.write(reinterpret_cast<const char*>(vecptr(avatar)), static_cast<std::streamsize>(avatar.size()));
+    }
+    catch (const boost::filesystem::filesystem_error& e) {
+        SWIFT_LOG(error) << "filesystem error: " << e.what() << std::endl;
+    }
 }
 
 boost::filesystem::path AvatarFileStorage::getAvatarPath(const std::string& hash) const {
@@ -69,7 +73,12 @@ boost::filesystem::path AvatarFileStorage::getAvatarPath(const std::string& hash
 
 ByteArray AvatarFileStorage::getAvatar(const std::string& hash) const {
     ByteArray data;
-    readByteArrayFromFile(data, getAvatarPath(hash));
+    try {
+        readByteArrayFromFile(data, getAvatarPath(hash));
+    }
+    catch (const boost::filesystem::filesystem_error& e) {
+        SWIFT_LOG(error) << "filesystem error: " << e.what() << std::endl;
+    }
     return data;
 }
 
@@ -98,7 +107,7 @@ void AvatarFileStorage::saveJIDAvatars() {
         file.close();
     }
     catch (...) {
-        std::cerr << "Error writing avatars file" << std::endl;
+        SWIFT_LOG(error) << "Error writing avatars file" << std::endl;
     }
 }
 
diff --git a/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp b/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp
index 241f375..5a35410 100644
--- a/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp
+++ b/Swiften/Avatars/UnitTest/AvatarManagerImplTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016 Isode Limited.
+ * Copyright (c) 2014-2018 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -91,6 +91,7 @@ class AvatarManagerImplTest : public CppUnit::TestFixture {
             /* send new presence to notify of blank avatar */
 
             vcardUpdate = std::make_shared<VCardUpdate>();
+            vcardUpdate->setPhotoHash("da39a3ee5e6b4b0d3255bfef95601890afd80709");
             presence = std::make_shared<Presence>();
             presence->setTo(ownerJID);
             presence->setFrom(personJID);
diff --git a/Swiften/Avatars/VCardUpdateAvatarManager.cpp b/Swiften/Avatars/VCardUpdateAvatarManager.cpp
index 3e8d87b..349af2f 100644
--- a/Swiften/Avatars/VCardUpdateAvatarManager.cpp
+++ b/Swiften/Avatars/VCardUpdateAvatarManager.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2018 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -32,6 +32,10 @@ void VCardUpdateAvatarManager::handlePresenceReceived(std::shared_ptr<Presence>
         return;
     }
     JID from = getAvatarJID(presence->getFrom());
+    if (update->getPhotoHash().size() != 40) {
+        SWIFT_LOG(debug) << "Invalid vCard avatar photo hash length. Must be hex-encoded SHA-1, i.e. 40 characters." << std::endl;
+        return;
+    }
     if (getAvatarHash(from) == update->getPhotoHash()) {
         return;
     }
-- 
cgit v0.10.2-6-g49f6