Blame SOURCES/satyr-0.13-ureport-auth-support.patch

f41043
From 3e11b3c67bc31662810f72571311d7d7580e3f0a Mon Sep 17 00:00:00 2001
f41043
From: Jakub Filak <jfilak@redhat.com>
f41043
Date: Mon, 18 Aug 2014 20:39:34 +0200
f41043
Subject: [SATYR PATCH 6/6] Add authentication data support in uReport
f41043
f41043
Support authentication data in uReport
f41043
f41043
We need this for 'machine id' element which should be present only if
f41043
users wishes to it.
f41043
f41043
The authentication entries are string based, key value pairs (JSON
f41043
string elements).
f41043
f41043
The entries are enclosed in an envelope object called 'auth'.
f41043
f41043
Example:
f41043
f41043
"auth" : {   "machineid" : "deadbeaf"
f41043
         }
f41043
f41043
Fixes #171
f41043
f41043
Signed-off-by: Jakub Filak <jfilak@redhat.com>
f41043
Signed-off-by: Martin Milata <mmilata@redhat.com>
f41043
f41043
mmilata: s/custom/auth/g, python bindings
f41043
f41043
tests: add a test for uReport auth data
f41043
f41043
Related to #171
f41043
f41043
Signed-off-by: Jakub Filak <jfilak@redhat.com>
f41043
Signed-off-by: Martin Milata <mmilata@redhat.com>
f41043
f41043
mmilata: python test
f41043
f41043
ureport: fix indentation of 'auth' key in JSON
f41043
f41043
Fixes a bug in commit 189f7adbba9c38bd434c30e7d0c07b546c373312
f41043
f41043
Related to #171
f41043
f41043
Signed-off-by: Jakub Filak <jfilak@redhat.com>
f41043
---
f41043
 include/report.h                |  17 ++++++
f41043
 lib/internal_utils.h            |  12 +++++
f41043
 lib/json.c                      |  26 ++++++++++
f41043
 lib/report.c                    |  82 +++++++++++++++++++++++++++++
f41043
 python/py_report.c              |  30 +++++++++++
f41043
 python/py_report.h              |   2 +
f41043
 tests/json_files/ureport-1-auth | 112 ++++++++++++++++++++++++++++++++++++++++
f41043
 tests/python/report.py          |   6 +++
f41043
 tests/report.at                 |  81 +++++++++++++++++++++++++++++
f41043
 9 files changed, 368 insertions(+)
f41043
 create mode 100644 tests/json_files/ureport-1-auth
f41043
f41043
diff --git a/include/report.h b/include/report.h
f41043
index 424b730..025d8f8 100644
f41043
--- a/include/report.h
f41043
+++ b/include/report.h
f41043
@@ -31,6 +31,13 @@ extern "C" {
f41043
 struct sr_json_value;
f41043
 struct sr_stacktrace;
f41043
 
f41043
+struct sr_report_custom_entry
f41043
+{
f41043
+    char *key;
f41043
+    char *value;
f41043
+    struct sr_report_custom_entry *next;
f41043
+};
f41043
+
f41043
 struct sr_report
f41043
 {
f41043
     uint32_t report_version;
f41043
@@ -49,6 +56,8 @@ struct sr_report
f41043
     struct sr_rpm_package *rpm_packages;
f41043
 
f41043
     struct sr_stacktrace *stacktrace;
f41043
+
f41043
+    struct sr_report_custom_entry *auth_entries;
f41043
 };
f41043
 
f41043
 struct sr_report *
f41043
@@ -60,6 +69,14 @@ sr_report_init(struct sr_report *report);
f41043
 void
f41043
 sr_report_free(struct sr_report *report);
f41043
 
f41043
+
f41043
+/* @brief Adds a new entry to 'auth' object
f41043
+ *
f41043
+ * The implementation is LIFO. The resulting list is in reversed.
f41043
+ */
f41043
+void
f41043
+sr_report_add_auth(struct sr_report *report, const char *key, const char *value);
f41043
+
f41043
 char *
f41043
 sr_report_to_json(struct sr_report *report);
f41043
 
f41043
diff --git a/lib/internal_utils.h b/lib/internal_utils.h
f41043
index 20f65de..3a10520 100644
f41043
--- a/lib/internal_utils.h
f41043
+++ b/lib/internal_utils.h
f41043
@@ -130,4 +130,16 @@ json_read_bool(struct sr_json_value *object, const char *key_name, bool *dest,
f41043
         abort();                                                                      \
f41043
     }
f41043
 
f41043
+/* returns the number of object's children */
f41043
+unsigned
f41043
+json_object_children_count(struct sr_json_value *object);
f41043
+
f41043
+/* returns the child_noth child and passes its name in child_name arg */
f41043
+struct sr_json_value *
f41043
+json_object_get_child(struct sr_json_value *object, unsigned child_no, const char **child_name);
f41043
+
f41043
+/* returns string's value */
f41043
+const char *
f41043
+json_string_get_value(struct sr_json_value *object);
f41043
+
f41043
 #endif
f41043
diff --git a/lib/json.c b/lib/json.c
f41043
index 35b7e6b..d777973 100644
f41043
--- a/lib/json.c
f41043
+++ b/lib/json.c
f41043
@@ -787,6 +787,32 @@ json_element(struct sr_json_value *object, const char *key_name)
f41043
     return NULL;
f41043
 }
