Rewrite pgp_locate_armor_header() to more strictly follow RFC4880
authorAndrej Kacian <ticho@claws-mail.org>
Fri, 1 Mar 2019 14:45:45 +0000 (15:45 +0100)
committerAndrej Kacian <ticho@claws-mail.org>
Fri, 1 Mar 2019 14:45:45 +0000 (15:45 +0100)
Not only has the armor header be at the beginning of
the line, but also there cannot be any non-whitespace
after it on the same line.

configure.ac
src/plugins/pgpcore/Makefile.am
src/plugins/pgpcore/pgp_utils.c
src/plugins/pgpcore/pgp_utils.h
src/plugins/pgpcore/tests/Makefile.am [new file with mode: 0644]
src/plugins/pgpcore/tests/pgp_utils_test.c [new file with mode: 0644]

index 1ac1b28..04c6ebb 100644 (file)
@@ -2147,6 +2147,7 @@ src/plugins/perl/tools/Makefile
 src/plugins/python/Makefile
 src/plugins/python/examples/Makefile
 src/plugins/pgpcore/Makefile
+src/plugins/pgpcore/tests/Makefile
 src/plugins/pgpmime/Makefile
 src/plugins/pgpinline/Makefile
 src/plugins/rssyl/Makefile
index c19ebcf..1c40467 100644 (file)
@@ -3,6 +3,11 @@
 # terms of the General Public License version 3 (or later).
 # See COPYING file for license details.
 
+if BUILD_TESTS
+include $(top_srcdir)/tests.mk
+SUBDIRS = . tests
+endif
+
 EXTRA_DIST = version.rc plugin.def claws.def
 
 IFLAGS = \
@@ -94,6 +99,3 @@ pgpcore_la_CPPFLAGS = \
 
 clean-local:
        rm -f libclaws.a
-
-
-.PHONY: test
index 31f2d34..3903285 100644 (file)
 
 #include <glib.h>
 
-#include "pgp_utils.h"
-#include "codeconv.h"
-#include "file-utils.h"
-
-gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header)
+/* It's only a valid armor header if it's at the
+ * beginning of the buffer or a new line, and if
+ * there is only whitespace after it on the rest
+ * of the line. */
+gchar *pgp_locate_armor_header(const gchar *haystack, const gchar *needle)
 {
-       gchar *pos;
-
-       pos = strstr(textdata, armor_header);
-       /*
-        * It's only a valid armor header if it's at the
-        * beginning of the buffer or a new line.
-        */
-       if (pos != NULL && (pos == textdata || *(pos-1) == '\n'))
-       {
-             return pos;
+       gchar *txt, *x, *i;
+       gint ok;
+
+       g_return_val_if_fail(haystack != NULL, NULL);
+       g_return_val_if_fail(needle != NULL, NULL);
+
+       /* Start at the beginning */
+       txt = (gchar *)haystack;
+       while (*txt != '\0') {
+
+               /* Find next occurrence */
+               x = strstr(txt, needle);
+
+               if (x == NULL)
+                       break;
+
+               /* Make sure that what we found is at the beginning of line */
+               if (x != haystack && *(x - 1) != '\n') {
+                       txt = x + 1;
+                       continue;
+               }
+
+               /* Now look at what's between end of needle and end of that line.
+                * If there is anything else than whitespace, stop looking. */
+               i = x + strlen(needle);
+               ok = 1;
+               while (*i != '\0' && *i != '\r' && *i != '\n') {
+                       if (!g_ascii_isspace(*i)) {
+                               ok = 0;
+                               break;
+                       }
+                       i++;
+               }
+
+               if (ok)
+                       return x;
+
+               /* We are at the end of haystack */
+               if (*i == '\0')
+                       return NULL;
+
+               txt = i + 1;
        }
+
        return NULL;
 }
+
 #endif /* USE_GPGME */
index aa296b8..eb603cb 100644 (file)
@@ -27,6 +27,6 @@
 
 #include "procmime.h"
 
-gchar *pgp_locate_armor_header(gchar *textdata, const gchar *armor_header);
+gchar *pgp_locate_armor_header(const gchar *textdata, const gchar *armor_header);
 
 #endif /* __PGP_UTILS_H__ */
diff --git a/src/plugins/pgpcore/tests/Makefile.am b/src/plugins/pgpcore/tests/Makefile.am
new file mode 100644 (file)
index 0000000..3bcc12d
--- /dev/null
@@ -0,0 +1,18 @@
+include $(top_srcdir)/tests.mk
+
+common_ldadd = \
+       $(GLIB_LIBS)
+
+AM_CPPFLAGS = \
+       $(GLIB_CFLAGS) \
+       -I.. \
+       -I$(top_srcdir)/src \
+       -I$(top_srcdir)/src/common
+
+TEST_PROGS += pgp_utils_test
+pgp_utils_test_SOURCES = pgp_utils_test.c
+pgp_utils_test_LDADD = $(common_ldadd) ../pgpcore_la-pgp_utils.o
+
+noinst_PROGRAMS = $(TEST_PROGS)
+
+.PHONY: test
diff --git a/src/plugins/pgpcore/tests/pgp_utils_test.c b/src/plugins/pgpcore/tests/pgp_utils_test.c
new file mode 100644 (file)
index 0000000..d4a407a
--- /dev/null
@@ -0,0 +1,85 @@
+#include "pgp_utils.h"
+
+#define HEADER "HEADER"
+struct td {
+       gchar *input;
+       gchar *expected_output;
+};
+
+static void
+test_pgp_locate_armor_header_null()
+{
+       if (!g_test_undefined())
+               return;
+
+       if (g_test_subprocess()) {
+               gchar *out = pgp_locate_armor_header(NULL, HEADER);
+               g_assert_null(out);
+               return;
+       }
+
+       g_test_trap_subprocess(NULL, 0, 0);
+       g_test_trap_assert_stderr("*assertion*failed*");
+       g_test_trap_assert_failed();
+}
+
+static void
+test_pgp_locate_armor_header(gconstpointer user_data)
+{
+       struct td *data = (struct td *)user_data;
+       gchar *out = pgp_locate_armor_header(data->input, HEADER);
+
+       g_assert_cmpstr(out, ==, data->expected_output);
+}
+
+struct td td_justheader = {
+       "HEADER",
+       "HEADER"
+};
+
+struct td td_leading = {
+       "leadingHEADER",
+       NULL
+};
+
+struct td td_trailingspaces = {
+       "HEADER     ",
+       "HEADER     "
+};
+
+struct td td_trailingtext1 = {
+       "HEADERblah",
+       NULL
+};
+
+struct td td_trailingtext2 = {
+       "HEADER   blah",
+       NULL
+};
+
+struct td td_leadinglines = {
+       "foo\nHEADER\nbar",
+       "HEADER\nbar"
+};
+
+#define TEST(name, data) \
+       g_test_add_data_func("/plugins/pgpcore/pgp_locate_armor_header_"name, \
+                       &data, \
+                       test_pgp_locate_armor_header)
+int
+main (int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/plugins/pgpcore/pgp_locate_armor_header_null",
+                       test_pgp_locate_armor_header_null);
+
+       TEST("justheader", td_justheader);
+       TEST("leading", td_leading);
+       TEST("trailingspaces", td_trailingspaces);
+       TEST("trailingtext1", td_trailingtext1);
+       TEST("trailingtext2", td_trailingtext2);
+       TEST("leadinglines", td_leadinglines);
+
+       return g_test_run();
+}