• 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 
16 #ifndef OHOS_WIFI_CONFIG_FILE_IMPL_H
17 #define OHOS_WIFI_CONFIG_FILE_IMPL_H
18 #include <fstream>
19 #include <sstream>
20 #include <string>
21 #include <unistd.h>
22 #include <vector>
23 #include <mutex>
24 #include "wifi_config_file_spec.h"
25 #include "wifi_log.h"
26 #ifdef FEATURE_ENCRYPTION_SUPPORT
27 #include "wifi_encryption_util.h"
28 #endif
29 
30 namespace OHOS {
31 namespace Wifi {
32 constexpr int WIFI_CONFIG_FILE_LINE_MAX_LENGTH = 4096;
33 /**
34  * @Description Remove head and tail space
35  *
36  * @param str - String
37  */
TrimString(std::string & str)38 static inline void TrimString(std::string &str)
39 {
40     int i = 0;
41     int j = static_cast<int>(str.length()) - 1;
42     while (i < static_cast<int>(str.length()) && str[i] == ' ') {
43         ++i;
44     }
45     while (j >= 0 && str[j] == ' ') {
46         --j;
47     }
48     str = ((i > j) ? "" : str.substr(i, j - i + 1));
49 }
50 
51 /**
52  * @Description Delete comment message begin with ; and #
53  *
54  * @param str - String
55  */
DelComment(std::string & str)56 static inline void DelComment(std::string &str)
57 {
58     std::string::size_type i = 0;
59     for (; i < str.length(); ++i) {
60         if (str[i] == ';' || str[i] == '#') {
61             str = str.substr(0, i);
62             break;
63         }
64     }
65     return;
66 }
67 
68 template<typename T>
69 class WifiConfigFileImpl {
70 public:
71     /**
72      * @Description Set the config file path
73      *
74      * @param fileName - file name
75      * @return int - 0 success
76      */
77     int SetConfigFilePath(const std::string &fileName);
78 
79     /**
80      * @Description Set the Encryption info and Encryption tag
81      *
82      * @param key - key
83      * @param iv - iv
84      * @return int - 0 success
85      */
86     int SetEncryptionInfo(const std::string &key, const std::string &iv);
87 
88     /**
89      * @Description Unset the Encryption info: delete the key loaded in hks
90      *
91      * @return int - 0 success
92      */
93     int UnsetEncryptionInfo();
94 
95     /**
96      * @Description read and parses the network section of ini config file, need call SetConfigFilePath first
97      *
98      * @return int - 0 Success; >0 parse failed
99      */
100     int ReadNetworkSection(T &item, std::istream &fs, std::string &line);
101 
102     /**
103      * @Description read and parses the networks of ini config file, need call SetConfigFilePath first
104      *
105      * @return int - 0 Success; >0 parse failed
106      */
107     int ReadNetwork(T &item, std::istream &fs, std::string &line);
108 
109     /**
110      * @Description read ini config file, need call SetConfigFilePath first
111      */
ReadFile(std::istream & fs)112     void ReadFile(std::istream &fs)
113     {
114         std::lock_guard<std::mutex> lock(valueMutex_);
115         mValues.clear();
116         T item;
117         std::string line;
118         int configError;
119         while (std::getline(fs, line)) {
120             TrimString(line);
121             if (line.empty()) {
122                 continue;
123             }
124             if (line[0] == '[' && line[line.length() - 1] == '{') {
125                 ClearTClass(item); /* template function, needing specialization */
126                 configError = ReadNetwork(item, fs, line);
127                 if (configError > 0) {
128                     LOGE("Parse network failed.");
129                     continue;
130                 }
131                 mValues.push_back(item);
132             }
133         }
134     }
135 
136     /**
137      * @Description Write to temp file, then rename to ini config file
138      *
139      * @param content - write data
140      * @return int - 0 Success
141      */
WriteFile(const std::string & content)142     int WriteFile(const std::string &content)
143     {
144         if (mFileName.empty()) {
145             LOGE("File name is empty.");
146             return -1;
147         }
148         std::string tempFileName = mFileName + ".temp";
149         FILE* fp = fopen(tempFileName.c_str(), "w");
150         if (!fp) {
151             LOGE("Temp config file: %{public}s, fopen() failed!", tempFileName.c_str());
152             return -1;
153         }
154         size_t ret = fwrite(content.c_str(), 1, content.length(), fp);
155         if (ret != content.length()) {
156             LOGE("Temp config file: %{public}s, fwrite() failed!", tempFileName.c_str());
157             (void)fclose(fp);
158             (void)remove(tempFileName.c_str());
159             return -1;
160         }
161         (void)fflush(fp);
162         (void)fsync(fileno(fp));
163         (void)fclose(fp);
164 
165         if (rename(tempFileName.c_str(), mFileName.c_str()) != 0) {
166             LOGE("Save config file: %{public}s, rename() failed!", mFileName.c_str());
167             (void)remove(tempFileName.c_str());
168             return -1;
169         }
170         return 0;
171     }
172 
173     /**
174      * @Description read and parses the ini config file, need call SetConfigFilePath first
175      * need call SetEncryptionInfo first when load encrypted config file
176      *
177      * @return int - 0 Success; -1 file not exist
178      */
179     int LoadConfig();
180 
181     /**
182      * @Description Save config to file
183      * need call SetEncryptionInfo first when save encrypted config file
184      *
185      * @return int - 0 Success; -1 Failed
186      */
SaveConfig()187     int SaveConfig()
188     {
189         std::string content;
190         std::lock_guard<std::mutex> lock(valueMutex_);
191         {
192             std::ostringstream ss;
193             LOGI("Save config:%{public}s size:%{public}d", GetTClassName<T>().c_str(),
194                 static_cast<int>(mValues.size()));
195             for (std::size_t i = 0; i < mValues.size(); ++i) {
196                 T &item = mValues[i];
197                 /*
198                 * here use template function GetTClassName OutTClassString, needing
199                 * specialization.
200                 */
201                 ss << "[" << GetTClassName<T>() << "_" << (i + 1) << "] {" << std::endl;
202                 ss << OutTClassString(item) << std::endl;
203                 ss << "}" << std::endl;
204             }
205             content = ss.str();
206         }
207 #ifdef FEATURE_ENCRYPTION_SUPPORT
208         if (mSetEncryption) {
209             WifiLoopEncrypt(mEncryptionInfo, content, mEncry);
210             std::fill(content.begin(), content.end(), 0);
211             content = mEncry.encryptedPassword;
212         }
213 #endif
214         mValues.clear(); /* clear values */
215         if (WriteFile(content) != 0) {
216             return -1;
217         }
218         return 0;
219     }
220 
221     /**
222      * @Description Get config values
223      *
224      * @param results - output config values
225      * @return int - 0 Success, -1 Failed
226      */
GetValue(std::vector<T> & results)227     int GetValue(std::vector<T> &results)
228     {
229         std::lock_guard<std::mutex> lock(valueMutex_);
230         std::swap(results, mValues);
231         return 0;
232     }
233 
234     /**
235      * @Description Get config values
236      *
237      * @return config values
238      */
GetValue()239     const std::vector<T>& GetValue()
240     {
241         std::lock_guard<std::mutex> lock(valueMutex_);
242         return mValues;
243     }
244 
245     /**
246      * @Description Set the config value
247      *
248      * @param values - input config values
249      * @return int - 0 Success, -1 Failed
250      */
SetValue(const std::vector<T> & values)251     int SetValue(const std::vector<T> &values)
252     {
253         std::lock_guard<std::mutex> lock(valueMutex_);
254         mValues = values;
255         return 0;
256     }
257 
258 private:
259     std::string mFileName;
260     std::vector<T> mValues;
261     bool mSetEncryption;
262     std::mutex valueMutex_;
263 #ifdef FEATURE_ENCRYPTION_SUPPORT
264     WifiEncryptionInfo mEncryptionInfo;
265     EncryptedData mEncry;
266 #endif
267 };
268 
269 template<typename T>
SetConfigFilePath(const std::string & fileName)270 int WifiConfigFileImpl<T>::SetConfigFilePath(const std::string &fileName)
271 {
272     mFileName = fileName;
273     mSetEncryption = false;
274     return 0;
275 }
276 
277 template<typename T>
SetEncryptionInfo(const std::string & key,const std::string & iv)278 int WifiConfigFileImpl<T>::SetEncryptionInfo(const std::string &key, const std::string &iv)
279 {
280 #ifdef FEATURE_ENCRYPTION_SUPPORT
281     mSetEncryption = true;
282     mEncryptionInfo.SetFile(GetTClassName<T>());
283     if (!key.empty()) {
284         ImportKey(mEncryptionInfo, key);
285     }
286     mEncry.IV = iv;
287 #endif
288     return 0;
289 }
290 
291 template<typename T>
UnsetEncryptionInfo()292 int WifiConfigFileImpl<T>::UnsetEncryptionInfo()
293 {
294 #ifdef FEATURE_ENCRYPTION_SUPPORT
295     DeleteKey(mEncryptionInfo);
296 #endif
297     return 0;
298 }
299 
300 template<typename T>
ReadNetworkSection(T & item,std::istream & fs,std::string & line)301 int WifiConfigFileImpl<T>::ReadNetworkSection(T &item, std::istream &fs, std::string &line)
302 {
303     int sectionError = 0;
304     while (std::getline(fs, line)) {
305         TrimString(line);
306         if (line.empty()) {
307             continue;
308         }
309         if (line.length() > WIFI_CONFIG_FILE_LINE_MAX_LENGTH) {
310             LOGE("%{public}s %{public}s line length is too big.", __func__, GetTClassName<T>().c_str());
311             sectionError++;
312             break;
313         }
314         if (line[0] == '<' && line[line.length() - 1] == '>') {
315             return sectionError;
316         }
317         std::string::size_type npos = line.find("=");
318         if (npos == std::string::npos) {
319             LOGE("Invalid config line");
320             sectionError++;
321             continue;
322         }
323         std::string key = line.substr(0, npos);
324         std::string value = line.substr(npos + 1);
325         TrimString(key);
326         TrimString(value);
327         /* template function, needing specialization */
328         sectionError += SetTClassKeyValue(item, key, value);
329         std::fill(value.begin(), value.end(), 0);
330     }
331     LOGE("Section config not end correctly");
332     sectionError++;
333     return sectionError;
334 }
335 
336 template<typename T>
ReadNetwork(T & item,std::istream & fs,std::string & line)337 int WifiConfigFileImpl<T>::ReadNetwork(T &item, std::istream &fs, std::string &line)
338 {
339     int networkError = 0;
340     while (std::getline(fs, line)) {
341         TrimString(line);
342         if (line.empty()) {
343             continue;
344         }
345         if (line[0] == '<' && line[line.length() - 1] == '>') {
346             networkError += ReadNetworkSection(item, fs, line);
347         } else if (line.compare("}") == 0) {
348             return networkError;
349         } else {
350             LOGE("Invalid config line");
351             networkError++;
352         }
353     }
354     LOGE("Network config not end correctly");
355     networkError++;
356     return networkError;
357 }
358 
359 template<typename T>
LoadConfig()360 int WifiConfigFileImpl<T>::LoadConfig()
361 {
362     if (mFileName.empty()) {
363         LOGE("File name is empty.");
364         return -1;
365     }
366     std::ifstream fs(mFileName.c_str());
367     if (!fs.is_open()) {
368         LOGE("Loading config file: %{public}s, fs.is_open() failed!", mFileName.c_str());
369         return -1;
370     }
371 #ifdef FEATURE_ENCRYPTION_SUPPORT
372     if (mSetEncryption) {
373         std::string content((std::istreambuf_iterator<char>(fs)), std::istreambuf_iterator<char>());
374         mEncry.encryptedPassword = content;
375         WifiLoopDecrypt(mEncryptionInfo, mEncry, content);
376         std::stringstream strStream(content);
377         ReadFile(strStream);
378         std::fill(content.begin(), content.end(), 0);
379     } else {
380         ReadFile(fs);
381     }
382 #else
383     ReadFile(fs);
384 #endif
385     fs.close();
386     return 0;
387 }
388 }  // namespace Wifi
389 }  // namespace OHOS
390 #endif