f41043
 
f41043
+unsigned
f41043
+json_object_children_count(struct sr_json_value *object)
f41043
+{
f41043
+    assert(object->type == SR_JSON_OBJECT);
f41043
+
f41043
+    return object->u.object.length;
f41043
+}
f41043
+
f41043
+struct sr_json_value *
f41043
+json_object_get_child(struct sr_json_value *object, unsigned child_no, const char **child_name)
f41043
+{
f41043
+    assert(object->type == SR_JSON_OBJECT);
f41043
+    assert(child_no < object->u.object.length);
f41043
+
f41043
+    *child_name = object->u.object.values[child_no].name;
f41043
+    return object->u.object.values[child_no].value;
f41043
+}
f41043
+
f41043
+const char *
f41043
+json_string_get_value(struct sr_json_value *object)
f41043
+{
f41043
+    assert(object->type == SR_JSON_STRING);
f41043
+
f41043
+    return object->u.string.ptr;
f41043
+}
f41043
+
f41043
 #define DEFINE_JSON_READ(name, c_type, json_type, json_member, conversion)                       \
f41043
     bool                                                                                         \
f41043
     name(struct sr_json_value *object, const char *key_name, c_type *dest, char **error_message) \
f41043
diff --git a/lib/report.c b/lib/report.c
f41043
index a6ecae4..411df64 100644
f41043
--- a/lib/report.c
f41043
+++ b/lib/report.c
f41043
@@ -66,6 +66,7 @@ sr_report_init(struct sr_report *report)
f41043
     report->component_name = NULL;
f41043
     report->rpm_packages = NULL;
f41043
     report->stacktrace = NULL;
f41043
+    report->auth_entries = NULL;
f41043
 }
f41043
 
f41043
 void
f41043
@@ -75,9 +76,36 @@ sr_report_free(struct sr_report *report)
f41043
     sr_operating_system_free(report->operating_system);
f41043
     sr_rpm_package_free(report->rpm_packages, true);
f41043
     sr_stacktrace_free(report->stacktrace);
f41043
+
f41043
+    struct sr_report_custom_entry *iter = report->auth_entries;
f41043
+    while (iter)
f41043
+    {
f41043
+        struct sr_report_custom_entry *tmp = iter->next;
f41043
+
f41043
+        free(iter->value);
f41043
+        free(iter->key);
f41043
+        free(iter);
f41043
+
f41043
+        iter = tmp;
f41043
+    }
f41043
+
f41043
     free(report);
f41043
 }
f41043
 
