• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "notification_locale.h"
17 #include "hilog_wrapper.h"
18 #include "locale_config.h"
19 #include "locale_matcher.h"
20 
21 namespace {
22 constexpr const char *LOCALE_CONFIG_PATH = "/system/etc/peripheral/resources/locale_path.json";
23 constexpr const char *SYSTEM_PERIPHERAL_RESOURCE_PATH = "/system/etc/peripheral/resources/";
24 constexpr const char *ELEMENT_STRING_FILE = "/element/string.json";
25 constexpr const char *DEFAULT_LANGUAGE_EN = "base";
26 } // namespace
27 
28 namespace OHOS {
29 namespace ExternalDeviceManager {
30 namespace {
IsPathValid(const std::string & path)31 bool IsPathValid(const std::string &path)
32 {
33     // Check for directory traversal patterns
34     if (path.find("..") != std::string::npos) {
35         return false;
36     }
37 
38     // Check for absolute paths
39     if (!path.empty() && (path[0] == '/' || path[0] == '\\')) {
40         return false;
41     }
42 
43     // Check for other suspicious characters
44     const std::string forbiddenChars = "\\:*?\"<>|";
45     return path.find_first_of(forbiddenChars) == std::string::npos;
46 }
47 } // namespace
48 
49 std::shared_ptr<NotificationLocale> NotificationLocale::instance_ = nullptr;
50 std::mutex NotificationLocale::instanceMutex_;
GetInstance()51 NotificationLocale &NotificationLocale::GetInstance()
52 {
53     std::lock_guard<std::mutex> lock(instanceMutex_);
54     if (instance_ == nullptr) {
55         instance_ = std::make_shared<NotificationLocale>();
56     }
57     return *(instance_.get());
58 }
59 
ParseJsonfile(const std::string & targetPath,std::unordered_map<std::string,std::string> & container)60 bool NotificationLocale::ParseJsonfile(
61     const std::string &targetPath, std::unordered_map<std::string, std::string> &container)
62 {
63     if (access(targetPath.c_str(), F_OK) != 0) {
64         EDM_LOGE(MODULE_SERVICE, "targetPath %{public}s invalid", targetPath.c_str());
65         return false;
66     }
67     std::ifstream inputStream(targetPath.c_str(), std::ios::in | std::ios::binary);
68     std::string fileStr(std::istreambuf_iterator<char> {inputStream}, std::istreambuf_iterator<char> {});
69     cJSON *root = cJSON_Parse(fileStr.c_str());
70     if (!root) {
71         EDM_LOGE(MODULE_SERVICE, "%{public}s json parse error", targetPath.c_str());
72         return false;
73     }
74     if (cJSON_IsNull(root) || !cJSON_IsObject(root)) {
75         EDM_LOGE(MODULE_SERVICE, "%{public}s json root error", targetPath.c_str());
76         cJSON_Delete(root);
77         return false;
78     }
79     cJSON *stringConf = cJSON_GetObjectItemCaseSensitive(root, "string");
80     if (!stringConf || cJSON_IsNull(stringConf) || !cJSON_IsArray(stringConf)) {
81         EDM_LOGE(MODULE_SERVICE, "%{public}s stringConf invalid", targetPath.c_str());
82         cJSON_Delete(root);
83         return false;
84     }
85     cJSON *conf = nullptr;
86     cJSON_ArrayForEach(conf, stringConf)
87     {
88         cJSON *nameObj = cJSON_GetObjectItemCaseSensitive(conf, "name");
89         cJSON *valueObj = cJSON_GetObjectItemCaseSensitive(conf, "value");
90         if (nameObj && valueObj && cJSON_IsString(nameObj) && cJSON_IsString(valueObj) &&
91             (strlen(nameObj->valuestring) > 0) && (strlen(valueObj->valuestring) > 0)) {
92             container.insert(std::make_pair(nameObj->valuestring, valueObj->valuestring));
93         }
94     }
95     cJSON_Delete(root);
96     return true;
97 }
98 
ParseLocaleCfg()99 void NotificationLocale::ParseLocaleCfg()
100 {
101     if (islanguageMapInit_) {
102         return;
103     }
104     languageMap_.clear();
105     if (ParseJsonfile(LOCALE_CONFIG_PATH, languageMap_)) {
106         islanguageMapInit_ = true;
107     }
108 }
109 
UpdateStringMap()110 void NotificationLocale::UpdateStringMap()
111 {
112     std::lock_guard<std::mutex> lock(localeMutex_);
113     OHOS::Global::I18n::LocaleInfo locale(Global::I18n::LocaleConfig::GetSystemLocale());
114     std::string curBaseName = locale.GetBaseName();
115     if (localeBaseName_ == curBaseName) {
116         return;
117     }
118 
119     localeBaseName_ = curBaseName;
120     std::string language = DEFAULT_LANGUAGE_EN;
121 
122     if (languageMap_.find(localeBaseName_) != languageMap_.end()) {
123         language = languageMap_[localeBaseName_];
124     }
125 
126     // Validate language path to prevent directory traversal
127     if (!IsPathValid(language)) {
128         EDM_LOGE(MODULE_SERVICE, "Invalid language path detected: %{public}s", language.c_str());
129         language = DEFAULT_LANGUAGE_EN;
130     }
131 
132     stringMap_.clear();
133     std::string resourcePath = SYSTEM_PERIPHERAL_RESOURCE_PATH + language + ELEMENT_STRING_FILE;
134     // Additional path validation
135     if (resourcePath.find("/../") != std::string::npos) {
136         EDM_LOGE(MODULE_SERVICE, "Potential path traversal attack detected");
137         return;
138     }
139     ParseJsonfile(resourcePath, stringMap_);
140 }
141 
GetValueByKey(const std::string & key)142 std::string NotificationLocale::GetValueByKey(const std::string &key)
143 {
144     std::lock_guard<std::mutex> lock(localeMutex_);
145     auto iter = stringMap_.find(key);
146     if (iter != stringMap_.end()) {
147         return iter->second;
148     }
149     EDM_LOGE(MODULE_SERVICE, "fail to get related string by key(%{public}s)", key.c_str());
150     return "";
151 }
152 } // namespace ExternalDeviceManager
153 } // namespace OHOS
154