RedirectHash class created in restricted_html file
authorTĂșlio Cavalcanti <tulio.cavalcanti@intra2net.com>
Tue, 18 Sep 2018 13:12:10 +0000 (15:12 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Tue, 2 Oct 2018 12:15:55 +0000 (14:15 +0200)
class used to find all redirect urls in a html text and add a query
parameter "urlauth" with a hash as value to them.

CMakeLists.txt
src/CMakeLists.txt
src/restricted_html.cpp
src/restricted_html.hpp
test/test_crypto.cpp
test/test_restricted_html.cpp

index 18d53b6..918945b 100644 (file)
@@ -135,6 +135,11 @@ include(FindPkgConfig)
 # Find Boost
 find_package(Boost 1.44 COMPONENTS iostreams unit_test_framework thread REQUIRED)
 
+# Find pcrecpp
+pkg_check_modules(PCRECPP REQUIRED libpcrecpp)
+INCLUDE_DIRECTORIES(${PCRECPP_INCLUDE_DIRS})
+LINK_DIRECTORIES(${PCRECPP_LIBRARY_DIRS})
+
 # Find libxml++
 if (BUILD_XMLLIB)
     pkg_check_modules(XMLPP REQUIRED libxml++-2.6)
index 605b81e..a1894cc 100644 (file)
@@ -66,7 +66,8 @@ target_link_libraries(i2ncommon
                       ${Boost_IOSTREAMS_LIBRARIES}
                       ${Boost_THREAD_LIBRARIES}
                       ${ICONV_LIBRARIES}
-                      ${OPENSSL_LIBRARIES})
+                      ${OPENSSL_LIBRARIES}
+                      ${PCRECPP_LIBRARIES})
 
 set_target_properties(i2ncommon PROPERTIES VERSION ${VERSION} SOVERSION 7)
 set_target_properties(i2ncommon PROPERTIES OUTPUT_NAME i2ncommon CLEAN_DIRECT_OUTPUT 1)
index d59bcff..85424fa 100644 (file)
@@ -30,6 +30,10 @@ on this file might be covered by the GNU General Public License.
 
 #include <stringfunc.hxx>
 #include <restricted_html.hpp>
+#include <pcrecpp.h>
+#include <fstream>
+#include "crypto.hxx"
+#include "filefunc.hxx"
 
 using namespace std;
 
@@ -164,4 +168,83 @@ string encode_url(string s)
 
     return out.str();
 }
+
+/**
+* @brief Change the attribute Filename from which the SecretId is going
+* to be read.
+*
+* @param s custom_filename string new filename.
+*/
+void RedirectHash::set_custom_filename(string custom_filename)
+{
+    Filename = custom_filename;
+}
+
+/**
+* @brief Reads the file Filename and loads the data into SecretId.
+*/
+void RedirectHash::load_secret_id()
+{
+    SecretId = read_file(Filename);
+
+    if (SecretId.empty())
+        throw runtime_error("Inexistent file or empty");
+}
+
+/**
+* @brief Hashes the given url with the SecretId and returns a base64 hash.
+*
+* @param s &url string.
+*
+* @return base64 raw hash
+*/
+string RedirectHash::hash_url(const string &url)
+{
+    if (SecretId.empty())
+        load_secret_id();
+
+    return base64_encode(hash_data_raw(url + SecretId, MD5));
+}
+
+/**
+* @brief Reads a HTML file, removes all ##BEGIN_URL## and ##END_URL## tags and
+* adds urlauth param to the url in between these tags.
+*
+* @param s &html string.
+*
+* @return new html with the urls signed
+*/
+string RedirectHash::sign_urls(const string &html)
+{
+    string ret(html);
+    string url;
+    string re = "##BEGIN_URL##(.*?)##END_URL##";
+    pcrecpp::RE re_match(re);
+    while (re_match.PartialMatch(ret, &url))
+    {
+        string hashed_url = hash_url(url);
+
+        replace_all(ret,
+                    "##BEGIN_URL##" + url + "##END_URL##",
+                    encode_url(url) + "&urlauth=" + encode_url(hashed_url));
+    }
+    return ret;
+}
+
+/**
+* @brief Validates if the given url is the correspondent url to the given
+* authtag hash.
+*
+* @param s &url string;
+*          &authtag string hash;
+*
+* @return bool true if the given url is the correspondent url to the
+* authtag hash, else returns false
+*/
+bool RedirectHash::validate_redirect_authtag(const string &url,
+                                             const string &authtag)
+{
+    return authtag == hash_url(url);
+}
+
 } // eo namespace I2n