f41043
+void
f41043
+sr_report_add_auth(struct sr_report *report, const char *key, const char *value)
f41043
+{
f41043
+    struct sr_report_custom_entry *new_entry = sr_malloc(sizeof(*new_entry));
f41043
+    new_entry->key = sr_strdup(key);
f41043
+    new_entry->value = sr_strdup(value);
f41043
+
f41043
+    /* prepend the new value
f41043
+     * it is much faster and easier
f41043
+     * we can do it because we do not to preserve the order(?) */
f41043
+    new_entry->next = report->auth_entries;
f41043
+    report->auth_entries = new_entry;
f41043
+}
f41043
+
f41043
 /* The object has to be non-empty, i.e. contain at least one key-value pair. */
f41043
 static void
f41043
 dismantle_object(char *obj)
f41043
@@ -221,6 +249,34 @@ sr_report_to_json(struct sr_report *report)
f41043
         free(rpms_str_indented);
f41043
     }
f41043
 
f41043
+    /* Custom entries.
f41043
+     *    "auth" : {   "foo": "blah"
f41043
+     *             ,   "one": "two"
f41043
+     *             }
f41043
+     */
f41043
+    struct sr_report_custom_entry *iter = report->auth_entries;
f41043
+    if (iter)
f41043
+    {
f41043
+        sr_strbuf_append_strf(strbuf, ",   \"auth\": {   ");
f41043
+        sr_json_append_escaped(strbuf, iter->key);
f41043
+        sr_strbuf_append_str(strbuf, ": ");
f41043
+        sr_json_append_escaped(strbuf, iter->value);
f41043
+        sr_strbuf_append_str(strbuf, "\n");
f41043
+
f41043
+        /* the first entry is prefix with '{', see lines above */
f41043
+        iter = iter->next;
f41043
+        while (iter)
f41043
+        {
f41043
+            sr_strbuf_append_strf(strbuf, "            ,   ");
f41043
+            sr_json_append_escaped(strbuf, iter->key);
f41043
+            sr_strbuf_append_str(strbuf, ": ");
f41043
+            sr_json_append_escaped(strbuf, iter->value);
f41043
+            sr_strbuf_append_str(strbuf, "\n");
f41043
+            iter = iter->next;
f41043
+        }
f41043
+        sr_strbuf_append_str(strbuf, "            } ");
f41043
+    }
f41043
+
f41043
     sr_strbuf_append_str(strbuf, "}");
f41043
     return sr_strbuf_free_nobuf(strbuf);
f41043
 }
f41043
@@ -336,6 +392,32 @@ sr_report_from_json(struct sr_json_value *root, char **error_message)
f41043
 
f41043
     }
f41043
 
f41043
+    /* Authentication entries. */
f41043
+    struct sr_json_value *extra = json_element(root, "auth");
f41043
+    if (extra)
f41043
+    {
f41043
+        if (!JSON_CHECK_TYPE(extra, SR_JSON_OBJECT, "auth"))
f41043
+            goto fail;
f41043
+
f41043
+        const unsigned children = json_object_children_count(extra);
f41043
+
f41043
+        /* from the last children down to the first for easier testing :)
f41043
+         * keep it as it is as long as sr_report_add_auth() does LIFO */
f41043
+        for (unsigned i = 1; i <= children; ++i)
f41043
+        {
f41043
+            const char *child_name = NULL;
f41043
+            struct sr_json_value *child_object = json_object_get_child(extra,
f41043
+                                                                       children - i,
f41043
+                                                                       &child_name);
f41043
+
f41043
+            if (!JSON_CHECK_TYPE(child_object, SR_JSON_STRING, child_name))
f41043
+                continue;
f41043
+
f41043
+            const char *child_value = json_string_get_value(child_object);
f41043
+            sr_report_add_auth(report, child_name, child_value);
f41043
+        }
f41043
+    }
f41043
+
f41043
     return report;
f41043
 
f41043
 fail:
f41043
diff --git a/python/py_report.c b/python/py_report.c
f41043
index d314027..8aa35dd 100644
f41043
--- a/python/py_report.c
f41043
+++ b/python/py_report.c
f41043
@@ -42,6 +42,8 @@
f41043
 #define to_json_doc "Usage: report.to_json()\n\n" \
f41043
                     "Returns: string - the report serialized as JSON"
