• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include <cerrno>
16 #include <cstdio>
17 #include <fstream>
18 #include <iostream>
19 #include <unistd.h>
20 #include <vector>
21 #ifdef WITH_SELINUX
22 #include <policycoreutils.h>
23 #endif // WITH_SELINUX
24 #include "account_error_no.h"
25 #include "account_info.h"
26 #include "account_log_wrapper.h"
27 #include "directory_ex.h"
28 #include "file_ex.h"
29 #include "hisysevent_adapter.h"
30 #include "ohos_account_data_deal.h"
31 namespace OHOS {
32 namespace AccountSA {
33 namespace {
34 const std::string ACCOUNT_CFG_FILE_NAME = "/account.json";
35 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_NAME = "account_name";
36 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID = "raw_uid";
37 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_UID = "open_id";
38 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS = "bind_status";
39 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME = "account_nickname";
40 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR = "account_avatar";
41 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA = "account_scalableData";
42 const std::string DATADEAL_JSON_KEY_USERID = "user_id";
43 const std::string DATADEAL_JSON_KEY_BIND_TIME = "bind_time";
44 } // namespace
45 
OhosAccountDataDeal(const std::string & configFileDir)46 OhosAccountDataDeal::OhosAccountDataDeal(const std::string &configFileDir) : configFileDir_(configFileDir)
47 {
48     initOk_ = false;
49 }
50 
Init(int32_t userId)51 ErrCode OhosAccountDataDeal::Init(int32_t userId)
52 {
53     std::string configFile = configFileDir_ + std::to_string(userId) + ACCOUNT_CFG_FILE_NAME;
54     if (!FileExists(configFile)) {
55         ACCOUNT_LOGI("file %{public}s not exist, create!", configFile.c_str());
56         BuildJsonFileFromScratch(userId);
57 #ifdef WITH_SELINUX
58         Restorecon(configFile.c_str());
59 #endif // WITH_SELINUX
60     }
61 
62     std::ifstream fin(configFile);
63     if (!fin) {
64         ACCOUNT_LOGE("Failed to open config file %{public}s, errno %{public}d.", configFile.c_str(), errno);
65         ReportOhosAccountOperationFail(userId, OPERATION_INIT_OPEN_FILE_TO_READ, errno, configFile);
66         return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
67     }
68 
69     // NOT-allow exceptions when parse json file
70     std::lock_guard<std::mutex> lock(mutex_);
71     jsonData_ = json::parse(fin, nullptr, false);
72     fin.close();
73     if (!jsonData_.is_structured()) {
74         ACCOUNT_LOGE("Invalid json file, remove");
75         if (RemoveFile(configFile)) {
76             ACCOUNT_LOGE("Remove invalid json file %{public}s failed, errno %{public}d.", configFile.c_str(), errno);
77             ReportOhosAccountOperationFail(userId, OPERATION_REMOVE_FILE, errno, configFile);
78         }
79         return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
80     }
81 
82     initOk_ = true;
83     return ERR_OK;
84 }
85 
AccountInfoFromJson(AccountInfo & accountInfo,int32_t userId)86 ErrCode OhosAccountDataDeal::AccountInfoFromJson(AccountInfo &accountInfo, int32_t userId)
87 {
88     if (!initOk_) {
89         ACCOUNT_LOGE("not init yet!");
90         return ERR_ACCOUNT_DATADEAL_NOT_READY;
91     }
92     return GetAccountInfo(accountInfo, userId);
93 }
94 
AccountInfoToJson(const AccountInfo & accountInfo) const95 ErrCode OhosAccountDataDeal::AccountInfoToJson(const AccountInfo &accountInfo) const
96 {
97     if (!initOk_) {
98         ACCOUNT_LOGE("Not init ok");
99         return ERR_ACCOUNT_DATADEAL_NOT_READY;
100     }
101     return SaveAccountInfo(accountInfo);
102 }
103 
SaveAccountInfo(const AccountInfo & accountInfo) const104 ErrCode OhosAccountDataDeal::SaveAccountInfo(const AccountInfo &accountInfo) const
105 {
106     std::string scalableDataStr = (accountInfo.ohosAccountInfo_.scalableData_).ToString();
107     nlohmann::json jsonData = json {
108         {DATADEAL_JSON_KEY_BIND_TIME, accountInfo.bindTime_},
109         {DATADEAL_JSON_KEY_USERID, accountInfo.userId_},
110         {DATADEAL_JSON_KEY_OHOSACCOUNT_NAME, accountInfo.ohosAccountInfo_.name_},
111         {DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID, accountInfo.ohosAccountInfo_.GetRawUid()},
112         {DATADEAL_JSON_KEY_OHOSACCOUNT_UID, accountInfo.ohosAccountInfo_.uid_},
113         {DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS, accountInfo.ohosAccountInfo_.status_},
114         {DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME, accountInfo.ohosAccountInfo_.nickname_},
115         {DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR, accountInfo.ohosAccountInfo_.avatar_},
116         {DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA, scalableDataStr}
117     };
118     std::string accountInfoValue = jsonData.dump(-1, ' ', false, json::error_handler_t::ignore);
119     std::string configFile = configFileDir_ + std::to_string(accountInfo.userId_) + ACCOUNT_CFG_FILE_NAME;
120     FILE *fp = fopen(configFile.c_str(), "wb");
121     if (fp == nullptr) {
122         ACCOUNT_LOGE("failed to open %{public}s, errno %{public}d.", configFile.c_str(), errno);
123         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
124         return ERR_ACCOUNT_COMMON_FILE_OPEN_FAILED;
125     }
126     size_t num = fwrite(accountInfoValue.c_str(), sizeof(char), accountInfoValue.length(), fp);
127     if (num != accountInfoValue.length()) {
128         ACCOUNT_LOGE("failed to fwrite %{public}s, errno %{public}d.", configFile.c_str(), errno);
129         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
130         fclose(fp);
131         return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
132     }
133     if (fflush(fp) != 0) {
134         ACCOUNT_LOGE("failed to fflush %{public}s, errno %{public}d.", configFile.c_str(), errno);
135         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
136         fclose(fp);
137         return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
138     }
139     if (fsync(fileno(fp)) != 0) {
140         ACCOUNT_LOGE("failed to fsync %{public}s, errno %{public}d.", configFile.c_str(), errno);
141         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
142         fclose(fp);
143         return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
144     }
145     fclose(fp);
146 
147     // change mode
148     if (!ChangeModeFile(configFile, S_IRUSR | S_IWUSR)) {
149         ACCOUNT_LOGE("failed to change mode for file %{public}s, errno %{public}d.", configFile.c_str(), errno);
150         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_CHANGE_MODE_FILE, errno, configFile);
151         return ERR_OHOSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR;
152     }
153     return ERR_OK;
154 }
155 
ParseJsonFromFile(const std::string & filePath,nlohmann::json & jsonData,int32_t userId)156 ErrCode OhosAccountDataDeal::ParseJsonFromFile(const std::string &filePath, nlohmann::json &jsonData, int32_t userId)
157 {
158     std::ifstream fin(filePath);
159     if (!fin) {
160         ACCOUNT_LOGE("Failed to open config file %{public}s, errno %{public}d.", filePath.c_str(), errno);
161         ReportOhosAccountOperationFail(userId, OPERATION_OPEN_FILE_TO_READ, errno, filePath);
162         return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
163     }
164     // NOT-allow exceptions when parse json file
165     jsonData = json::parse(fin, nullptr, false);
166     fin.close();
167     if (!jsonData.is_structured()) {
168         ACCOUNT_LOGE("Invalid json file,  %{public}s, remove", filePath.c_str());
169         return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
170     }
171     return ERR_OK;
172 }
173 
GetAccountInfo(AccountInfo & accountInfo,const int32_t userId)174 ErrCode OhosAccountDataDeal::GetAccountInfo(AccountInfo &accountInfo, const int32_t userId)
175 {
176     std::string configFile = configFileDir_ + std::to_string(userId) + ACCOUNT_CFG_FILE_NAME;
177     if (!FileExists(configFile)) {
178         ACCOUNT_LOGI("file %{public}s not exist, create!", configFile.c_str());
179         BuildJsonFileFromScratch(userId); // create default config file for first login
180 #ifdef WITH_SELINUX
181         Restorecon(configFile.c_str());
182 #endif // WITH_SELINUX
183     }
184     std::lock_guard<std::mutex> lock(mutex_);
185     ErrCode ret = ParseJsonFromFile(configFile, jsonData_, userId);
186     if (ret != ERR_OK) {
187         return ret;
188     }
189 
190     const auto &jsonObjectEnd = jsonData_.end();
191     if (jsonData_.find(DATADEAL_JSON_KEY_BIND_TIME) != jsonObjectEnd) {
192         accountInfo.bindTime_ = jsonData_.at(DATADEAL_JSON_KEY_BIND_TIME).get<std::time_t>();
193     }
194 
195     if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_NAME) != jsonObjectEnd) {
196         accountInfo.ohosAccountInfo_.name_ = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_NAME).get<std::string>();
197     }
198 
199     if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID) != jsonObjectEnd) {
200         std::string rawUid = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID).get<std::string>();
201         accountInfo.ohosAccountInfo_.SetRawUid(rawUid);
202     }
203 
204     if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_UID) != jsonObjectEnd) {
205         accountInfo.ohosAccountInfo_.uid_ = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_UID).get<std::string>();
206     }
207 
208     if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS) != jsonObjectEnd) {
209         accountInfo.ohosAccountInfo_.status_ = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS).get<int32_t>();
210     }
211 
212     if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME) != jsonObjectEnd) {
213         accountInfo.ohosAccountInfo_.nickname_ =
214             jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME).get<std::string>();
215     }
216 
217     if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR) != jsonObjectEnd) {
218         accountInfo.ohosAccountInfo_.avatar_ = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR).get<std::string>();
219     }
220 
221     if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA) != jsonObjectEnd) {
222         auto scalableDataJson = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA).get<std::string>();
223         sptr<AAFwk::Want> want = AAFwk::Want::FromString(scalableDataJson);
224         if (want == nullptr) {
225             return ERR_ACCOUNT_COMMON_NULL_PTR_ERROR;
226         }
227         accountInfo.ohosAccountInfo_.scalableData_ = *want;
228     }
229     accountInfo.userId_ = userId;
230     return ERR_OK;
231 }
232 
BuildJsonFileFromScratch(int32_t userId) const233 void OhosAccountDataDeal::BuildJsonFileFromScratch(int32_t userId) const
234 {
235     AccountInfo accountInfo;
236     accountInfo.userId_ = userId;
237     accountInfo.bindTime_ = 0;
238     accountInfo.ohosAccountInfo_.uid_ = DEFAULT_OHOS_ACCOUNT_UID;
239     accountInfo.ohosAccountInfo_.name_ = DEFAULT_OHOS_ACCOUNT_NAME;
240     accountInfo.ohosAccountInfo_.status_ = ACCOUNT_STATE_UNBOUND;
241     accountInfo.digest_ = "";
242     accountInfo.ohosAccountInfo_.SetRawUid(DEFAULT_OHOS_ACCOUNT_UID);
243     SaveAccountInfo(accountInfo);
244 }
245 } // namespace AccountSA
246 } // namespace OHOS