diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | packaging/cert-checker.manifest | 3 | ||||
-rw-r--r-- | packaging/cert-checker.spec | 12 | ||||
-rw-r--r-- | src/CMakeLists.txt | 12 | ||||
-rw-r--r-- | src/dpl/core/include/cchecker/dpl/serialization.h | 496 | ||||
-rw-r--r-- | src/dpl/core/src/serialization.cpp | 31 | ||||
-rw-r--r-- | src/include/cchecker/UIBackend.h | 21 | ||||
-rw-r--r-- | src/include/cchecker/popup-runner.h | 50 | ||||
-rw-r--r-- | src/logic.cpp | 2 | ||||
-rw-r--r-- | src/po/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/po/en_GB.po | 14 | ||||
-rw-r--r-- | src/po/en_US.po | 14 | ||||
-rw-r--r-- | src/ui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/ui/UIBackend.cpp | 165 | ||||
-rw-r--r-- | src/ui/popup-bin/CMakeLists.txt | 61 | ||||
-rw-r--r-- | src/ui/popup-bin/popup.cpp | 296 | ||||
-rw-r--r-- | src/ui/popup-bin/popup.h | 38 | ||||
-rw-r--r-- | src/ui/popup-runner.cpp | 301 | ||||
-rw-r--r-- | systemd/cert-checker.service | 3 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tests/popup_test.cpp | 14 | ||||
-rw-r--r-- | tests/stubs_.cpp | 3 |
22 files changed, 1360 insertions, 187 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cbbc23..0f6baa2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,8 @@ ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG") ADD_DEFINITIONS("-DPOPUP=1") SET(TARGET_CERT_CHECKER "cert-checker") +SET(TARGET_CERT_CHECKER_POPUP "cert-checker-popup") +# Tests SET(TARGET_CERT_CHECKER_TESTS "cert-checker-tests") SET(TARGET_CERT_CHECKER_TESTS_LOGIC "cert-checker-tests-logic") SET(TARGET_CERT_CHECKER_POPUP_TEST "cert-checker-popup-test") diff --git a/packaging/cert-checker.manifest b/packaging/cert-checker.manifest index b91193d..75b0fa5 100644 --- a/packaging/cert-checker.manifest +++ b/packaging/cert-checker.manifest @@ -2,7 +2,4 @@ <request> <domain name="_"/> </request> - <assign> - <filesystem path="/usr/dbspace/.cert-checker.db" label="System"/> - </assign> </manifest> diff --git a/packaging/cert-checker.spec b/packaging/cert-checker.spec index 093401c..bfd5dc0 100644 --- a/packaging/cert-checker.spec +++ b/packaging/cert-checker.spec @@ -9,13 +9,14 @@ Source1: %{name}.manifest BuildRequires: cmake BuildRequires: zip BuildRequires: gettext-tools +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(cert-svc-vcore) BuildRequires: pkgconfig(db-util) -BuildRequires: pkgconfig(icu-i18n) -BuildRequires: pkgconfig(glib-2.0) -BuildRequires: pkgconfig(notification) BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(dbus-glib-1) -BuildRequires: pkgconfig(cert-svc-vcore) +BuildRequires: pkgconfig(elementary) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(icu-i18n) BuildRequires: pkgconfig(key-manager) BuildRequires: pkgconfig(libsystemd-journal) BuildRequires: pkgconfig(libtzplatform-config) @@ -78,7 +79,7 @@ if [ $1 = 2 ]; then # update systemctl restart cert-checker.service fi - +chsmack -a System %{TZ_SYS_DB}/.cert-checker.db %preun if [ $1 = 0 ]; then @@ -95,6 +96,7 @@ fi %files -f %{name}.lang %{_bindir}/cert-checker +%{_bindir}/cert-checker-popup %manifest %{_datadir}/%{name}.manifest %{_datadir}/license/%{name} %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.cert-checker.db diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e61cf4a..76a91d1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,13 +1,14 @@ PKG_CHECK_MODULES(CERT_CHECKER_DEP REQUIRED + capi-appfw-application cert-svc-vcore dbus-1 dbus-glib-1 db-util + elementary glib-2.0 gio-2.0 icu-i18n - notification key-manager libsystemd-journal libtzplatform-config @@ -31,6 +32,7 @@ SET(CERT_CHECKER_SOURCES ${CERT_CHECKER_SRC_PATH}/dpl/core/src/exception.cpp ${CERT_CHECKER_SRC_PATH}/dpl/core/src/noncopyable.cpp ${CERT_CHECKER_SRC_PATH}/dpl/core/src/string.cpp + ${CERT_CHECKER_SRC_PATH}/dpl/core/src/serialization.cpp # dpl DB ${CERT_CHECKER_SRC_PATH}/dpl/db/src/sql_connection.cpp ${CERT_CHECKER_SRC_PATH}/dpl/db/src/naive_synchronization_object.cpp @@ -38,6 +40,7 @@ SET(CERT_CHECKER_SOURCES ${CERT_CHECKER_SRC_PATH}/db/sql_query.cpp # UI ${CERT_CHECKER_SRC_PATH}/ui/UIBackend.cpp + ${CERT_CHECKER_SRC_PATH}/ui/popup-runner.cpp ) INCLUDE_DIRECTORIES(SYSTEM @@ -49,10 +52,17 @@ INCLUDE_DIRECTORIES(SYSTEM ADD_EXECUTABLE(${TARGET_CERT_CHECKER} ${CERT_CHECKER_SOURCES}) +SET_TARGET_PROPERTIES(${TARGET_CERT_CHECKER} PROPERTIES + COMPILE_FLAGS + -fpie +) + TARGET_LINK_LIBRARIES(${TARGET_CERT_CHECKER} ${CERT_CHECKER_DEP_LIBRARIES} + -pie ) INSTALL(TARGETS ${TARGET_CERT_CHECKER} DESTINATION ${BINDIR}) ADD_SUBDIRECTORY(po) +ADD_SUBDIRECTORY(ui) diff --git a/src/dpl/core/include/cchecker/dpl/serialization.h b/src/dpl/core/include/cchecker/dpl/serialization.h new file mode 100644 index 0000000..5628350 --- /dev/null +++ b/src/dpl/core/include/cchecker/dpl/serialization.h @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2011-2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file serialization.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Interfaces and templates used for data serialization. + */ +#ifndef CCHECKER_SERIALIZATION_H +#define CCHECKER_SERIALIZATION_H + +#include <stdint.h> + +#include <string> +#include <vector> +#include <list> +#include <map> +#include <memory> + +namespace CCHECKER { +// Abstract data stream buffer +class IStream +{ + public: + virtual void Read(size_t num, void * bytes) = 0; + virtual void Write(size_t num, const void * bytes) = 0; + virtual ~IStream(){} +}; + +// Serializable interface +class ISerializable +{ + public: + /* ISerializable(){}; + * ISerializable(IStream&){}; */ + virtual void Serialize(IStream &) const = 0; + virtual ~ISerializable(){} +}; + +struct Serialization { + // serialization + // normal functions + + // ISerializable objects + static void Serialize(IStream& stream, const ISerializable& object) + { + object.Serialize(stream); + } + + static void Serialize(IStream& stream, const ISerializable* const object) + { + object->Serialize(stream); + } + + // char + static void Serialize(IStream& stream, const char value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const char* const value) + { + stream.Write(sizeof(*value), value); + } + + // unsigned char + static void Serialize(IStream& stream, const unsigned char value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const unsigned char* const value) + { + stream.Write(sizeof(*value), value); + } + + // unsigned int32 + static void Serialize(IStream& stream, const uint32_t value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const uint32_t* const value) + { + stream.Write(sizeof(*value), value); + } + + // int32 + static void Serialize(IStream& stream, const int32_t value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const int32_t* const value) + { + stream.Write(sizeof(*value), value); + } + + // unsigned int64 + static void Serialize(IStream& stream, const uint64_t value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const uint64_t* const value) + { + stream.Write(sizeof(*value), value); + } + + // int64 + static void Serialize(IStream& stream, const int64_t value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const int64_t* const value) + { + stream.Write(sizeof(*value), value); + } + + // bool + static void Serialize(IStream& stream, const bool value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const bool* const value) + { + stream.Write(sizeof(*value), value); + } + + // std::string + template <typename T, typename R, typename A> + static void Serialize(IStream& stream, const std::basic_string<T,R,A>& str) + { + int length = str.size(); + stream.Write(sizeof(length), &length); + stream.Write(length*sizeof(T), str.data()); + } + + template<typename T, typename R, typename A> + static void Serialize(IStream& stream, const std::basic_string<T,R,A>* const str) + { + int length = str->size(); + stream.Write(sizeof(length), &length); + stream.Write(length*sizeof(T), str->data()); + } + + // STL templates + + // std::list + template <typename T> + static void Serialize(IStream& stream, const std::list<T>& list) + { + int length = list.size(); + stream.Write(sizeof(length), &length); + for (typename std::list<T>::const_iterator list_iter = list.begin(); + list_iter != list.end(); list_iter++) + { + Serialize(stream, *list_iter); + } + } + template <typename T> + static void Serialize(IStream& stream, const std::list<T>* const list) + { + Serialize(stream, *list); + } + + // RawBuffer + template <typename A> + static void Serialize(IStream& stream, const std::vector<unsigned char, A>& vec) + { + int length = vec.size(); + stream.Write(sizeof(length), &length); + stream.Write(length, vec.data()); + } + + template <typename A> + static void Serialize(IStream& stream, const std::vector<unsigned char, A>* const vec) + { + Serialize(stream, *vec); + } + + // std::vector + template <typename T, typename A> + static void Serialize(IStream& stream, const std::vector<T, A>& vec) + { + int length = vec.size(); + stream.Write(sizeof(length), &length); + for (const auto &i : vec) + { + Serialize(stream, i); + } + } + template <typename T, typename A> + static void Serialize(IStream& stream, const std::vector<T, A>* const vec) + { + Serialize(stream, *vec); + } + + // std::pair + template <typename A, typename B> + static void Serialize(IStream& stream, const std::pair<A, B>& p) + { + Serialize(stream, p.first); + Serialize(stream, p.second); + } + template <typename A, typename B> + static void Serialize(IStream& stream, const std::pair<A, B>* const p) + { + Serialize(stream, *p); + } + + // std::map + template <typename K, typename T> + static void Serialize(IStream& stream, const std::map<K, T>& map) + { + int length = map.size(); + stream.Write(sizeof(length), &length); + typename std::map<K, T>::const_iterator it; + for (it = map.begin(); it != map.end(); ++it) { + Serialize(stream, (*it).first); + Serialize(stream, (*it).second); + } + } + template <typename K, typename T> + static void Serialize(IStream& stream, const std::map<K, T>* const map) + { + Serialize(stream, *map); + } + + // std::unique_ptr + template <typename T> + static void Serialize(IStream& stream, const std::unique_ptr<T>& p) + { + Serialize(stream, *p); + } + +}; // struct Serialization + +struct Deserialization { + // deserialization + // normal functions + + // ISerializable objects + // T instead of ISerializable is needed to call proper constructor + template <typename T> + static void Deserialize(IStream& stream, T& object) + { + object = T(stream); + } + template <typename T> + static void Deserialize(IStream& stream, T*& object) + { + object = new T(stream); + } + + // char + static void Deserialize(IStream& stream, char& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, char*& value) + { + value = new char; + stream.Read(sizeof(*value), value); + } + + // unsigned char + static void Deserialize(IStream& stream, unsigned char& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, unsigned char*& value) + { + value = new unsigned char; + stream.Read(sizeof(*value), value); + } + + // unsigned int32 + static void Deserialize(IStream& stream, uint32_t& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, uint32_t*& value) + { + value = new uint32_t; + stream.Read(sizeof(*value), value); + } + + // int32 + static void Deserialize(IStream& stream, int32_t& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, int32_t*& value) + { + value = new int32_t; + stream.Read(sizeof(*value), value); + } + + // unsigned int64 + static void Deserialize(IStream& stream, uint64_t& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, uint64_t*& value) + { + value = new uint64_t; + stream.Read(sizeof(*value), value); + } + + // int64 + static void Deserialize(IStream& stream, int64_t& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, int64_t*& value) + { + value = new int64_t; + stream.Read(sizeof(*value), value); + } + + // bool + static void Deserialize(IStream& stream, bool& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, bool*& value) + { + value = new bool; + stream.Read(sizeof(*value), value); + } + + template <typename T, typename R, typename A> + static void Deserialize(IStream& stream, std::basic_string<T,R,A>& str) + { + int length; + stream.Read(sizeof(length), &length); + std::vector<T> buf(length); + stream.Read(length*sizeof(T), buf.data()); + str = std::basic_string<T,R,A>(buf.data(), buf.data()+length); + } + + template <typename T, typename R, typename A> + static void Deserialize(IStream& stream, std::basic_string<T,R,A>*& str) + { + int length; + stream.Read(sizeof(length), &length); + std::vector<T> buf(length); + stream.Read(length*sizeof(T), buf.data()); + str = new std::basic_string<T,R,A>(buf.data(), buf.data()+length); + } + + // STL templates + + // std::list + template <typename T> + static void Deserialize(IStream& stream, std::list<T>& list) + { + int length; + stream.Read(sizeof(length), &length); + for (int i = 0; i < length; ++i) { + T obj; + Deserialize(stream, obj); + list.push_back(std::move(obj)); + } + } + template <typename T> + static void Deserialize(IStream& stream, std::list<T>*& list) + { + list = new std::list<T>; + Deserialize(stream, *list); + } + + // RawBuffer + template <typename A> + static void Deserialize(IStream& stream, std::vector<unsigned char, A>& vec) + { + int length; + stream.Read(sizeof(length), &length); + vec.resize(length); + stream.Read(length, vec.data()); + } + + template <typename A> + static void Deserialize(IStream& stream, std::vector<unsigned char, A>*& vec) + { + vec = new std::vector<unsigned char,A>; + Deserialize(stream, *vec); + } + + // std::vector + template <typename T, typename A> + static void Deserialize(IStream& stream, std::vector<T,A>& vec) + { + int length; + stream.Read(sizeof(length), &length); + for (int i = 0; i < length; ++i) { + T obj; + Deserialize(stream, obj); + vec.push_back(std::move(obj)); + } + } + template <typename T, typename A> + static void Deserialize(IStream& stream, std::vector<T,A>*& vec) + { + vec = new std::vector<T,A>; + Deserialize(stream, *vec); + } + + // std::pair + template <typename A, typename B> + static void Deserialize(IStream& stream, std::pair<A, B>& p) + { + Deserialize(stream, p.first); + Deserialize(stream, p.second); + } + template <typename A, typename B> + static void Deserialize(IStream& stream, std::pair<A, B>*& p) + { + p = new std::pair<A, B>; + Deserialize(stream, *p); + } + + // std::map + template <typename K, typename T> + static void Deserialize(IStream& stream, std::map<K, T>& map) + { + int length; + stream.Read(sizeof(length), &length); + for (int i = 0; i < length; ++i) { + K key; + T obj; + Deserialize(stream, key); + Deserialize(stream, obj); + map[key] = std::move(obj); + } + } + template <typename K, typename T> + static void Deserialize(IStream& stream, std::map<K, T>*& map) + { + map = new std::map<K, T>; + Deserialize(stream, *map); + } +}; // struct Deserialization + +// generic serialization +template <typename... Args> +struct Serializer; + +template <typename First, typename... Args> +struct Serializer<First, Args...> : public Serializer<Args...> { + static void Serialize(IStream& stream, const First& f, const Args&... args) { + Serialization::Serialize(stream, f); + Serializer<Args...>::Serialize(stream, args...); + } +}; + +// end of recursion +template <> +struct Serializer<> { + static void Serialize(IStream&) { + return; + } +}; + +// generic deserialization +template <typename... Args> +struct Deserializer; + +template <typename First, typename... Args> +struct Deserializer<First, Args...> : public Deserializer<Args...> { + static void Deserialize(IStream& stream, First& f, Args&... args) { + Deserialization::Deserialize(stream, f); + Deserializer<Args...>::Deserialize(stream, args...); + } +}; + +// end of recursion +template <> +struct Deserializer<> { + static void Deserialize(IStream&) { + return; + } +}; + +} // CCHECKER + +#endif // CCHECKER_SERIALIZATION_H diff --git a/src/dpl/core/src/serialization.cpp b/src/dpl/core/src/serialization.cpp new file mode 100644 index 0000000..e7dbba7 --- /dev/null +++ b/src/dpl/core/src/serialization.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file serialization.cpp + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of data serialization. + */ +#include <stddef.h> +#include <cchecker/dpl/serialization.h> + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/src/include/cchecker/UIBackend.h b/src/include/cchecker/UIBackend.h index e59f0d7..6133078 100644 --- a/src/include/cchecker/UIBackend.h +++ b/src/include/cchecker/UIBackend.h @@ -21,24 +21,25 @@ #pragma once -#include <notification.h> - #include <cchecker/app.h> namespace CCHECKER { namespace UI { -enum response_e { - DONT_UNINSTALL, - UNINSTALL, - ERROR +enum popup_status : int { + NO_ERROR = 0, + EXIT_ERROR = 1 }; -// FIXME: notification framework is corrupted and it doesn't work as it should +enum response_e : int { + DONT_UNINSTALL = 2, + UNINSTALL = 3, + RESPONSE_ERROR = 4 +}; class UIBackend { public: - explicit UIBackend(int timeout = 60); //timeout in seconds + explicit UIBackend(int timeout = 60); //timeout in seconds (zero or less means infinity) virtual ~UIBackend(); // Displays popup with question, and - if needed - app_control for removing application. @@ -48,10 +49,8 @@ public: bool call_popup(const app_t &app); private: - response_e run(); - bool create_ui(const std::string &app_id, const std::string &pkg_id); + response_e run(const app_t &app); - notification_h m_notification; const int m_responseTimeout; // seconds }; diff --git a/src/include/cchecker/popup-runner.h b/src/include/cchecker/popup-runner.h new file mode 100644 index 0000000..addaa3b --- /dev/null +++ b/src/include/cchecker/popup-runner.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file popup-runner.h + * @author Janusz Kozerski (j.kozerski@samsung.com) + * @version 1.0 + */ + +#include <vector> + +#include <cchecker/dpl/serialization.h> + +namespace CCHECKER{ +namespace UI{ + +class BinaryStream : public CCHECKER::IStream { + public: + void Read (size_t num, void * bytes); + void Write(size_t num, const void * bytes); + + BinaryStream(); + ~BinaryStream(); + + const unsigned char* char_pointer() const; + size_t size() const; + + private: + std::vector<unsigned char> m_data; + size_t m_readPosition; +}; + +response_e run_popup( + const app_t &app, + int timeout); // zero or negative timeout means infinity + +} // UI +} // CCHECKER diff --git a/src/logic.cpp b/src/logic.cpp index 170f566..346a19c 100644 --- a/src/logic.cpp +++ b/src/logic.cpp @@ -21,7 +21,6 @@ */ #include <stdexcept> #include <tzplatform_config.h> -#include <app_control_internal.h> #include <cchecker/logic.h> #include <cchecker/log.h> @@ -429,7 +428,6 @@ bool Logic::process_app(app_t& app) { app.verified = app_t::verified_t::NO; #if POPUP // Do not remove app here - just waits for user answer from popup -// Temporary solution because notification framework doesn't work return call_ui(app); #else return true; diff --git a/src/po/CMakeLists.txt b/src/po/CMakeLists.txt index 3cb076f..b89f4cb 100644 --- a/src/po/CMakeLists.txt +++ b/src/po/CMakeLists.txt @@ -17,7 +17,7 @@ # SET(POFILES - en.po pl.po + en.po en_GB.po en_US.po pl.po ) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) diff --git a/src/po/en_GB.po b/src/po/en_GB.po new file mode 100644 index 0000000..764b151 --- /dev/null +++ b/src/po/en_GB.po @@ -0,0 +1,14 @@ +msgid "SID_TITLE_OCSP_VERIFICATION_FAILED" +msgstr "OCSP verification failed" + +msgid "SID_CONTENT_OCSP_VERIFICATION_FAILED" +msgstr "A certificate of an application %s (%s) was revoked." + +msgid "SID_CONTENT_OCSP_PACKAGE VERIFICATION_FAILED" +msgstr "A certificate of one of applications in package %s was revoked." + +msgid "SID_BTN_OCSP_KEEP_APP" +msgstr "Keep" + +msgid "SID_BTN_OCSP_UNINSTALL_APP" +msgstr "Uninstall" diff --git a/src/po/en_US.po b/src/po/en_US.po new file mode 100644 index 0000000..764b151 --- /dev/null +++ b/src/po/en_US.po @@ -0,0 +1,14 @@ +msgid "SID_TITLE_OCSP_VERIFICATION_FAILED" +msgstr "OCSP verification failed" + +msgid "SID_CONTENT_OCSP_VERIFICATION_FAILED" +msgstr "A certificate of an application %s (%s) was revoked." + +msgid "SID_CONTENT_OCSP_PACKAGE VERIFICATION_FAILED" +msgstr "A certificate of one of applications in package %s was revoked." + +msgid "SID_BTN_OCSP_KEEP_APP" +msgstr "Keep" + +msgid "SID_BTN_OCSP_UNINSTALL_APP" +msgstr "Uninstall" diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt new file mode 100644 index 0000000..4a31011 --- /dev/null +++ b/src/ui/CMakeLists.txt @@ -0,0 +1 @@ +ADD_SUBDIRECTORY(popup-bin)
\ No newline at end of file diff --git a/src/ui/UIBackend.cpp b/src/ui/UIBackend.cpp index 5fd33a4..accac7c 100644 --- a/src/ui/UIBackend.cpp +++ b/src/ui/UIBackend.cpp @@ -19,185 +19,38 @@ * @brief This file implements class for ask user window */ -#include <bundle.h> -#include <cerrno> -#include <csignal> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <string> -#include <libintl.h> -#include <notification_internal.h> -#include <notification_error.h> -#include <app_control_internal.h> +#include <app_control.h> #include <cchecker/log.h> #include <cchecker/UIBackend.h> +#include <cchecker/popup-runner.h> namespace CCHECKER { namespace UI { -namespace { // anonymus -const char *errorToString(int error) { - if (error == NOTIFICATION_ERROR_INVALID_PARAMETER) - return "NOTIFICATION_ERROR_INVALID_PARAMETER"; - if (error == NOTIFICATION_ERROR_OUT_OF_MEMORY) - return "NOTIFICATION_ERROR_OUT_OF_MEMORY"; - if (error == NOTIFICATION_ERROR_FROM_DB) - return "NOTIFICATION_ERROR_FROM_DB"; - if (error == NOTIFICATION_ERROR_ALREADY_EXIST_ID) - return "NOTIFICATION_ERROR_ALREADY_EXIST_ID"; - if (error == NOTIFICATION_ERROR_FROM_DBUS) - return "NOTIFICATION_ERROR_FROM_DBUS"; - if (error == NOTIFICATION_ERROR_NOT_EXIST_ID) - return "NOTIFICATION_ERROR_NOT_EXIST_ID"; - if (error == NOTIFICATION_ERROR_IO_ERROR) - return "NOTIFICATION_ERROR_IO_ERROR"; - if (error == NOTIFICATION_ERROR_SERVICE_NOT_READY) - return "NOTIFICATION_ERROR_SERVICE_NOT_READY"; - if (error == NOTIFICATION_ERROR_NONE) - return "NOTIFICATION_ERROR_NONE"; - - return "UNHANDLED ERROR"; -} -} // anonymus - UIBackend::UIBackend(int timeout) : - m_notification(nullptr), m_responseTimeout(timeout) {} -UIBackend::~UIBackend() { - notification_free(m_notification); -} - -bool UIBackend::create_ui(const std::string &app_id, const std::string &pkg_id) -{ - if(m_notification) { - notification_free(m_notification); - m_notification = nullptr; - } - - m_notification = notification_create(NOTIFICATION_TYPE_NOTI); - if (m_notification == nullptr) { - LogError("Failed to create notification."); - return false; - } - - int err = notification_set_pkgname(m_notification, "cert-checker"); - if (err != NOTIFICATION_ERROR_NONE) { - LogError("Unable to set notification pkgname: <" << errorToString(err) << ">"); - return false; - } - - // Set title - char *dialogTitle = dgettext(PROJECT_NAME, "SID_TITLE_OCSP_VERIFICATION_FAILED"); - err = notification_set_text(m_notification, NOTIFICATION_TEXT_TYPE_TITLE, dialogTitle, nullptr, - NOTIFICATION_VARIABLE_TYPE_NONE); - if (err != NOTIFICATION_ERROR_NONE) { - LogError("Unable to set notification title: <" << errorToString(err) << ">"); - return false; - } - - // Set message - // App ID may be absent, so in that case we need to use only package ID - if (app_id == std::string(TEMP_APP_ID)) { - char *content = dgettext(PROJECT_NAME, "SID_CONTENT_OCSP_PACKAGE VERIFICATION_FAILED"); - err = notification_set_text(m_notification, NOTIFICATION_TEXT_TYPE_CONTENT, content, nullptr, - NOTIFICATION_VARIABLE_TYPE_STRING, pkg_id.c_str(), - NOTIFICATION_VARIABLE_TYPE_NONE); - } - else { - char *content = dgettext(PROJECT_NAME, "SID_CONTENT_OCSP_VERIFICATION_FAILED"); - err = notification_set_text(m_notification, NOTIFICATION_TEXT_TYPE_CONTENT, content, nullptr, - NOTIFICATION_VARIABLE_TYPE_STRING, app_id.c_str(), - NOTIFICATION_VARIABLE_TYPE_STRING, pkg_id.c_str(), - NOTIFICATION_VARIABLE_TYPE_NONE); - } - if (err != NOTIFICATION_ERROR_NONE) { - LogError("Unable to set notification content: <" << errorToString(err) << ">"); - return false; - } - - char *btn_keep = dgettext(PROJECT_NAME, "SID_BTN_OCSP_KEEP_APP"); - char *btn_uninstall = dgettext(PROJECT_NAME, "SID_BTN_OCSP_UNINSTALL_APP"); - - std::string buttons = std::string(btn_keep) + std::string(",") + std::string(btn_uninstall); - - bundle *b = bundle_create(); - if (!b) { - int erryes = errno; - LogError("Unable to create bundle: <" << strerror(erryes) << ">"); - return false; - } - - if (bundle_add(b, "buttons", buttons.c_str())) { - int erryes = errno; - LogError("Unable to add button to bundle: <" << strerror(erryes) << ">"); - bundle_free(b); - return false; - } - - err = notification_set_execute_option(m_notification, NOTIFICATION_EXECUTE_TYPE_RESPONDING, - nullptr, nullptr, b); - if (err != NOTIFICATION_ERROR_NONE) { - LogError("Unable to set execute option: <" << errorToString(err) << ">"); - bundle_free(b); - return false; - } - bundle_free(b); - - err = notification_insert(m_notification, nullptr); - if (err != NOTIFICATION_ERROR_NONE) { - LogError("Unable to insert notification: <" << errorToString(err) << ">"); - return false; - } - - return true; -} +UIBackend::~UIBackend() +{} -response_e UIBackend::run() +response_e UIBackend::run(const app_t &app) { - response_e response = response_e(ERROR); - try { - int buttonClicked = 0; - int ret = notification_wait_response(m_notification, m_responseTimeout, - &buttonClicked, nullptr); - LogDebug("notification_wait_response finished with ret code: [" << ret << "]"); - - if (ret == NOTIFICATION_ERROR_NONE) { - // FIXME: magic numbers - if (buttonClicked == 1) { - response = response_e(DONT_UNINSTALL); - LogDebug("notification_wait_response, button clicked: DON'T UNINSTALL"); - } else if (buttonClicked == 2) { - response = response_e(UNINSTALL); - LogDebug("notification_wait_response, Button clicked: UNINSTALL"); - } else { - response = response_e(ERROR); - LogError("notification_wait_response, timeouted"); - } - } - } catch (const std::exception &e) { - LogError("Unexpected exception: <" << e.what() << ">"); - } catch (...) { - LogError("Unexpected unknown exception caught!"); - } - return response; + return run_popup(app, m_responseTimeout); } bool UIBackend::call_popup(const app_t &app) { response_e resp; - create_ui(app.app_id, app.pkg_id); - resp = run(); + resp = run(app); LogDebug(app.str() << " response: " << resp); - if (resp == ERROR) { + if (resp == response_e::RESPONSE_ERROR) { return false; } - else if (resp == UNINSTALL) { + else if (resp == response_e::UNINSTALL) { app_control_h service = NULL; int result = 0; result = app_control_create(&service); diff --git a/src/ui/popup-bin/CMakeLists.txt b/src/ui/popup-bin/CMakeLists.txt new file mode 100644 index 0000000..a8bddfa --- /dev/null +++ b/src/ui/popup-bin/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file CMakeLists.txt +# @author Janusz Kozerski (j.kozerski@samsung.com) +# +# @version 1.0 +# + +PKG_CHECK_MODULES(CERT_CHECKER_POPUP_DEP + elementary + libsystemd-journal + REQUIRED) + +set(CERT_CHECKER_POPUP_SRC_DIR ${PROJECT_SOURCE_DIR}/src/ui/popup-bin) + +set(CERT_CHECKER_POPUP_SOURCES + ${CERT_CHECKER_POPUP_SRC_DIR}/popup.cpp + ${CERT_CHECKER_SRC_PATH}/ui/popup-runner.cpp + ${CERT_CHECKER_SRC_PATH}/app.cpp + # logs + ${CERT_CHECKER_SRC_PATH}/log/log.cpp + # dpl + ${CERT_CHECKER_SRC_PATH}/dpl/core/src/serialization.cpp +) + +ADD_DEFINITIONS(${CERT_CHECKER_POPUP_DEP_CFLAGS}) + +INCLUDE_DIRECTORIES( + ${CERT_CHECKER_POPUP_SRC_DIR} + ${CERT_CHECKER_POPUP_DEP_INCLUDE_DIRS} + ${CERT_CHECKER_SRC_PATH}/include/ +) + +ADD_EXECUTABLE(${TARGET_CERT_CHECKER_POPUP} + ${CERT_CHECKER_POPUP_SOURCES} +) + +SET_TARGET_PROPERTIES(${TARGET_CERT_CHECKER_POPUP} PROPERTIES + COMPILE_FLAGS + -fpie +) + +TARGET_LINK_LIBRARIES(${TARGET_CERT_CHECKER_POPUP} + ${CERT_CHECKER_POPUP_DEP_LIBRARIES} + -pie +) + +INSTALL(TARGETS ${TARGET_CERT_CHECKER_POPUP} DESTINATION ${BINDIR}) diff --git a/src/ui/popup-bin/popup.cpp b/src/ui/popup-bin/popup.cpp new file mode 100644 index 0000000..6b3032a --- /dev/null +++ b/src/ui/popup-bin/popup.cpp @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file popup.cpp + * @author Janusz Kozerski (j.kozerski@samsung.com) + * @version 1.0 + */ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <vector> +#include <libintl.h> +#include <sys/select.h> +#include <time.h> + +#include <Elementary.h> + +#include <popup.h> +#include <cchecker/log.h> +#include <cchecker/UIBackend.h> +#include <cchecker/popup-runner.h> +#include <cchecker/dpl/serialization.h> + +using namespace CCHECKER::UI; + +namespace { // anonymous + +void on_done(void) { + // Quit the efl-mainloop + LogDebug("elm_exit()"); + elm_exit(); +} + +void keep_answer(void *data, Evas_Object * /* obj */, void * /* event_info */) { + + LogDebug("keep_answer"); + if(NULL == data){ + LogError("data is NULL; return"); + return; + } + struct cert_checker_popup_data *pdp = static_cast <struct cert_checker_popup_data *> (data); + pdp->result = response_e::DONT_UNINSTALL; + + on_done(); +} + +void uninstall_answer(void *data, Evas_Object * /* obj */, void * /* event_info */) { + + LogDebug("uninstall_answer"); + if(NULL == data){ + LogError("data is NULL; return"); + return; + } + struct cert_checker_popup_data *pdp = static_cast <struct cert_checker_popup_data *> (data); + pdp->result = response_e::UNINSTALL; + + on_done(); +} + +void show_popup(struct cert_checker_popup_data *pdp) { + LogDebug("show_popup()"); + + if(NULL == pdp){ + LogError("pdp is NULL; return"); + return; + } + + pdp->win = elm_win_add(NULL, + dgettext(PROJECT_NAME, "SID_TITLE_OCSP_VERIFICATION_FAILED"), + ELM_WIN_NOTIFICATION); + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + elm_win_autodel_set(pdp->win, EINA_TRUE); + evas_object_show(pdp->win); + elm_win_indicator_opacity_set(pdp->win, ELM_WIN_INDICATOR_TRANSLUCENT); + + pdp->popup = elm_popup_add(pdp->win); + + pdp->box = elm_box_add(pdp->popup); + evas_object_size_hint_weight_set(pdp->box, EVAS_HINT_EXPAND, 0); + evas_object_size_hint_align_set(pdp->box, EVAS_HINT_FILL, 0.0); + + pdp->title = elm_label_add(pdp->popup); + elm_object_style_set(pdp->title, "elm.text.title"); + elm_object_text_set(pdp->title, dgettext(PROJECT_NAME, "SID_TITLE_OCSP_VERIFICATION_FAILED")); + evas_object_show(pdp->title); + elm_box_pack_end(pdp->box, pdp->title); + + pdp->content = elm_label_add(pdp->popup); + elm_object_style_set(pdp->content, "elm.swallow.content"); + elm_label_line_wrap_set(pdp->content, ELM_WRAP_MIXED); + + char *buff = NULL; + int ret; + + // Set message + // App ID may be absent, so in that case we need to use only package ID + if (pdp->app_id == std::string(CCHECKER::TEMP_APP_ID)) { + char *content = dgettext(PROJECT_NAME, "SID_CONTENT_OCSP_PACKAGE VERIFICATION_FAILED"); + ret = asprintf(&buff, content, pdp->pkg_id.c_str()); + } + else { + char *content = dgettext(PROJECT_NAME, "SID_CONTENT_OCSP_VERIFICATION_FAILED"); + ret = asprintf(&buff, content, pdp->app_id.c_str(), pdp->pkg_id.c_str()); + } + + if(-1 == ret){ + LogError("asprintf failed - returned -1"); + evas_object_del(pdp->content); + evas_object_del(pdp->popup); + evas_object_del(pdp->win); + return; + } + elm_object_text_set(pdp->content, buff); + LogDebug("Popup label: " << buff); + free(buff); + evas_object_size_hint_weight_set(pdp->content, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(pdp->content, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(pdp->content); + elm_box_pack_end(pdp->box, pdp->content); + + elm_object_part_content_set(pdp->popup, "default", pdp->box); + + pdp->keep_button = elm_button_add(pdp->popup); + elm_object_style_set(pdp->keep_button, "elm.swallow.content.button1"); + elm_object_text_set(pdp->keep_button, dgettext(PROJECT_NAME, "SID_BTN_OCSP_KEEP_APP")); + elm_object_part_content_set(pdp->popup, "button1", pdp->keep_button); + evas_object_smart_callback_add(pdp->keep_button, "clicked", keep_answer, pdp); + + pdp->uninstall_button = elm_button_add(pdp->popup); + elm_object_style_set(pdp->uninstall_button, "elm.swallow.content.button2"); + elm_object_text_set(pdp->uninstall_button, dgettext(PROJECT_NAME, "SID_BTN_OCSP_UNINSTALL_APP")); + elm_object_part_content_set(pdp->popup, "button2 ", pdp->uninstall_button); + evas_object_smart_callback_add(pdp->uninstall_button, "clicked", uninstall_answer, pdp); + + evas_object_show(pdp->popup); + + // Showing the popup window + evas_object_show(pdp->win); + + // Run the efl mainloop + elm_run(); + + // Shutdown elementary + LogDebug("elm_shutdown()"); + elm_shutdown(); +} + +static int wait_for_parent_info (int pipe_in) +{ + // wait for parameters from pipe_in + // timeout is set for 10 seconds + struct timeval timeout = {10L, 0L}; + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(pipe_in, &readfds); + + int sel = select(pipe_in + 1, &readfds, NULL, NULL, &timeout); + if (sel == -1) { + LogError("Cannot get info from parent. Exit popup - ERROR (" << errno << ")"); + close(pipe_in); + return -1; + } + else if (sel == 0) { + LogError("Timeout reached! Exit popup - ERROR"); + close(pipe_in); + return -1; + } + return 0; +} + +void deserialize (cert_checker_popup_data *pdp, char *line, ssize_t line_length) +{ + BinaryStream stream; + stream.Write(line_length, static_cast <void *> (line)); + + std::string app_id; + std::string pkg_id; + + LogDebug("------- Deserialization -------"); + // Deserialization order: + // app_id, pkg_id + + CCHECKER::Deserialization::Deserialize(stream, app_id); + LogDebug("app_id : " << app_id.c_str()); + pdp->app_id = app_id.c_str(); + + CCHECKER::Deserialization::Deserialize(stream, pkg_id); + LogDebug("pkg_id : " << pkg_id.c_str()); + pdp->pkg_id = pkg_id.c_str(); +} + +} // anonymous + +EAPI_MAIN int +elm_main(int argc, char **argv) +{ + // int pipe_in and int pipe_out should be passed to Popup via args. + + // These parameters should be passed to Popup via pipe_in: + // std::string app_id + // std::string pkg_id + + struct cert_checker_popup_data pd; + struct cert_checker_popup_data *pdp = &pd; + + LogDebug("############################ popup binary ################################"); + + setlocale(LC_ALL, ""); + + if(argc < 3){ + LogError("To few args passed in exec to popup-bin - should be at least 3:"); + LogError("(binary-name, pipe_in, pipe_out)"); + LogError("return ERROR"); + return popup_status::EXIT_ERROR; + } + + LogDebug("Passed args: " << argv[0] <<", " << argv[1] << ", " << argv[2]); + + int pipe_in; + int pipe_out; + + // Parsing args (pipe_in, pipe_out) + if ( 0 == sscanf(argv[1], "%d", &pipe_in) ){ + LogError("Error while parsing pipe_in; return ERROR"); + return popup_status::EXIT_ERROR; + } + if ( 0 == sscanf(argv[2], "%d", &pipe_out) ){ + LogError("Error while parsing pipe_out; return ERROR"); + return popup_status::EXIT_ERROR; + } + LogDebug("Parsed pipes: IN: " << pipe_in <<", OUT: " << pipe_out); + + if (wait_for_parent_info(pipe_in) == -1) { + close(pipe_out); + return popup_status::EXIT_ERROR; + } + + int buff_size = 1024; + char line[buff_size]; + + ssize_t count = 0; + + do { + count = TEMP_FAILURE_RETRY(read(pipe_in, line, buff_size)); + } while (0 == count); + if(count < 0){ + close(pipe_in); + close(pipe_out); + LogError("read returned a negative value (" << count <<")"); + LogError("errno: " << strerror( errno ) ); + LogError("Exit popup - ERROR"); + return popup_status::EXIT_ERROR; + } + LogDebug("Read bytes : " << count); + close(pipe_in); // cleanup + + deserialize(pdp, line, count); + + pdp->result = response_e::RESPONSE_ERROR; + + show_popup(pdp); // Showing popup + + // sending validation_result to popup-runner + BinaryStream stream_out; + + LogDebug("pdp->result : " << pdp->result); + CCHECKER::Serialization::Serialize(stream_out, pdp->result); + if(-1 == TEMP_FAILURE_RETRY(write(pipe_out, stream_out.char_pointer(), stream_out.size()))){ + LogError("Write to pipe failed!"); + close(pipe_out); + return popup_status::EXIT_ERROR; + } + + close(pipe_out); + + LogDebug("############################ /popup binary ################################"); + LogDebug("Return: " << popup_status::NO_ERROR); + return popup_status::NO_ERROR; +} +ELM_MAIN() diff --git a/src/ui/popup-bin/popup.h b/src/ui/popup-bin/popup.h new file mode 100644 index 0000000..4a5d32a --- /dev/null +++ b/src/ui/popup-bin/popup.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file popup.h + * @author Janusz Kozerski (j.kozerski@samsung.com) + * @version 1.0 + */ + +#include <Elementary.h> + +#include <cchecker/UIBackend.h> + +struct cert_checker_popup_data { + std::string app_id; + std::string pkg_id; + CCHECKER::UI::response_e result; + + Evas_Object *popup = NULL; + Evas_Object *win = NULL; + Evas_Object *box = NULL; + Evas_Object *title = NULL; + Evas_Object *content = NULL; + Evas_Object *keep_button = NULL; + Evas_Object *uninstall_button = NULL; +}; diff --git a/src/ui/popup-runner.cpp b/src/ui/popup-runner.cpp new file mode 100644 index 0000000..6411558 --- /dev/null +++ b/src/ui/popup-runner.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file popup-runner.cpp + * @author Janusz Kozerski (j.kozerski@samsung.com) + * @version 1.0 + */ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <iostream> +#include <sstream> +#include <sys/types.h> +#include <sys/wait.h> + +#include <cchecker/app.h> +#include <cchecker/logic.h> +#include <cchecker/log.h> +#include <cchecker/UIBackend.h> +#include <cchecker/popup-runner.h> + +namespace { // anonymous + +using namespace CCHECKER::UI; + +const char *POPUP_EXEC = "/usr/bin/cert-checker-popup"; // check-checker-popup binary + +std::string response_to_str (response_e response) +{ + switch (response) { + case response_e::DONT_UNINSTALL: + return "DONT_UNINSTALL"; + case response_e::UNINSTALL: + return "UNINSTALL"; + default: + return "RESPONSE_ERROR"; + } +} + +int wait_for_popup (int popup_pid, int timeout) +{ + int status; + int ret; + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, NULL); + siginfo_t info; + struct timespec time = {timeout, 0L}; + + if (timeout > 0) + ret = TEMP_FAILURE_RETRY(sigtimedwait(&set, &info, &time)); + else + ret = TEMP_FAILURE_RETRY(sigwaitinfo(&set, &info)); + + sigprocmask(SIG_UNBLOCK, &set, NULL); + + if (ret == -1 && errno == EAGAIN) { + LogError("POPUP TIMEOUT"); + goto err; + } + else if (ret == SIGCHLD && info.si_pid == popup_pid) { + // call waitpid on the child process to get rid of zombie process + waitpid(popup_pid, NULL, 0); + + // The proper signal has been caught and its pid matches to popup_pid + // Now check the popup exit status + status = WEXITSTATUS(info.si_status); + LogDebug("STATUS EXIT ON POPUP (CHILD: " << info.si_pid << "): " << status); + + switch (static_cast<popup_status>(status)) { + + case popup_status::NO_ERROR: + LogDebug("NO_ERROR"); + return 0; + + case popup_status::EXIT_ERROR: + LogError("ERROR"); + return -1; + + default: // Unknown exit status + LogError("UNKNOWN_ERROR"); + return -1; + } + } + else { + LogError("Some other signal has been caught (pid: " << info.si_pid << ", signal: " << info.si_signo << ")"); + goto err; + } + +err: + // kill popup process and return error + kill(popup_pid, SIGKILL); + + // call waitpid on the child process to get rid of zombie process + waitpid(popup_pid, NULL, 0); + return -1; +} + +void child_process (int fd_send_to_child[2], int fd_send_to_parent[2]) +{ + LogDebug("Child"); + + // read data from parent + close(fd_send_to_child[1]); + + // send data to parent + close(fd_send_to_parent[0]); + + std::stringstream pipe_in_buff; + std::stringstream pipe_out_buff; + pipe_in_buff << fd_send_to_parent[1]; + pipe_out_buff << fd_send_to_child[0]; + std::string pipe_in = pipe_in_buff.str(); + std::string pipe_out = pipe_out_buff.str(); + + LogDebug("Passed file descriptors: " << fd_send_to_child[0] << ", "<< fd_send_to_parent[1]); + + if (execl(POPUP_EXEC, POPUP_EXEC, pipe_out.c_str(), pipe_in.c_str(), NULL) < 0){ + LogError("execl FAILED"); + } + + LogError("This should not happen!!!"); + _exit(response_e::RESPONSE_ERROR); +} + +int send_message_to_child(const BinaryStream &stream, int fd_send_to_child) +{ + LogDebug("Sending message to popup-bin process"); + unsigned int begin = 0; + int tmp; + while (begin < stream.size()) { + tmp = TEMP_FAILURE_RETRY(write(fd_send_to_child, + stream.char_pointer() + begin, + stream.size() - begin)); + if(-1 == tmp){ + LogError("Write to pipe failed!"); + return -1; + } + begin += tmp; + } + LogDebug("Message has been sent"); + return 0; +} + +response_e parse_response (int count, char *data) +{ + LogDebug("RESULT FROM POPUP PIPE (CHILD) : [ " << count << " ]"); + int response_int; + response_e response; + BinaryStream stream_in; + stream_in.Write(count, data); + CCHECKER::Deserialization::Deserialize(stream_in, response_int); + response = static_cast <response_e> (response_int); + LogDebug("response :" << response_to_str(response)); + return response; +} + +} // anonymous namespace + +namespace CCHECKER { +namespace UI { + +// BinaryStream class implementation +void BinaryStream::Read(size_t num, void * bytes) +{ + size_t max_size = m_data.size(); + for (size_t i = 0; i < num; ++i) { + if( i + m_readPosition >= max_size){ + return; + } + static_cast <unsigned char*> (bytes)[i] = m_data[i + m_readPosition]; + } + m_readPosition += num; +} + +void BinaryStream::Write(size_t num, const void * bytes) +{ + for (size_t i = 0; i < num; ++i) { + m_data.push_back(static_cast <const unsigned char*> (bytes)[i]); + } +} + +BinaryStream::BinaryStream() : + m_readPosition(0) +{} + +BinaryStream::~BinaryStream() {} + +const unsigned char* BinaryStream::char_pointer() const +{ + return &m_data[0]; +} + +size_t BinaryStream::size() const +{ + return m_data.size(); +} +// BinaryStream + +response_e run_popup( + const app_t &app, + int timeout) +{ + LogDebug(app.str()); + + // serialization + BinaryStream stream; + CCHECKER::Serialization::Serialize(stream, app.app_id); + CCHECKER::Serialization::Serialize(stream, app.pkg_id); + + int fd_send_to_child[2]; + int fd_send_to_parent[2]; + pid_t childpid; + + if(0 != pipe(fd_send_to_child)){ + LogError("Cannot create pipes!"); + return response_e::RESPONSE_ERROR; + } + if(0 != pipe(fd_send_to_parent)){ + LogError("Cannot create pipes!"); + close(fd_send_to_child[0]); + close(fd_send_to_child[1]); + return response_e::RESPONSE_ERROR; + } + + if ((childpid = fork()) == -1) { + LogError("Fork() ERROR"); + close(fd_send_to_child[0]); + close(fd_send_to_parent[1]); + goto error; + } + + if(childpid == 0) { // Child process + child_process (fd_send_to_child, fd_send_to_parent); + } + else { // Parent process + LogDebug("Parent (child pid: " << childpid << ")"); + + // send data to child + close(fd_send_to_child[0]); + + // read data from child + close(fd_send_to_parent[1]); + + // writing to child + if (send_message_to_child(stream, fd_send_to_child[1])) + goto error; + + // wait for child + if (wait_for_popup(childpid, timeout) != 0 ) + goto error; + + // Read message from popup (child) + int buff_size = 1024; + char result[buff_size]; + int count; + count = TEMP_FAILURE_RETRY(read(fd_send_to_parent[0], result, buff_size)); + + // Parsing response from child + response_e response; + if (0 < count) + response = parse_response(count, result); + else { + LogDebug("ERROR, count = " << count);; + goto error; + } + + LogDebug("popup-runner: EXIT SUCCESS"); + // cleanup + close(fd_send_to_parent[0]); + close(fd_send_to_child[1]); + return response; + } + + LogError("This should not happen!!!"); +error: + // cleanup + LogDebug("popup-runner: EXIT ERROR"); + close(fd_send_to_parent[0]); + close(fd_send_to_child[1]); + return response_e::RESPONSE_ERROR; +} + +} // UI +} // CCHECKER diff --git a/systemd/cert-checker.service b/systemd/cert-checker.service index 58529b9..ba5fad7 100644 --- a/systemd/cert-checker.service +++ b/systemd/cert-checker.service @@ -3,6 +3,9 @@ Description=Start the Cert-Checker Requires=dbus.service [Service] +EnvironmentFile=/etc/sysconfig/enlightenment +# Makes popup bigger +Environment="ELM_SCALE=4.0" Type=simple ExecStart=/usr/bin/cert-checker diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef836cd..511aeb9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,13 +1,14 @@ PKG_CHECK_MODULES(CERT_CHECKER_TESTS_DEP REQUIRED + capi-appfw-application cert-svc-vcore + db-util dbus-1 dbus-glib-1 - db-util + elementary glib-2.0 gio-2.0 icu-i18n - notification key-manager libsystemd-journal libtzplatform-config @@ -76,6 +77,7 @@ SET(CERT_CHECKER_POPUP_TEST_SOURCES ${CERT_CHECKER_TESTS_SRC_PATH}/popup_test.cpp # cert-checker ${CERT_CHECKER_SRC_PATH}/app.cpp + ${CERT_CHECKER_SRC_PATH}/ui/popup-runner.cpp ${CERT_CHECKER_SRC_PATH}/ui/UIBackend.cpp # logs ${CERT_CHECKER_SRC_PATH}/log/log.cpp diff --git a/tests/popup_test.cpp b/tests/popup_test.cpp index e2e1e3d..d08747e 100644 --- a/tests/popup_test.cpp +++ b/tests/popup_test.cpp @@ -25,13 +25,19 @@ using namespace CCHECKER; -int main(void) +int main(int argc, char** argv) { - LogDebug("Cert-checker start!"); + LogDebug("Cert-checker popup-test start!"); + + int timeout = 60; + if (argc > 1) { + timeout = atoi(argv[1]); + } + LogDebug("popup-test timeout: " << timeout); setlocale(LC_ALL, ""); - UI::UIBackend ui(20); // timeout 20 seconds + UI::UIBackend ui(timeout); app_t app(std::string("test_APP_ID"), std::string("test PKG ID"), @@ -40,6 +46,6 @@ int main(void) ui.call_popup(app); - LogDebug("Cert-checker exit!"); + LogDebug("Cert-checker popup-test exit!"); return 0; } diff --git a/tests/stubs_.cpp b/tests/stubs_.cpp index b475690..9eb8cfa 100644 --- a/tests/stubs_.cpp +++ b/tests/stubs_.cpp @@ -112,8 +112,7 @@ void DB::SqlQuery::get_app_list(std::list<app_t> &apps_buffer) // UI UI::UIBackend::UIBackend(int timeout) : - m_notification(nullptr), - m_responseTimeout(timeout) + m_responseTimeout(timeout) {} UI::UIBackend::~UIBackend() |