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 "visit_record_json_manager.h"
17 
18 #include "accesstoken_kit.h"
19 #include "dlp_permission_log.h"
20 #include "dlp_permission.h"
21 
22 namespace OHOS {
23 namespace Security {
24 namespace DlpPermission {
25 using namespace Security::AccessToken;
26 using Json = nlohmann::json;
27 using namespace OHOS;
28 namespace {
29 const std::string BUNDLENAME = "bundleName";
30 const std::string DOCURI = "docUri";
31 const std::string USERID = "userId";
32 const std::string TIMESTAMP = "timestamp";
33 const std::string RECORDLIST = "recordList";
34 const std::string ORIGINAL_TOKENID = "originalTokenId";
35 static const uint32_t MAX_RETENTION_SIZE = 1024;
36 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION,
37                                                        "VisitRecordJsonManager" };
38 }
39 
VisitRecordJsonManager()40 VisitRecordJsonManager::VisitRecordJsonManager()
41 {
42     infoList_.clear();
43 }
44 
~VisitRecordJsonManager()45 VisitRecordJsonManager::~VisitRecordJsonManager()
46 {
47     infoList_.clear();
48 }
49 
AddVisitRecord(const std::string & bundleName,const int32_t & userId,const std::string & docUri,const int64_t timestamp,const AccessTokenID originalTokenId)50 int32_t VisitRecordJsonManager::AddVisitRecord(const std::string& bundleName, const int32_t& userId,
51     const std::string& docUri, const int64_t timestamp, const AccessTokenID originalTokenId)
52 {
53     std::lock_guard<std::mutex> lock(mutex_);
54     if (infoList_.size() > MAX_RETENTION_SIZE) {
55         DLP_LOG_ERROR(LABEL, "size bigger than MAX_RETENTION_SIZE");
56         return DLP_JSON_UPDATE_ERROR;
57     }
58     for (auto iter = infoList_.begin(); iter != infoList_.end(); ++iter) {
59         if (iter->bundleName == bundleName && iter->userId == userId && iter->docUri == docUri) {
60             infoList_.erase(iter);
61             break;
62         }
63     }
64     VisitRecordInfo info;
65     info.bundleName = bundleName;
66     info.userId = userId;
67     info.docUri = docUri;
68     info.timestamp = timestamp;
69     info.originalTokenId = originalTokenId;
70     infoList_.emplace_back(info);
71     return DLP_OK;
72 }
73 
AddVisitRecord(const std::string & bundleName,const int32_t & userId,const std::string & docUri)74 int32_t VisitRecordJsonManager::AddVisitRecord(const std::string& bundleName, const int32_t& userId,
75     const std::string& docUri)
76 {
77     int64_t time =
78         std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
79             .count();
80     AccessTokenID originalTokenId = AccessToken::AccessTokenKit::GetHapTokenID(userId, bundleName, 0);
81     if (originalTokenId == 0) {
82         DLP_LOG_ERROR(LABEL, "Get normal tokenId error.");
83         return DLP_SERVICE_ERROR_VALUE_INVALID;
84     }
85     return AddVisitRecord(bundleName, userId, docUri, time, originalTokenId);
86 }
87 
GetVisitRecordList(const std::string & bundleName,const int32_t & userId,std::vector<VisitedDLPFileInfo> & infoVec)88 int32_t VisitRecordJsonManager::GetVisitRecordList(const std::string& bundleName, const int32_t& userId,
89     std::vector<VisitedDLPFileInfo>& infoVec)
90 {
91     std::lock_guard<std::mutex> lock(mutex_);
92     if (infoList_.empty()) {
93         return DLP_FILE_NO_NEED_UPDATE;
94     }
95     AccessTokenID originalTokenId = AccessToken::AccessTokenKit::GetHapTokenID(userId, bundleName, 0);
96     if (originalTokenId == 0) {
97         DLP_LOG_ERROR(LABEL, "Get normal tokenId error.");
98         return DLP_SERVICE_ERROR_VALUE_INVALID;
99     }
100     bool isFind = false;
101     for (auto iter = infoList_.begin(); iter != infoList_.end();) {
102         if (iter->bundleName != bundleName || iter->userId != userId) {
103             ++iter;
104             continue;
105         }
106         if (iter->originalTokenId == originalTokenId) {
107             VisitedDLPFileInfo info;
108             info.docUri = iter->docUri;
109             info.visitTimestamp = iter->timestamp;
110             infoVec.emplace_back(info);
111         }
112         iter = infoList_.erase(iter);
113         isFind = true;
114     }
115     if (!isFind) {
116         DLP_LOG_INFO(LABEL, "not find bundleName:%{public}s,userId:%{public}d", bundleName.c_str(), userId);
117         return DLP_FILE_NO_NEED_UPDATE;
118     }
119     return DLP_OK;
120 }
121 
122 
VisitRecordInfoToJson(Json & json,const VisitRecordInfo & info) const123 void VisitRecordJsonManager::VisitRecordInfoToJson(Json& json, const VisitRecordInfo& info) const
124 {
125     json = Json { { BUNDLENAME, info.bundleName },
126         { USERID, info.userId },
127         { DOCURI, info.docUri },
128         { TIMESTAMP, info.timestamp },
129         { ORIGINAL_TOKENID, info.originalTokenId} };
130 }
131 
VisitRecordInfoFromJson(const Json & json,VisitRecordInfo & info) const132 bool VisitRecordJsonManager::VisitRecordInfoFromJson(const Json& json, VisitRecordInfo& info) const
133 {
134     std::string bundleName = "";
135     std::string docUri = "";
136     int32_t userId = -1;
137     int64_t timestamp = -1;
138     AccessTokenID originalTokenId = 0;
139     if (json.contains(BUNDLENAME) && json.at(BUNDLENAME).is_string()) {
140         json.at(BUNDLENAME).get_to(bundleName);
141     }
142     if (json.contains(DOCURI) && json.at(DOCURI).is_string()) {
143         json.at(DOCURI).get_to(docUri);
144     }
145     if (json.contains(USERID) && json.at(USERID).is_number()) {
146         json.at(USERID).get_to(userId);
147     }
148     if (json.contains(TIMESTAMP) && json.at(TIMESTAMP).is_number()) {
149         json.at(TIMESTAMP).get_to(timestamp);
150     }
151     if (json.contains(ORIGINAL_TOKENID) && json.at(ORIGINAL_TOKENID).is_number()) {
152         json.at(ORIGINAL_TOKENID).get_to(originalTokenId);
153     }
154     if (bundleName.empty() || userId < 0 || docUri.empty() || timestamp < 0 || originalTokenId == 0) {
155         DLP_LOG_ERROR(LABEL, "param is invalid");
156         return false;
157     }
158     info.bundleName = bundleName;
159     info.userId = userId;
160     info.docUri = docUri;
161     info.timestamp = timestamp;
162     info.originalTokenId = originalTokenId;
163     return true;
164 }
165 
ToJson() const166 Json VisitRecordJsonManager::ToJson() const
167 {
168     std::lock_guard<std::mutex> lock(mutex_);
169     Json jsonObject;
170     for (auto iter = infoList_.begin(); iter != infoList_.end(); ++iter) {
171         Json infoJson;
172         VisitRecordInfoToJson(infoJson, *iter);
173         jsonObject[RECORDLIST].push_back(infoJson);
174     }
175     return jsonObject;
176 }
177 
FromJson(const Json & jsonObject)178 void VisitRecordJsonManager::FromJson(const Json& jsonObject)
179 {
180     if (jsonObject.is_null() || jsonObject.is_discarded()) {
181         DLP_LOG_ERROR(LABEL, "json error");
182         return;
183     }
184     if (!jsonObject.contains(RECORDLIST)) {
185         DLP_LOG_ERROR(LABEL, "jsonObject not contains RECORDLIST");
186         return;
187     }
188     for (const auto& json : jsonObject[RECORDLIST]) {
189         VisitRecordInfo info;
190         if (VisitRecordInfoFromJson(json, info)) {
191             AddVisitRecord(info.bundleName, info.userId, info.docUri, info.timestamp, info.originalTokenId);
192         }
193     }
194 }
195 
ToString() const196 std::string VisitRecordJsonManager::ToString() const
197 {
198     {
199         std::lock_guard<std::mutex> lock(mutex_);
200         if (infoList_.empty()) {
201             return "";
202         }
203     }
204     auto jsonObject = ToJson();
205     return jsonObject.dump();
206 }
207 } // namespace DlpPermission
208 } // namespace Security
209 } // namespace OHOS
210