diff options
author | Janusz Kozerski <j.kozerski@samsung.com> | 2015-06-22 15:07:51 +0200 |
---|---|---|
committer | Janusz Kozerski <j.kozerski@samsung.com> | 2015-08-03 16:14:30 +0200 |
commit | a091055a43789a3fb3586dd364ba857765b685cc (patch) | |
tree | 639c9245f193556cd300529ef04eba1d484d0755 /src | |
parent | 6be76744f1e8a8291b410437867cd2c1ca9b576a (diff) | |
download | cert-checker-a091055a43789a3fb3586dd364ba857765b685cc.tar.gz cert-checker-a091055a43789a3fb3586dd364ba857765b685cc.tar.bz2 cert-checker-a091055a43789a3fb3586dd364ba857765b685cc.zip |
Add popup UI (+tests)
Notification framework currently doesn't work properly on tizen.org/common.
To test UI run: cert-checker-popup-test, and check if UI is displayed correctly.
Change-Id: I0eb9b134c77c82eb77b4834b81a1cd1fa19dd620
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/cert-checker.cpp | 1 | ||||
-rw-r--r-- | src/include/cchecker/UIBackend.h | 59 | ||||
-rw-r--r-- | src/include/cchecker/logic.h | 4 | ||||
-rw-r--r-- | src/logic.cpp | 47 | ||||
-rw-r--r-- | src/po/CMakeLists.txt | 44 | ||||
-rw-r--r-- | src/po/en.po | 14 | ||||
-rw-r--r-- | src/po/pl.po | 14 | ||||
-rw-r--r-- | src/ui/UIBackend.cpp | 218 |
9 files changed, 398 insertions, 7 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d5a56eb..e61cf4a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,8 @@ SET(CERT_CHECKER_SOURCES ${CERT_CHECKER_SRC_PATH}/dpl/db/src/naive_synchronization_object.cpp # DB ${CERT_CHECKER_SRC_PATH}/db/sql_query.cpp + # UI + ${CERT_CHECKER_SRC_PATH}/ui/UIBackend.cpp ) INCLUDE_DIRECTORIES(SYSTEM @@ -52,3 +54,5 @@ TARGET_LINK_LIBRARIES(${TARGET_CERT_CHECKER} ) INSTALL(TARGETS ${TARGET_CERT_CHECKER} DESTINATION ${BINDIR}) + +ADD_SUBDIRECTORY(po) diff --git a/src/cert-checker.cpp b/src/cert-checker.cpp index e754d94..c6e7537 100644 --- a/src/cert-checker.cpp +++ b/src/cert-checker.cpp @@ -31,6 +31,7 @@ int main(void) { LogDebug("Cert-checker start!"); + setlocale(LC_ALL, ""); GMainLoop *main_loop = g_main_loop_new(NULL, FALSE); Logic logic; diff --git a/src/include/cchecker/UIBackend.h b/src/include/cchecker/UIBackend.h new file mode 100644 index 0000000..e59f0d7 --- /dev/null +++ b/src/include/cchecker/UIBackend.h @@ -0,0 +1,59 @@ +/* + * 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 UIBackend.h + * @author Janusz Kozerski <j.kozerski@samsung.com> + * @brief This file declares class for ask user window + */ + +#pragma once + +#include <notification.h> + +#include <cchecker/app.h> + +namespace CCHECKER { +namespace UI { + +enum response_e { + DONT_UNINSTALL, + UNINSTALL, + ERROR +}; + +// FIXME: notification framework is corrupted and it doesn't work as it should + +class UIBackend { +public: + explicit UIBackend(int timeout = 60); //timeout in seconds + virtual ~UIBackend(); + + // Displays popup with question, and - if needed - app_control for removing application. + // Returns true if UI was displayed correctly and user's response was collected. + // If there was a problem with displaying UI or a timeout has been reached (no user's response) + // then returns false. + bool call_popup(const app_t &app); + +private: + response_e run(); + bool create_ui(const std::string &app_id, const std::string &pkg_id); + + notification_h m_notification; + const int m_responseTimeout; // seconds +}; + +} // UI +} // CCHECKER diff --git a/src/include/cchecker/logic.h b/src/include/cchecker/logic.h index cf1c63d..aa50388 100644 --- a/src/include/cchecker/logic.h +++ b/src/include/cchecker/logic.h @@ -100,7 +100,7 @@ class Logic { void process_all(void); void process_queue(void); void process_event(const event_t &event); - error_t process_buffer(void); + void process_buffer(void); bool get_online(void) const; void set_online(bool online); @@ -108,6 +108,8 @@ class Logic { bool get_should_exit(void) const; void set_should_exit(void); + void call_ui(const app_t &app); + Queue m_queue; Certs m_certs; std::list<app_t> m_buffer; diff --git a/src/logic.cpp b/src/logic.cpp index 63c2e15..aef6aec 100644 --- a/src/logic.cpp +++ b/src/logic.cpp @@ -21,13 +21,18 @@ */ #include <stdexcept> #include <tzplatform_config.h> +#include <app_control_internal.h> #include <cchecker/logic.h> #include <cchecker/log.h> #include <cchecker/sql_query.h> +#include <cchecker/UIBackend.h> using namespace std; +// FIXME: Popup temporary disabled +#define POPUP 0 + namespace CCHECKER { namespace { @@ -376,12 +381,39 @@ void Logic::process_queue(void) } } -error_t Logic::process_buffer(void) +void Logic::call_ui(const app_t &app) +{ + UI::UIBackend ui; + + if (ui.call_popup(app)) { // If calling popup or app_controll service will fail, + // do not remove application, and ask about it once again later + remove_app_from_buffer_and_database(app); + LogDebug("Popup shown correctly. Application will be removed from DB and buffer"); + } + else + LogDebug("Popup error. Application will be marked to show popup later."); +} + +void Logic::process_buffer(void) { for (auto iter = m_buffer.begin(); iter != m_buffer.end();) { - // If OCSP checking fails we should remove application from buffer and database + + // Check if app hasn't already been verified. + // If yes then just try to display popup once again, and go the next app. +#if POPUP + if (iter->verified == app_t::verified_t::NO) { + app_t app_cpy = *iter; + LogDebug(app_cpy.str() << " has been verified before. Popup should be shown."); + call_ui(app_cpy); + iter++; + continue; + } +#endif + Certs::ocsp_response_t ret; ret = m_certs.check_ocsp(*iter); + + // If OCSP returns success or OCSP checking fails we should remove application from buffer and database if (ret == Certs::ocsp_response_t::OCSP_APP_OK || ret == Certs::ocsp_response_t::OCSP_CERT_ERROR) { LogDebug(iter->str() << " OCSP verified (or not available for app's chains)"); @@ -391,12 +423,16 @@ error_t Logic::process_buffer(void) } else if (ret == Certs::ocsp_response_t::OCSP_APP_REVOKED) { LogDebug(iter->str() << " certificate has been revoked. Popup should be shown"); + iter->verified = app_t::verified_t::NO; app_t app_cpy = *iter; iter++; - // TODO: Do not remove app here - just waits for user answer from popup - // Temporary solution because popup doesn't work +#if POPUP +// Do not remove app here - just waits for user answer from popup +// Temporary solution because notification framework doesn't work + call_ui(app_cpy); +#else remove_app_from_buffer_and_database(app_cpy); - +#endif } else { LogDebug(iter->str() << " should be checked again later"); @@ -405,7 +441,6 @@ error_t Logic::process_buffer(void) iter++; } } - return NO_ERROR; } void Logic::process_all() diff --git a/src/po/CMakeLists.txt b/src/po/CMakeLists.txt new file mode 100644 index 0000000..3cb076f --- /dev/null +++ b/src/po/CMakeLists.txt @@ -0,0 +1,44 @@ +# 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 Adam Malinowski <a.malinowsk2@partner.samsung.com> +# + +SET(POFILES + en.po pl.po +) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(SHAREDIR "${PREFIX}/share") +SET(LOCALEDIR "${SHAREDIR}/locale") +SET(MSGFMT "/usr/bin/msgfmt") + +FOREACH(pofile ${POFILES}) + SET(pofile ${CMAKE_CURRENT_SOURCE_DIR}/${pofile}) + MESSAGE("PO: ${pofile}") + GET_FILENAME_COMPONENT(absPofile ${pofile} ABSOLUTE) + GET_FILENAME_COMPONENT(lang ${absPofile} NAME_WE) + SET(moFile ${CMAKE_CURRENT_BINARY_DIR}/${lang}.mo) + ADD_CUSTOM_COMMAND( + OUTPUT ${moFile} + COMMAND ${MSGFMT} -o ${moFile} ${absPofile} + DEPENDS ${absPofile} + ) + INSTALL(FILES ${moFile} + DESTINATION ${LOCALEDIR}/${lang}/LC_MESSAGES RENAME ${PROJECT_NAME}.mo) + SET(moFiles ${moFiles} ${moFile}) +ENDFOREACH(pofile) + +ADD_CUSTOM_TARGET(po ALL DEPENDS ${moFiles}) diff --git a/src/po/en.po b/src/po/en.po new file mode 100644 index 0000000..764b151 --- /dev/null +++ b/src/po/en.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/pl.po b/src/po/pl.po new file mode 100644 index 0000000..cff940e --- /dev/null +++ b/src/po/pl.po @@ -0,0 +1,14 @@ +msgid "SID_TITLE_OCSP_VERIFICATION_FAILED" +msgstr "Veryfikacja OCSP nie powiodła się" + +msgid "SID_CONTENT_OCSP_VERIFICATION_FAILED" +msgstr "Certifikat aplikacji %s (%s) został odwołany." + +msgid "SID_CONTENT_OCSP_PACKAGE VERIFICATION_FAILED" +msgstr "Certyfikat jednej z aplikacji w pakiecie %s został odwołany." + +msgid "SID_BTN_OCSP_KEEP_APP" +msgstr "Zachowaj" + +msgid "SID_BTN_OCSP_UNINSTALL_APP" +msgstr "Usuń" diff --git a/src/ui/UIBackend.cpp b/src/ui/UIBackend.cpp new file mode 100644 index 0000000..5fd33a4 --- /dev/null +++ b/src/ui/UIBackend.cpp @@ -0,0 +1,218 @@ +/* + * 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 UIBackend.cpp + * @author Janusz Kozerski <j.kozerski@samsung.com> + * @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 <cchecker/log.h> +#include <cchecker/UIBackend.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; +} + +response_e UIBackend::run() +{ + 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; +} + +bool UIBackend::call_popup(const app_t &app) +{ + response_e resp; + + create_ui(app.app_id, app.pkg_id); + resp = run(); + LogDebug(app.str() << " response: " << resp); + if (resp == ERROR) { + return false; + } + + else if (resp == UNINSTALL) { + app_control_h service = NULL; + int result = 0; + result = app_control_create(&service); + if (!service || result != APP_CONTROL_ERROR_NONE) { + return false; + } + app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT); + app_control_set_app_id(service, "setting-manage-applications-efl"); + app_control_add_extra_data(service, "viewtype", "application-info"); + app_control_add_extra_data(service, "pkgname", app.pkg_id.c_str()); + app_control_send_launch_request(service, NULL, NULL); + app_control_destroy(service); + } + return true; +} + +} // UI +} // CCHECKER |