e4056d20b9c2507e0f71dcc80af43a4517324015
[platform/core/appfw/watchface-complication.git] / watchface-common / watchface-util.cc
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <dlog.h>
18 #include <unistd.h>
19 #include <aul.h>
20 #include <fcntl.h>
21 #include <glib.h>
22 #include <gio/gio.h>
23 #include <cynara-client.h>
24 #include <cynara-creds-gdbus.h>
25 #include <cynara-session.h>
26 #include <pkgmgr-info.h>
27 #include <pkgmgr_installer_info.h>
28 #include <system_info.h>
29
30 #include <string>
31 #include <map>
32 #include <list>
33
34 #include "watchface-common/watchface-util.hh"
35 #include "watchface-common/include/watchface-common.h"
36 #include "watchface-common/watchface-common-internal.hh"
37 #include "watchface-common/include/watchface-common-internal.h"
38
39 #ifdef LOG_TAG
40 #undef LOG_TAG
41 #endif
42
43 #define MAX_PACKAGE_STR_SIZE 512
44 #define SMACK_LABEL_LEN 255
45 #define COMPLICATION_BUS_NAME_PREFIX "org.tizen.watchface_complication._"
46 #define COMPLICATION_PATH_PREFIX "/org/tizen/watchface_complication_"
47 #define EDITABLE_PATH_PREFIX "/org/tizen/watchface_editable_"
48 #define COMPLICATION_OBJECT_PATH "/org/tizen/watchface_complication"
49 #define MAX_CACHE_COUNT 10
50 #define ROOT_USER 0
51
52 #define LOG_TAG "WATCHFACE_COMPLICATION"
53
54 using namespace std;
55 using namespace tizen_base;
56 namespace watchface_complication {
57 namespace util {
58   static int __cynara_check(const char* client, const char* user,
59       const char* privilege) {
60     int ret, cynara_ret;
61     cynara* p_cynara = NULL;
62
63     ret = cynara_initialize(&p_cynara, NULL);
64     if (ret != CYNARA_API_SUCCESS) {
65       LOGE("cannot init cynara [%d] failed!", ret);
66       return WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
67     }
68
69     cynara_ret = cynara_check(p_cynara, client, "", user, privilege);
70     if (cynara_ret == CYNARA_API_ACCESS_ALLOWED) {
71       ret = WATCHFACE_COMPLICATION_ERROR_NONE;
72     } else {
73       if (cynara_ret == CYNARA_API_ACCESS_DENIED)
74         ret = WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED;
75       else
76         ret = WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
77
78       LOGE("cynara access check [%s][%d] failed!", privilege, ret);
79     }
80
81     cynara_finish(p_cynara);
82
83     return ret;
84   }
85
86   bool CheckWatchFeatureEnabled(void) {
87     static bool feature = false;
88     static bool retrieved = false;
89     int ret;
90     if (retrieved == true)
91       return feature;
92
93     ret = system_info_get_platform_bool(
94       "http://tizen.org/feature/watch_app", &feature);
95     if (ret != SYSTEM_INFO_ERROR_NONE) {
96       LOGE("failed to get system info for watch_app feature");
97       return false;
98     }
99     retrieved = true;
100     return feature;
101   }
102
103   int CheckPrivilege(const char* privilege) {
104     int fd;
105     int ret;
106     char subject_label[SMACK_LABEL_LEN + 1] = {0, };
107     char uid[10] = {0, };
108
109     fd = open("/proc/self/attr/current", O_RDONLY);
110     if (fd == -1) {
111       LOGE("open [%d] failed!", errno);
112       return WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
113     }
114
115     ret = read(fd, subject_label, SMACK_LABEL_LEN);
116     if (ret < 0) {
117       LOGE("read [%d] failed!", errno);
118       ret = WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
119     } else {
120       snprintf(uid, sizeof(uid), "%d", getuid());
121       ret = __cynara_check(subject_label, uid, privilege);
122     }
123
124     close(fd);
125     return ret;
126   }
127
128   int CheckPrivilege(string privilege, cynara_result* pcr) {
129     int ret = WATCHFACE_COMPLICATION_ERROR_NONE;
130     if (*pcr == COMPLICATION_CYNARA_DENIED) {
131       LOGE("Permission denied");
132       return WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED;
133     } else if (*pcr == COMPLICATION_CYNARA_UNKNOWN) {
134       ret = CheckPrivilege(privilege.c_str());
135       if (ret == WATCHFACE_COMPLICATION_ERROR_NONE) {
136         *pcr = COMPLICATION_CYNARA_ALLOWED;
137       } else if (ret == WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED) {
138         *pcr = COMPLICATION_CYNARA_DENIED;
139         return ret;
140       } else {
141         return ret;
142       }
143     }
144     return ret;
145   }
146
147   int CheckPrivilege(std::string& privilege, GDBusConnection* connection,
148                        std::string& sender_name, std::string& sender_appid) {
149     int ret;
150     char* client = NULL;
151     char* user = NULL;
152
153     ret = cynara_creds_gdbus_get_client(connection, sender_name.c_str(),
154                                          CLIENT_METHOD_DEFAULT, &client);
155     if (ret != CYNARA_API_SUCCESS) {
156       LOGE("failed to get client");
157       ret = WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
158       goto out;
159     }
160
161     ret = cynara_creds_gdbus_get_user(connection, sender_name.c_str(),
162                                         USER_METHOD_DEFAULT, &user);
163     if (ret != CYNARA_API_SUCCESS) {
164       LOGE("failed to get user");
165       ret = WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
166       goto out;
167     }
168
169     LOGD("appid(%s), client(%s), user(%s)", sender_appid.c_str(), client, user);
170
171     ret = __cynara_check(client, user, privilege.c_str());
172
173 out:
174     if (client)
175       free(client);
176     if (user)
177       free(user);
178
179     return ret;
180   }
181
182   std::string GetSenderAppid(GDBusConnection* conn,
183       const std::string& sender_name) {
184     int ret = 0;
185     char buffer[MAX_PACKAGE_STR_SIZE + 1] = {0, };
186     int pid = GetSenderPid(conn, sender_name);
187
188     ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
189     if (ret != AUL_R_OK) {
190       LOGE("Failed to get the sender ID: (%s) (%d)", sender_name.c_str(), pid);
191       return std::string();
192     }
193     return std::string(buffer);
194   }
195
196   int GetSenderPid(GDBusConnection* conn, const std::string& sender_name) {
197     GDBusMessage* msg = NULL;
198     GDBusMessage* reply = NULL;
199     GError* err = NULL;
200     GVariant* body;
201     int pid = 0;
202
203     msg = g_dbus_message_new_method_call("org.freedesktop.DBus",
204                           "/org/freedesktop/DBus",
205                           "org.freedesktop.DBus",
206                           "GetConnectionUnixProcessID");
207     if (!msg) {
208       LOGE("Can't allocate new method call");
209       goto out;
210     }
211
212     g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name.c_str()));
213     reply = g_dbus_connection_send_message_with_reply_sync(conn, msg,
214                     G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
215
216     if (!reply) {
217       if (err != NULL) {
218         LOGE("Failed to get pid [%s]", err->message);
219         g_error_free(err);
220       }
221       goto out;
222     }
223
224     body = g_dbus_message_get_body(reply);
225     g_variant_get(body, "(u)", &pid);
226
227 out:
228     if (msg)
229       g_object_unref(msg);
230     if (reply)
231       g_object_unref(reply);
232
233     return pid;
234   }
235
236   bool CheckSender(const char* sender_app_id,
237                     const std::string& sender_name,
238                     GDBusConnection* conn) {
239     int ret = 0;
240     char buffer[MAX_PACKAGE_STR_SIZE] = {0, };
241     int pid = GetSenderPid(conn, sender_name);
242
243     ret = aul_app_get_appid_bypid(pid, buffer, sizeof(buffer));
244     if (ret != AUL_R_OK) {
245       LOGE("Failed to get the sender ID: (%s) (%d)", sender_name.c_str(), pid);
246       return false;
247     }
248
249     if (strcmp(buffer, sender_app_id) != 0) {
250       LOGE("invalid appid : (%s) (%s)", buffer, sender_app_id);
251       return false;
252     }
253
254     return true;
255   }
256
257   bool CheckComplicationType(int type) {
258     switch (type) {
259     case WATCHFACE_COMPLICATION_TYPE_NO_DATA:
260       return true;
261     case WATCHFACE_COMPLICATION_TYPE_SHORT_TEXT:
262       return true;
263     case WATCHFACE_COMPLICATION_TYPE_LONG_TEXT:
264       return true;
265     case WATCHFACE_COMPLICATION_TYPE_RANGED_VALUE:
266       return true;
267     case WATCHFACE_COMPLICATION_TYPE_TIME:
268       return true;
269     case WATCHFACE_COMPLICATION_TYPE_ICON:
270       return true;
271     case WATCHFACE_COMPLICATION_TYPE_IMAGE:
272       return true;
273     case WATCHFACE_COMPLICATION_TYPE_SMALL_IMAGE:
274       return true;
275     default:
276       return false;
277     }
278   }
279
280   bool CheckCertificate(const std::string& provider_app_id) {
281     static std::map<std::string, bool> cache;
282     bool ret;
283
284     auto cp = cache.find(provider_app_id);
285     if (cp != cache.end())
286       return cp->second;
287
288     pkgmgrinfo_cert_compare_result_type_e res;
289     std::string app_id = GetAppId();
290     int cert_ret = pkgmgrinfo_pkginfo_compare_usr_app_cert_info(app_id.c_str(),
291                       provider_app_id.c_str(), getuid(), &res);
292     if (cert_ret < 0) {
293       LOGE("CheckCertificate() Failed %d", cert_ret);
294       return false;
295     }
296     if (res == PMINFO_CERT_COMPARE_MATCH) {
297       ret = true;
298     } else {
299       ret = false;
300       LOGI("CheckCertificate() Failed : CERTIFICATE_NOT_MATCH");
301     }
302
303     if (cache.size() >= MAX_CACHE_COUNT)
304       cache.clear();
305
306     cache[provider_app_id] = ret;
307
308     return ret;
309   }
310
311   std::string EncodeStr(EncodeType type, std::string appid) {
312     char* encoded_path;
313     std::string encoded_path_str;
314     std::string encoded_str;
315
316     if (appid.empty())
317       return "";
318
319     encoded_path = g_compute_checksum_for_string(G_CHECKSUM_MD5,
320                   appid.c_str(), -1);
321     if (encoded_path == NULL)
322       return "";
323
324     encoded_path_str = std::string(encoded_path);
325     if (type == EncodeType::CompPath)
326       encoded_str = COMPLICATION_PATH_PREFIX + encoded_path_str;
327     else if (type == EncodeType::EditablePath)
328       encoded_str = EDITABLE_PATH_PREFIX + encoded_path_str;
329     else
330       encoded_str = COMPLICATION_BUS_NAME_PREFIX + encoded_path_str;
331
332     free(encoded_path);
333
334     return encoded_str;
335   }
336
337   std::string EncodeStr(EncodeType type, std::string appid, int compid) {
338     if (appid.empty())
339       return "";
340     std::string str = appid + "_" + std::to_string(compid);
341
342     return EncodeStr(type, str);
343   }
344
345   std::string GetCmdStr(CmdType type) {
346     std::string ret;
347     switch (type) {
348     case CompUpdateRequest :
349       ret = "__COMP_UPDATE_REQUEST__";
350       break;
351     case CompUpdated :
352       ret = "__COMP_UPDATED__";
353       break;
354     case CompNotifyDataUpdate :
355       ret = "__COMP_NOTIFY_DATA_UPDATE__";
356       break;
357     case CompNotifyListeningStatus :
358       ret = "__COMP_NOTIFY_LISTENING_STATUS__";
359       break;
360     case EditableEditRequest :
361       ret = "__EDITABLE_EDIT_REQUEST__";
362       break;
363     case EditableEditPreview :
364       ret = "__EDITABLE_EDIT_PREVIEW__";
365       break;
366     case EditableEditComplete :
367       ret = "__EDITABLE_EDIT_COMPLETE__";
368       break;
369     case EditableEditCancel :
370       ret = "__EDITABLE_EDIT_CANCEL__";
371       break;
372     case EditableEditReady :
373       ret = "__EDITABLE_EDIT_READY__";
374       break;
375     case SetupReply :
376       ret = "__SETUP_REPLY__";
377       break;
378     case ProviderReady :
379       ret = "__PROVIDER_READY__";
380       break;
381     case EditResult :
382       ret = "__EDIT_RESULT__";
383       break;
384     default :
385       break;
386     }
387
388     return ret;
389   }
390
391   std::string GetAppId() {
392     static std::string appid = "";
393     char appid_buf[MAX_PACKAGE_STR_SIZE] = {0, };
394
395     if (!appid.empty()) {
396       LOGI("appid(%s)", appid.c_str());
397       return appid;
398     }
399
400     int pid = getpid();
401     int ret = aul_app_get_appid_bypid(pid, appid_buf, sizeof(appid_buf));
402     if (ret != AUL_R_OK) {
403       LOGE("Fail to get appid");
404       return "";
405     }
406     appid = std::string(appid_buf);
407     return appid;
408   }
409
410   int GetDataType(Bundle shared_data) {
411     string shared_type = shared_data.GetString(DATA_TYPE_KEY);
412     if (shared_type.empty()) {
413       LOGE("failed to get data type");
414       return WATCHFACE_COMPLICATION_ERROR_INVALID_PARAMETER;
415     }
416
417     int comp_type = stoi(shared_type);
418     if (!CheckComplicationType(comp_type)) {
419       LOGE("Invalid param for type(%d)", comp_type);
420       return WATCHFACE_COMPLICATION_ERROR_INVALID_PARAMETER;
421     }
422     return comp_type;
423   }
424
425   bool IsValidData(Bundle shared_data) {
426     int type = GetDataType(shared_data);
427     bool is_valid = true;
428
429     switch (type) {
430       case WATCHFACE_COMPLICATION_TYPE_SHORT_TEXT : {
431         if (shared_data.GetString(SHORT_TEXT_KEY).empty())
432           is_valid = false;
433         break;
434       }
435       case WATCHFACE_COMPLICATION_TYPE_LONG_TEXT : {
436         if (shared_data.GetString(LONG_TEXT_KEY).empty())
437           is_valid = false;
438         break;
439       }
440       case WATCHFACE_COMPLICATION_TYPE_RANGED_VALUE : {
441         if (shared_data.GetString(RANGE_CUR_KEY).empty() ||
442             shared_data.GetString(RANGE_MAX_KEY).empty() ||
443             shared_data.GetString(RANGE_MIN_KEY).empty())
444           is_valid = false;
445         break;
446       }
447       case WATCHFACE_COMPLICATION_TYPE_TIME : {
448         if (shared_data.GetString(TIME_KEY).empty() &&
449           shared_data.GetString(TIME_ZONE_ID_KEY).empty())
450           is_valid = false;
451         break;
452       }
453       case WATCHFACE_COMPLICATION_TYPE_ICON : {
454         if (shared_data.GetString(ICON_KEY).empty())
455           is_valid = false;
456         break;
457       }
458       case WATCHFACE_COMPLICATION_TYPE_IMAGE : {
459         if (shared_data.GetString(IMAGE_KEY).empty())
460           is_valid = false;
461         break;
462       }
463       case WATCHFACE_COMPLICATION_TYPE_SMALL_IMAGE : {
464         if (shared_data.GetString(SMALL_IMAGE_KEY).empty())
465           is_valid = false;
466         break;
467       }
468       case WATCHFACE_COMPLICATION_TYPE_NO_DATA :
469         is_valid = true;
470         break;
471       default :
472         is_valid = false;
473         break;
474     }
475
476     if (!is_valid)
477       LOGE("Invalid data (%d)", type);
478     return is_valid;
479   }
480
481   std::string GetAppPath(const char* appid, char* path) {
482     char* root_path;
483     aul_get_app_shared_resource_path_by_appid(appid, &root_path);
484     std::string app_path =
485         "" + std::string(root_path) + "../../" + std::string(path);
486     free(root_path);
487     LOGI("%s", app_path.c_str());
488     return app_path;
489   }
490
491   int ConvertPathToAppPath(const char* appid, bundle* data) {
492     list<string> key_list {ICON_KEY, IMAGE_KEY, AOD_ICON_KEY,
493            AOD_IMAGE_KEY, SMALL_IMAGE_KEY, AOD_SMALL_IMAGE_KEY};
494     for (auto& i : key_list) {
495       char* path;
496       int ret = bundle_get_str(data, i.c_str(), &path);
497       if (ret != BUNDLE_ERROR_NONE)
498         continue;
499       char* dup_path = strdup(path);
500       bundle_del(data, i.c_str());
501       ret = bundle_add_str(data, i.c_str(),
502           util::GetAppPath(appid, dup_path).c_str());
503       free(dup_path);
504       if (ret != BUNDLE_ERROR_NONE) {
505         LOGE("fail to add app path");
506         return WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
507       }
508     }
509     return WATCHFACE_COMPLICATION_ERROR_NONE;
510   }
511
512   int ConvertAulError(int ret) {
513     if (ret == AUL_R_OK)
514       return WATCHFACE_COMPLICATION_ERROR_NONE;
515     if (ret == AUL_R_EILLACC)
516       return WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED;
517     else if (ret == AUL_R_EINVAL)
518       return WATCHFACE_COMPLICATION_ERROR_INVALID_PARAMETER;
519     else
520       return WATCHFACE_COMPLICATION_ERROR_IO_ERROR;
521   }
522
523   void DestroyTimeInfo(struct complication_time_info_s* info_s) {
524     if (info_s->timezone)
525       free(info_s->timezone);
526
527     if (info_s->timezone_id)
528       free(info_s->timezone_id);
529
530     if (info_s->country)
531       free(info_s->country);
532
533     if (info_s->city)
534       free(info_s->city);
535     free(info_s);
536   }
537
538   const char* DBHelper::GetParserDataPath() const {
539     uid_t target_uid;
540     const char* path;
541     bool is_global;
542
543     pkgmgr_installer_info_get_target_uid(&target_uid);
544
545     if (target_uid == ROOT_USER
546       || target_uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
547       is_global = true;
548     else
549       is_global = false;
550
551     if (!is_global)
552         tzplatform_set_user(target_uid);
553
554     path = tzplatform_mkpath(is_global ? TZ_SYS_DB : TZ_USER_DB,
555         ".complication_provider.db");
556     tzplatform_reset_user();
557
558     return path;
559   }
560
561   bool DBHelper::Open() {
562     const char* path = GetParserDataPath();
563     if (path == nullptr)
564       return false;
565
566     sqlite3* db = nullptr;
567     int ret = sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, nullptr);
568     if (ret != SQLITE_OK) {
569       LOGE("open db(%s) error: %d", path, ret);
570       return false;
571     }
572     db_.reset(db);
573     return Exec("PRAGMA foreign_keys = ON");
574   }
575
576   bool DBHelper::Open(int mode) {
577     const char* path = GetParserDataPath();
578     if (path == nullptr)
579       return false;
580
581     sqlite3* db = nullptr;
582     int ret = sqlite3_open_v2(path, &db, mode, nullptr);
583     if (ret != SQLITE_OK) {
584       LOGE("open db(%s) error: %d", path, ret);
585       return false;
586     }
587     db_.reset(db);
588     return Exec("PRAGMA foreign_keys = ON");
589   }
590
591   void DBHelper::Close() {
592     db_.reset();
593   }
594
595   bool DBHelper::Exec(const std::string& query) {
596     if (sqlite3_exec(db_.get(), query.c_str(), NULL, NULL, NULL) != SQLITE_OK) {
597       LOGE("exec error %s", sqlite3_errmsg(db_.get()));
598       return false;
599     }
600     return true;
601   }
602
603   bool DBHelper::Prepare(const std::string& query) {
604     sqlite3_stmt* stmt = nullptr;
605     if (sqlite3_prepare_v2(db_.get(), query.c_str(), query.size(), &stmt,
606         nullptr) != SQLITE_OK) {
607       LOGE("prepare error: %s", sqlite3_errmsg(db_.get()));
608       return false;
609     }
610
611     stmt_.reset(stmt);
612
613     return true;
614   }
615
616   const DBHelper::Cursor& DBHelper::GetCursor() const {
617     return stmt_;
618   }
619
620   int DBHelper::Step() const {
621     int ret = sqlite3_step(stmt_.get());
622     if (ret != SQLITE_DONE && ret != SQLITE_ROW)
623       LOGE("step error: %s", sqlite3_errmsg(db_.get()));
624     return ret;
625   }
626
627   int DBHelper::Reset() const {
628     return sqlite3_reset(stmt_.get());
629   }
630
631   bool DBHelper::Bind(int pos, std::string text) {
632     int ret = sqlite3_bind_text(stmt_.get(), pos, text.c_str(),
633       -1, SQLITE_TRANSIENT);
634     if (ret != SQLITE_OK) {
635       LOGE("bind error: %s", sqlite3_errmsg(db_.get()));
636       return false;
637     }
638
639     return true;
640   }
641
642   bool DBHelper::Bind(int pos, int val) {
643     if (sqlite3_bind_int(stmt_.get(), pos, val) != SQLITE_OK) {
644       LOGE("bind error: %s", sqlite3_errmsg(db_.get()));
645       return false;
646     }
647
648     return true;
649   }
650
651   const char* DBHelper::GetText(int pos) const {
652     return reinterpret_cast<const char*>(sqlite3_column_text(stmt_.get(), pos));
653   }
654
655   int DBHelper::GetInt(int pos) const {
656     return sqlite3_column_int(stmt_.get(), pos);
657   }
658
659 }  // namespace util
660 }  // namespace watchface_complication