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 "net_proxy_adapter_impl.h"
17 
18 #include <vector>
19 
20 #include "nweb_log.h"
21 #include "parameter.h"
22 
23 namespace OHOS::NWeb {
24 static constexpr const char* DEFAULT_HTTP_PROXY_HOST = "NONE";
25 static constexpr const char* DEFAULT_HTTP_PROXY_EXCLUSION_LIST = "NONE";
26 static constexpr const char* EMPTY_HTTP_PROXY_HOST = "";
27 
28 namespace Base64 {
29 static std::string BASE64_CHARS = /* NOLINT */
30     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
31     "abcdefghijklmnopqrstuvwxyz"
32     "0123456789+/";
33 
34 static constexpr const uint32_t CHAR_ARRAY_LENGTH_THREE = 3;
35 static constexpr const uint32_t CHAR_ARRAY_LENGTH_FOUR = 4;
36 
37 enum BASE64_ENCODE_CONSTANT : uint8_t {
38     BASE64_ENCODE_MASK1 = 0xfc,
39     BASE64_ENCODE_MASK2 = 0x03,
40     BASE64_ENCODE_MASK3 = 0x0f,
41     BASE64_ENCODE_MASK4 = 0x3f,
42     BASE64_ENCODE_MASK5 = 0xf0,
43     BASE64_ENCODE_MASK6 = 0xc0,
44     BASE64_ENCODE_OFFSET2 = 2,
45     BASE64_ENCODE_OFFSET4 = 4,
46     BASE64_ENCODE_OFFSET6 = 6,
47     BASE64_ENCODE_INDEX0 = 0,
48     BASE64_ENCODE_INDEX1 = 1,
49     BASE64_ENCODE_INDEX2 = 2,
50 };
51 
52 enum BASE64_DECODE_CONSTANT : uint8_t {
53     BASE64_DECODE_MASK1 = 0x30,
54     BASE64_DECODE_MASK2 = 0xf,
55     BASE64_DECODE_MASK3 = 0x3c,
56     BASE64_DECODE_MASK4 = 0x3,
57     BASE64_DECODE_OFFSET2 = 2,
58     BASE64_DECODE_OFFSET4 = 4,
59     BASE64_DECODE_OFFSET6 = 6,
60     BASE64_DECODE_INDEX0 = 0,
61     BASE64_DECODE_INDEX1 = 1,
62     BASE64_DECODE_INDEX2 = 2,
63     BASE64_DECODE_INDEX3 = 3,
64 };
65 
IsBase64Char(const char c)66 static inline bool IsBase64Char(const char c)
67 {
68     return (isalnum(c) || (c == '+') || (c == '/'));
69 }
70 
MakeCharFour(const std::array<uint8_t,CHAR_ARRAY_LENGTH_THREE> & charArrayThree,std::array<uint8_t,CHAR_ARRAY_LENGTH_FOUR> & charArrayFour)71 static inline void MakeCharFour(const std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE>& charArrayThree,
72     std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR>& charArrayFour)
73 {
74     const uint8_t table[CHAR_ARRAY_LENGTH_FOUR] = {
75         static_cast<uint8_t>((charArrayThree[BASE64_ENCODE_INDEX0] & BASE64_ENCODE_MASK1) >> BASE64_ENCODE_OFFSET2),
76         static_cast<uint8_t>(((charArrayThree[BASE64_ENCODE_INDEX0] & BASE64_ENCODE_MASK2) << BASE64_ENCODE_OFFSET4) +
77                              ((charArrayThree[BASE64_ENCODE_INDEX1] & BASE64_ENCODE_MASK5) >> BASE64_ENCODE_OFFSET4)),
78         static_cast<uint8_t>(((charArrayThree[BASE64_ENCODE_INDEX1] & BASE64_ENCODE_MASK3) << BASE64_ENCODE_OFFSET2) +
79                              ((charArrayThree[BASE64_ENCODE_INDEX2] & BASE64_ENCODE_MASK6) >> BASE64_ENCODE_OFFSET6)),
80         static_cast<uint8_t>(charArrayThree[BASE64_ENCODE_INDEX2] & BASE64_ENCODE_MASK4),
81     };
82     for (size_t index = 0; index < CHAR_ARRAY_LENGTH_FOUR; ++index) {
83         charArrayFour[index] = table[index];
84     }
85 }
86 
MakeCharTree(const std::array<uint8_t,CHAR_ARRAY_LENGTH_FOUR> & charArrayFour,std::array<uint8_t,CHAR_ARRAY_LENGTH_THREE> & charArrayThree)87 static inline void MakeCharTree(const std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR>& charArrayFour,
88     std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE>& charArrayThree)
89 {
90     const uint8_t table[CHAR_ARRAY_LENGTH_THREE] = {
91         static_cast<uint8_t>((charArrayFour[BASE64_DECODE_INDEX0] << BASE64_DECODE_OFFSET2) +
92                              ((charArrayFour[BASE64_DECODE_INDEX1] & BASE64_DECODE_MASK1) >> BASE64_DECODE_OFFSET4)),
93         static_cast<uint8_t>(((charArrayFour[BASE64_DECODE_INDEX1] & BASE64_DECODE_MASK2) << BASE64_DECODE_OFFSET4) +
94                              ((charArrayFour[BASE64_DECODE_INDEX2] & BASE64_DECODE_MASK3) >> BASE64_DECODE_OFFSET2)),
95         static_cast<uint8_t>(((charArrayFour[BASE64_DECODE_INDEX2] & BASE64_DECODE_MASK4) << BASE64_DECODE_OFFSET6) +
96                              charArrayFour[BASE64_DECODE_INDEX3]),
97     };
98     for (size_t index = 0; index < CHAR_ARRAY_LENGTH_THREE; ++index) {
99         charArrayThree[index] = table[index];
100     }
101 }
102 
Encode(const std::string & source)103 std::string Encode(const std::string& source)
104 {
105     auto it = source.begin();
106     std::string ret;
107     size_t index = 0;
108     std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = { 0 };
109     std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = { 0 };
110 
111     while (it != source.end()) {
112         charArrayThree[index] = *it;
113         ++index;
114         ++it;
115         if (index != CHAR_ARRAY_LENGTH_THREE) {
116             continue;
117         }
118         MakeCharFour(charArrayThree, charArrayFour);
119         std::for_each(charArrayFour.begin(), charArrayFour.end(), [&ret](uint8_t idx) { ret += BASE64_CHARS[idx]; });
120         index = 0;
121     }
122     if (index == 0) {
123         return ret;
124     }
125 
126     for (auto i = index; i < CHAR_ARRAY_LENGTH_THREE; ++i) {
127         charArrayThree[i] = 0;
128     }
129     MakeCharFour(charArrayThree, charArrayFour);
130 
131     for (size_t i = 0; i < index + 1; ++i) {
132         ret += BASE64_CHARS[charArrayFour[i]];
133     }
134 
135     while (index < CHAR_ARRAY_LENGTH_THREE) {
136         ret += '=';
137         ++index;
138     }
139     return ret;
140 }
141 
Decode(const std::string & encoded)142 std::string Decode(const std::string& encoded)
143 {
144     auto it = encoded.begin();
145     size_t index = 0;
146     std::array<uint8_t, CHAR_ARRAY_LENGTH_THREE> charArrayThree = { 0 };
147     std::array<uint8_t, CHAR_ARRAY_LENGTH_FOUR> charArrayFour = { 0 };
148     std::string ret;
149 
150     while (it != encoded.end() && IsBase64Char(*it)) {
151         charArrayFour[index] = *it;
152         ++index;
153         ++it;
154         if (index != CHAR_ARRAY_LENGTH_FOUR) {
155             continue;
156         }
157         for (index = 0; index < CHAR_ARRAY_LENGTH_FOUR; ++index) {
158             charArrayFour[index] = BASE64_CHARS.find(static_cast<char>(charArrayFour[index]));
159         }
160         MakeCharTree(charArrayFour, charArrayThree);
161         std::for_each(
162             charArrayThree.begin(), charArrayThree.end(), [&ret](uint8_t idx) { ret += static_cast<char>(idx); });
163         index = 0;
164     }
165     if (index == 0) {
166         return ret;
167     }
168 
169     for (auto i = index; i < CHAR_ARRAY_LENGTH_FOUR; ++i) {
170         charArrayFour[i] = 0;
171     }
172     for (unsigned char& i : charArrayFour) {
173         std::string::size_type idx = BASE64_CHARS.find(static_cast<char>(i));
174         if (idx != std::string::npos) {
175             i = static_cast<unsigned char>(idx);
176         }
177     }
178     MakeCharTree(charArrayFour, charArrayThree);
179 
180     for (size_t i = 0; i < index - 1; i++) {
181         ret += static_cast<char>(charArrayThree[i]);
182     }
183     return ret;
184 }
185 } // namespace Base64
186 
NetProxyEventSubscriber(EventFwk::CommonEventSubscribeInfo & in,std::shared_ptr<NetProxyEventCallbackAdapter> cb)187 NetProxyEventSubscriber::NetProxyEventSubscriber(
188     EventFwk::CommonEventSubscribeInfo& in, std::shared_ptr<NetProxyEventCallbackAdapter> cb)
189     : EventFwk::CommonEventSubscriber(in), eventCallback_(cb)
190 {}
191 
GetInstance()192 NetProxyAdapterImpl& NetProxyAdapterImpl::GetInstance()
193 {
194     static NetProxyAdapterImpl instance;
195     return instance;
196 }
197 
RegNetProxyEvent(std::shared_ptr<NetProxyEventCallbackAdapter> eventCallback)198 void NetProxyAdapterImpl::RegNetProxyEvent(std::shared_ptr<NetProxyEventCallbackAdapter> eventCallback)
199 {
200     WVLOG_I("reg netproxy event");
201     cb_ = std::move(eventCallback);
202     if (!cb_) {
203         WVLOG_E("reg netproxy event, callback is null");
204     }
205 }
206 
Changed()207 void NetProxyAdapterImpl::Changed()
208 {
209     if (listen_) {
210         return;
211     }
212     WVLOG_I("start NetProxy changed");
213     listen_ = true;
214 
215     std::string host;
216     uint16_t port;
217     std::string pacUrl;
218     std::vector<std::string> exclusionList;
219     std::string exclusion;
220 
221     GetProperty(host, port, pacUrl, exclusion);
222     exclusionList.push_back(exclusion);
223     if (cb_) {
224         cb_->Changed(host, port, "", exclusionList);
225     }
226 }
227 
StartListen()228 bool NetProxyAdapterImpl::StartListen()
229 {
230     WVLOG_I("start netproxy listen");
231     Changed();
232     EventFwk::MatchingSkills skill = EventFwk::MatchingSkills();
233     skill.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_HTTP_PROXY_CHANGE);
234     EventFwk::CommonEventSubscribeInfo info(skill);
235     info.SetPriority(1); //The higher the value, the higher the priority
236     if (!cb_) {
237         WVLOG_E("start netproxy listen, callback is null");
238         return false;
239     }
240     commonEventSubscriber_ = std::make_shared<NetProxyEventSubscriber>(info, cb_);
241     if (!commonEventSubscriber_) {
242         WVLOG_E("start netproxy listen, common event subscriber is null");
243         return false;
244     }
245 
246     bool ret = EventFwk::CommonEventManager::SubscribeCommonEvent(commonEventSubscriber_);
247     if (ret == false) {
248         WVLOG_E("start netproxy listen, subscribe common event failed");
249         return false;
250     }
251 
252     StartListenAppProxy();
253     return true;
254 }
255 
StartListenAppProxy()256 void NetProxyAdapterImpl::StartListenAppProxy()
257 {
258     std::function<void(const NetManagerStandard::HttpProxy& httpProxy)> callback =
259         [this](const NetManagerStandard::HttpProxy& receiveHttpProxy) {
260             NetManagerStandard::HttpProxy httpProxy = receiveHttpProxy;
261             WVLOG_D("App netproxy config change, receive host is %{public}s, port is %{public}d",
262                 httpProxy.GetHost().c_str(), httpProxy.GetPort());
263             std::string host;
264             host.assign(httpProxy.GetHost());
265             if (host == EMPTY_HTTP_PROXY_HOST) {
266                 WVLOG_D("App netproxy config change, clear proxy");
267                 NetManagerStandard::HttpProxy tempHttpProxy;
268                 int32_t ret = NetManagerStandard::NetConnClient::GetInstance().GetDefaultHttpProxy(tempHttpProxy);
269                 if (ret != NetManagerStandard::NET_CONN_SUCCESS) {
270                     WVLOG_E("App netproxy config change, get default http proxy from OH network failed");
271                     return;
272                 }
273                 WVLOG_D("App netproxy config clear, GetDefaultHttpProxy host is %{public}s, port is %{public}d",
274                     tempHttpProxy.GetHost().c_str(), tempHttpProxy.GetPort());
275                 httpProxy = tempHttpProxy;
276                 host.assign(httpProxy.GetHost());
277             }
278 
279             if (host == DEFAULT_HTTP_PROXY_HOST) {
280                 WVLOG_W("get netproxy property failed, host is null");
281                 host = std::string();
282             }
283             std::vector<std::string> exclusionList;
284             auto exclusion = httpProxy.GetExclusionList();
285             exclusionList.assign(exclusion.begin(), exclusion.end());
286             uint16_t port = httpProxy.GetPort();
287 
288             for (auto it : exclusionList) {
289                 WVLOG_D("App netproxy config change, exclusion is %{public}s", it.c_str());
290             }
291             if (cb_) {
292                 WVLOG_D("App netproxy config change, host is %{public}s, port is %{public}d", host.c_str(), port);
293                 cb_->Changed(host, port, "", exclusionList);
294             }
295         };
296     uint32_t appId;
297     NetManagerStandard::NetConnClient::GetInstance().RegisterAppHttpProxyCallback(callback, appId);
298     appProxyCallbackId_ = appId;
299     WVLOG_D("App netproxy config change, fromNet , appId =is %{public}d", appId);
300 }
301 
StopListen()302 void NetProxyAdapterImpl::StopListen()
303 {
304     WVLOG_I("stop netproxy listen");
305     if (commonEventSubscriber_) {
306         bool result = EventFwk::CommonEventManager::UnSubscribeCommonEvent(commonEventSubscriber_);
307         if (result) {
308             commonEventSubscriber_ = nullptr;
309         } else {
310             WVLOG_E("stop netproxy listen, unsubscribe common event failed");
311         }
312     }
313 
314     WVLOG_D("App netproxy,UnregisterAppHttpProxyCallback, appId is %{public}d", appProxyCallbackId_);
315     NetManagerStandard::NetConnClient::GetInstance().UnregisterAppHttpProxyCallback(appProxyCallbackId_);
316 }
317 
OnReceiveEvent(const EventFwk::CommonEventData & data)318 void NetProxyEventSubscriber::OnReceiveEvent(const EventFwk::CommonEventData& data)
319 {
320     const std::string action = data.GetWant().GetAction();
321     WVLOG_D("netproxy config change, netproxy action: %{public}s", action.c_str());
322     if (action != EventFwk::CommonEventSupport::COMMON_EVENT_HTTP_PROXY_CHANGE) {
323         WVLOG_E("netproxy config change, action error, action is %{public}s", action.c_str());
324         return;
325     }
326 
327     NetManagerStandard::HttpProxy httpProxy;
328     int32_t ret = NetManagerStandard::NetConnClient::GetInstance().GetDefaultHttpProxy(httpProxy);
329     if (ret != NetManagerStandard::NET_CONN_SUCCESS) {
330         WVLOG_E("netproxy config change, get default http proxy from OH network failed");
331         return;
332     }
333 
334     WVLOG_D("netproxy config change, host is %{public}s, port is %{public}d", httpProxy.GetHost().c_str(),
335         httpProxy.GetPort());
336     for (auto it : httpProxy.GetExclusionList()) {
337         WVLOG_D("netproxy config change, exclusion is %{public}s", it.c_str());
338     }
339 
340     std::string host;
341     uint16_t port;
342     std::vector<std::string> exclusionList;
343     host.assign(httpProxy.GetHost());
344     port = httpProxy.GetPort();
345     auto exclusion = httpProxy.GetExclusionList();
346     exclusionList.assign(exclusion.begin(), exclusion.end());
347 
348     if (!eventCallback_) {
349         WVLOG_E("netproxy config change, event callback is null");
350         return;
351     }
352 
353     eventCallback_->Changed(host, port, "", exclusionList);
354 }
355 
GetProperty(std::string & host,uint16_t & port,std::string & pacUrl,std::string & exclusion)356 void NetProxyAdapterImpl::GetProperty(std::string& host, uint16_t& port, std::string& pacUrl, std::string& exclusion)
357 {
358     std::string httpProxyExclusions;
359     NetManagerStandard::HttpProxy httpProxy;
360     int32_t ret = NetManagerStandard::NetConnClient::GetInstance().GetDefaultHttpProxy(httpProxy);
361     if (ret != NetManagerStandard::NET_CONN_SUCCESS) {
362         WVLOG_E("netproxy config change, get default http proxy from OH network failed");
363         return;
364     }
365 
366     host = httpProxy.GetHost();
367     if (host == DEFAULT_HTTP_PROXY_HOST) {
368         WVLOG_E("get netproxy property failed, host is null");
369         host = std::string();
370     }
371 
372     for (const auto& s : httpProxy.GetExclusionList()) {
373         httpProxyExclusions.append(s + ",");
374     }
375     if (!httpProxyExclusions.empty()) {
376         httpProxyExclusions.pop_back();
377     }
378 
379     exclusion = httpProxyExclusions;
380     if (exclusion == DEFAULT_HTTP_PROXY_EXCLUSION_LIST) {
381         WVLOG_E("get netproxy property failed, exclusion is null");
382         exclusion = std::string();
383     }
384 
385     port = httpProxy.GetPort();
386 
387     WVLOG_D("get netproxy property, host is %{public}s, port is %{public}d, exclusion is %{public}s", host.c_str(),
388         port, exclusion.c_str());
389 }
390 } // namespace OHOS::NWeb
391