f41043
 
f41043
+#define auth_doc "Dictinary of key/value pairs used for authentication"
f41043
+
f41043
 /* See python/py_common.h and python/py_gdb_frame.c for generic getters/setters documentation. */
f41043
 #define GSOFF_PY_STRUCT sr_py_report
f41043
 #define GSOFF_PY_MEMBER report
f41043
@@ -64,6 +66,7 @@ report_getset[] =
f41043
     SR_ATTRIBUTE_STRING(component_name,   "Name of the software component this report pertains to (string)"       ),
f41043
     { (char*)"report_version", sr_py_report_get_version, sr_py_setter_readonly, (char*)"Version of the report (int)", NULL },
f41043
     { (char*)"report_type", sr_py_report_get_type, sr_py_report_set_type, (char*)"Report type (string)", NULL },
f41043
+    { (char*)"auth",        sr_py_report_get_auth, sr_py_report_set_auth, (char*)auth_doc, NULL               },
f41043
     { NULL },
f41043
 };
f41043
 
f41043
@@ -492,3 +495,30 @@ sr_py_report_to_json(PyObject *self, PyObject *args)
f41043
     free(json);
f41043
     return result;
f41043
 }
f41043
+
f41043
+PyObject *
f41043
+sr_py_report_get_auth(PyObject *self, void *data)
f41043
+{
f41043
+    struct sr_report *report = ((struct sr_py_report *)self)->report;
f41043
+    struct sr_report_custom_entry *ae = report->auth_entries;
f41043
+
f41043
+    PyObject *auth = PyDict_New();
f41043
+    for (ae = report->auth_entries; ae; ae = ae->next)
f41043
+    {
f41043
+        PyObject *val = PyString_FromString(ae->value);
f41043
+        if (!val)
f41043
+            return NULL;
f41043
+
f41043
+        if (PyDict_SetItemString(auth, ae->key, val) == -1)
f41043
+            return NULL;
f41043
+    }
f41043
+
f41043
+    return auth;
f41043
+}
f41043
+
f41043
+int
f41043
+sr_py_report_set_auth(PyObject *self, PyObject *rhs, void *data)
f41043
+{
f41043
+    PyErr_SetString(PyExc_NotImplementedError, "Setting auth data is not implemented.");
f41043
+    return -1;
f41043
+}
f41043
diff --git a/python/py_report.h b/python/py_report.h
f41043
index a451dbc..88ec30f 100644
f41043
--- a/python/py_report.h
f41043
+++ b/python/py_report.h
f41043
@@ -65,6 +65,8 @@ PyObject *sr_py_report_str(PyObject *self);
f41043
 PyObject *sr_py_report_get_version(PyObject *self, void *data);
f41043
 PyObject *sr_py_report_get_type(PyObject *self, void *data);
f41043
 int sr_py_report_set_type(PyObject *self, PyObject *rhs, void *data);
f41043
+PyObject *sr_py_report_get_auth(PyObject *self, void *data);
f41043
+int sr_py_report_set_auth(PyObject *self, PyObject *rhs, void *data);
f41043
 
