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 "securec.h"
19
20 #include "cert_manager_api.h"
21 #include "cm_log.h"
22
23 #include "cm_napi_dialog_common.h"
24 #include "want.h"
25 #include "want_params_wrapper.h"
26
27 namespace CMNapi {
28 namespace {
29 const std::string PARAM_UI_EXTENSION_TYPE = "ability.want.params.uiExtensionType";
30 const std::string SYS_COMMON_UI = "sys/commonUI";
31 const std::string CERT_MANAGER_BUNDLENAME = "com.ohos.certmanager";
32 const std::string CERT_MANAGER_ABILITYNAME = "CertPickerUIExtAbility";
33 const std::string CERT_MANAGER_PAGE_TYPE = "pageType";
34 constexpr int32_t PARAM0 = 0;
35 constexpr int32_t PARAM1 = 1;
36 constexpr int32_t PARAM_SIZE_TWO = 2;
37 } // namespace
38
CommonAsyncContext(napi_env env)39 CommonAsyncContext::CommonAsyncContext(napi_env env)
40 {
41 CM_LOG_D("CommonAsyncContext");
42 this->env = env;
43 }
44
~CommonAsyncContext()45 CommonAsyncContext::~CommonAsyncContext()
46 {
47 CM_LOG_D("~CommonAsyncContext");
48 }
49
CmUIExtensionCallback(std::shared_ptr<CmUIExtensionRequestContext> & reqContext)50 CmUIExtensionCallback::CmUIExtensionCallback(std::shared_ptr<CmUIExtensionRequestContext>& reqContext)
51 {
52 this->reqContext_ = reqContext;
53 }
54
SetSessionId(const int32_t sessionId)55 void CmUIExtensionCallback::SetSessionId(const int32_t sessionId)
56 {
57 this->sessionId_ = sessionId;
58 }
59
SetErrorCode(int32_t code)60 bool CmUIExtensionCallback::SetErrorCode(int32_t code)
61 {
62 if (this->reqContext_ == nullptr) {
63 CM_LOG_E("OnError reqContext is nullptr");
64 return false;
65 }
66 if (this->alreadyCallback_) {
67 CM_LOG_D("alreadyCallback");
68 return false;
69 }
70 this->alreadyCallback_ = true;
71 this->reqContext_->errCode = code;
72 return true;
73 }
74
OnRelease(const int32_t releaseCode)75 void CmUIExtensionCallback::OnRelease(const int32_t releaseCode)
76 {
77 CM_LOG_D("UIExtensionComponent OnRelease(), releaseCode = %d", releaseCode);
78 if (SetErrorCode(releaseCode)) {
79 SendMessageBack();
80 }
81 }
82
OnResult(const int32_t resultCode,const OHOS::AAFwk::Want & result)83 void CmUIExtensionCallback::OnResult(const int32_t resultCode, const OHOS::AAFwk::Want& result)
84 {
85 CM_LOG_D("UIExtensionComponent OnResult(), resultCode = %d", resultCode);
86 this->resultCode_ = resultCode;
87 this->resultWant_ = result;
88 if (SetErrorCode(0)) {
89 SendMessageBack();
90 }
91 }
92
OnReceive(const OHOS::AAFwk::WantParams & request)93 void CmUIExtensionCallback::OnReceive(const OHOS::AAFwk::WantParams& request)
94 {
95 CM_LOG_D("UIExtensionComponent OnReceive()");
96 if (SetErrorCode(0)) {
97 SendMessageBack();
98 }
99 }
100
OnError(const int32_t errorCode,const std::string & name,const std::string & message)101 void CmUIExtensionCallback::OnError(const int32_t errorCode, const std::string& name, const std::string& message)
102 {
103 CM_LOG_E("UIExtensionComponent OnError(), errorCode = %d, name = %s, message = %s",
104 errorCode, name.c_str(), message.c_str());
105 if (SetErrorCode(errorCode)) {
106 SendMessageBack();
107 }
108 }
109
OnRemoteReady(const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy> & uiProxy)110 void CmUIExtensionCallback::OnRemoteReady(const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy>& uiProxy)
111 {
112 CM_LOG_D("UIExtensionComponent OnRemoteReady()");
113 }
114
OnDestroy()115 void CmUIExtensionCallback::OnDestroy()
116 {
117 CM_LOG_D("UIExtensionComponent OnDestroy()");
118 if (SetErrorCode(0)) {
119 SendMessageBack();
120 }
121 }
122
ProcessCallback(napi_env env,const CommonAsyncContext * asyncContext)123 void ProcessCallback(napi_env env, const CommonAsyncContext* asyncContext)
124 {
125 napi_value args[PARAM_SIZE_TWO] = {nullptr};
126
127 if (asyncContext->errCode == CM_SUCCESS) {
128 NAPI_CALL_RETURN_VOID(env, napi_create_uint32(env, 0, &args[PARAM0]));
129 NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, true, &args[PARAM1]));
130 } else {
131 args[PARAM0] = GenerateBusinessError(env, asyncContext->errCode);
132 NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &args[PARAM1]));
133 }
134
135 if (asyncContext->deferred != nullptr) {
136 GeneratePromise(env, asyncContext->deferred, asyncContext->errCode, args, CM_ARRAY_SIZE(args));
137 }
138 }
139
SendMessageBack()140 void CmUIExtensionCallback::SendMessageBack()
141 {
142 CM_LOG_I("start SendMessageBack");
143 if (this->reqContext_ == nullptr) {
144 CM_LOG_E("reqContext is nullptr");
145 return;
146 }
147
148 auto abilityContext = this->reqContext_->context;
149 if (abilityContext != nullptr) {
150 auto uiContent = abilityContext->GetUIContent();
151 if (uiContent != nullptr) {
152 CM_LOG_D("CloseModalUIExtension");
153 uiContent->CloseModalUIExtension(this->sessionId_);
154 }
155 }
156
157 CM_LOG_D("ProcessCallback");
158 ProcessCallback(this->reqContext_->env, this->reqContext_.get());
159 }
160
ParseCmUIAbilityContextReq(napi_env env,const napi_value & obj,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> & abilityContext)161 bool ParseCmUIAbilityContextReq(
162 napi_env env, const napi_value& obj, std::shared_ptr<OHOS::AbilityRuntime::AbilityContext>& abilityContext)
163 {
164 bool stageMode = false;
165 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, obj, stageMode);
166 if (status != napi_ok || !stageMode) {
167 CM_LOG_E("not stage mode");
168 return false;
169 }
170
171 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, obj);
172 if (context == nullptr) {
173 CM_LOG_E("get context failed");
174 return false;
175 }
176
177 abilityContext = OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
178 if (abilityContext == nullptr) {
179 CM_LOG_E("get abilityContext failed");
180 return false;
181 }
182 CM_LOG_I("end ParseUIAbilityContextReq");
183 return true;
184 }
185
StartUIExtensionAbility(std::shared_ptr<CmUIExtensionRequestContext> asyncContext,OHOS::AAFwk::Want want)186 static void StartUIExtensionAbility(std::shared_ptr<CmUIExtensionRequestContext> asyncContext,
187 OHOS::AAFwk::Want want)
188 {
189 CM_LOG_D("begin StartUIExtensionAbility");
190 auto abilityContext = asyncContext->context;
191 if (abilityContext == nullptr) {
192 CM_LOG_E("abilityContext is null");
193 ThrowError(asyncContext->env, PARAM_ERROR, "abilityContext is null");
194 return;
195 }
196 auto uiContent = abilityContext->GetUIContent();
197 if (uiContent == nullptr) {
198 CM_LOG_E("uiContent is null");
199 ThrowError(asyncContext->env, PARAM_ERROR, "uiContent is null");
200 return;
201 }
202
203 auto uiExtCallback = std::make_shared<CmUIExtensionCallback>(asyncContext);
204 OHOS::Ace::ModalUIExtensionCallbacks extensionCallbacks = {
205 [uiExtCallback](int32_t releaseCode) { uiExtCallback->OnRelease(releaseCode); },
206 [uiExtCallback](int32_t resultCode, const OHOS::AAFwk::Want& result) {
207 uiExtCallback->OnResult(resultCode, result); },
208 [uiExtCallback](const OHOS::AAFwk::WantParams& request) { uiExtCallback->OnReceive(request); },
209 [uiExtCallback](int32_t errorCode, const std::string& name, const std::string& message) {
210 uiExtCallback->OnError(errorCode, name, message); },
211 [uiExtCallback](const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy>& uiProxy) {
212 uiExtCallback->OnRemoteReady(uiProxy); },
213 [uiExtCallback]() { uiExtCallback->OnDestroy(); }
214 };
215
216 OHOS::Ace::ModalUIExtensionConfig uiExtConfig;
217 uiExtConfig.isProhibitBack = false;
218 int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallbacks, uiExtConfig);
219 CM_LOG_I("end CreateModalUIExtension");
220 if (sessionId == 0) {
221 CM_LOG_E("CreateModalUIExtension failed");
222 ThrowError(asyncContext->env, PARAM_ERROR, "CreateModalUIExtension failed");
223 }
224 uiExtCallback->SetSessionId(sessionId);
225 return;
226 }
227
IsCmDialogPageTypeEnum(const uint32_t value)228 static bool IsCmDialogPageTypeEnum(const uint32_t value)
229 {
230 switch (static_cast<CmDialogPageType>(value)) {
231 case CmDialogPageType::PAGE_MAIN:
232 case CmDialogPageType::PAGE_CA_CERTIFICATE:
233 case CmDialogPageType::PAGE_CREDENTIAL:
234 case CmDialogPageType::PAGE_INSTALL_CERTIFICATE:
235 return true;
236 default:
237 return false;
238 }
239 }
240
CMNapiOpenCertManagerDialog(napi_env env,napi_callback_info info)241 napi_value CMNapiOpenCertManagerDialog(napi_env env, napi_callback_info info)
242 {
243 CM_LOG_I("cert manager dialog enter");
244 size_t argc = PARAM_SIZE_TWO;
245 napi_value argv[PARAM_SIZE_TWO] = { nullptr };
246 napi_value result = nullptr;
247 NAPI_CALL(env, napi_get_undefined(env, &result));
248 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
249 if (argc != PARAM_SIZE_TWO) {
250 CM_LOG_E("params number mismatch");
251 std::string errMsg = "Parameter Error. Params number mismatch, need " + std::to_string(PARAM_SIZE_TWO)
252 + ", given " + std::to_string(argc);
253 ThrowError(env, PARAM_ERROR, errMsg);
254 return result;
255 }
256
257 // Parse first argument for context.
258 auto asyncContext = std::make_shared<CmUIExtensionRequestContext>(env);
259 if (!ParseCmUIAbilityContextReq(env, argv[PARAM0], asyncContext->context)) {
260 CM_LOG_E("ParseUIAbilityContextReq failed");
261 ThrowError(env, PARAM_ERROR, "Get context failed.");
262 return result;
263 }
264
265 // Parse second argument for page type.
266 result = ParseUint32(env, argv[PARAM1], asyncContext->pageType);
267 if (result == nullptr) {
268 CM_LOG_E("parse type failed");
269 ThrowError(env, PARAM_ERROR, "parse type failed");
270 return result;
271 }
272
273 if (!IsCmDialogPageTypeEnum(asyncContext->pageType)) {
274 CM_LOG_E("pageType invalid");
275 ThrowError(env, PARAM_ERROR, "pageType invalid");
276 return nullptr;
277 }
278
279 asyncContext->env = env;
280 OHOS::AAFwk::Want want;
281 want.SetElementName(CERT_MANAGER_BUNDLENAME, CERT_MANAGER_ABILITYNAME);
282 want.SetParam(CERT_MANAGER_PAGE_TYPE, static_cast<int32_t>(asyncContext->pageType));
283 want.SetParam(PARAM_UI_EXTENSION_TYPE, SYS_COMMON_UI);
284 NAPI_CALL(env, napi_create_promise(env, &asyncContext->deferred, &result));
285
286 // Start ui extension by context.
287 StartUIExtensionAbility(asyncContext, want);
288 CM_LOG_D("cert manager dialog end");
289 return result;
290 }
291 } // namespace CMNapi
292
293