index 09b3d14..1d84c6d 100644 (file)
@@ -33,9 +33,32 @@ namespace I2n
 {
 
 
-    std::string decode_url(std::string s);
+std::string decode_url(std::string s);
 
-    std::string encode_url(std::string s);
+std::string encode_url(std::string s);
+
+
+class RedirectHash
+{
+    public:
+        RedirectHash() : Filename("/var/intranator/etc/redirect_secret_id"){}
+
+        void set_custom_filename(std::string custom_filename);
+
+        void load_secret_id();
+
+        std::string hash_url(const std::string &url);
+
+        std::string sign_urls(const std::string &html);
+
+        bool validate_redirect_authtag(const std::string &url,
+                                        const std::string &authtag);
+
+    private:
+        std::string Filename;
+
+        std::string SecretId;
+};
 
 } // eo namespace I2n
 
index 6f3edff..ac83656 100644 (file)
@@ -40,7 +40,7 @@ class TestCryptoFixture
 {
 protected:
 
-    char* Filename;
+    string Filename;
 
     tmpfstream Tempfile;
 
@@ -51,7 +51,7 @@ protected:
         Tempfile << "Long Data and or Password";
         Tempfile.close();
 
-        Filename = (char*)Tempfile.get_tmp_filename().c_str();
+        Filename = Tempfile.get_tmp_filename();
     }
 
 public:
index d744ed2..bc95180 100644 (file)
@@ -25,6 +25,7 @@ on this file might be covered by the GNU General Public License.
  */
 #define BOOST_TEST_DYN_LINK
 #include <boost/test/unit_test.hpp>
+#include <tmpfstream.hpp>
 
 #include <restricted_html.hpp>
 
@@ -61,4 +62,55 @@ BOOST_AUTO_TEST_CASE(EncodeStringURL2)
                       output);
 }
 
+BOOST_AUTO_TEST_CASE(RedirectHash1)
+{
+    tmpfstream TempFile;
+    string TempFilePattern = "/tmp/libi2ncommon_test_restricted_html_XXXXXX";
+    TempFile.open(TempFilePattern);
+    TempFile << "ABCDEF";
+    TempFile.close();
+
+    RedirectHash redirect_hash = RedirectHash();
+    redirect_hash.set_custom_filename(TempFile.get_tmp_filename());
+
+    string url1 = "http://www.domain.com/params?param=p";
+    string url2 = "http://www.google.com/search?q=test";
+
+    string url1_encoded = "http%3A%2F%2Fwww%2Edomain%2Ecom%2Fparams%3Fparam%3Dp";
+    string url2_encoded = "http%3A%2F%2Fwww%2Egoogle%2Ecom%2Fsearch%3Fq%3Dtest";
+
+    string hash1 = "a2Dlksjt5kBrt6Or4nKdxQ==";
+    string hash2 = "2BdwBA6vlqJS/3vWzUxa1w==";
+
+    string hash1_encoded = "a2Dlksjt5kBrt6Or4nKdxQ%3D%3D";
+    string hash2_encoded = "2BdwBA6vlqJS%2F3vWzUxa1w%3D%3D";
+
+    BOOST_CHECK_EQUAL(encode_url(url1) , url1_encoded);
+    BOOST_CHECK_EQUAL(encode_url(url2) , url2_encoded);
+
+    const string html = ("<html>"
+                         "<a href=\"/arnie?form=redirect&url=##BEGIN_URL##" +
+                         url1 +"##END_URL##\" target=\"_top\">Further information</a>"
+                         "<a href=\"/arnie?form=redirect&url=##BEGIN_URL##" +
+                         url2 +"##END_URL##\" target=\"_top\">Further information</a>"
+                         "</html>");
+
+    const string result = ("<html>"
+                           "<a href=\"/arnie?form=redirect&url=" + url1_encoded + "&urlauth=" +
+                           hash1_encoded + "\" target=\"_top\">Further information</a>"
+                           "<a href=\"/arnie?form=redirect&url=" + url2_encoded + "&urlauth=" +
+                           hash2_encoded + "\" target=\"_top\">Further information</a>"
+                           "</html>");
+
+
+    string new_html = redirect_hash.sign_urls(html);
+
+    BOOST_CHECK_EQUAL(result, new_html);
+
+    BOOST_CHECK(redirect_hash.validate_redirect_authtag(url1, hash1));
+    BOOST_CHECK(redirect_hash.validate_redirect_authtag(url2, hash2));
+
+    TempFile.unlink();
+}
+
 BOOST_AUTO_TEST_SUITE_END()