1 /*
2  * Copyright (c) 2023-2024 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 "js_auto_fill_extension_util.h"
17 
18 #include "hilog_tag_wrapper.h"
19 #include "napi_common_util.h"
20 #include "napi_common_want.h"
21 
22 namespace OHOS {
23 namespace AbilityRuntime {
24 namespace {
25 constexpr const char *VIEW_DATA_BUNDLE_NAME = "bundleName";
26 constexpr const char *VIEW_DATA_MODULE_NAME = "moduleName";
27 constexpr const char *VIEW_DATA_ABILITY_NAME = "abilityName";
28 constexpr const char *VIEW_DATA_PAGEURL = "pageUrl";
29 constexpr const char *VIEW_DATA_USER_SELECTED = "isUserSelected";
30 constexpr const char *VIEW_DATA_OTHER_ACCOUNT = "isOtherAccount";
31 constexpr const char *VIEW_DATA_PAGE_NODE_INFOS = "pageNodeInfos";
32 constexpr const char *VIEW_DATA_VIEW_DATA = "viewData";
33 constexpr const char *VIEW_DATA_TYPE = "type";
34 constexpr const char *VIEW_DATA_PAGE_RECT = "pageRect";
35 constexpr const char *CUSTOM_DATA_CUSTOM_DATA = "customData";
36 constexpr const char *CUSTOM_DATA_DATA = "data";
37 constexpr const char *PAGE_INFO_ID = "id";
38 constexpr const char *PAGE_INFO_DEPTH = "depth";
39 constexpr const char *PAGE_INFO_AUTOFILLTYPE = "autoFillType";
40 constexpr const char *PAGE_INFO_TAG = "tag";
41 constexpr const char *PAGE_INFO_VALUE = "value";
42 constexpr const char *PAGE_INFO_PLACEHOLDER = "placeholder";
43 constexpr const char *PAGE_INFO_META_DATA = "metadata";
44 constexpr const char *PAGE_INFO_PASSWORDRULES = "passwordRules";
45 constexpr const char *PAGE_INFO_ENABLEAUTOFILL = "enableAutoFill";
46 constexpr const char *PAGE_INFO_IS_FOCUS = "isFocus";
47 constexpr const char *PAGE_INFO_PAGE_NODE_RECT = "rect";
48 constexpr const char *WANT_PARAMS_VIEW_DATA = "ohos.ability.params.viewData";
49 constexpr const char *WANT_PARAMS_CUSTOM_DATA = "ohos.ability.params.customData";
50 constexpr const char *WANT_PARAMS_AUTO_FILL_TYPE_KEY = "ability.want.params.AutoFillType";
51 constexpr const char *WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY = "ohos.ability.params.popupWindow";
52 constexpr const char *WANT_PARAMS_IS_POPUP = "isPopup";
53 constexpr const char *RECT_POSITION_LEFT = "left";
54 constexpr const char *RECT_POSITION_TOP = "top";
55 constexpr const char *RECT_WIDTH = "width";
56 constexpr const char *RECT_HEIGHT = "height";
57 constexpr uint32_t PAGE_NODE_COUNT_MAX = 100;
58 } // namespace
59 
WrapViewData(const napi_env env,const AbilityBase::ViewData & viewData)60 napi_value JsAutoFillExtensionUtil::WrapViewData(const napi_env env, const AbilityBase::ViewData &viewData)
61 {
62     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
63     napi_value jsObject = nullptr;
64     NAPI_CALL(env, napi_create_object(env, &jsObject));
65     napi_value jsValue = nullptr;
66     jsValue = WrapStringToJS(env, viewData.bundleName);
67     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_BUNDLE_NAME, jsValue);
68 
69     jsValue = WrapStringToJS(env, viewData.abilityName);
70     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_ABILITY_NAME, jsValue);
71 
72     jsValue = WrapStringToJS(env, viewData.moduleName);
73     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_MODULE_NAME, jsValue);
74 
75     jsValue = WrapStringToJS(env, viewData.pageUrl);
76     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_PAGEURL, jsValue);
77 
78     jsValue = WrapBoolToJS(env, viewData.isUserSelected);
79     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_USER_SELECTED, jsValue);
80 
81     jsValue = WrapBoolToJS(env, viewData.isOtherAccount);
82     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_OTHER_ACCOUNT, jsValue);
83 
84     napi_value jsArray = nullptr;
85     NAPI_CALL(env, napi_create_array(env, &jsArray));
86     napi_value jsSubValue = nullptr;
87     uint32_t index = 0;
88     for (auto element : viewData.nodes) {
89         jsSubValue = WrapPageNodeInfo(env, element);
90         if (jsSubValue != nullptr && napi_set_element(env, jsArray, index, jsSubValue) == napi_ok) {
91             index++;
92         } else {
93             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Set element fail");
94         }
95     }
96 
97     jsValue = WrapRectData(env, viewData.pageRect);
98     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_PAGE_RECT, jsValue);
99 
100     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_PAGE_NODE_INFOS, jsArray);
101     return jsObject;
102 }
103 
WrapCustomData(const napi_env env,const AAFwk::WantParams & param)104 napi_value JsAutoFillExtensionUtil::WrapCustomData(const napi_env env, const AAFwk::WantParams &param)
105 {
106     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
107     napi_value jsObject = nullptr;
108     NAPI_CALL(env, napi_create_object(env, &jsObject));
109     napi_value jsValue = nullptr;
110     jsValue = WrapWantParams(env, param);
111     SetPropertyValueByPropertyName(env, jsObject, CUSTOM_DATA_DATA, jsValue);
112     return jsObject;
113 }
114 
WrapPageNodeInfo(const napi_env env,const AbilityBase::PageNodeInfo & pageNodeInfo)115 napi_value JsAutoFillExtensionUtil::WrapPageNodeInfo(const napi_env env, const AbilityBase::PageNodeInfo &pageNodeInfo)
116 {
117     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
118     napi_value jsObject = nullptr;
119     NAPI_CALL(env, napi_create_object(env, &jsObject));
120     napi_value jsValue = nullptr;
121     jsValue = AppExecFwk::WrapInt32ToJS(env, pageNodeInfo.id);
122     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_ID, jsValue);
123 
124     jsValue = AppExecFwk::WrapInt32ToJS(env, pageNodeInfo.depth);
125     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_DEPTH, jsValue);
126 
127     jsValue = AppExecFwk::WrapInt32ToJS(env, static_cast<int32_t>(pageNodeInfo.autoFillType));
128     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_AUTOFILLTYPE, jsValue);
129 
130     jsValue = WrapStringToJS(env, pageNodeInfo.tag);
131     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_TAG, jsValue);
132 
133     jsValue = WrapStringToJS(env, pageNodeInfo.value);
134     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_VALUE, jsValue);
135 
136     jsValue = WrapStringToJS(env, pageNodeInfo.passwordRules);
137     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_PASSWORDRULES, jsValue);
138 
139     jsValue = WrapStringToJS(env, pageNodeInfo.placeholder);
140     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_PLACEHOLDER, jsValue);
141 
142     jsValue = WrapStringToJS(env, pageNodeInfo.metadata);
143     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_META_DATA, jsValue);
144 
145     jsValue = WrapBoolToJS(env, pageNodeInfo.enableAutoFill);
146     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_ENABLEAUTOFILL, jsValue);
147 
148     jsValue = WrapRectData(env, pageNodeInfo.rect);
149     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_PAGE_NODE_RECT, jsValue);
150 
151     jsValue = WrapBoolToJS(env, pageNodeInfo.isFocus);
152     SetPropertyValueByPropertyName(env, jsObject, PAGE_INFO_IS_FOCUS, jsValue);
153 
154     return jsObject;
155 }
156 
WrapRectData(const napi_env env,const AbilityBase::Rect & rect)157 napi_value JsAutoFillExtensionUtil::WrapRectData(const napi_env env, const AbilityBase::Rect &rect)
158 {
159     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
160     napi_value jsObject = nullptr;
161     NAPI_CALL(env, napi_create_object(env, &jsObject));
162     napi_value jsValue = nullptr;
163     jsValue = AppExecFwk::WrapDoubleToJS(env, rect.left);
164     SetPropertyValueByPropertyName(env, jsObject, RECT_POSITION_LEFT, jsValue);
165 
166     jsValue = AppExecFwk::WrapDoubleToJS(env, rect.top);
167     SetPropertyValueByPropertyName(env, jsObject, RECT_POSITION_TOP, jsValue);
168 
169     jsValue = AppExecFwk::WrapDoubleToJS(env, rect.width);
170     SetPropertyValueByPropertyName(env, jsObject, RECT_WIDTH, jsValue);
171 
172     jsValue = AppExecFwk::WrapDoubleToJS(env, rect.height);
173     SetPropertyValueByPropertyName(env, jsObject, RECT_HEIGHT, jsValue);
174 
175     return jsObject;
176 }
177 
UnwrapViewData(const napi_env env,const napi_value value,AbilityBase::ViewData & viewData)178 void JsAutoFillExtensionUtil::UnwrapViewData(
179     const napi_env env, const napi_value value, AbilityBase::ViewData &viewData)
180 {
181     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
182     napi_value jsViewData = GetPropertyValueByPropertyName(env, value, VIEW_DATA_VIEW_DATA, napi_object);
183     if (jsViewData == nullptr) {
184         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Get ViewData from JS failed");
185         return;
186     }
187 
188     napi_value jsValue = nullptr;
189     jsValue = GetPropertyValueByPropertyName(env, jsViewData, VIEW_DATA_BUNDLE_NAME, napi_string);
190     viewData.bundleName = UnwrapStringFromJS(env, jsValue, "");
191     jsValue = GetPropertyValueByPropertyName(env, jsViewData, VIEW_DATA_MODULE_NAME, napi_string);
192     viewData.moduleName = UnwrapStringFromJS(env, jsValue, "");
193     jsValue = GetPropertyValueByPropertyName(env, jsViewData, VIEW_DATA_ABILITY_NAME, napi_string);
194     viewData.abilityName = UnwrapStringFromJS(env, jsValue, "");
195     jsValue = GetPropertyValueByPropertyName(env, jsViewData, VIEW_DATA_PAGEURL, napi_string);
196     viewData.pageUrl = UnwrapStringFromJS(env, jsValue, "");
197     UnwrapBooleanByPropertyName(env, jsViewData, VIEW_DATA_USER_SELECTED, viewData.isUserSelected);
198     UnwrapBooleanByPropertyName(env, jsViewData, VIEW_DATA_OTHER_ACCOUNT, viewData.isOtherAccount);
199     jsValue = GetPropertyValueByPropertyName(env, jsViewData, VIEW_DATA_PAGE_NODE_INFOS, napi_object);
200     if (jsValue != nullptr) {
201         uint32_t jsProCount = 0;
202         if (!IsArrayForNapiValue(env, jsValue, jsProCount)) {
203             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Get PAGE_NODE_INFOS from JS failed");
204             return;
205         }
206 
207         for (uint32_t index = 0; index < jsProCount && index < PAGE_NODE_COUNT_MAX; index++) {
208             napi_value jsNode = nullptr;
209             napi_get_element(env, jsValue, index, &jsNode);
210             AbilityBase::PageNodeInfo node;
211             UnwrapPageNodeInfo(env, jsNode, node);
212             viewData.nodes.emplace_back(node);
213         }
214     }
215     jsValue = GetPropertyValueByPropertyName(env, jsViewData, VIEW_DATA_PAGE_RECT, napi_object);
216     UnwrapRectData(env, jsValue, viewData.pageRect);
217 }
218 
UnwrapPageNodeInfo(const napi_env env,const napi_value jsNode,AbilityBase::PageNodeInfo & node)219 void JsAutoFillExtensionUtil::UnwrapPageNodeInfo(
220     const napi_env env, const napi_value jsNode, AbilityBase::PageNodeInfo &node)
221 {
222     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
223     UnwrapInt32ByPropertyName(env, jsNode, PAGE_INFO_ID, node.id);
224     UnwrapInt32ByPropertyName(env, jsNode, PAGE_INFO_DEPTH, node.depth);
225     int32_t type;
226     UnwrapInt32ByPropertyName(env, jsNode, PAGE_INFO_AUTOFILLTYPE, type);
227     node.autoFillType = static_cast<AbilityBase::AutoFillType>(type);
228     UnwrapStringByPropertyName(env, jsNode, PAGE_INFO_TAG, node.tag);
229     UnwrapStringByPropertyName(env, jsNode, PAGE_INFO_VALUE, node.value);
230     UnwrapStringByPropertyName(env, jsNode, PAGE_INFO_PASSWORDRULES, node.passwordRules);
231     UnwrapStringByPropertyName(env, jsNode, PAGE_INFO_PLACEHOLDER, node.placeholder);
232     UnwrapStringByPropertyName(env, jsNode, PAGE_INFO_META_DATA, node.metadata);
233     UnwrapBooleanByPropertyName(env, jsNode, PAGE_INFO_ENABLEAUTOFILL, node.enableAutoFill);
234     auto jsValue = GetPropertyValueByPropertyName(env, jsNode, PAGE_INFO_PAGE_NODE_RECT, napi_object);
235     UnwrapRectData(env, jsValue, node.rect);
236     UnwrapBooleanByPropertyName(env, jsNode, PAGE_INFO_IS_FOCUS, node.isFocus);
237 }
238 
UnwrapRectData(const napi_env env,const napi_value value,AbilityBase::Rect & rect)239 void JsAutoFillExtensionUtil::UnwrapRectData(
240     const napi_env env, const napi_value value, AbilityBase::Rect &rect)
241 {
242     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
243     int32_t position;
244     UnwrapInt32ByPropertyName(env, value, RECT_POSITION_LEFT, position);
245     rect.left = position;
246 
247     UnwrapInt32ByPropertyName(env, value, RECT_POSITION_TOP, position);
248     rect.top = position;
249 
250     UnwrapInt32ByPropertyName(env, value, RECT_WIDTH, position);
251     rect.width = position;
252 
253     UnwrapInt32ByPropertyName(env, value, RECT_HEIGHT, position);
254     rect.height = position;
255 }
256 
WrapFillRequest(const AAFwk::Want & want,const napi_env env)257 napi_value JsAutoFillExtensionUtil::WrapFillRequest(const AAFwk::Want &want, const napi_env env)
258 {
259     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
260     napi_value jsObject = nullptr;
261     NAPI_CALL(env, napi_create_object(env, &jsObject));
262     if (jsObject == nullptr) {
263         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "create jsObject failed");
264         return nullptr;
265     }
266 
267     if (want.HasParameter(WANT_PARAMS_AUTO_FILL_TYPE_KEY)) {
268         auto type = want.GetIntParam(WANT_PARAMS_AUTO_FILL_TYPE_KEY, -1);
269         TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Auto fill request type: %{public}d", type);
270 
271         napi_value jsValue = AppExecFwk::WrapInt32ToJS(env, type);
272         SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_TYPE, jsValue);
273     }
274 
275     if (want.HasParameter(WANT_PARAMS_VIEW_DATA)) {
276         std::string viewDataString = want.GetStringParam(WANT_PARAMS_VIEW_DATA);
277         if (viewDataString.empty()) {
278             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty view data");
279             return jsObject;
280         }
281 
282         AbilityBase::ViewData viewData;
283         viewData.FromJsonString(viewDataString);
284         napi_value viewDataValue = WrapViewData(env, viewData);
285         SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_VIEW_DATA, viewDataValue);
286     }
287 
288     if (want.HasParameter(WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY)) {
289         auto isPopup = want.GetBoolParam(WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY, false);
290 
291         napi_value jsValue = AppExecFwk::WrapBoolToJS(env, isPopup);
292         SetPropertyValueByPropertyName(env, jsObject, WANT_PARAMS_IS_POPUP, jsValue);
293     }
294 
295     if (want.HasParameter(WANT_PARAMS_CUSTOM_DATA)) {
296         std::string customDataString = want.GetStringParam(WANT_PARAMS_CUSTOM_DATA);
297         if (customDataString.empty()) {
298             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty custom data");
299             return jsObject;
300         }
301         if (!AAFwk::WantParamWrapper::ValidateStr(customDataString)) {
302             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "invalid Custom data string");
303             return jsObject;
304         }
305         AAFwk::WantParams param = AAFwk::WantParamWrapper::ParseWantParams(customDataString);
306         napi_value customValue = nullptr;
307         customValue = WrapCustomData(env, param);
308         SetPropertyValueByPropertyName(env, jsObject, CUSTOM_DATA_CUSTOM_DATA, customValue);
309     }
310     return jsObject;
311 }
312 
WrapUpdateRequest(const AAFwk::WantParams & wantParams,const napi_env env)313 napi_value JsAutoFillExtensionUtil::WrapUpdateRequest(const AAFwk::WantParams &wantParams, const napi_env env)
314 {
315     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
316     napi_value jsObject = nullptr;
317     NAPI_CALL(env, napi_create_object(env, &jsObject));
318     if (jsObject == nullptr) {
319         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to create Object");
320         return nullptr;
321     }
322 
323     std::string viewDataString = wantParams.GetStringParam(WANT_PARAMS_VIEW_DATA);
324     if (viewDataString.empty()) {
325         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "empty view data");
326         return jsObject;
327     }
328 
329     AbilityBase::ViewData viewData;
330     viewData.FromJsonString(viewDataString);
331     napi_value viewDataValue = WrapViewData(env, viewData);
332     SetPropertyValueByPropertyName(env, jsObject, VIEW_DATA_VIEW_DATA, viewDataValue);
333     return jsObject;
334 }
335 
UnwrapFillResponse(const napi_env env,const napi_value value,FillResponse & response)336 void JsAutoFillExtensionUtil::UnwrapFillResponse(const napi_env env, const napi_value value, FillResponse &response)
337 {
338     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
339     UnwrapViewData(env, value, response.viewData);
340 }
341 
UnwrapPopupSize(const napi_env env,const napi_value value,PopupSize & popupSize)342 void JsAutoFillExtensionUtil::UnwrapPopupSize(const napi_env env, const napi_value value, PopupSize &popupSize)
343 {
344     UnwrapInt32ByPropertyName(env, value, RECT_WIDTH, popupSize.width);
345     UnwrapInt32ByPropertyName(env, value, RECT_HEIGHT, popupSize.height);
346 }
347 } // namespace AbilityRuntime
348 } // namespace OHOS