1 /*
2 * Copyright (C) 2024 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 "medialibrary_urisensitive_operations.h"
17
18 #include <iostream>
19 #include <sstream>
20 #include <string>
21 #include <cstdint>
22
23 #include "common_func.h"
24 #include "ipc_skeleton.h"
25 #include "medialibrary_errno.h"
26 #include "medialibrary_object_utils.h"
27 #include "medialibrary_type_const.h"
28 #include "media_file_utils.h"
29 #include "media_log.h"
30 #include "media_app_uri_sensitive_column.h"
31 #include "media_column.h"
32 #include "medialibrary_appstate_observer.h"
33 #include "medialibrary_rdb_transaction.h"
34 #include "media_library_manager.h"
35 #include "permission_utils.h"
36 #include "result_set_utils.h"
37 #include "rdb_utils.h"
38
39 namespace OHOS {
40 namespace Media {
41 using namespace std;
42 using namespace OHOS::NativeRdb;
43 using namespace OHOS::DataShare;
44 using namespace OHOS::RdbDataShareAdapter;
45
46 constexpr int32_t NO_DB_OPERATION = -1;
47 constexpr int32_t UPDATE_DB_OPERATION = 0;
48 constexpr int32_t INSERT_DB_OPERATION = 1;
49 constexpr int32_t PHOTOSTYPE = 1;
50 constexpr int32_t AUDIOSTYPE = 2;
51
52 constexpr int32_t FILE_ID_INDEX = 0;
53 constexpr int32_t URI_TYPE_INDEX = 1;
54 constexpr int32_t SENSITIVE_TYPE_INDEX = 2;
55 constexpr int32_t APP_ID_INDEX = 3;
56
57 const string DB_OPERATION = "uriSensitive_operation";
58
UpdateOperation(MediaLibraryCommand & cmd,NativeRdb::RdbPredicates & rdbPredicate,std::shared_ptr<TransactionOperations> trans)59 int32_t UriSensitiveOperations::UpdateOperation(MediaLibraryCommand &cmd,
60 NativeRdb::RdbPredicates &rdbPredicate, std::shared_ptr<TransactionOperations> trans)
61 {
62 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
63 if (rdbStore == nullptr) {
64 MEDIA_ERR_LOG("UriSensitive update operation, rdbStore is null.");
65 return E_HAS_DB_ERROR;
66 }
67 cmd.SetTableName(AppUriSensitiveColumn::APP_URI_SENSITIVE_TABLE);
68 int32_t updateRows;
69 if (trans == nullptr) {
70 updateRows = MediaLibraryRdbStore::UpdateWithDateTime(cmd.GetValueBucket(), rdbPredicate);
71 } else {
72 updateRows = trans->Update(cmd.GetValueBucket(), rdbPredicate);
73 }
74 if (updateRows < 0) {
75 MEDIA_ERR_LOG("UriSensitive Update db failed, errCode = %{public}d", updateRows);
76 return E_HAS_DB_ERROR;
77 }
78 return static_cast<int32_t>(updateRows);
79 }
80
DeleteAllSensitiveOperation(AsyncTaskData * data)81 static void DeleteAllSensitiveOperation(AsyncTaskData *data)
82 {
83 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
84 if (rdbStore == nullptr) {
85 MEDIA_ERR_LOG("UriSensitive update operation, rdbStore is null.");
86 }
87
88 int32_t ret = rdbStore->ExecuteSql(AppUriSensitiveColumn::CREATE_APP_URI_SENSITIVE_TABLE);
89 if (ret < 0) {
90 MEDIA_ERR_LOG("UriSensitive table delete all temporary Sensitive failed");
91 return;
92 }
93
94 ret = rdbStore->ExecuteSql(AppUriSensitiveColumn::CREATE_URI_URITYPE_APPID_INDEX);
95 if (ret < 0) {
96 MEDIA_ERR_LOG("UriSensitive table delete all temporary Sensitive failed");
97 return;
98 }
99
100 ret = rdbStore->ExecuteSql(AppUriSensitiveColumn::DELETE_APP_URI_SENSITIVE_TABLE);
101 if (ret < 0) {
102 MEDIA_ERR_LOG("UriSensitive table delete all temporary Sensitive failed");
103 return;
104 }
105 MEDIA_INFO_LOG("UriSensitive table delete all %{public}d rows temporary Sensitive success", ret);
106 }
107
DeleteAllSensitiveAsync()108 void UriSensitiveOperations::DeleteAllSensitiveAsync()
109 {
110 shared_ptr<MediaLibraryAsyncWorker> asyncWorker = MediaLibraryAsyncWorker::GetInstance();
111 if (asyncWorker == nullptr) {
112 MEDIA_ERR_LOG("Can not get asyncWorker");
113 return;
114 }
115 shared_ptr<MediaLibraryAsyncTask> notifyAsyncTask =
116 make_shared<MediaLibraryAsyncTask>(DeleteAllSensitiveOperation, nullptr);
117 asyncWorker->AddTask(notifyAsyncTask, true);
118 }
119
DeleteOperation(MediaLibraryCommand & cmd)120 int32_t UriSensitiveOperations::DeleteOperation(MediaLibraryCommand &cmd)
121 {
122 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
123 if (rdbStore == nullptr) {
124 MEDIA_ERR_LOG("UriSensitive update operation, rdbStore is null.");
125 return E_HAS_DB_ERROR;
126 }
127 cmd.SetTableName(AppUriSensitiveColumn::APP_URI_SENSITIVE_TABLE);
128 int32_t deleteRows = -1;
129 int32_t errCode = rdbStore->Delete(cmd, deleteRows);
130 if (errCode != NativeRdb::E_OK || deleteRows < 0) {
131 MEDIA_ERR_LOG("UriSensitive delete db failed, errCode = %{public}d", errCode);
132 return E_HAS_DB_ERROR;
133 }
134 return static_cast<int32_t>(deleteRows);
135 }
136
InsertOperation(MediaLibraryCommand & cmd)137 int32_t UriSensitiveOperations::InsertOperation(MediaLibraryCommand &cmd)
138 {
139 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
140 if (rdbStore == nullptr) {
141 MEDIA_ERR_LOG("UriSensitive insert operation, rdbStore is null.");
142 return E_HAS_DB_ERROR;
143 }
144 cmd.SetTableName(AppUriSensitiveColumn::APP_URI_SENSITIVE_TABLE);
145 int64_t rowId = -1;
146 int32_t errCode = rdbStore->Insert(cmd, rowId);
147 if (errCode != NativeRdb::E_OK || rowId < 0) {
148 MEDIA_ERR_LOG("UriSensitive insert db failed, errCode = %{public}d", errCode);
149 return E_HAS_DB_ERROR;
150 }
151 return static_cast<int32_t>(rowId);
152 }
153
BatchInsertOperation(MediaLibraryCommand & cmd,const std::vector<ValuesBucket> & values,std::shared_ptr<TransactionOperations> trans)154 int32_t UriSensitiveOperations::BatchInsertOperation(MediaLibraryCommand &cmd,
155 const std::vector<ValuesBucket> &values, std::shared_ptr<TransactionOperations> trans)
156 {
157 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
158 if (rdbStore == nullptr) {
159 MEDIA_ERR_LOG("UriSensitive insert operation, rdbStore is null.");
160 return E_HAS_DB_ERROR;
161 }
162 cmd.SetTableName(AppUriSensitiveColumn::APP_URI_SENSITIVE_TABLE);
163 int64_t outInsertNum = -1;
164 int32_t errCode;
165 if (trans == nullptr) {
166 errCode = rdbStore->BatchInsert(cmd, outInsertNum, values);
167 } else {
168 errCode = trans->BatchInsert(cmd, outInsertNum, values);
169 }
170 if (errCode != NativeRdb::E_OK || outInsertNum < 0) {
171 MEDIA_ERR_LOG("UriSensitive Insert into db failed, errCode = %{public}d", errCode);
172 return E_HAS_DB_ERROR;
173 }
174 return static_cast<int32_t>(outInsertNum);
175 }
176
QueryUriSensitive(MediaLibraryCommand & cmd,const std::vector<DataShareValuesBucket> & values,std::shared_ptr<OHOS::NativeRdb::ResultSet> & resultSet)177 static void QueryUriSensitive(MediaLibraryCommand &cmd, const std::vector<DataShareValuesBucket> &values,
178 std::shared_ptr<OHOS::NativeRdb::ResultSet> &resultSet)
179 {
180 vector<string> columns;
181 vector<string> predicateInColumns;
182 DataSharePredicates predicates;
183 bool isValid;
184 string appid = values.at(0).Get(AppUriSensitiveColumn::APP_ID, isValid);
185 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
186 if (rdbStore == nullptr) {
187 MEDIA_ERR_LOG("UriSensitive query operation, rdbStore is null.");
188 return;
189 }
190 cmd.SetTableName(AppUriSensitiveColumn::APP_URI_SENSITIVE_TABLE);
191 for (const auto &val : values) {
192 predicateInColumns.push_back(static_cast<string>(val.Get(AppUriSensitiveColumn::FILE_ID, isValid)));
193 }
194 predicates.In(AppUriSensitiveColumn::FILE_ID, predicateInColumns);
195 predicates.And()->EqualTo(AppUriSensitiveColumn::APP_ID, appid);
196 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
197 resultSet = MediaLibraryRdbStore::QueryWithFilter(rdbPredicate, columns);
198 return;
199 }
200
CanConvertToInt32(const std::string & str)201 static bool CanConvertToInt32(const std::string &str)
202 {
203 std::istringstream iss(str);
204 int32_t num = 0;
205 iss >> num;
206 return iss.eof() && !iss.fail();
207 }
208
GetFileId(const DataShareValuesBucket & values,bool & isValid)209 static int32_t GetFileId(const DataShareValuesBucket &values, bool &isValid)
210 {
211 int32_t ret = E_ERR;
212 string fileIdStr = static_cast<string>(values.Get(AppUriSensitiveColumn::FILE_ID, isValid));
213 if (CanConvertToInt32(fileIdStr)) {
214 ret = static_cast<int32_t>(std::stoi(fileIdStr));
215 }
216 return ret;
217 }
218
GetSingleDbOperation(const vector<DataShareValuesBucket> & values,vector<int32_t> & dbOperation,vector<int32_t> & querySingleResultSet,int index)219 static void GetSingleDbOperation(const vector<DataShareValuesBucket> &values, vector<int32_t> &dbOperation,
220 vector<int32_t> &querySingleResultSet, int index)
221 {
222 bool isValid;
223 int32_t fileId = GetFileId(values.at(index), isValid);
224 if (fileId == E_ERR) {
225 MEDIA_ERR_LOG("Failed GetFileId.");
226 return;
227 }
228 int32_t uriType = values.at(index).Get(AppUriSensitiveColumn::URI_TYPE, isValid);
229 int32_t sensitiveType = values.at(index).Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValid);
230 if ((fileId == querySingleResultSet.at(FILE_ID_INDEX)) && (uriType == querySingleResultSet.at(URI_TYPE_INDEX))) {
231 if (sensitiveType == querySingleResultSet.at(SENSITIVE_TYPE_INDEX)) {
232 dbOperation[index] = NO_DB_OPERATION;
233 } else {
234 dbOperation[index] = UPDATE_DB_OPERATION;
235 }
236 }
237 }
238
GetAllUriDbOperation(const vector<DataShareValuesBucket> & values,vector<int32_t> & dbOperation,std::shared_ptr<OHOS::NativeRdb::ResultSet> & queryResult)239 static void GetAllUriDbOperation(const vector<DataShareValuesBucket> &values, vector<int32_t> &dbOperation,
240 std::shared_ptr<OHOS::NativeRdb::ResultSet> &queryResult)
241 {
242 for (const auto &val : values) {
243 dbOperation.push_back(INSERT_DB_OPERATION);
244 }
245 if ((queryResult == nullptr) || (queryResult->GoToFirstRow() != NativeRdb::E_OK)) {
246 MEDIA_INFO_LOG("UriSensitive query result is null.");
247 return;
248 }
249 do {
250 vector<int32_t> querySingleResultSet;
251 querySingleResultSet.push_back(GetInt32Val(AppUriSensitiveColumn::FILE_ID, queryResult));
252 querySingleResultSet.push_back(GetInt32Val(AppUriSensitiveColumn::URI_TYPE, queryResult));
253 querySingleResultSet.push_back(GetInt32Val(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, queryResult));
254 for (size_t i = 0; i < values.size(); i++) {
255 GetSingleDbOperation(values, dbOperation, querySingleResultSet, i);
256 }
257 } while (!queryResult->GoToNextRow());
258 }
259
BatchUpdate(MediaLibraryCommand & cmd,std::vector<string> inColumn,int32_t tableType,const std::vector<DataShareValuesBucket> & values,std::shared_ptr<TransactionOperations> trans)260 static void BatchUpdate(MediaLibraryCommand &cmd, std::vector<string> inColumn, int32_t tableType,
261 const std::vector<DataShareValuesBucket> &values, std::shared_ptr<TransactionOperations> trans)
262 {
263 cmd.SetTableName(AppUriSensitiveColumn::APP_URI_SENSITIVE_TABLE);
264 bool isValid;
265 string appid = values.at(0).Get(AppUriSensitiveColumn::APP_ID, isValid);
266 int32_t sensitiveType = values.at(0).Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValid);
267 DataShareValuesBucket valuesBucket;
268 DataSharePredicates predicates;
269 predicates.In(AppUriSensitiveColumn::FILE_ID, inColumn);
270 predicates.EqualTo(AppUriSensitiveColumn::APP_ID, appid);
271 predicates.And()->EqualTo(AppUriSensitiveColumn::URI_TYPE, to_string(tableType));
272 valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, sensitiveType);
273 ValuesBucket value = RdbUtils::ToValuesBucket(valuesBucket);
274 if (value.IsEmpty()) {
275 MEDIA_ERR_LOG("MediaLibraryDataManager Insert: Input parameter is invalid");
276 return;
277 }
278 cmd.SetValueBucket(value);
279 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
280 UriSensitiveOperations::UpdateOperation(cmd, rdbPredicate, trans);
281 }
282
AppstateOberserverBuild(int32_t sensitiveType)283 static void AppstateOberserverBuild(int32_t sensitiveType)
284 {
285 MedialibraryAppStateObserverManager::GetInstance().SubscribeAppState();
286 }
287
ValueBucketCheck(const std::vector<DataShareValuesBucket> & values)288 static int32_t ValueBucketCheck(const std::vector<DataShareValuesBucket> &values)
289 {
290 bool isValidArr[] = {false, false, false, false};
291 if (values.empty()) {
292 return E_ERR;
293 }
294 for (const auto &val : values) {
295 val.Get(AppUriSensitiveColumn::FILE_ID, isValidArr[FILE_ID_INDEX]);
296 val.Get(AppUriSensitiveColumn::URI_TYPE, isValidArr[URI_TYPE_INDEX]);
297 val.Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValidArr[SENSITIVE_TYPE_INDEX]);
298 val.Get(AppUriSensitiveColumn::APP_ID, isValidArr[APP_ID_INDEX]);
299 for (size_t i = 0; i < sizeof(isValidArr); i++) {
300 if ((isValidArr[i]) == false) {
301 return E_ERR;
302 }
303 }
304 }
305 return E_OK;
306 }
307
InsertValueBucketPrepare(const std::vector<DataShareValuesBucket> & values,int32_t fileId,int32_t uriType,std::vector<ValuesBucket> & batchInsertBucket)308 static void InsertValueBucketPrepare(const std::vector<DataShareValuesBucket> &values, int32_t fileId,
309 int32_t uriType, std::vector<ValuesBucket> &batchInsertBucket)
310 {
311 bool isValid;
312 ValuesBucket insertValues;
313 string appid = values.at(0).Get(AppUriSensitiveColumn::APP_ID, isValid);
314 int32_t sensitiveType = values.at(0).Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValid);
315 insertValues.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, sensitiveType);
316 insertValues.Put(AppUriSensitiveColumn::FILE_ID, fileId);
317 insertValues.Put(AppUriSensitiveColumn::APP_ID, appid);
318 insertValues.Put(AppUriSensitiveColumn::URI_TYPE, uriType);
319 insertValues.Put(AppUriSensitiveColumn::DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
320 batchInsertBucket.push_back(insertValues);
321 }
322
GrantUriSensitive(MediaLibraryCommand & cmd,const std::vector<DataShareValuesBucket> & values)323 int32_t UriSensitiveOperations::GrantUriSensitive(MediaLibraryCommand &cmd,
324 const std::vector<DataShareValuesBucket> &values)
325 {
326 std::vector<string> photosValues;
327 std::vector<string> audiosValues;
328 std::vector<int32_t> dbOperation;
329 std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet;
330 std::vector<ValuesBucket> batchInsertBucket;
331 bool photoNeedToUpdate = false;
332 bool audioNeedToUpdate = false;
333 bool needToInsert = false;
334 bool isValid = false;
335 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
336 std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
337 int32_t err = E_OK;
338 std::function<int(void)> func = [&]()->int {
339 if (ValueBucketCheck(values) != E_OK) {
340 return E_ERR;
341 }
342 string appid = values.at(0).Get(AppUriSensitiveColumn::APP_ID, isValid);
343 int32_t sensitiveType = values.at(0).Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValid);
344 AppstateOberserverBuild(sensitiveType);
345 QueryUriSensitive(cmd, values, resultSet);
346 GetAllUriDbOperation(values, dbOperation, resultSet);
347 for (size_t i = 0; i < values.size(); i++) {
348 int32_t fileId = GetFileId(values.at(i), isValid);
349 int32_t uriType = values.at(i).Get(AppUriSensitiveColumn::URI_TYPE, isValid);
350 if ((dbOperation.at(i) == UPDATE_DB_OPERATION) && (uriType == PHOTOSTYPE)) {
351 photoNeedToUpdate = true;
352 photosValues.push_back(static_cast<string>(values.at(i).Get(AppUriSensitiveColumn::FILE_ID, isValid)));
353 } else if ((dbOperation.at(i) == UPDATE_DB_OPERATION) && (uriType == AUDIOSTYPE)) {
354 audioNeedToUpdate = true;
355 audiosValues.push_back(static_cast<string>(values.at(i).Get(AppUriSensitiveColumn::FILE_ID, isValid)));
356 } else if (dbOperation.at(i) == INSERT_DB_OPERATION) {
357 needToInsert = true;
358 InsertValueBucketPrepare(values, fileId, uriType, batchInsertBucket);
359 }
360 }
361 if (photoNeedToUpdate) {
362 BatchUpdate(cmd, photosValues, PHOTOSTYPE, values, trans);
363 }
364 if (audioNeedToUpdate) {
365 BatchUpdate(cmd, audiosValues, AUDIOSTYPE, values, trans);
366 }
367 if (needToInsert) {
368 UriSensitiveOperations::BatchInsertOperation(cmd, batchInsertBucket, trans);
369 }
370 return err;
371 };
372 err = trans->RetryTrans(func);
373 if (err != E_OK) {
374 MEDIA_ERR_LOG("GrantUriSensitive: tans finish fail!, ret:%{public}d", err);
375 return err;
376 }
377 return E_OK;
378 }
379
QuerySensitiveType(const std::string & appId,const std::string & fileId)380 int32_t UriSensitiveOperations::QuerySensitiveType(const std::string &appId, const std::string &fileId)
381 {
382 NativeRdb::RdbPredicates rdbPredicate(AppUriSensitiveColumn::APP_URI_SENSITIVE_TABLE);
383 rdbPredicate.And()->EqualTo(AppUriSensitiveColumn::APP_ID, appId);
384 rdbPredicate.And()->EqualTo(AppUriSensitiveColumn::FILE_ID, fileId);
385
386 vector<string> columns;
387 columns.push_back(AppUriSensitiveColumn::ID);
388 columns.push_back(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE);
389
390 auto resultSet = MediaLibraryRdbStore::QueryWithFilter(rdbPredicate, columns);
391 if (resultSet == nullptr) {
392 return 0;
393 }
394
395 int32_t numRows = 0;
396 resultSet->GetRowCount(numRows);
397 if (numRows == 0) {
398 return 0;
399 }
400 resultSet->GoToFirstRow();
401 return MediaLibraryRdbStore::GetInt(resultSet, AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE);
402 }
QueryAppId(const std::string & fileId)403 std::string UriSensitiveOperations::QueryAppId(const std::string &fileId)
404 {
405 NativeRdb::RdbPredicates rdbPredicate(PhotoColumn::PHOTOS_TABLE);
406 rdbPredicate.And()->EqualTo(MediaColumn::MEDIA_ID, fileId);
407
408 vector<string> columns;
409 columns.push_back(MediaColumn::MEDIA_ID);
410 columns.push_back(MediaColumn::MEDIA_OWNER_APPID);
411
412 auto resultSet = MediaLibraryRdbStore::QueryWithFilter(rdbPredicate, columns);
413 if (resultSet == nullptr) {
414 return 0;
415 }
416
417 int32_t numRows = 0;
418 resultSet->GetRowCount(numRows);
419 if (numRows == 0) {
420 return 0;
421 }
422 resultSet->GoToFirstRow();
423 return MediaLibraryRdbStore::GetString(resultSet, MediaColumn::MEDIA_OWNER_APPID);
424 }
425 }
426 }