1 /*
2 * Copyright (c) 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 #include "napi_web_cookie_manager.h"
17
18 #include <cstdint>
19 #include <uv.h>
20 #include <vector>
21
22 #include "business_error.h"
23 #include "napi/native_common.h"
24 #include "nweb_cookie_manager.h"
25 #include "nweb_helper.h"
26 #include "nweb_log.h"
27 #include "napi_parse_utils.h"
28 #include "web_errors.h"
29 #include "securec.h"
30
31 namespace OHOS {
32 namespace NWeb {
Init(napi_env env,napi_value exports)33 napi_value NapiWebCookieManager::Init(napi_env env, napi_value exports)
34 {
35 napi_property_descriptor properties[] = {
36 DECLARE_NAPI_STATIC_FUNCTION("getCookie", NapiWebCookieManager::JsGetCookie),
37 DECLARE_NAPI_STATIC_FUNCTION("setCookie", NapiWebCookieManager::JsSetCookie),
38 DECLARE_NAPI_STATIC_FUNCTION("isCookieAllowed", NapiWebCookieManager::JsIsCookieAllowed),
39 DECLARE_NAPI_STATIC_FUNCTION("putAcceptCookieEnabled", NapiWebCookieManager::JsPutAcceptCookieEnabled),
40 DECLARE_NAPI_STATIC_FUNCTION("isThirdPartyCookieAllowed",
41 NapiWebCookieManager::JsIsThirdPartyCookieAllowed),
42 DECLARE_NAPI_STATIC_FUNCTION("putAcceptThirdPartyCookieEnabled",
43 NapiWebCookieManager::JsPutAcceptThirdPartyCookieEnabled),
44 DECLARE_NAPI_STATIC_FUNCTION("existCookie", NapiWebCookieManager::JsExistCookie),
45 DECLARE_NAPI_STATIC_FUNCTION("deleteEntireCookie", NapiWebCookieManager::JsDeleteEntireCookie),
46 DECLARE_NAPI_STATIC_FUNCTION("deleteSessionCookie", NapiWebCookieManager::JsDeleteSessionCookie),
47 DECLARE_NAPI_STATIC_FUNCTION("saveCookieAsync", NapiWebCookieManager::JsSaveCookieAsync),
48 };
49 napi_value constructor = nullptr;
50
51 napi_define_class(env, WEB_COOKIE_MANAGER_CLASS_NAME.c_str(), WEB_COOKIE_MANAGER_CLASS_NAME.length(),
52 JsConstructor, nullptr, sizeof(properties) / sizeof(properties[0]), properties, &constructor);
53 NAPI_ASSERT(env, constructor != nullptr, "NapiWebCookieManager define js class failed");
54 napi_status status = napi_set_named_property(env, exports, "WebCookieManager", constructor);
55 NAPI_ASSERT(env, status == napi_ok, "NapiWebCookieManager set property failed");
56 return exports;
57 }
58
JsConstructor(napi_env env,napi_callback_info info)59 napi_value NapiWebCookieManager::JsConstructor(napi_env env, napi_callback_info info)
60 {
61 napi_value thisVar = nullptr;
62
63 size_t argc = INTEGER_TWO;
64 napi_value argv[INTEGER_TWO] = { 0 };
65 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
66 return thisVar;
67 }
68
GetStringPara(napi_env env,napi_value argv,std::string & outValue)69 bool NapiWebCookieManager::GetStringPara(napi_env env, napi_value argv, std::string& outValue)
70 {
71 constexpr int32_t MAX_STRING_LENGTH = 40960;
72 size_t bufferSize = 0;
73 napi_valuetype valueType = napi_null;
74
75 napi_typeof(env, argv, &valueType);
76 if (valueType != napi_string) {
77 return false;
78 }
79 napi_get_value_string_utf8(env, argv, nullptr, 0, &bufferSize);
80 if (bufferSize > MAX_STRING_LENGTH) {
81 return false;
82 }
83 char stringValue[bufferSize + 1];
84 size_t jsStringLength = 0;
85 napi_get_value_string_utf8(env, argv, stringValue, bufferSize + 1, &jsStringLength);
86 if (jsStringLength != bufferSize) {
87 return false;
88 }
89 outValue = stringValue;
90 return true;
91 }
92
GetBooleanPara(napi_env env,napi_value argv,bool & outValue)93 bool NapiWebCookieManager::GetBooleanPara(napi_env env, napi_value argv, bool& outValue)
94 {
95 napi_valuetype valueType = napi_null;
96
97 napi_typeof(env, argv, &valueType);
98 if (valueType != napi_boolean) {
99 return false;
100 }
101
102 bool boolValue;
103 napi_get_value_bool(env, argv, &boolValue);
104 outValue = boolValue;
105 return true;
106 }
107
JsGetCookie(napi_env env,napi_callback_info info)108 napi_value NapiWebCookieManager::JsGetCookie(napi_env env, napi_callback_info info)
109 {
110 napi_value retValue = nullptr;
111 size_t argc = INTEGER_ONE;
112 napi_value argv[INTEGER_ONE] = { 0 };
113
114 napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
115 if (argc != INTEGER_ONE) {
116 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
117 return nullptr;
118 }
119
120 std::string url;
121 if (!GetStringPara(env, argv[INTEGER_ZERO], url)) {
122 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
123 return nullptr;
124 }
125
126 napi_value result = nullptr;
127 std::string cookieContent = "";
128
129 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
130 if (cookieManager != nullptr) {
131 cookieContent = cookieManager->ReturnCookie(url);
132 }
133
134 if (cookieContent == "") {
135 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_URL);
136 return nullptr;
137 }
138 napi_create_string_utf8(env, cookieContent.c_str(), cookieContent.length(), &result);
139 return result;
140 }
141
JsSetCookie(napi_env env,napi_callback_info info)142 napi_value NapiWebCookieManager::JsSetCookie(napi_env env, napi_callback_info info)
143 {
144 napi_value retValue = nullptr;
145 size_t argc = INTEGER_TWO;
146 napi_value argv[INTEGER_TWO] = { 0 };
147
148 napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
149 if (argc != INTEGER_TWO) {
150 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
151 return nullptr;
152 }
153
154 std::string url;
155 std::string value;
156 if (!GetStringPara(env, argv[INTEGER_ZERO], url)) {
157 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
158 return nullptr;
159 }
160 if (!GetStringPara(env, argv[INTEGER_ONE], value)) {
161 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
162 return nullptr;
163 }
164
165 napi_value result = nullptr;
166 int isSet = -1;
167
168 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
169 if (cookieManager != nullptr) {
170 isSet = cookieManager->SetCookie(url, value);
171 }
172 if (isSet == NWebError::INVALID_URL) {
173 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_URL);
174 return nullptr;
175 } else if (isSet == NWebError::INVALID_COOKIE_VALUE) {
176 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::INVALID_COOKIE_VALUE);
177 return nullptr;
178 }
179 NAPI_CALL(env, napi_get_undefined(env, &result));
180 return result;
181 }
182
JsIsCookieAllowed(napi_env env,napi_callback_info info)183 napi_value NapiWebCookieManager::JsIsCookieAllowed(napi_env env, napi_callback_info info)
184 {
185 napi_value result = nullptr;
186 bool accept = true;
187
188 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
189 if (cookieManager != nullptr) {
190 accept = cookieManager->IsAcceptCookieAllowed();
191 }
192 NAPI_CALL(env, napi_get_boolean(env, accept, &result));
193 return result;
194 }
195
JsPutAcceptCookieEnabled(napi_env env,napi_callback_info info)196 napi_value NapiWebCookieManager::JsPutAcceptCookieEnabled(napi_env env, napi_callback_info info)
197 {
198 napi_value retValue = nullptr;
199 size_t argc = INTEGER_ONE;
200 napi_value argv[INTEGER_ONE] = { 0 };
201
202 napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
203 if (argc != INTEGER_ONE) {
204 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
205 return nullptr;
206 }
207
208 bool accept;
209 if (!GetBooleanPara(env, argv[INTEGER_ZERO], accept)) {
210 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
211 return nullptr;
212 }
213
214 napi_value result = nullptr;
215
216 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
217 if (cookieManager != nullptr) {
218 cookieManager->PutAcceptCookieEnabled(accept);
219 }
220 NAPI_CALL(env, napi_get_undefined(env, &result));
221 return result;
222 }
223
JsIsThirdPartyCookieAllowed(napi_env env,napi_callback_info info)224 napi_value NapiWebCookieManager::JsIsThirdPartyCookieAllowed(napi_env env, napi_callback_info info)
225 {
226 napi_value result = nullptr;
227 bool accept = true;
228
229 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
230 if (cookieManager != nullptr) {
231 accept = cookieManager->IsThirdPartyCookieAllowed();
232 }
233 NAPI_CALL(env, napi_get_boolean(env, accept, &result));
234 return result;
235 }
236
JsPutAcceptThirdPartyCookieEnabled(napi_env env,napi_callback_info info)237 napi_value NapiWebCookieManager::JsPutAcceptThirdPartyCookieEnabled(napi_env env, napi_callback_info info)
238 {
239 napi_value retValue = nullptr;
240 size_t argc = INTEGER_ONE;
241 napi_value argv[INTEGER_ONE] = { 0 };
242
243 napi_get_cb_info(env, info, &argc, argv, &retValue, nullptr);
244 if (argc != INTEGER_ONE) {
245 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
246 return nullptr;
247 }
248
249 bool accept;
250 if (!GetBooleanPara(env, argv[INTEGER_ZERO], accept)) {
251 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
252 return nullptr;
253 }
254
255 napi_value result = nullptr;
256
257 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
258 if (cookieManager != nullptr) {
259 cookieManager->PutAcceptThirdPartyCookieEnabled(accept);
260 }
261 NAPI_CALL(env, napi_get_undefined(env, &result));
262 return result;
263 }
264
JsExistCookie(napi_env env,napi_callback_info info)265 napi_value NapiWebCookieManager::JsExistCookie(napi_env env, napi_callback_info info)
266 {
267 napi_value result = nullptr;
268 bool exist = true;
269
270 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
271 if (cookieManager != nullptr) {
272 exist = cookieManager->ExistCookies();
273 }
274 NAPI_CALL(env, napi_get_boolean(env, exist, &result));
275 return result;
276 }
277
JsDeleteEntireCookie(napi_env env,napi_callback_info info)278 napi_value NapiWebCookieManager::JsDeleteEntireCookie(napi_env env, napi_callback_info info)
279 {
280 napi_value result = nullptr;
281
282 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
283 if (cookieManager != nullptr) {
284 cookieManager->DeleteCookieEntirely(nullptr);
285 }
286 NAPI_CALL(env, napi_get_undefined(env, &result));
287 return result;
288 }
289
JsDeleteSessionCookie(napi_env env,napi_callback_info info)290 napi_value NapiWebCookieManager::JsDeleteSessionCookie(napi_env env, napi_callback_info info)
291 {
292 napi_value result = nullptr;
293
294 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
295 if (cookieManager != nullptr) {
296 cookieManager->DeleteSessionCookies(nullptr);
297 }
298 napi_get_undefined(env, &result);
299 return result;
300 }
301
SaveCookieAsyncCallback(napi_env env,napi_ref jsCallback)302 void SaveCookieAsyncCallback(napi_env env, napi_ref jsCallback)
303 {
304 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
305 if (cookieManager == nullptr) {
306 napi_value jsResult = nullptr;
307 napi_get_null(env, &jsResult);
308 napi_value callback = nullptr;
309 napi_get_reference_value(env, jsCallback, &callback);
310 napi_value callbackResult = nullptr;
311 napi_call_function(env, nullptr, callback, INTEGER_ONE, &jsResult, &callbackResult);
312 napi_delete_reference(env, jsCallback);
313 } else {
314 auto callbackImpl = std::make_shared<OHOS::NWeb::NWebSaveCookieCallbackImpl>(env, jsCallback, nullptr);
315 cookieManager->Store(callbackImpl);
316 }
317 }
318
SaveCookieAsyncPromise(napi_env env,napi_deferred deferred)319 void SaveCookieAsyncPromise(napi_env env, napi_deferred deferred)
320 {
321 OHOS::NWeb::NWebCookieManager* cookieManager = OHOS::NWeb::NWebHelper::Instance().GetCookieManager();
322 if (cookieManager == nullptr) {
323 napi_value jsResult = nullptr;
324 napi_get_undefined(env, &jsResult);
325 napi_reject_deferred(env, deferred, jsResult);
326 } else {
327 auto callbackImpl = std::make_shared<OHOS::NWeb::NWebSaveCookieCallbackImpl>(env, nullptr, deferred);
328 cookieManager->Store(callbackImpl);
329 }
330 }
331
JsSaveCookieAsync(napi_env env,napi_callback_info info)332 napi_value NapiWebCookieManager::JsSaveCookieAsync(napi_env env, napi_callback_info info)
333 {
334 napi_value thisVar = nullptr;
335
336 size_t argc = INTEGER_ONE;
337 size_t argcPromise = INTEGER_ZERO;
338 size_t argcCallback = INTEGER_ONE;
339 napi_value argv[INTEGER_ONE] = {0};
340
341 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
342 if (argc != argcPromise && argc != argcCallback) {
343 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
344 return nullptr;
345 }
346
347 napi_value result = nullptr;
348 napi_get_undefined(env, &result);
349
350 if (argc == argcCallback) {
351 napi_valuetype valueType = napi_null;
352 napi_typeof(env, argv[argcCallback - 1], &valueType);
353 if (valueType != napi_function) {
354 NWebError::BusinessError::ThrowErrorByErrcode(env, NWebError::PARAM_CHECK_ERROR);
355 return nullptr;
356 }
357 napi_ref jsCallback = nullptr;
358 napi_create_reference(env, argv[argcCallback - 1], INTEGER_ONE, &jsCallback);
359
360 if (jsCallback) {
361 SaveCookieAsyncCallback(env, jsCallback);
362 }
363 return result;
364 }
365
366 napi_deferred deferred = nullptr;
367 napi_value promise = nullptr;
368 napi_create_promise(env, &deferred, &promise);
369 if (promise && deferred) {
370 SaveCookieAsyncPromise(env, deferred);
371 }
372 return promise;
373 }
374
UvJsCallbackThreadWoker(uv_work_t * work,int status)375 void NWebSaveCookieCallbackImpl::UvJsCallbackThreadWoker(uv_work_t *work, int status)
376 {
377 if (work == nullptr) {
378 WVLOG_E("uv work is null");
379 return;
380 }
381 NapiWebCookieManager::WebCookieManagerParam *data =
382 reinterpret_cast<NapiWebCookieManager::WebCookieManagerParam*>(work->data);
383 if (data == nullptr) {
384 WVLOG_E("WebCookieManagerParam is null");
385 delete work;
386 work = nullptr;
387 return;
388 }
389 napi_handle_scope scope = nullptr;
390 napi_open_handle_scope(data->env_, &scope);
391 if (scope == nullptr) {
392 return;
393 }
394
395 if (data->callback_) {
396 napi_value result[INTEGER_ONE] = {0};
397 napi_get_null(data->env_, &result[INTEGER_ZERO]);
398
399 napi_value onSaveCookieFunc = nullptr;
400 napi_get_reference_value(data->env_, data->callback_, &onSaveCookieFunc);
401 napi_value callbackResult = nullptr;
402 napi_call_function(data->env_, nullptr, onSaveCookieFunc,
403 INTEGER_ONE, &result[INTEGER_ZERO], &callbackResult);
404 napi_delete_reference(data->env_, data->callback_);
405 } else if (data->deferred_) {
406 napi_value jsResult = nullptr;
407 napi_get_undefined(data->env_, &jsResult);
408 napi_resolve_deferred(data->env_, data->deferred_, jsResult);
409 }
410
411 napi_close_handle_scope(data->env_, scope);
412 delete data;
413 data = nullptr;
414 delete work;
415 work = nullptr;
416 }
417
OnReceiveValue(bool result)418 void NWebSaveCookieCallbackImpl::OnReceiveValue(bool result)
419 {
420 WVLOG_D("save cookie received result, result = %{public}d", result);
421 uv_loop_s *loop = nullptr;
422 uv_work_t *work = nullptr;
423 napi_get_uv_event_loop(env_, &loop);
424 if (loop == nullptr) {
425 WVLOG_E("get uv event loop failed");
426 return;
427 }
428 work = new (std::nothrow) uv_work_t;
429 if (work == nullptr) {
430 WVLOG_E("new uv work failed");
431 return;
432 }
433 NapiWebCookieManager::WebCookieManagerParam *param =
434 new (std::nothrow) NapiWebCookieManager::WebCookieManagerParam();
435 if (param == nullptr) {
436 WVLOG_E("new WebCookieManagerParam failed");
437 delete work;
438 return;
439 }
440 param->env_ = env_;
441 param->callback_ = callback_;
442 param->deferred_ = deferred_;
443
444 work->data = reinterpret_cast<void*>(param);
445 int ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, UvJsCallbackThreadWoker);
446 if (ret != 0) {
447 if (param != nullptr) {
448 delete param;
449 param = nullptr;
450 }
451 if (work != nullptr) {
452 delete work;
453 work = nullptr;
454 }
455 }
456 }
457 } // namespace NWeb
458 } // namespace OHOS