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 }