1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "config_database_helper.h"
17 #include <vector>
18 #include <array>
19 #include "string_ex.h"
20 #include "config_define.h"
21 #include "rdb_event_store_callback.h"
22 #include "security_guard_define.h"
23 #include "security_guard_log.h"
24 
25 namespace OHOS::Security::SecurityGuard {
ConfigDatabaseHelper(std::string dbTable)26 ConfigDatabaseHelper::ConfigDatabaseHelper(std::string dbTable)
27 {
28     dbTable_ = dbTable;
29 }
30 
Init()31 int ConfigDatabaseHelper::Init()
32 {
33     return SUCCESS;
34 }
35 
InsertAppInfo(const AppInfo & info)36 int ConfigDatabaseHelper::InsertAppInfo(const AppInfo& info)
37 {
38     NativeRdb::ValuesBucket values {};
39     SetValuesBucket(info, values);
40     int64_t rowId;
41     int ret = Insert(rowId, dbTable_, values);
42     if (ret != NativeRdb::E_OK) {
43         SGLOGI("failed to add app info, appName=%{public}s, ret=%{public}d", info.appName.c_str(), ret);
44         return DB_OPT_ERR;
45     }
46     return SUCCESS;
47 }
48 
InsertAllAppInfo(const std::vector<AppInfo> & infos)49 int ConfigDatabaseHelper::InsertAllAppInfo(const std::vector<AppInfo>& infos)
50 {
51     SGLOGI("InsertAllAppInfo....");
52     std::vector<NativeRdb::ValuesBucket> values {};
53     for (auto iter : infos) {
54         NativeRdb::ValuesBucket value {};
55         SetValuesBucket(iter, value);
56         values.emplace_back(value);
57     }
58     int64_t rowId;
59     int ret = BatchInsert(rowId, dbTable_, values);
60     if (ret != NativeRdb::E_OK) {
61         SGLOGE("failed to batch insert event, ret=%{public}d", ret);
62         return DB_OPT_ERR;
63     }
64     return SUCCESS;
65 }
66 
QueryAllAppInfo(std::vector<AppInfo> & infos)67 int ConfigDatabaseHelper::QueryAllAppInfo(std::vector<AppInfo> &infos)
68 {
69     SGLOGI("QueryAllAppInfo....");
70     NativeRdb::RdbPredicates predicates(dbTable_);
71     return QueryAppInfoBase(predicates, infos);
72 }
73 
QueryAppInfoBase(const NativeRdb::RdbPredicates & predicates,std::vector<AppInfo> & infos)74 int32_t ConfigDatabaseHelper::QueryAppInfoBase(const NativeRdb::RdbPredicates &predicates, std::vector<AppInfo> &infos)
75 {
76     std::vector<std::string> columns {APP_NAME, APP_FINGERPRINT, APP_ATTRIBUTES, IS_GLOBAL_APP};
77     std::shared_ptr<NativeRdb::ResultSet> resultSet = Query(predicates, columns);
78     if (resultSet == nullptr) {
79         SGLOGE("failed to get event");
80         return DB_OPT_ERR;
81     }
82     AppInfoTableInfo table;
83     int32_t ret = GetResultSetTableInfo(resultSet, table);
84     if (ret != SUCCESS) {
85         return ret;
86     }
87     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
88         AppInfo info;
89         resultSet->GetString(table.appNameIndex, info.appName);
90         resultSet->GetString(table.appHashIndex, info.appHash);
91         std::string attrStr;
92         std::vector<std::string> tmpVec;
93         resultSet->GetString(table.appAttrIndex, attrStr);
94         SplitStr(attrStr, ",", tmpVec);
95         info.attrs = tmpVec;
96         resultSet->GetInt(table.appIsGlobalAppIndex, info.isGlobalApp);
97         infos.emplace_back(info);
98     }
99     resultSet->Close();
100     return SUCCESS;
101 }
102 
GetResultSetTableInfo(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,AppInfoTableInfo & table)103 int32_t ConfigDatabaseHelper::GetResultSetTableInfo(const std::shared_ptr<NativeRdb::ResultSet> &resultSet,
104     AppInfoTableInfo &table)
105 {
106     int32_t rowCount = 0;
107     int32_t columnCount = 0;
108     std::vector<std::string> columnNames;
109     if (resultSet->GetRowCount(rowCount) != NativeRdb::E_OK ||
110         resultSet->GetColumnCount(columnCount) != NativeRdb::E_OK ||
111         resultSet->GetAllColumnNames(columnNames) != NativeRdb::E_OK) {
112         SGLOGE("get table info failed");
113         return DB_LOAD_ERR;
114     }
115     int32_t columnNamesCount = static_cast<int32_t>(columnNames.size());
116     for (int32_t i = 0; i < columnNamesCount; i++) {
117         std::string columnName = columnNames.at(i);
118         if (columnName == ID) {
119             table.primaryKeyIndex = i;
120         }
121         if (columnName == APP_NAME) {
122             table.appNameIndex = i;
123         }
124         if (columnName == APP_FINGERPRINT) {
125             table.appHashIndex = i;
126         }
127         if (columnName == APP_ATTRIBUTES) {
128             table.appAttrIndex = i;
129         }
130         if (columnName == IS_GLOBAL_APP) {
131             table.appIsGlobalAppIndex = i;
132         }
133     }
134     table.rowCount = rowCount;
135     table.columnCount = columnCount;
136     SGLOGD("info: row=%{public}d col=%{public}d appNameIdx=%{public}d appHashIdx=%{public}d "
137         "appAttrIdx=%{public}d", rowCount, columnCount,
138         table.appNameIndex, table.appHashIndex, table.appAttrIndex);
139     return SUCCESS;
140 }
141 
QueryAppInfosByName(const std::string & appName,std::vector<AppInfo> & infos)142 int ConfigDatabaseHelper::QueryAppInfosByName(const std::string &appName, std::vector<AppInfo> &infos)
143 {
144     std::vector<std::string> columns {APP_NAME, APP_FINGERPRINT, APP_ATTRIBUTES, IS_GLOBAL_APP};
145     NativeRdb::RdbPredicates predicates(dbTable_);
146     predicates.EqualTo(APP_NAME, appName);
147     predicates.OrderByDesc(ID);
148     std::shared_ptr<NativeRdb::ResultSet> resultSet = Query(predicates, columns);
149     if (resultSet == nullptr) {
150         SGLOGI("failed to get appInfo");
151         return DB_OPT_ERR;
152     }
153     AppInfoTableInfo table;
154     int32_t ret = GetResultSetTableInfo(resultSet, table);
155     if (ret != SUCCESS) {
156         return ret;
157     }
158     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
159         AppInfo info {};
160         resultSet->GetString(table.appNameIndex, info.appName);
161         resultSet->GetString(table.appHashIndex, info.appHash);
162         std::string attrStr;
163         std::vector<std::string> tmpVec;
164         resultSet->GetString(table.appAttrIndex, attrStr);
165         SplitStr(attrStr, ",", tmpVec);
166         info.attrs = tmpVec;
167         resultSet->GetInt(table.appIsGlobalAppIndex, info.isGlobalApp);
168         infos.emplace_back(info);
169     }
170     resultSet->Close();
171     return SUCCESS;
172 }
173 
DeleteAppInfoByNameAndGlobbalFlag(const std::string & appName,int isGlobalApp)174 int ConfigDatabaseHelper::DeleteAppInfoByNameAndGlobbalFlag(const std::string &appName, int isGlobalApp)
175 {
176     SGLOGI("DeleteAppInfoByName, appName=%{public}s", appName.c_str());
177     NativeRdb::RdbPredicates queryPredicates(dbTable_);
178     queryPredicates.EqualTo(APP_NAME, appName);
179     queryPredicates.EqualTo(IS_GLOBAL_APP, isGlobalApp);
180     queryPredicates.OrderByAsc(ID);
181     std::vector<std::string> columns { ID };
182     std::shared_ptr<NativeRdb::ResultSet> resultSet = Query(queryPredicates, columns);
183     if (resultSet == nullptr) {
184         SGLOGI("failed to get event, appName=%{public}s", appName.c_str());
185         return DB_OPT_ERR;
186     }
187     int64_t primaryKey = -1;
188     std::vector<std::string> primaryKeyVec;
189     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
190         resultSet->GetLong(0, primaryKey);
191         primaryKeyVec.emplace_back(std::to_string(primaryKey));
192     }
193     resultSet->Close();
194     int rowId;
195     NativeRdb::RdbPredicates deletePredicates(dbTable_);
196     deletePredicates.In(ID, primaryKeyVec);
197     deletePredicates.EqualTo(APP_NAME, appName);
198     deletePredicates.EqualTo(IS_GLOBAL_APP, isGlobalApp);
199     int ret = Delete(rowId, deletePredicates);
200     if (ret != NativeRdb::E_OK) {
201         SGLOGE("failed to delete event, appName=%{public}s, ret=%{public}d", appName.c_str(), ret);
202         return DB_OPT_ERR;
203     }
204     return SUCCESS;
205 }
206 
DeleteAppInfoByIsGlobalApp(int isGlobalApp)207 int ConfigDatabaseHelper::DeleteAppInfoByIsGlobalApp(int isGlobalApp)
208 {
209     NativeRdb::RdbPredicates queryPredicates(dbTable_);
210     queryPredicates.EqualTo(IS_GLOBAL_APP, isGlobalApp);
211     queryPredicates.OrderByAsc(ID);
212     std::vector<std::string> columns { ID };
213     std::shared_ptr<NativeRdb::ResultSet> resultSet = Query(queryPredicates, columns);
214     if (resultSet == nullptr) {
215         SGLOGI("failed to get resultSet");
216         return DB_OPT_ERR;
217     }
218     int64_t primaryKey = -1;
219     std::vector<std::string> primaryKeyVec;
220     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
221         resultSet->GetLong(0, primaryKey);
222         primaryKeyVec.emplace_back(std::to_string(primaryKey));
223     }
224     resultSet->Close();
225     int rowId;
226     NativeRdb::RdbPredicates deletePredicates(dbTable_);
227     deletePredicates.In(ID, primaryKeyVec);
228     deletePredicates.EqualTo(IS_GLOBAL_APP, isGlobalApp);
229     int ret = Delete(rowId, deletePredicates);
230     if (ret != NativeRdb::E_OK) {
231         SGLOGE("failed to delete App, ret=%{public}d", ret);
232         return DB_OPT_ERR;
233     }
234     return SUCCESS;
235 }
236 
QueryAppInfoByAttribute(const std::string attr,std::vector<AppInfo> & infos)237 int ConfigDatabaseHelper::QueryAppInfoByAttribute(const std::string attr, std::vector<AppInfo> &infos)
238 {
239     NativeRdb::RdbPredicates predicates(dbTable_);
240     std::vector<std::string> columns {APP_NAME, APP_FINGERPRINT, APP_ATTRIBUTES, IS_GLOBAL_APP};
241     std::shared_ptr<NativeRdb::ResultSet> resultSet = Query(predicates, columns);
242     if (resultSet == nullptr) {
243         SGLOGI("failed to get event");
244         return DB_OPT_ERR;
245     }
246     AppInfoTableInfo table;
247     int32_t ret = GetResultSetTableInfo(resultSet, table);
248     if (ret != SUCCESS) {
249         return ret;
250     }
251     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
252         AppInfo info;
253         std::string attrStr;
254         std::vector<std::string> tmpVec;
255         resultSet->GetString(table.appAttrIndex, attrStr);
256         if (attrStr.find(attr) == std::string::npos) {
257             continue;
258         }
259         SplitStr(attrStr, ",", tmpVec);
260         info.attrs = tmpVec;
261         resultSet->GetString(table.appNameIndex, info.appName);
262         resultSet->GetString(table.appHashIndex, info.appHash);
263         infos.emplace_back(info);
264     }
265     resultSet->Close();
266     return SUCCESS;
267 }
268 
SetValuesBucket(const AppInfo & event,NativeRdb::ValuesBucket & values)269 void ConfigDatabaseHelper::SetValuesBucket(const AppInfo &event, NativeRdb::ValuesBucket &values)
270 {
271     std::string attrStr;
272     uint32_t index = 1;
273     // construct attr vector to string, exp: 111,222,333
274     for (auto iter : event.attrs) {
275         attrStr.append(iter);
276         if (index == event.attrs.size()) {
277             break;
278         }
279         attrStr.append(",");
280         index++;
281     }
282     values.PutString(APP_NAME, event.appName);
283     values.PutString(APP_FINGERPRINT, event.appHash);
284     values.PutString(APP_ATTRIBUTES, attrStr);
285     values.PutInt(IS_GLOBAL_APP, event.isGlobalApp);
286 }
287 
CreateTable()288 std::string ConfigDatabaseHelper::CreateTable()
289 {
290     std::string table;
291     table.append("CREATE TABLE IF NOT EXISTS ").append(dbTable_);
292     table.append("(").append(ID).append(" INTEGER PRIMARY KEY AUTOINCREMENT, ");
293     table.append(APP_NAME).append(" TEXT NOT NULL, ");
294     table.append(APP_FINGERPRINT).append(" TEXT NOT NULL, ");
295     table.append(APP_ATTRIBUTES).append(" TEXT NOT NULL, ");
296     table.append(IS_GLOBAL_APP).append(" INTEGER NOT NULL)");
297     return table;
298 }
299 } // namespace OHOS::Security::SecurityGuard