f41043
 /**
f41043
  * Methods.
f41043
diff --git a/tests/json_files/ureport-1-auth b/tests/json_files/ureport-1-auth
f41043
new file mode 100644
f41043
index 0000000..a8db2df
f41043
--- /dev/null
f41043
+++ b/tests/json_files/ureport-1-auth
f41043
@@ -0,0 +1,112 @@
f41043
+{
f41043
+  "ureport_version": 2,
f41043
+
f41043
+  "reason": "Program /usr/bin/sleep was terminated by signal 11",
f41043
+
f41043
+  "os": {
f41043
+    "name": "fedora",
f41043
+    "version": "18",
f41043
+    "architecture": "x86_64"
f41043
+  },
f41043
+
f41043
+  "problem": {
f41043
+    "type": "core",
f41043
+
f41043
+    "executable": "/usr/bin/sleep",
f41043
+
f41043
+    "signal": 11,
f41043
+
f41043
+    "component": "coreutils",
f41043
+
f41043
+    "user": {
f41043
+      "local": true,
f41043
+      "root": false
f41043
+    },
f41043
+
f41043
+    "stacktrace": [
f41043
+      {
f41043
+        "crash_thread": true,
f41043
+
f41043
+        "frames": [
f41043
+          {
f41043
+            "build_id": "5f6632d75fd027f5b7b410787f3f06c6bf73eee6",
f41043
+            "build_id_offset": 767024,
f41043
+            "file_name": "/lib64/libc.so.6",
f41043
+            "address": 251315074096,
f41043
+            "fingerprint": "6c1eb9626919a2a5f6a4fc4c2edc9b21b33b7354",
f41043
+            "function_name": "__nanosleep"
f41043
+          },
f41043
+          {
f41043
+            "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
f41043
+            "build_id_offset": 16567,
f41043
+            "file_name": "/usr/bin/sleep",
f41043
+            "address": 4210871,
f41043
+            "fingerprint": "d24433b82a2c751fc580f47154823e0bed641a54",
f41043
+            "function_name": "close_stdout"
f41043
+          },
f41043
+          {
f41043
+            "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
f41043
+            "build_id_offset": 16202,
f41043
+            "file_name": "/usr/bin/sleep",
f41043
+            "address": 4210506,
f41043
+            "fingerprint": "562719fb960d1c4dbf30c04b3cff37c82acc3d2d",
f41043
+            "function_name": "close_stdout"
f41043
+          },
f41043
+          {
f41043
+            "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
f41043
+            "build_id_offset": 6404,
f41043
+            "fingerprint": "2e8fb95adafe21d035b9bcb9993810fecf4be657",
f41043
+            "file_name": "/usr/bin/sleep",
f41043
+            "address": 4200708
f41043
+          },
f41043
+          {
f41043
+            "build_id": "5f6632d75fd027f5b7b410787f3f06c6bf73eee6",
f41043
+            "build_id_offset": 137733,
f41043
+            "file_name": "/lib64/libc.so.6",
f41043
+            "address": 251314444805,
f41043
+            "fingerprint": "075acda5d3230e115cf7c88597eaba416bdaa6bb",
f41043
+            "function_name": "__libc_start_main"
f41043
+          }
f41043
+        ]
f41043
+      }
f41043
+    ]
f41043
+  },
f41043
+
f41043
+  "packages": [
f41043
+    {
f41043
+      "name": "coreutils",
f41043
+      "epoch": 0,
f41043
+      "version": "8.17",
f41043
+      "architecture": "x86_64",
f41043
+      "package_role": "affected",
f41043
+      "release": "8.fc18",
f41043
+      "install_time": 1371464601
f41043
+    },
f41043
+    {
f41043
+      "name": "glibc",
f41043
+      "epoch": 0,
f41043
+      "version": "2.16",
f41043
+      "architecture": "x86_64",
f41043
+      "release": "31.fc18",
f41043
+      "install_time": 1371464176
f41043
+    },
f41043
+    {
f41043
+      "name": "glibc-common",
f41043
+      "epoch": 0,
f41043
+      "version": "2.16",
f41043
+      "architecture": "x86_64",
f41043
+      "release": "31.fc18",
f41043
+      "install_time": 1371464184
f41043
+    }
f41043
+  ],
f41043
+
f41043
+  "reporter": {
f41043
+    "version": "0.3",
f41043
+    "name": "satyr"
f41043
+  },
f41043
+
f41043
+  "auth": {
f41043
+    "hostname": "localhost",
f41043
+    "machine_id": "0000"
f41043
+  }
f41043
+}
f41043
diff --git a/tests/python/report.py b/tests/python/report.py
f41043
index 83fa76b..5f731b5 100755
f41043
--- a/tests/python/report.py
f41043
+++ b/tests/python/report.py
f41043
@@ -91,6 +91,12 @@ class TestReport(BindingsTestCase):
f41043
     def test_hash(self):
f41043
         self.assertHashable(self.report)
f41043
 
f41043
+    def test_auth(self):
f41043
+        self.assertFalse(self.report.auth)
f41043
+        self.assertRaises(NotImplementedError, self.report.__setattr__, 'auth', {'hostname': 'darkstar'})
f41043
+
f41043
+        report_with_auth = satyr.Report(load_input_contents('../json_files/ureport-1-auth'))
f41043
+        self.assertEqual(report_with_auth.auth, {'hostname': 'localhost', 'machine_id': '0000'})
f41043
 
f41043
 if __name__ == '__main__':
f41043
     unittest.main()
f41043
diff --git a/tests/report.at b/tests/report.at
f41043
index 8736137..1e773d2 100644
f41043
--- a/tests/report.at
f41043
+++ b/tests/report.at
f41043
@@ -57,3 +57,84 @@ int main(void)
f41043
   return 0;
f41043
 }
f41043
 ]])
f41043
+
f41043
+## ------------------ ##
f41043
+## sr_report_add_auth ##
f41043
+## ------------------ ##
f41043
+
f41043
+AT_TESTFUN([sr_report_add_auth],
f41043
+[[
f41043
+#include <assert.h>
f41043
+#include <stdio.h>
f41043
+#include <stdlib.h>
f41043
+#include <string.h>
f41043
+#include "report.h"
f41043
+
f41043
+void check_struct(struct sr_report *report, const char **expected)
f41043
+{
f41043
+    const char **exp_iter = expected;
f41043
+    struct sr_report_custom_entry *cust_iter = report->auth_entries;
f41043
+
f41043
+    while(cust_iter && *exp_iter)
f41043
+    {
f41043
+        fprintf(stdout, "Expected('%s':'%s') vs. Current('%s':'%s')\n",
f41043
+            exp_iter[0], exp_iter[1], cust_iter->key, cust_iter->value);
f41043
+
f41043
+        assert(strcmp(cust_iter->key, exp_iter[0]) == 0 &&
f41043
+               strcmp(cust_iter->value, exp_iter[1]) == 0);
f41043
+
f41043
+        cust_iter = cust_iter->next;
f41043
+        exp_iter += 2;
f41043
+    }
f41043
+
f41043
+    assert(cust_iter == NULL);
f41043
+    assert(*exp_iter == NULL);
f41043
+}
f41043
+
f41043
+void check_json(const char *json, const char **expected)
f41043
+{
f41043
+    const char **exp_iter = expected;
f41043
+    while (*exp_iter)
f41043
+    {
f41043
+        char *entry = NULL;
f41043
+        asprintf(&entry, "\"%s\": \"%s\"", exp_iter[0], exp_iter[1]);
f41043
+
f41043
+        fprintf(stdout, "Checking: '%s'\n", entry);
f41043
+
f41043
+        if (strstr(json, entry) == NULL)
f41043
+        {
f41043
+            fprintf(stderr, "JSON:\n%s\n", json);
f41043
+            abort();
f41043
+        }
f41043
+
f41043
+        exp_iter += 2;
f41043
+    }
f41043
+}
f41043
+
f41043
+
f41043
+int main(void)
f41043
+{
f41043
+  struct sr_report *report = sr_report_new();
f41043
+
f41043
+  sr_report_add_auth(report, "foo", "blah");
f41043
+  sr_report_add_auth(report, "abrt", "awesome");
f41043
+  sr_report_add_auth(report, "satyr", "wonderful");
f41043
+
f41043
+  const char *expected[] = { "satyr", "wonderful", "abrt", "awesome", "foo", "blah", NULL };
f41043
+
f41043
+  check_struct(report, expected);
f41043
+
f41043
+  sr_report_to_json(report);
f41043
+
f41043
+  char *json = sr_report_to_json(report);
f41043
+
f41043
+  check_json(json, expected);
f41043
+
f41043
+  char *error = NULL;
f41043
+  struct sr_report *copy = sr_report_from_json_text(json, &error);
f41043
+
f41043
+  check_struct(copy, expected);
f41043
+
f41043
+  return 0;
f41043
+}
f41043
+]])
f41043
-- 
f41043
1.9.3
f41043