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 <cstdint>
17 #include <memory>
18 #include <mutex>
19
20 #include "ability_manager_client.h"
21 #include "errorcode_convertor.h"
22 #include "extension_ability_info.h"
23 #include "module_template.h"
24 #include "napi/native_node_api.h"
25 #include "napi_common_want.h"
26 #include "napi_utils.h"
27 #include "net_datashare_utils_iface.h"
28 #include "net_manager_constants.h"
29 #include "netmanager_ext_log.h"
30 #include "networkvpn_client.h"
31 #include "vpn_connection_ext.h"
32 #include "vpn_extension_context.h"
33 #include "vpn_monitor_ext.h"
34 #include "want.h"
35
36 namespace OHOS {
37 namespace NetManagerStandard {
38 constexpr int32_t ARG_NUM_0 = 0;
39 constexpr int32_t PARAM_ONE = 1;
40
CreateResolvedPromise(napi_env env)41 static napi_value CreateResolvedPromise(napi_env env)
42 {
43 napi_deferred deferred = nullptr;
44 napi_value promise = nullptr;
45 if (napi_create_promise(env, &deferred, &promise) != napi_ok) {
46 return NapiUtils::GetUndefined(env);
47 }
48 napi_resolve_deferred(env, deferred, NapiUtils::GetUndefined(env));
49 return promise;
50 }
51
CreateRejectedPromise(napi_env env)52 static napi_value CreateRejectedPromise(napi_env env)
53 {
54 napi_deferred deferred = nullptr;
55 napi_value promise = nullptr;
56 if (napi_create_promise(env, &deferred, &promise) != napi_ok) {
57 return NapiUtils::GetUndefined(env);
58 }
59 napi_reject_deferred(env, deferred, NapiUtils::GetUndefined(env));
60 return promise;
61 }
62
ResolvePromiseInIpcThread(napi_env env,napi_deferred deferred)63 static void ResolvePromiseInIpcThread(napi_env env, napi_deferred deferred)
64 {
65 napi_send_event(
66 env, [env, deferred]() { napi_resolve_deferred(env, deferred, NapiUtils::GetUndefined(env)); },
67 napi_eprio_high);
68 }
69
RejectPromiseInIpcThread(napi_env env,napi_deferred deferred)70 static void RejectPromiseInIpcThread(napi_env env, napi_deferred deferred)
71 {
72 napi_send_event(
73 env, [env, deferred]() { napi_reject_deferred(env, deferred, NapiUtils::GetUndefined(env)); }, napi_eprio_high);
74 }
75
CreateObserveDataSharePromise(napi_env env,const std::string & bundleName)76 static napi_value CreateObserveDataSharePromise(napi_env env, const std::string &bundleName)
77 {
78 napi_deferred deferred = nullptr;
79 napi_value promise = nullptr;
80 if (napi_create_promise(env, &deferred, &promise) != napi_ok) {
81 return NapiUtils::GetUndefined(env);
82 }
83
84 auto once = std::make_shared<std::once_flag>();
85 auto callbackId = std::make_shared<int32_t>();
86 auto deferWrapper = std::make_shared<napi_deferred>();
87 *deferWrapper = deferred;
88 auto onChange = [env, deferWrapper, bundleName, once, callbackId]() {
89 if (!once) {
90 return;
91 }
92 std::call_once(*once, [env, deferWrapper, bundleName, callbackId]() {
93 bool vpnDialogSelect = false;
94 std::string vpnExtMode = std::to_string(vpnDialogSelect);
95 int32_t ret = NetDataShareHelperUtilsIface::Query(VPNEXT_MODE_URI, bundleName, vpnExtMode);
96 NETMANAGER_EXT_LOGI("query vpn state after dialog: %{public}d %{public}s", ret, vpnExtMode.c_str());
97 if (callbackId) {
98 NetDataShareHelperUtilsIface::UnregisterObserver(VPNEXT_MODE_URI, *callbackId);
99 }
100 if (deferWrapper && *deferWrapper) {
101 auto deferred = *deferWrapper;
102 *deferWrapper = nullptr;
103 if (vpnExtMode == "1") {
104 ResolvePromiseInIpcThread(env, deferred);
105 } else {
106 RejectPromiseInIpcThread(env, deferred);
107 }
108 }
109 });
110 };
111
112 *callbackId = NetDataShareHelperUtilsIface::RegisterObserver(VPNEXT_MODE_URI, onChange);
113 return promise;
114 }
115
MakeDataExt(napi_env env,size_t argc,napi_value * argv,EventManager * manager)116 static void *MakeDataExt(napi_env env, size_t argc, napi_value *argv, EventManager *manager)
117 {
118 if ((argc != PARAM_ONE) || (NapiUtils::GetValueType(env, argv[ARG_NUM_0]) != napi_object)) {
119 NETMANAGER_EXT_LOGE("funciton prameter error");
120 napi_throw_error(env, std::to_string(NETMANAGER_EXT_ERR_PARAMETER_ERROR).c_str(), "Parameter error");
121 return nullptr;
122 }
123
124 VpnExtensionContext *vpnExtensionContext = nullptr;
125 napi_status status = napi_unwrap(env, argv[ARG_NUM_0], reinterpret_cast<void **>(&vpnExtensionContext));
126 if (status != napi_ok || vpnExtensionContext == nullptr) {
127 NETMANAGER_EXT_LOGE("Failed to get vpnExtensionContext napi instance");
128 napi_throw_error(env, std::to_string(NETMANAGER_EXT_ERR_PARAMETER_ERROR).c_str(), "Parameter error");
129 return nullptr;
130 }
131
132 int32_t ret = NetworkVpnClient::GetInstance().CreateVpnConnection(true);
133 if (ret != NETMANAGER_EXT_SUCCESS) {
134 NETMANAGER_EXT_LOGE("execute CreateVpnConnection failed: %{public}d", ret);
135 std::string errorMsg = NetBaseErrorCodeConvertor().ConvertErrorCode(ret);
136 napi_throw_error(env, std::to_string(ret).c_str(), errorMsg.c_str());
137 return nullptr;
138 }
139 return reinterpret_cast<void *>(&NetworkVpnClient::GetInstance());
140 }
141
Replace(std::string s)142 static std::string Replace(std::string s)
143 {
144 std::string tmp = VPN_DIALOG_POSTFIX;
145 auto pos = s.find(tmp);
146 if (pos == std::string::npos) {
147 return s;
148 }
149 s.replace(pos, tmp.length(), "");
150 return s;
151 }
152
ProcessPermissionRequests(napi_env env,const std::string & bundleName,const std::string & abilityName)153 napi_value ProcessPermissionRequests(napi_env env, const std::string &bundleName, const std::string &abilityName)
154 {
155 std::string selfAppName;
156 std::string selfBundleName;
157 auto getAppNameRes = NetworkVpnClient::GetInstance().GetSelfAppName(selfAppName, selfBundleName);
158 NETMANAGER_EXT_LOGI("StartVpnExtensionAbility SelfAppName = %{public}s %{public}d", selfAppName.c_str(),
159 getAppNameRes);
160 if (bundleName != selfBundleName) {
161 NETMANAGER_EXT_LOGE("Not allowed to start other bundleName vpn!");
162 return CreateRejectedPromise(env);
163 }
164
165 bool vpnDialogSelect = false;
166 std::string vpnExtMode = std::to_string(vpnDialogSelect);
167 int32_t ret = NetDataShareHelperUtilsIface::Query(VPNEXT_MODE_URI, bundleName, vpnExtMode);
168 if (ret != 0 || vpnExtMode != "1") {
169 NETMANAGER_EXT_LOGE("dataShareHelperUtils Query error, err = %{public}d", ret);
170 VpnMonitor::GetInstance().ShowVpnDialog(bundleName, abilityName, selfAppName);
171 return CreateObserveDataSharePromise(env, bundleName);
172 }
173 return nullptr;
174 }
175
StartVpnExtensionAbility(napi_env env,napi_callback_info info)176 napi_value StartVpnExtensionAbility(napi_env env, napi_callback_info info)
177 {
178 napi_value thisVal = nullptr;
179 std::size_t argc = MAX_PARAM_NUM;
180
181 napi_value argv[MAX_PARAM_NUM] = {nullptr};
182 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
183 if ((argc != PARAM_ONE) || (NapiUtils::GetValueType(env, argv[ARG_NUM_0]) != napi_object)) {
184 NETMANAGER_EXT_LOGE("funciton prameter error");
185 napi_throw_error(env, std::to_string(NETMANAGER_EXT_ERR_PARAMETER_ERROR).c_str(), "Parameter error");
186 return CreateRejectedPromise(env);
187 }
188 AAFwk::Want want;
189 int32_t accountId = -1;
190 if (!AppExecFwk::UnwrapWant(env, argv[0], want)) {
191 NETMANAGER_EXT_LOGE("Failed to parse want");
192 napi_throw_error(env, std::to_string(NETMANAGER_EXT_ERR_PARAMETER_ERROR).c_str(), "Parse want error");
193 return CreateRejectedPromise(env);
194 }
195
196 std::string bundleName = want.GetElement().GetBundleName();
197 std::string abilityName = want.GetElement().GetAbilityName();
198 if (abilityName.find(VPN_DIALOG_POSTFIX) == std::string::npos) {
199 NetworkVpnClient::GetInstance().SetSelfVpnPid();
200 napi_value retVal = ProcessPermissionRequests(env, bundleName, abilityName);
201 if (retVal != nullptr) {
202 return retVal;
203 }
204 }
205 auto elem = want.GetElement();
206 elem.SetAbilityName(Replace(abilityName));
207 want.SetElement(elem);
208 ErrCode err = AAFwk::AbilityManagerClient::GetInstance()->StartExtensionAbility(
209 want, nullptr, accountId, AppExecFwk::ExtensionAbilityType::VPN);
210 NETMANAGER_EXT_LOGI("execute StartVpnExtensionAbility result: %{public}d", err);
211 if (err == 0) {
212 int32_t rst = NetworkVpnClient::GetInstance().RegisterBundleName(bundleName, Replace(abilityName));
213 NETMANAGER_EXT_LOGI("VPN RegisterBundleName result = %{public}d", rst);
214 }
215 return CreateResolvedPromise(env);
216 }
217
StopVpnExtensionAbility(napi_env env,napi_callback_info info)218 napi_value StopVpnExtensionAbility(napi_env env, napi_callback_info info)
219 {
220 napi_value thisVal = nullptr;
221 std::size_t argc = MAX_PARAM_NUM;
222
223 napi_value argv[MAX_PARAM_NUM] = {nullptr};
224 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
225 if ((argc != PARAM_ONE) || (NapiUtils::GetValueType(env, argv[ARG_NUM_0]) != napi_object)) {
226 NETMANAGER_EXT_LOGE("funciton prameter error");
227 napi_throw_error(env, std::to_string(NETMANAGER_EXT_ERR_PARAMETER_ERROR).c_str(), "Parameter error");
228 return CreateRejectedPromise(env);
229 }
230 AAFwk::Want want;
231 int32_t accountId = -1;
232 if (!AppExecFwk::UnwrapWant(env, argv[0], want)) {
233 NETMANAGER_EXT_LOGE("Failed to parse want");
234 napi_throw_error(env, std::to_string(NETMANAGER_EXT_ERR_PARAMETER_ERROR).c_str(), "Parse want error");
235 return CreateRejectedPromise(env);
236 }
237
238 std::string bundleName = want.GetElement().GetBundleName();
239 std::string selfAppName;
240 std::string selfBundleName;
241 auto getAppNameRes = NetworkVpnClient::GetInstance().GetSelfAppName(selfAppName, selfBundleName);
242 NETMANAGER_EXT_LOGI("StopVpnExtensionAbility SelfAppName = %{public}s %{public}d", selfAppName.c_str(),
243 getAppNameRes);
244 if (bundleName != selfBundleName) {
245 NETMANAGER_EXT_LOGE("Not allowed to stop other bundleName vpn!");
246 return CreateRejectedPromise(env);
247 }
248 bool vpnDialogSelect = false;
249 std::string vpnExtMode = std::to_string(vpnDialogSelect);
250 int32_t ret = NetDataShareHelperUtilsIface::Query(VPNEXT_MODE_URI, bundleName, vpnExtMode);
251 if (ret != 0 || vpnExtMode != "1") {
252 NETMANAGER_EXT_LOGE("dataShareHelperUtils Query error, err = %{public}d", ret);
253 return CreateRejectedPromise(env);
254 }
255
256 ErrCode err = AAFwk::AbilityManagerClient::GetInstance()->StopExtensionAbility(
257 want, nullptr, accountId, AppExecFwk::ExtensionAbilityType::VPN);
258 NETMANAGER_EXT_LOGI("execute StopExtensionAbility result: %{public}d", err);
259 return CreateResolvedPromise(env);
260 }
261
CreateVpnConnection(napi_env env,napi_callback_info info)262 static napi_value CreateVpnConnection(napi_env env, napi_callback_info info)
263 {
264 return ModuleTemplate::NewInstance(env, info, VPN_CONNECTION_EXT, MakeDataExt, [](napi_env, void *data, void *) {
265 NETMANAGER_EXT_LOGI("finalize VpnConnection");
266 });
267 }
268
UpdateVpnAuthorize(napi_env env,napi_callback_info info)269 static napi_value UpdateVpnAuthorize(napi_env env, napi_callback_info info)
270 {
271 napi_value thisVal = nullptr;
272 std::size_t argc = MAX_PARAM_NUM;
273 napi_value argv[MAX_PARAM_NUM] = {nullptr};
274 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
275
276 if ((argc != PARAM_ONE) || (NapiUtils::GetValueType(env, argv[ARG_NUM_0]) != napi_string)) {
277 NETMANAGER_EXT_LOGE("funciton prameter error");
278 napi_throw_error(env, std::to_string(NETMANAGER_EXT_ERR_PARAMETER_ERROR).c_str(), "Parameter error");
279 return nullptr;
280 }
281 std::string bundleName = NapiUtils::GetStringFromValueUtf8(env, argv[ARG_NUM_0]);
282
283 bool vpnDialogSelect = true;
284 if (bundleName.find(VPN_DIALOG_POSTFIX) != std::string::npos) {
285 vpnDialogSelect = false;
286 bundleName = Replace(bundleName);
287 }
288 std::string vpnExtMode = std::to_string(vpnDialogSelect);
289 int32_t ret = NetDataShareHelperUtilsIface::Update(VPNEXT_MODE_URI, bundleName, vpnExtMode);
290 NETMANAGER_EXT_LOGI("UpdateVpnAuthorize result. ret = %{public}d", ret);
291
292 napi_value jsValue = nullptr;
293 napi_get_boolean(env, true, &jsValue);
294 return jsValue;
295 }
296
RegisterVpnExtModule(napi_env env,napi_value exports)297 napi_value RegisterVpnExtModule(napi_env env, napi_value exports)
298 {
299 NapiUtils::DefineProperties(env, exports,
300 {
301 DECLARE_NAPI_FUNCTION(CREATE_VPN_CONNECTION, CreateVpnConnection),
302 DECLARE_NAPI_FUNCTION(START_VPN_EXTENSION, StartVpnExtensionAbility),
303 DECLARE_NAPI_FUNCTION(STOP_VPN_EXTENSION, StopVpnExtensionAbility),
304 DECLARE_NAPI_FUNCTION(UPDATE_VPN_AUTHORIZE, UpdateVpnAuthorize),
305 });
306 ModuleTemplate::DefineClass(env, exports,
307 {
308 DECLARE_NAPI_FUNCTION(SET_UP_EXT, VpnConnectionExt::SetUp),
309 DECLARE_NAPI_FUNCTION(PROTECT_EXT, VpnConnectionExt::Protect),
310 DECLARE_NAPI_FUNCTION(DESTROY_EXT, VpnConnectionExt::Destroy),
311 },
312 VPN_CONNECTION_EXT);
313 return exports;
314 }
315
316 static napi_module g_vpnModule = {
317 .nm_version = 1,
318 .nm_flags = 0,
319 .nm_filename = nullptr,
320 .nm_register_func = RegisterVpnExtModule,
321 .nm_modname = VPN_EXT_MODULE_NAME,
322 .nm_priv = nullptr,
323 .reserved = {nullptr},
324 };
325
VpnNapiRegister()326 extern "C" __attribute__((constructor)) void VpnNapiRegister()
327 {
328 napi_module_register(&g_vpnModule);
329 }
330 } // namespace NetManagerStandard
331 } // namespace OHOS
332