1 /*
2  * Copyright (c) 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 "cm_napi_open_dialog.h"
17 
18 #include "syspara/parameters.h"
19 #include "securec.h"
20 
21 #include "cert_manager_api.h"
22 #include "cm_log.h"
23 #include "iservice_registry.h"
24 #include "bundle_mgr_proxy.h"
25 #include "system_ability_definition.h"
26 
27 #include "cm_napi_dialog_common.h"
28 #include "want.h"
29 #include "want_params_wrapper.h"
30 
31 namespace CMNapi {
32 
33 class CmInstallUIExtensionCallback : public CmUIExtensionCallback {
34 public:
CmInstallUIExtensionCallback(std::shared_ptr<CmUIExtensionRequestContext> & reqContext)35     explicit CmInstallUIExtensionCallback(
36         std::shared_ptr<CmUIExtensionRequestContext>& reqContext) : CmUIExtensionCallback(reqContext)
37     {
38         this->reqContext_ = reqContext;
39     }
40 
~CmInstallUIExtensionCallback()41     ~CmInstallUIExtensionCallback() override
42     {
43         CM_LOG_D("~CmInstallUIExtensionCallback");
44     }
45 
OnRelease(const int32_t releaseCode)46     void OnRelease(const int32_t releaseCode) override
47     {
48         CM_LOG_D("InstallUIExtensionComponent OnRelease(), releaseCode = %d", releaseCode);
49         if (SetErrorCode(CMR_DIALOG_ERROR_OPERATION_CANCELS)) {
50             SendMessageBack();
51         }
52     }
53 
OnResult(const int32_t resultCode,const OHOS::AAFwk::Want & result)54     void OnResult(const int32_t resultCode, const OHOS::AAFwk::Want& result) override
55     {
56         CM_LOG_D("InstallUIExtensionComponent OnResult(), resultCode = %d", resultCode);
57         this->resultCode_ = resultCode;
58         this->resultWant_ = result;
59         if (SetErrorCode(CMR_DIALOG_ERROR_INSTALL_FAILED)) {
60             SendMessageBack();
61         }
62     }
63 
OnReceive(const OHOS::AAFwk::WantParams & request)64     void OnReceive(const OHOS::AAFwk::WantParams& request) override
65     {
66         CM_LOG_D("InstallUIExtensionComponent OnReceive()");
67         this->reqContext_->uri = request.GetStringParam("uri");
68         if (SetErrorCode(0)) {
69             SendMessageBack();
70         }
71     }
72 
ProcessCallback(napi_env env,const CommonAsyncContext * asyncContext)73     void ProcessCallback(napi_env env, const CommonAsyncContext* asyncContext) override
74     {
75         napi_value args = nullptr;
76         if (asyncContext->errCode == CM_SUCCESS) {
77             NAPI_CALL_RETURN_VOID(env,
78                 napi_create_string_utf8(env, asyncContext->uri.c_str(), NAPI_AUTO_LENGTH, &args));
79         } else {
80             args = GenerateBusinessError(env, asyncContext->errCode);
81         }
82 
83         if (asyncContext->deferred != nullptr) {
84             if (asyncContext->errCode == CM_SUCCESS) {
85                 NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncContext->deferred, args));
86             } else {
87                 NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, asyncContext->deferred, args));
88             }
89         }
90     }
91 
OnDestroy()92     void OnDestroy() override
93     {
94         CM_LOG_D("InstallUIExtensionComponent OnDestroy()");
95     }
96 
97 private:
SetErrorCode(int32_t errCode)98     bool SetErrorCode(int32_t errCode)
99     {
100         if (this->reqContext_ == nullptr) {
101             CM_LOG_E("OnError reqContext is nullptr");
102             return false;
103         }
104         if (this->alreadyCallback_) {
105             CM_LOG_D("alreadyCallback");
106             return false;
107         }
108         this->alreadyCallback_ = true;
109         this->reqContext_->errCode = errCode;
110         return true;
111     };
112     int32_t resultCode_ = 0;
113     OHOS::AAFwk::Want resultWant_;
114     std::shared_ptr<CmUIExtensionRequestContext> reqContext_ = nullptr;
115     bool alreadyCallback_ = false;
116 };
117 
IsCmCertificateScopeEnum(const uint32_t value)118 static bool IsCmCertificateScopeEnum(const uint32_t value)
119 {
120     switch (static_cast<CertificateScope>(value)) {
121         case CertificateScope::CURRENT_USER:
122             return true;
123         default:
124             return false;
125     }
126 }
127 
IsCmCertificateTypeAndConvert(const uint32_t value,uint32_t & pageType)128 static bool IsCmCertificateTypeAndConvert(const uint32_t value, uint32_t &pageType)
129 {
130     switch (static_cast<CmCertificateType>(value)) {
131         case CmCertificateType::CA_CERT:
132             pageType = CmDialogPageType::PAGE_INSTALL_CA_GUIDE;
133             return true;
134         default:
135             return false;
136     }
137 }
138 
CMCheckArgvAndInitContext(std::shared_ptr<CmUIExtensionRequestContext> asyncContext,napi_value argv[],size_t length)139 static napi_value CMCheckArgvAndInitContext(std::shared_ptr<CmUIExtensionRequestContext> asyncContext,
140     napi_value argv[], size_t length)
141 {
142     if (length != PARAM_SIZE_FOUR) {
143         CM_LOG_E("params number vaild failed");
144         return nullptr;
145     }
146     // Parse first argument for context.
147     if (!ParseCmUIAbilityContextReq(asyncContext->env, argv[PARAM0], asyncContext->context)) {
148         CM_LOG_E("ParseUIAbilityContextReq failed");
149         return nullptr;
150     }
151 
152     // Parse second argument for certificate type.
153     uint32_t certificateType = 0;
154     if (ParseUint32(asyncContext->env, argv[PARAM1], certificateType) == nullptr) {
155         CM_LOG_E("parse type failed");
156         return nullptr;
157     }
158     if (!IsCmCertificateTypeAndConvert(certificateType, asyncContext->certificateType)) {
159         CM_LOG_E("certificateType invalid");
160         return nullptr;
161     }
162 
163     // Parse third argument for certificateScope.
164     if (ParseUint32(asyncContext->env, argv[PARAM2], asyncContext->certificateScope) == nullptr) {
165         CM_LOG_E("parse type failed");
166         return nullptr;
167     }
168     if (!IsCmCertificateScopeEnum(asyncContext->certificateScope)) {
169         CM_LOG_E("certificateScope invalid");
170         return nullptr;
171     }
172 
173     // Parse fourth argument for cert.
174     if (GetUint8ArrayToBase64Str(asyncContext->env, argv[PARAM3], asyncContext->certStr) == nullptr) {
175         CM_LOG_E("cert is not a uint8Array or the length is 0 or too long.");
176         return nullptr;
177     }
178     return GetInt32(asyncContext->env, 0);
179 }
180 
CMGetInstallCertWant(std::shared_ptr<CmUIExtensionRequestContext> asyncContext)181 static OHOS::AAFwk::Want CMGetInstallCertWant(std::shared_ptr<CmUIExtensionRequestContext> asyncContext)
182 {
183     OHOS::AAFwk::Want want;
184     want.SetElementName(CERT_MANAGER_BUNDLENAME, CERT_MANAGER_ABILITYNAME);
185     want.SetParam(CERT_MANAGER_PAGE_TYPE, static_cast<int32_t>(asyncContext->certificateType));
186     want.SetParam(CERT_MANAGER_CERTIFICATE_DATA, asyncContext->certStr);
187     want.SetParam(CERT_MANAGER_CERTSCOPE_TYPE, static_cast<int32_t>(asyncContext->certificateScope));
188     want.SetParam(CERT_MANAGER_CALLER_BUNDLENAME, asyncContext->labelName);
189     want.SetParam(PARAM_UI_EXTENSION_TYPE, SYS_COMMON_UI);
190     return want;
191 }
192 
GetBundleMgrProxy()193 static OHOS::sptr<OHOS::AppExecFwk::BundleMgrProxy> GetBundleMgrProxy()
194 {
195     auto systemAbilityManager = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
196     if (!systemAbilityManager) {
197         CM_LOG_E("fail to get system ability mgr.");
198         return nullptr;
199     }
200 
201     auto remoteObject = systemAbilityManager->GetSystemAbility(OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
202     if (!remoteObject) {
203         CM_LOG_E("fail to get bundle manager proxy.");
204         return nullptr;
205     }
206     return OHOS::iface_cast<OHOS::AppExecFwk::BundleMgrProxy>(remoteObject);
207 }
208 
GetCallerLabelName(std::shared_ptr<CmUIExtensionRequestContext> asyncContext)209 static int32_t GetCallerLabelName(std::shared_ptr<CmUIExtensionRequestContext> asyncContext)
210 {
211     OHOS::sptr<OHOS::AppExecFwk::BundleMgrProxy> bundleMgrProxy = GetBundleMgrProxy();
212     if (bundleMgrProxy == nullptr) {
213         CM_LOG_E("Failed to get bundle manager proxy.");
214         return CM_FAILURE;
215     }
216 
217     OHOS::AppExecFwk::BundleInfo bundleInfo;
218     int32_t flags = static_cast<int32_t>(OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_DEFAULT) |
219         static_cast<int32_t>(OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_APPLICATION) |
220         static_cast<int32_t>(OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_HAP_MODULE) |
221         static_cast<int32_t>(OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_ABILITY);
222     int32_t resCode = bundleMgrProxy->GetBundleInfoForSelf(flags, bundleInfo);
223     if (resCode != CM_SUCCESS) {
224         CM_LOG_E("Failed to get bundleInfo, resCode is %d", resCode);
225         return CM_FAILURE;
226     }
227 
228     if (asyncContext->context->GetResourceManager() == nullptr) {
229         CM_LOG_E("context get resourcemanager faild");
230         return CMR_ERROR_NULL_POINTER;
231     }
232 
233     resCode = asyncContext->context->GetResourceManager()->GetStringById(bundleInfo.applicationInfo.labelId,
234         asyncContext->labelName);
235     if (resCode != CM_SUCCESS) {
236         CM_LOG_E("getStringById is faild, resCode is %d", resCode);
237         return CM_FAILURE;
238     }
239     return CM_SUCCESS;
240 }
241 
CMNapiOpenInstallCertDialog(napi_env env,napi_callback_info info)242 napi_value CMNapiOpenInstallCertDialog(napi_env env, napi_callback_info info)
243 {
244     CM_LOG_D("cert install dialog enter");
245     napi_value result = nullptr;
246     NAPI_CALL(env, napi_get_undefined(env, &result));
247     if (OHOS::system::GetParameter("const.product.devicetype", "") != "2in1") {
248         CM_LOG_E("deviceType is not 2in1");
249         std::string errMsg = "DeviceType Error. deviceType is not 2in1";
250         ThrowError(env, DIALOG_ERROR_NOT_SUPPORTED, errMsg);
251         return result;
252     }
253 
254     size_t argc = PARAM_SIZE_FOUR;
255     napi_value argv[PARAM_SIZE_FOUR] = { nullptr };
256     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
257     if (argc != PARAM_SIZE_FOUR) {
258         CM_LOG_E("params number mismatch");
259         std::string errMsg = "Parameter Error. Params number mismatch, need " + std::to_string(PARAM_SIZE_FOUR)
260             + ", given " + std::to_string(argc);
261         ThrowError(env, PARAM_ERROR, errMsg);
262         return result;
263     }
264 
265     auto asyncContext = std::make_shared<CmUIExtensionRequestContext>(env);
266     asyncContext->env = env;
267     if (CMCheckArgvAndInitContext(asyncContext, argv, sizeof(argv) / sizeof(argv[0])) == nullptr) {
268         CM_LOG_E("check argv vaild and init faild");
269         ThrowError(env, PARAM_ERROR, "check argv vaild and init faild");
270         return nullptr;
271     }
272 
273     if (GetCallerLabelName(asyncContext) != CM_SUCCESS) {
274         CM_LOG_E("get caller labelName faild");
275         ThrowError(env, DIALOG_ERROR_GENERIC, "get caller labelName faild");
276         return nullptr;
277     }
278     NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred, &result));
279 
280     auto uiExtCallback = std::make_shared<CmInstallUIExtensionCallback>(asyncContext);
281     StartUIExtensionAbility(asyncContext, CMGetInstallCertWant(asyncContext), uiExtCallback);
282     CM_LOG_D("cert install dialog end");
283     return result;
284 }
285 }  // namespace CMNapi
286 
287