/*
- * Copyright (c) 2017 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-2020 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.
ppm_popup_response_e *responses,
size_t privacies_count)
{
- (void) popup_id;
- (void) privacies;
- (void) responses;
- (void) privacies_count;
+ if (!privacies || !responses || privacies_count < 1) {
+ return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
+ }
+
+ int ret = ppm_init_client();
+ if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
+ return ret;
+ }
+
+ askuser_popup_result* aresults = (askuser_popup_result*) calloc(1, sizeof(askuser_popup_result) * privacies_count);
+ if (!aresults) {
+ return PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (size_t i = 0; i < privacies_count; ++i) {
+ switch( responses[i] ) {
+ case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESPONSE_ALLOW_FOREVER :
+ aresults[i] = ASKUSER_POPUP_RESULT_ALLOW_FOREVER;
+ break;
+ case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESPONSE_DENY_FOREVER :
+ aresults[i] = ASKUSER_POPUP_RESULT_DENY_FOREVER;
+ break;
+ case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESPONSE_DENY_ONCE :
+ aresults[i] = ASKUSER_POPUP_RESULT_DENY_ONCE;
+ break;
+ default:
+ free(aresults);
+ return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ ret = askuser_popup_send_ext_response(ppm_handle->client, popup_id,
+ privacies, aresults, privacies_count);
+
+ free(aresults);
- return PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN;
+ return ret != ASKUSER_API_SUCCESS ? ask_user_to_ppm_error(ret) : PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
}
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-2020 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.
printPrompt(Mode::SERVER);
}
+ virtual void extResponse(int popup_id, std::vector<std::string> &&privacies, std::vector<int> &&responses) {
+ // TODO
+ (void) popup_id;
+ (void) privacies;
+ (void) responses;
+ }
+
void addRequest(ConnectionFd fd, RequestId id, const Privilege &privilege) {
auto &s = m_requests[fd];
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-2020 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.
virtual RequestId popupRequest(const std::vector<std::string> &privileges,
const askuser_popup_multiple_response_callback callback,
void *userData) = 0;
+ virtual int popupResponseExt(int popup_id, const std::vector<std::string> &privacies, std::vector<int> &responses) = 0;
virtual bool popupRequestInProgress(const std::string &privilege) const = 0;
};
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-2020 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.
});
}
+
+API
+int askuser_popup_send_ext_response(askuser_client *p_client, int popup_id,
+ const char **privacies,
+ const askuser_popup_result responses[],
+ size_t privacies_count)
+{
+ if (!privacies || !responses || privacies_count < 1) {
+ return ASKUSER_API_INVALID_PARAM;
+ }
+
+ return AskUser::Client::tryCatch([&]() {
+ std::vector<std::string> vprivacies(privacies_count);
+ std::vector<int> vresponses(privacies_count);
+
+ for (size_t i = 0; i < privacies_count; ++i) {
+ switch(responses[i]) {
+ case ASKUSER_POPUP_RESULT_ALLOW_FOREVER :
+ vresponses[i] = ASKUSER_ALLOW_FOREVER;
+ break;
+ case ASKUSER_POPUP_RESULT_DENY_FOREVER :
+ vresponses[i] = ASKUSER_DENY_FOREVER;
+ break;
+ case ASKUSER_POPUP_RESULT_DENY_ONCE :
+ vresponses[i] = ASKUSER_DENY_ONCE;
+ break;
+ default:
+ return ASKUSER_API_INVALID_PARAM;
+ }
+ vprivacies[i] = privacies[i];
+ }
+
+
+ int ret = p_client->impl->popupResponseExt(popup_id, vprivacies, vresponses);
+
+ // TODO there is no privilege check on server side now
+ // TODO we should be able to return ASKUSER_API_PERMISSION_DENIED in case when
+ // caller doesn't have a privilege (ie. http://tizen.org/privilege/internal/default/platform)
+ return ret != 0 ? ASKUSER_API_CONNECTION_ERROR : ASKUSER_API_SUCCESS;
+ });
+}
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-2020 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.
return conCtx.m_requestId;
}
+int ApiInterfaceImpl::popupResponseExt(int popup_id, const std::vector<std::string> &privacies, std::vector<int> &responses)
+{
+ return m_channel->popupResponseExt(popup_id, privacies, responses);
+}
+
bool ApiInterfaceImpl::popupRequestInProgress(const std::string &privilege) const
{
auto samePrivilege = [&] (const Request &req) {
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-2020 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.
virtual RequestId popupRequest(const std::vector<std::string> &privileges,
const askuser_popup_multiple_response_callback callback,
void *userData);
+ virtual int popupResponseExt(int popup_id, const std::vector<std::string> &privacies, std::vector<int> &responses);
virtual bool popupRequestInProgress(const std::string &privilege) const;
void updateConnection(Protocol::ConnectionFd fd, int mask);
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2017-2020 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.
//TODO: add sample code
+/**
+ * \brief Allows external UI popup app to pass per-privacy answers to askuser daemon
+ *
+ * \since_tizen 6.0
+ *
+ * \privlevel platform
+ *
+ * \param[in] p_client An instance of the askuser_client structure
+ * previously created by askuser_client_initialize().
+ * \param[in] popup_id The ID of the popup assigned by askuser daemon when UI popup app
+ * was invoked.
+ * \param[in] privacies The privacies array for which user response has been acquired.
+ * \param[in] responses The responses array for corresponding privacies.
+ * \param[in] privacies_count The number of elements in the privacies and results arrays.
+ *
+ * \return ASKUSER_API_SUCCESS on success
+ * \return a negative value in case of an error (see "Status return codes")
+ */
+int askuser_popup_send_ext_response(askuser_client *p_client, int popup_id,
+ const char **privacies,
+ const askuser_popup_result responses[],
+ size_t privacies_count);
#ifdef __cplusplus
}
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
return ConnectionContext{requestId, fd};
}
+int ClientChannel::popupResponseExt(int popup_id, const std::vector<std::string> &privacies, std::vector<int> &responses)
+{
+ int fd = connect();
+
+ std::stringstream ss;
+
+ ss << MSGID_EXT_POPUP_RESPONSE << " " << popup_id << " " << privacies.size();
+
+ for (auto &p : privacies)
+ ss << " " << base64Encode(p);
+
+ for (auto &r : responses)
+ ss << " " << r;
+
+ ss << '\n';
+
+ std::string str = ss.str();
+
+ ALOGD("popupResponseExt: sending message: " << str);
+
+ std::copy(str.begin(), str.end(), std::back_inserter(m_sockets[fd].output));
+
+ int ret = process(fd, FdMask::WRITE);
+
+ closeConnection(fd);
+
+ return ret;
+}
+
void ClientChannel::onAccept(int) {
}
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
virtual ~ClientChannel();
virtual ConnectionContext popupRequest(const std::vector<std::string> &privileges);
+ virtual int popupResponseExt(int popup_id, const std::vector<std::string> &privacies, std::vector<int> &responses);
private:
virtual void onAccept(int fd);
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
typedef int ConnectionFd;
typedef int RequestId;
+typedef int PopupId;
typedef std::string Privilege;
typedef std::vector<Privilege> PrivilegeVector;
const int MSGID_POPUP = 1;
const int MSGID_TOAST1 = 2;
const int MSGID_TOAST2 = 3;
+const int MSGID_EXT_POPUP_RESPONSE = 4;
const int MSGID_POPUP_RESPONSE = 1;
} // namespace Protocol
/*
- * Copyright (c) 2017 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
return std::to_string(cr.uid);
}
+pid_t getPIDFromSocket(int sockFd)
+{
+ struct ucred cr;
+ socklen_t len = sizeof(cr);
+
+ if (getsockopt(sockFd, SOL_SOCKET, SO_PEERCRED, &cr, &len) == -1) {
+ throw AskUser::Protocol::CredentialsException("Couldn't fetch credentials from a socket");
+ }
+
+ return cr.pid;
+}
+
std::string getSmackLabelFromSocket(int sockFd)
{
char *label;
Credentials::Credentials(int sockFd)
: label(getSmackLabelFromSocket(sockFd))
, uid(getUIDFromSocket(sockFd))
+, pid(getPIDFromSocket(sockFd))
{
}
/*
- * Copyright (c) 2017 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
std::string label;
std::string uid;
+ pid_t pid;
};
} // namespace Protocol
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
const std::size_t MIN_PRIVILEGE_ENC_LENGTH = lengthOfEncodedBase64(MIN_PRIVILEGE_LENGTH);
const std::size_t MAX_PRIVILEGE_ENC_LENGTH = lengthOfEncodedBase64(MAX_PRIVILEGE_LENGTH);
const std::size_t SEP_LEN = 1; // space or \n
+const std::size_t MIN_EXT_RESPONSE_POPUP_ID_LEN = 1;
+const std::size_t MAX_EXT_RESPONSE_POPUP_ID_LEN = maxNumberOfChars<int>();
+
+const std::size_t MIN_EXT_RESPONSE_MESSAGE_LENGHT = MIN_COMMAND_LENGTH +
+ SEP_LEN + // space
+ MIN_EXT_RESPONSE_POPUP_ID_LEN +
+ SEP_LEN + // space
+ MIN_PRIVS_NUMBER_LENGTH +
+ MIN_PRIVS_NUMBER * (
+ SEP_LEN + // space
+ MIN_PRIVILEGE_ENC_LENGTH + // assuming privacy can't be longer than privilege
+ SEP_LEN + // space
+ MIN_RESPONSE_STATUS_LEN) + // response
+ SEP_LEN; // new line
+
+const std::size_t MAX_EXT_RESPONSE_MESSAGE_LENGHT = MAX_COMMAND_LENGTH +
+ SEP_LEN + // space
+ MAX_EXT_RESPONSE_POPUP_ID_LEN +
+ SEP_LEN + // space
+ MAX_PRIVS_NUMBER_LENGTH +
+ MAX_PRIVS_NUMBER * (
+ SEP_LEN + // space
+ MAX_PRIVILEGE_ENC_LENGTH) + // assuming privacy can't be longer than privilege
+ SEP_LEN + // space
+ MAX_PRIVS_NUMBER * (
+ SEP_LEN + // space
+ MAX_RESPONSE_STATUS_LEN) +
+ SEP_LEN; // new line
const std::size_t MIN_REQUEST_MESSAGE_LENGTH = MIN_COMMAND_LENGTH +
SEP_LEN + // space
MAX_RESPONSE_STATUS_LEN) +
SEP_LEN; // new line
-const std::size_t MIN_MESSAGE_LENGTH = std::min(MIN_REQUEST_MESSAGE_LENGTH, MIN_RESPONSE_MESSAGE_LENGTH);
-const std::size_t MAX_MESSAGE_LENGTH = std::max(MAX_REQUEST_MESSAGE_LENGTH, MAX_RESPONSE_MESSAGE_LENGTH);
+const std::size_t MIN_MESSAGE_LENGTH = std::min(MIN_EXT_RESPONSE_MESSAGE_LENGHT,std::min(MIN_REQUEST_MESSAGE_LENGTH, MIN_RESPONSE_MESSAGE_LENGTH));
+const std::size_t MAX_MESSAGE_LENGTH = std::max(MAX_EXT_RESPONSE_MESSAGE_LENGHT,std::max(MAX_REQUEST_MESSAGE_LENGTH, MAX_RESPONSE_MESSAGE_LENGTH));
const unsigned int ASKUSER_MESSAGE_CMD_POS = 0;
const unsigned int ASKUSER_MESSAGE_REQUESTID_POS = 1;
const unsigned int ASKUSER_MESSAGE_PRIVILEGES_COUNT_POS = 2;
const unsigned int ASKUSER_MESSAGE_FIRST_PRIVILEGE_POS = 3;
const unsigned int ASKUSER_MESSAGE_MIN_MSG_PARAM_COUNT = 4; //cmd, requestId, privilegeCount, privilege
+const unsigned int ASKUSER_MESSAGE_MIN_EXT_RESPONSE_MSG_PARAM_COUNT = 5; //cmd, popup_id, privacyCount, privacy, response
+const unsigned int ASKUSER_MESSAGE_EXT_RESPONSE_POPUP_ID_POS = 1;
+const unsigned int ASKUSER_MESSAGE_EXT_RESPONSE_PRIV_COUNT_POS = 2;
+const unsigned int ASKUSER_MESSAGE_EXT_RESPONSE_FIRST_PRIV_POS = 3;
std::string base64Encode(std::string input);
std::string base64Decode(std::string input);
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
break;
}
+ case MSGID_EXT_POPUP_RESPONSE:
+ {
+ // TODO privilege check with Cynara should be here if we want to add it (ie. http://tizen.org/privilege/internal/default/platform)
+ // TODO how to return with access denied in this case?
+ unsigned int privaciesCount;
+ int popup_id;
+ if (message.size() < ASKUSER_MESSAGE_MIN_EXT_RESPONSE_MSG_PARAM_COUNT) {
+ ALOGE("Inappropriate message size for MSGID_EXT_POPUP_RESPONSE command, size: " << message.size());
+ return -EINVAL;
+ }
+ popup_id = std::stoi(message[ASKUSER_MESSAGE_EXT_RESPONSE_POPUP_ID_POS]);
+ privaciesCount = std::stoul(message[ASKUSER_MESSAGE_EXT_RESPONSE_PRIV_COUNT_POS]);
+ if (message.size() != 2 * privaciesCount + ASKUSER_MESSAGE_MIN_EXT_RESPONSE_MSG_PARAM_COUNT - 2) {
+ ALOGE("Inappropriate message size for MSGID_EXT_POPUP_RESPONSE command, size: " << message.size());
+ return -EINVAL;
+ }
+ ALOGD("privaciesCount: " << privaciesCount);
+ std::vector<std::string> privacies(privaciesCount);
+ std::vector<int> responses(privaciesCount);
+
+ for (unsigned int i = 0; i < privaciesCount; ++i) {
+ privacies[i] = base64Decode(message[ASKUSER_MESSAGE_EXT_RESPONSE_FIRST_PRIV_POS + i]);
+ responses[i] = std::stoi(message[ASKUSER_MESSAGE_EXT_RESPONSE_FIRST_PRIV_POS + privaciesCount + i]);
+ }
+ m_callbacks->extResponse(popup_id, std::move(privacies), std::move(responses));
+
+ break;
+ }
default :
ALOGE("Server received unknown message, command: " << command);
return -EINVAL;
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
* \param[in] privileges Privileges for which permissions are asked for
*/
virtual void popup(ConnectionFd fd, RequestId id, std::vector<std::string> &&privileges) = 0;
+
+ /**
+ * This function is called when external UI app retrived answer and askuser needs to answer to app
+ *
+ * \param[in] popup_id the ID (cookie) passed to UI app when requesting popup, identifies application request (its ConnectionFd and RequestId)
+ * \param[in] privacies the privacies for which the UI app is returning an answer (it can be a list smaller than originally requested)
+ * \param[in] responses the list of policy responses (Allow/Deny) for each privacy; vector size must be equal to privacies.size()
+ */
+ virtual void extResponse(int popup_id, std::vector<std::string> &&privacies, std::vector<int> &&responses) = 0;
};
typedef std::unique_ptr<IServerCallbacks> ServerCallbacksPtr;
/*
- * Copyright (c) 2017 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
}
}
+ virtual void extResponse(int popup_id, std::vector<std::string> &&privacies, std::vector<int> &&responses) {
+ // TODO
+ (void) popup_id;
+ (void) privacies;
+ (void) responses;
+ }
+
void setChannel(ServerChannel *ptr) {
m_channel = ptr;
}
capi-ui-efl-util
capi-system-info
efl-extension
+ aul
)
INCLUDE_DIRECTORIES(SYSTEM
${NOTIF_PATH}/ServerCallbacks.cpp
${NOTIF_PATH}/ui/Po.cpp
${NOTIF_PATH}/ui/Popupper.cpp
+ ${NOTIF_PATH}/ui/UIAppInvoker.cpp
)
ADD_EXECUTABLE(${TARGET_ASKUSER_NOTIFICATION} ${ASKUSER_NOTIFICATION_SOURCES})
/*
- * Copyright (c) 2017-2019 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
#include <policy/Policy.h>
#include <policy/PrivilegePolicy.h>
#include <ui/Po.h>
+#include <ui/UIAppInvoker.h>
#include "PolicyUpdater.h"
#include "ServerCallbacks.h"
int ASKUSER_IDLE_TIMER_SEC = 4;
-int uiResponseToClientResponse(NResponseType response) {
- int clientResponse;
-
- switch (response) {
- case NResponseType::Deny:
- clientResponse = ASKUSER_DENY_ONCE;
- break;
- case NResponseType::DenyAlways:
- clientResponse = ASKUSER_DENY_FOREVER;
- break;
- case NResponseType::Allow:
- case NResponseType::AllowAlways:
- clientResponse = ASKUSER_ALLOW_FOREVER;
- break;
- case NResponseType::None:
- clientResponse = ASKUSER_NONE;
- break;
- case NResponseType::Error:
- clientResponse = ASKUSER_UNKNOWN_ERROR;
- break;
- default:
- clientResponse = ASKUSER_UNKNOWN_ERROR;
- }
-
- return clientResponse;
-}
-
std::string clientResponseToPolicy(int clientResponse) {
std::string level;
ALOGD("Proper client connected");
stopTimer();
- ConnectionInfo connInfo{appId, pkgId, creds.uid, isHybrid};
+ ConnectionInfo connInfo{appId, pkgId, creds.uid, creds.pid, isHybrid};
m_connToInfo.insert(it, std::make_pair(fd, connInfo));
} catch (const std::exception &e) {
ALOGE("Failed to add channel fd " << fd);
auto queueIt = std::remove_if(m_pendingEvents.begin(), m_pendingEvents.end(),
[fd](const FdEvent &fdEvent) {return fdEvent.id.fd == fd;});
m_pendingEvents.erase(queueIt, m_pendingEvents.end());
-
- // Ignore error in policy setting, we can't do anything about it nor we can inform user about error
- (void)setPolicy(m_connToInfo[fd]); // TODO: now it doesn't set "Ask user" again
m_connToInfo.erase(fd);
m_fdInfo.erase(fd);
m_serverChannel->process(fd, 0);
// Handle next event if removed active fd
- if (fd == m_currentEvent.fd) {
- finishCurrentRequest();
- processEvents();
- }
+ // TODO remove eventInfo like: m_eventInfo.erase(respEvent.id);
+
return ECORE_CALLBACK_CANCEL;
}
case FdChange::CHANGE:
}
}
-void Logic::addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id,
+Protocol::PopupId Logic::genUniquePopupId() {
+ static int counter = 0;
+ return counter++;
+}
+
+void Logic::addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, Protocol::PopupId popup_id,
const std::vector<Privacy> &privacies,
const std::vector<PrivilegeStruct> &privilegesStructure) {
EventId eventId{fd, id};
ConnectionInfo &conn = m_connToInfo[fd];
- FdEvent fdEvent{eventId, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgId, privacies))};
+ FdEvent fdEvent{eventId, popup_id, std::shared_ptr<IUIEvent>(new ExtUIEvent(popup_id, conn.pid, conn.pkgId, privacies))};
+ fdEvent.event->process();
m_pendingEvents.emplace_back(std::move(fdEvent));
}
return;
}
- // we do have privacies to ask about, we need to generate event
+ int unique_id = genUniquePopupId();
std::vector<Privacy> privacies(uniquePrivacies.begin(), uniquePrivacies.end());
- addEvent(fd, id, privacies, privilegesStructure);
- processEvents();
-
+ addEvent(fd, id, unique_id, privacies, privilegesStructure);
} catch (const std::exception &e) {
ALOGE("Failed to handle popup request : " << e.what());
std::vector<int> responses(privileges.size(), ASKUSER_DENY_ONCE);
}
}
-Logic::~Logic()
+void Logic::extResponse(Protocol::PopupId popup_id, const std::vector<Privacy> &privacies, const std::vector<int> &responses)
{
- m_serverChannel.reset();
-}
+ ALOGD("Got response for popup_id : " << popup_id << " for privacies: ");
+ for (auto &p : privacies) {
+ ALOGD("---- privacy : " << p);
+ }
-bool Logic::isEventProcessed() {
- return m_currentEvent.fd != Protocol::INVALID_FD;
-}
+ FdEvent respEvent;
+ size_t pendingEventsIndex = 0;
+ for (FdEvent &ev : m_pendingEvents) {
+ if (ev.popup_id == popup_id) {
+ respEvent = ev;
+ break;
+ }
+ ++pendingEventsIndex;
+ }
-void Logic::finishCurrentRequest() {
- m_eventInfo.erase(m_currentEvent);
- m_popupper.popupClose();
+ if (respEvent.popup_id == -1) {
+ ALOGE("Got response for nonexisting popup_id : " << popup_id);
+ return;
+ }
- m_currentEvent = EventId();
- if (!m_pendingEvents.empty())
- m_pendingEvents.pop_front();
-}
+ auto it = m_eventInfo.find(respEvent.id);
-void Logic::processEvents() {
- // Active event processing
- if (isEventProcessed())
+ if (it == m_eventInfo.end()) {
+ ALOGE("Got response from strange event id ");
return;
+ }
- // No pending events
- if (m_pendingEvents.empty())
+ EventInfo &eventInfo = it->second;
+
+ auto itc = m_connToInfo.find(respEvent.id.fd);
+
+ if (itc == m_connToInfo.end()) {
+ ALOGE("Got response from inactive fd " << respEvent.id.fd);
return;
+ }
- FdEvent &fdEvent = m_pendingEvents.front();
- m_currentEvent = fdEvent.id;
- fdEvent.event->process();
+ ConnectionInfo &conn = itc->second;
+
+ try {
+ if (privacies.size() != responses.size()) {
+ ALOGE("Got improper answer from UI app, privacies size doesn't match responses size ("
+ << privacies.size() << " vs. "<< responses.size() << "); popup_id: " << popup_id);
+ throw Exception("Got improper answer from UI app");
+ }
+
+ std::map<Privacy, int> received;
+ unsigned int i = 0;
+ for (auto p : privacies) {
+ received[p] = responses[i++];
+
+ if (received[p] != ASKUSER_DENY_ONCE &&
+ received[p] != ASKUSER_DENY_FOREVER &&
+ received[p] != ASKUSER_ALLOW_FOREVER) {
+ ALOGE("Got improper answer from UI app, answers are improper for privacy: " << p << " answer: " << received[p]);
+ throw Exception("Got improper answer from UI app");
+ }
+ }
+
+ // fill missing responses (some privacies may have not received any answer)
+ // also, calculate final policy levels
+ std::map<Privacy, int> finalPrivacyResponses;
+ std::vector<std::string> levels(eventInfo.uniquePrivacies.size());
+ i = 0;
+
+ for (auto p : eventInfo.uniquePrivacies) {
+ finalPrivacyResponses[p] = (received.find(p) == received.end()) ? ASKUSER_UNKNOWN_ERROR : received[p];
+ levels[i] = clientResponseToPolicy(finalPrivacyResponses[p]);
+ ++i;
+ }
+
+ // set policy
+ ALOGD("Setting policy for app " << conn.appId);
+
+ if (!PolicyUpdater::update(conn.pkgId, conn.appId, conn.isHybrid, eventInfo.uniquePrivacies, levels)) {
+ ALOGE("Couldn't set policy for " << conn.appId);
+ throw Exception("Couldn't set policy");
+ }
+
+ std::vector<int> privResponses(eventInfo.privilegesStructure.size(), ASKUSER_UNKNOWN_ERROR);
+
+ for (i = 0; i < privResponses.size(); ++i) {
+ const auto &privilegeStruct = eventInfo.privilegesStructure[i];
+ const auto &policy = privilegeStruct.policy;
+ if (policy == "Allow") {
+ privResponses[i] = ASKUSER_ALLOW_FOREVER;
+ } else if (policy == "Deny") {
+ privResponses[i] = ASKUSER_DENY_FOREVER;
+ } else if (policy != "Ask user") {
+ privResponses[i] = ASKUSER_DENY_ONCE;
+ } else {
+ // Ask user policy - need to calcualte from existing responses to privacies
+ // but only privacies askable for this privilege should be used!
+ privResponses[i] = ASKUSER_ALLOW_FOREVER;
+ for (auto &privacy : privilegeStruct.askablePrivacies) {
+ const auto &privResponseIt = finalPrivacyResponses.find(privacy);
+ if (privResponseIt != finalPrivacyResponses.end()) {
+ privResponses[i] = std::min(privResponseIt->second, privResponses[i]);
+ }
+ else {
+ ALOGE("Unable to response for askable privacy: " << privacy);
+ privResponses[i] = ASKUSER_DENY_ONCE;
+ break;
+ }
+ }
+ }
+ }
+
+ // answer to application
+ m_serverChannel->popupResponses(respEvent.id.fd, respEvent.id.id, std::move(privResponses));
+
+ // remove event & info information
+ m_eventInfo.erase(respEvent.id);
+ m_pendingEvents.erase(m_pendingEvents.begin() + pendingEventsIndex);
+
+ } catch(const std::exception &e) {
+ ALOGE("Failed to handle popup request : " << e.what());
+ std::vector<int> responses(eventInfo.privilegesStructure.size(), ASKUSER_DENY_ONCE);
+ m_serverChannel->popupResponses(respEvent.id.fd, respEvent.id.id, std::move(responses));
+ }
+}
+
+Logic::~Logic()
+{
+ m_serverChannel.reset();
}
void Logic::registerSignalFd() {
}
void Logic::stop() {
- if (isEventProcessed()) {
- ConnectionInfo &conn = m_connToInfo[m_currentEvent.fd];
- processResponse(conn); // TODO used to be ASKUSER_DENY_ONCE, "Ask user"
- finishCurrentRequest();
- }
m_popupper.stop();
}
init_agent_log();
m_popupper.initialize();
Po::setLocale();
- m_popupper.registerPopupResponseHandler([&](std::vector<NResponseType> responses) { popupResponses(responses);});
registerSignalFd();
}
void Logic::run() {
- // TODO ensure we won't throw inside ecore loop
- m_popupper.start();
- m_popupper.shutdown();
-}
-
-bool Logic::setPolicy(const ConnectionInfo &conn) {
- ALOGD("Setting policy for app " << conn.appId);
- auto ¤tEvent = m_eventInfo[m_currentEvent];
- std::vector<std::string> levels(currentEvent.uniquePrivacies.size());
-
- for (size_t i = 0; i < levels.size(); ++i) {
- const auto &privacy = currentEvent.uniquePrivacies[i];
- levels[i] = clientResponseToPolicy(currentEvent.privacyResponses[privacy]);
- }
-
- if (!PolicyUpdater::update(conn.pkgId, conn.appId, conn.isHybrid, currentEvent.uniquePrivacies, levels)) {
- ALOGE("Couldn't set policy for " << conn.appId);
- return false;
- }
-
- return true;
-}
-
-void Logic::processResponse(const ConnectionInfo &conn) {
- auto ¤tEvent = m_eventInfo[m_currentEvent];
- std::vector<int> responses(currentEvent.privilegesStructure.size(), ASKUSER_UNKNOWN_ERROR);
-
- if (setPolicy(conn)) {
- for (size_t i = 0; i < responses.size(); ++i) {
- const auto &privilegeStruct = currentEvent.privilegesStructure[i];
- const auto &policy = privilegeStruct.policy;
- if (policy == "Allow") {
- responses[i] = ASKUSER_ALLOW_FOREVER;
- } else if (policy == "Deny") {
- responses[i] = ASKUSER_DENY_FOREVER;
- } else if (policy != "Ask user") {
- responses[i] = ASKUSER_DENY_ONCE;
- } else {
- // Ask user policy - need to calcualte from existing responses to privacies
- // but only privacies askable for this privilege should be used!
- responses[i] = ASKUSER_ALLOW_FOREVER;
- for (auto &privacy : privilegeStruct.askablePrivacies) {
- const auto &privResponseIt = currentEvent.privacyResponses.find(privacy);
- if (privResponseIt != currentEvent.privacyResponses.end()) {
- responses[i] = std::min(privResponseIt->second, responses[i]);
- }
- else {
- ALOGE("Unable to response for askable privacy: " << privacy);
- responses[i] = ASKUSER_DENY_ONCE;
- break;
- }
- }
- }
- }
- }
- m_serverChannel->popupResponses(m_currentEvent.fd, m_currentEvent.id, std::move(responses));
-}
-
-void Logic::popupResponses(const std::vector<NResponseType> &responses) {
- auto it = m_connToInfo.find(m_currentEvent.fd);
-
- if (it == m_connToInfo.end()) {
- ALOGE("Got response from inactive fd " << m_currentEvent.fd);
- return;
- }
-
- ConnectionInfo &conn = it->second;
- auto ¤tEvent = m_eventInfo[m_currentEvent];
-
- if (responses.size() != currentEvent.uniquePrivacies.size()) {
- ALOGE("Got invalid number of responses: " << responses.size() << " but expected: "
- << currentEvent.uniquePrivacies.size());
- finishCurrentRequest();
- processEvents();
- return;
- }
-
- for (size_t i = 0; i < responses.size(); ++i) {
- int clientResponse = uiResponseToClientResponse(responses[i]);
- const auto &privacy = currentEvent.uniquePrivacies[i];
- ALOGD("Client response for privacy " << privacy << " is " << clientResponse);
- currentEvent.privacyResponses[privacy] = clientResponse;
- }
-
- // No more privacies, since all are answered by one popup - request is ready for response
- processResponse(conn);
- finishCurrentRequest();
- processEvents();
+ m_popupper.start();
+ m_popupper.shutdown();
}
} // namespace Notification
/*
- * Copyright (c) 2017-2019 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
* @file src/agent/notification-daemon/Service.h
* @author Zofia Abramowska <z.abramowska@samsung.com>
* @author Tomasz Swierczek <t.swierczek@samsung.com>
- * @brief Declaration of Popupper class
+ * @brief Declaration of Logic class
*/
#pragma once
private:
std::string m_msg;
};
- Logic() : m_currentEvent{-1, -1}, m_timer(nullptr) {}
+ Logic() : m_timer(nullptr) {}
void init();
void run();
void stop();
void popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::vector<Privilege> &privileges);
+ void extResponse(int popup_id, const std::vector<Privacy> &privacies, const std::vector<int> &responses);
+
~Logic();
private:
struct EventId {
std::string appId;
std::string pkgId;
std::string user;
+ pid_t pid;
bool isHybrid;
};
std::vector<Privacy> askablePrivacies;
};
+ //Generate popup ID (cookie) for external UI app
+ Protocol::PopupId genUniquePopupId();
+
//Initialization
void registerSignalFd();
void prepareChannel();
static Eina_Bool timerHandler(void *data);
//static Eina_Bool signalHandler(void *data, int type, void *event);
- void addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id,
+ void addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, Protocol::PopupId popup_id,
const std::vector<Privacy> &privacies,
const std::vector<PrivilegeStruct> &privilegesStructure);
Eina_Bool processChannel(int fd, int mask);
bool identifyClient(const std::string &label, std::string &appId, std::string &pkgId);
- void processEvents();
- void processResponse(const ConnectionInfo &conn);
- bool isEventProcessed();
- void finishCurrentRequest();
-
void startTimer();
void stopTimer();
- void popupResponses(const std::vector<NResponseType> &response);
-
bool processError(EventId id, int error);
- bool setPolicy(const ConnectionInfo &conn);
std::unique_ptr<AskUser::Protocol::ServerChannel> m_serverChannel;
Popupper m_popupper;
struct FdEvent {
EventId id;
- std::unique_ptr<IUIEvent> event;
+ Protocol::PopupId popup_id;
+ std::shared_ptr<IUIEvent> event;
+ FdEvent():
+ id{-1, -1},
+ popup_id (-1)
+ {}
+ FdEvent(EventId an_id, Protocol::PopupId an_popup_id, std::shared_ptr<IUIEvent> an_event):
+ id(an_id.fd, an_id.id),
+ popup_id(an_popup_id),
+ event(an_event)
+ {}
+ FdEvent(const FdEvent &other):
+ id(other.id.fd, other.id.id),
+ popup_id(other.popup_id),
+ event(other.event)
+ {}
+ FdEvent& operator=(const FdEvent &other) {
+ id.fd = other.id.fd;
+ id.id = other.id.id;
+ popup_id = other.popup_id;
+ event = other.event;
+ return *this;
+ }
};
- EventId m_currentEvent;
std::deque<FdEvent> m_pendingEvents;
enum class FdChange {
/*
- * Copyright (c) 2016-2019 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-2020 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.
return false;
}
-} // namespace Agent
+} // namespace Notification
} // namespace AskUser
/*
- * Copyright (c) 2016 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016-2020 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.
const std::vector<std::string> &levels);
};
-} // namespace Agent
+} // namespace Notification
} // namespace AskUser
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
m_service->popup(fd, id, privileges);
}
+void ServerCallbacks::extResponse(int popup_id, std::vector<std::string> &&privacies, std::vector<int> &&responses) {
+ m_service->extResponse(popup_id, privacies, responses);
+}
+
} /* namespace Notification */
} /* namespace Askuser */
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
virtual void newConnection(ConnectionFd fd, const Credentials &creds);
virtual void updateConnection(ConnectionFd fd, int mask);
virtual void popup(ConnectionFd fd, RequestId id, std::vector<std::string> &&privileges);
+ virtual void extResponse(int popup_id, std::vector<std::string> &&privacies, std::vector<int> &&responses);
- virtual ~ServerCallbacks() {}
+ virtual ~ServerCallbacks() {};
private:
AskUser::Notification::Logic *m_service;
};
/*
- * Copyright (c) 2017 - 2018 Samsung Electronics Co.
+ * Copyright (c) 2017-2020 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.
#include <string>
#include <vector>
+#include <exception/Exception.h>
#include <ui/Popupper.h>
+#include <ui/UIAppInvoker.h>
namespace AskUser {
namespace Notification {
Popupper *m_popupper;
};
+class ExtUIEvent : public IUIEvent {
+public:
+ ExtUIEvent(int popup_id, pid_t caller_app_pid, std::string pkg_id, std::vector<std::string> privacies)
+ : IUIEvent(NULL),
+ m_popup_id(popup_id),
+ m_caller_app_pid(caller_app_pid),
+ m_pkg_id(pkg_id),
+ m_privacies(privacies)
+ {}
+ virtual void process() {
+ (void)UIAppInvoker::invoke(m_popup_id, m_caller_app_pid, m_pkg_id, m_privacies);
+ }
+private:
+ int m_popup_id;
+ pid_t m_caller_app_pid;
+ std::string m_pkg_id;
+ std::vector<std::string> m_privacies;
+};
+
class EventPopupCheck : public IUIEvent {
public:
EventPopupCheck(Popupper *popupper, const std::string &pkgId, const std::vector<std::string> &privacies)
{}
virtual void process() {
- m_popupper->popupCheck(m_pkgId, m_privacies);
+ // TODO we don't want askuser popups now, just the external app UI
+ // m_popupper->popupCheck(m_pkgId, m_privacies);
}
private:
std::string m_pkgId;
--- /dev/null
+/*
+ * Copyright (c) 2020 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 UIAppInvoker.cpp
+ * @author Tomasz Swierczek <t.swierczek@samsung.com>
+ * @brief This file implements API used to call external UI app for popup using AUL bundle API
+ */
+#include "UIAppInvoker.h"
+
+#include <log/alog.h>
+
+#include <aul.h>
+#include <aul_svc.h>
+
+#define PID_BUFFER_SIZE 64
+
+namespace AskUser {
+
+namespace Notification {
+
+bool UIAppInvoker::invoke(int popup_id, pid_t caller_app_pid, const std::string &pkg_id, const std::vector<std::string> &privacies) {
+ ALOGD("Launching popup app for popup_id: " << popup_id << ", pkg_id of requestor app: " << pkg_id);
+
+ char buf[PID_BUFFER_SIZE];
+ bundle *b = NULL;
+ char** privacies_c = NULL;
+ int ret = -1;
+ size_t i = 0;
+
+ b = bundle_create();
+
+ if (!b) {
+ ALOGE("Cannot allocate memory for bundle creation");
+ return false;
+ }
+
+ /* Sets the caller process ID - TODO: should it be the applications PID like it is now? */
+ snprintf(buf, sizeof(buf), "%d", caller_app_pid);
+ ret = bundle_add_str(b, AUL_K_CALLER_PID, buf);
+ if (ret < 0) {
+ ALOGE("bundle_add_str() failed. ret = " << ret);
+ goto error_exit;
+ }
+
+ /* Sets the caller user ID - askuser notification works in user domain, has same UID as the apps have */
+ snprintf(buf, sizeof(buf), "%u", getuid());
+ ret = bundle_add_str(b, AUL_K_CALLER_UID, buf);
+ if (ret < 0) {
+ ALOGE("bundle_add_str() failed. ret = " << ret);
+ goto error_exit;
+ }
+
+ /* Sets caller appid, assuming here we need pkg id */
+ snprintf(buf, sizeof(buf), "%s", pkg_id.c_str());
+ ret = bundle_add_str(b, AUL_K_CALLER_APPID, buf);
+ if (ret < 0) {
+ ALOGE("bundle_add_str() failed. ret = " << ret);
+ goto error_exit;
+ }
+
+ /* Sets privacies to show */
+ privacies_c = new char*[privacies.size()];
+ if (!privacies_c) {
+ ALOGE("Cannot allocate memory for bundle creation");
+ ret = -1;
+ goto error_exit;
+ }
+
+ memset(privacies_c, 0, privacies.size());
+
+ for (auto p : privacies) {
+ if (!(privacies_c[i] = new char[p.size() + 1])){
+ ALOGE("Cannot allocate memory for bundle creation");
+ ret = -1;
+ goto error_exit;
+ }
+ strcpy(privacies_c[i], p.c_str());
+ ++i;
+ }
+
+ ret = bundle_add_str_array(b, "privacy_list", const_cast<const char**>(privacies_c), privacies.size());
+ if (ret < 0) {
+ ALOGE("bundle_add_str_array() failed. ret = " << ret);
+ goto error_exit;
+ }
+
+ /* Add popup_id - here its int, but it can be arbitrary buffer */
+ ret = bundle_add_byte(b, "popup_id", &popup_id, sizeof(popup_id));
+ if (ret < 0) {
+ ALOGE("bundle_add_byte() failed. ret = " << ret);
+ goto error_exit;
+ }
+
+ /* Sets App Group Launch Mode */
+ ret = aul_svc_set_launch_mode(b, "group");
+ if (ret < 0) {
+ ALOGE("aul_svc_set_launch_mode() failed. ret = " << ret);
+ goto error_exit;
+ }
+
+ /* Set Popup UI style */
+ ret = aul_svc_add_data(b, "launch_type", "single");
+ if (ret < 0) {
+ ALOGE("aul_svc_add_data() failed. ret = " << ret);
+ goto error_exit;
+ }
+ /* Launch askuser-popup */
+ ret = aul_forward_app("org.tizen.askuser-popup", b);
+ if (ret < 0)
+ ALOGE("aul_forward_app() failed. ret = " << ret);
+ else
+ ALOGD("Launched app pid " << ret);
+
+error_exit:
+ bundle_free(b);
+ if (privacies_c)
+ for (i = 0; i < privacies.size(); ++i)
+ delete [] privacies_c[i];
+ delete [] privacies_c;
+
+ return ret >= 0;
+}
+
+} // namespace Notification
+
+} // namespace AskUser
--- /dev/null
+/*
+ * Copyright (c) 2020 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 UIAppInvoker.h
+ * @author Tomasz Swierczek <t.swierczek@samsung.com>
+ * @brief This file defines API used to call external UI app for popup
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <unistd.h>
+#include <sys/types.h>
+
+namespace AskUser {
+
+namespace Notification {
+
+namespace UIAppInvoker {
+ bool invoke(int popup_id, pid_t caller_app_pid, const std::string &pkg_id, const std::vector<std::string> &privacies);
+} // UIAppInvoker
+
+} // namespace Notification
+
+} // namespace AskUser