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 #include "widget_context.h"
16
17 #include <algorithm>
18
19 #include "context_helper.h"
20 #include "context_pool.h"
21 #include "iam_check.h"
22 #include "iam_logger.h"
23 #include "iam_ptr.h"
24 #include "iam_time.h"
25 #include "schedule_node.h"
26 #include "schedule_node_callback.h"
27 #include "widget_schedule_node_impl.h"
28 #include "widget_context_callback_impl.h"
29 #include "widget_client.h"
30 #include "widget_json.h"
31 #include "bool_wrapper.h"
32 #include "double_wrapper.h"
33 #include "int_wrapper.h"
34 #include "string_wrapper.h"
35 #include "want_params_wrapper.h"
36 #include "ability_connection.h"
37 #include "ability_connect_callback.h"
38 #include "refbase.h"
39 #include "hisysevent_adapter.h"
40
41 #define LOG_LABEL UserIam::Common::LABEL_USER_AUTH_SA
42
43 namespace OHOS {
44 namespace UserIam {
45 namespace UserAuth {
46 constexpr int32_t DEFAULT_VALUE = -1;
47 const std::string UI_EXTENSION_TYPE_SET = "sysDialog/userAuth";
48
WidgetContext(uint64_t contextId,const ContextFactory::AuthWidgetContextPara & para,std::shared_ptr<ContextCallback> callback)49 WidgetContext::WidgetContext(uint64_t contextId, const ContextFactory::AuthWidgetContextPara ¶,
50 std::shared_ptr<ContextCallback> callback)
51 : contextId_(contextId), description_("UserAuthWidget"), callback_(callback), hasStarted_(false),
52 latestError_(ResultCode::GENERAL_ERROR), para_(para), schedule_(nullptr), connection_(nullptr)
53 {
54 }
55
~WidgetContext()56 WidgetContext::~WidgetContext()
57 {
58 IAM_LOGI("release WidgetContext");
59 }
60
Start()61 bool WidgetContext::Start()
62 {
63 std::lock_guard<std::recursive_mutex> lock(mutex_);
64 IAM_LOGI("%{public}s start", description_.c_str());
65 if (hasStarted_) {
66 IAM_LOGI("%{public}s context has started, cannot start again", description_.c_str());
67 return false;
68 }
69 hasStarted_ = true;
70 return OnStart();
71 }
72
Stop()73 bool WidgetContext::Stop()
74 {
75 IAM_LOGI("%{public}s start", description_.c_str());
76 return OnStop();
77 }
78
GetContextId() const79 uint64_t WidgetContext::GetContextId() const
80 {
81 return contextId_;
82 }
83
GetContextType() const84 ContextType WidgetContext::GetContextType() const
85 {
86 return WIDGET_AUTH_CONTEXT;
87 }
88
GetScheduleNode(uint64_t scheduleId) const89 std::shared_ptr<ScheduleNode> WidgetContext::GetScheduleNode(uint64_t scheduleId) const
90 {
91 return nullptr;
92 }
93
GetTokenId() const94 uint32_t WidgetContext::GetTokenId() const
95 {
96 return para_.tokenId;
97 }
98
GetLatestError() const99 int32_t WidgetContext::GetLatestError() const
100 {
101 return latestError_;
102 }
103
SetLatestError(int32_t error)104 void WidgetContext::SetLatestError(int32_t error)
105 {
106 if (error != ResultCode::SUCCESS) {
107 latestError_ = error;
108 }
109 }
110
BuildSchedule()111 bool WidgetContext::BuildSchedule()
112 {
113 schedule_ = Common::MakeShared<WidgetScheduleNodeImpl>();
114 IF_FALSE_LOGE_AND_RETURN_VAL(schedule_ != nullptr, false);
115 schedule_->SetCallback(shared_from_this());
116 return true;
117 }
118
GetAuthContextCallback(AuthType authType,AuthTrustLevel authTrustLevel,sptr<IamCallbackInterface> & callback)119 std::shared_ptr<ContextCallback> WidgetContext::GetAuthContextCallback(AuthType authType,
120 AuthTrustLevel authTrustLevel, sptr<IamCallbackInterface> &callback)
121 {
122 if (callback == nullptr) {
123 IAM_LOGE("callback is nullptr");
124 return nullptr;
125 }
126 auto contextCallback = ContextCallback::NewInstance(callback, TRACE_AUTH_USER);
127 if (contextCallback == nullptr) {
128 IAM_LOGE("failed to construct context callback");
129 Attributes extraInfo;
130 callback->OnResult(ResultCode::GENERAL_ERROR, extraInfo);
131 return nullptr;
132 }
133 auto callingUid = static_cast<uint64_t>(para_.callingUid);
134 contextCallback->SetTraceCallingUid(callingUid);
135 contextCallback->SetTraceAuthTrustLevel(authTrustLevel);
136 return contextCallback;
137 }
138
BuildTask(const std::vector<uint8_t> & challenge,AuthType authType,AuthTrustLevel authTrustLevel)139 std::shared_ptr<Context> WidgetContext::BuildTask(const std::vector<uint8_t> &challenge,
140 AuthType authType, AuthTrustLevel authTrustLevel)
141 {
142 if (callback_ == nullptr) {
143 IAM_LOGE("invalid widget context callback, failed to build task");
144 return nullptr;
145 }
146 auto userId = para_.userId;
147 auto tokenId = WidgetClient::Instance().GetAuthTokenId();
148 IAM_LOGI("Real userId: %{public}d, Real tokenId: %{public}u", userId, tokenId);
149 sptr<IamCallbackInterface> iamCallback(new (std::nothrow) WidgetContextCallbackImpl(weak_from_this(),
150 static_cast<int32_t>(authType)));
151 auto contextCallback = GetAuthContextCallback(authType, authTrustLevel, iamCallback);
152 if (contextCallback == nullptr) {
153 IAM_LOGE("failed to get simple context callback");
154 return nullptr;
155 }
156 callback_->SetTraceUserId(userId);
157 ContextFactory::AuthContextPara para = {};
158 para.tokenId = tokenId;
159 para.userId = userId;
160 para.authType = authType;
161 para.atl = authTrustLevel;
162 para.challenge = challenge;
163 para.endAfterFirstFail = true;
164 auto context = ContextFactory::CreateSimpleAuthContext(para, contextCallback);
165 if (!ContextPool::Instance().Insert(context)) {
166 IAM_LOGE("failed to insert context");
167 Attributes extraInfo;
168 callback_->OnResult(ResultCode::GENERAL_ERROR, extraInfo);
169 return nullptr;
170 }
171 contextCallback->SetCleaner(ContextHelper::Cleaner(context));
172 std::lock_guard<std::recursive_mutex> lock(mutex_);
173 return context;
174 }
175
OnStart()176 bool WidgetContext::OnStart()
177 {
178 IAM_LOGI("%{public}s start", description_.c_str());
179 if (!BuildSchedule()) {
180 IAM_LOGE("failed to create widget schedule");
181 return false;
182 }
183 WidgetClient::Instance().SetWidgetContextId(GetContextId());
184 WidgetClient::Instance().SetWidgetParam(para_.widgetParam);
185 WidgetClient::Instance().SetAuthTypeList(para_.authTypeList);
186 WidgetClient::Instance().SetWidgetSchedule(schedule_);
187 schedule_->StartSchedule();
188
189 IAM_LOGI("WidgetContext start success.");
190 return true;
191 }
192
OnResult(int32_t resultCode,const std::shared_ptr<Attributes> & scheduleResultAttr)193 void WidgetContext::OnResult(int32_t resultCode, const std::shared_ptr<Attributes> &scheduleResultAttr)
194 {
195 IAM_LOGI("%{public}s receive result code %{public}d", description_.c_str(), resultCode);
196 }
197
OnStop()198 bool WidgetContext::OnStop()
199 {
200 // response app.cancel()
201 IAM_LOGI("%{public}s start", description_.c_str());
202 End(ResultCode::CANCELED);
203 return true;
204 }
205
AuthResult(int32_t resultCode,int32_t at,const Attributes & finalResult)206 void WidgetContext::AuthResult(int32_t resultCode, int32_t at, const Attributes &finalResult)
207 {
208 IAM_LOGI("recv task result: %{public}d, authType: %{public}d", resultCode, at);
209 int32_t remainTimes = -1;
210 int32_t freezingTime = -1;
211 if (!finalResult.GetInt32Value(Attributes::ATTR_REMAIN_TIMES, remainTimes)) {
212 IAM_LOGE("get remainTimes failed.");
213 return;
214 }
215 if (!finalResult.GetInt32Value(Attributes::ATTR_FREEZING_TIME, freezingTime)) {
216 IAM_LOGE("get freezingTime failed.");
217 return;
218 }
219 AuthType authType = static_cast<AuthType>(at);
220 WidgetClient::Instance().ReportWidgetResult(resultCode, authType, freezingTime, remainTimes);
221 if (schedule_ == nullptr) {
222 IAM_LOGE("schedule is nullptr.");
223 return;
224 }
225
226 IAM_LOGI("call schedule:");
227 if (resultCode == ResultCode::SUCCESS) {
228 finalResult.GetUint8ArrayValue(Attributes::ATTR_SIGNATURE, authResultInfo_.token);
229 authResultInfo_.authType = authType;
230 schedule_->SuccessAuth(authType);
231 } else {
232 // failed
233 SetLatestError(resultCode);
234 schedule_->StopAuthList({authType});
235 }
236 }
237
238 // WidgetScheduleNodeCallback
LaunchWidget()239 bool WidgetContext::LaunchWidget()
240 {
241 IAM_LOGI("launch widget");
242 if (!ConnectExtension()) {
243 IAM_LOGE("failed to launch widget.");
244 return false;
245 }
246 return true;
247 }
248
ExecuteAuthList(const std::set<AuthType> & authTypeList)249 void WidgetContext::ExecuteAuthList(const std::set<AuthType> &authTypeList)
250 {
251 IAM_LOGI("execute auth list");
252 // create task, and start it
253 std::lock_guard<std::recursive_mutex> lock(mutex_);
254 for (auto &authType : authTypeList) {
255 auto task = BuildTask(para_.challenge, authType, para_.atl);
256 if (task == nullptr) {
257 IAM_LOGE("failed to create task, authType: %{public}s", AuthType2Str(authType).c_str());
258 continue;
259 }
260 task->Start();
261 TaskInfo taskInfo {
262 .authType = authType,
263 .task = task
264 };
265 runTaskInfoList_.push_back(taskInfo);
266 }
267 }
268
EndAuthAsCancel()269 void WidgetContext::EndAuthAsCancel()
270 {
271 IAM_LOGI("end auth as cancel");
272 std::lock_guard<std::recursive_mutex> lock(mutex_);
273 // report CANCELED to App
274 End(ResultCode::CANCELED);
275 }
276
EndAuthAsNaviPin()277 void WidgetContext::EndAuthAsNaviPin()
278 {
279 IAM_LOGI("end auth as navi pin");
280 std::lock_guard<std::recursive_mutex> lock(mutex_);
281 // report CANCELED_FROM_WIDGET to App
282 End(ResultCode::CANCELED_FROM_WIDGET);
283 }
284
StopAuthList(const std::vector<AuthType> & authTypeList)285 void WidgetContext::StopAuthList(const std::vector<AuthType> &authTypeList)
286 {
287 IAM_LOGI("stop auth list");
288 std::lock_guard<std::recursive_mutex> lock(mutex_);
289 for (auto &authType : authTypeList) {
290 auto it = std::find_if(runTaskInfoList_.begin(),
291 runTaskInfoList_.end(), [authType] (const TaskInfo &taskInfo) {
292 return (taskInfo.authType == authType);
293 });
294 if (it != runTaskInfoList_.end()) {
295 if (it->task == nullptr) {
296 IAM_LOGE("task is nullptr");
297 return;
298 }
299 it->task->Stop();
300 runTaskInfoList_.erase(it);
301 }
302 }
303 }
304
SuccessAuth(AuthType authType)305 void WidgetContext::SuccessAuth(AuthType authType)
306 {
307 IAM_LOGI("success auth. authType:%{public}d", static_cast<int32_t>(authType));
308 std::lock_guard<std::recursive_mutex> lock(mutex_);
309 // report success to App
310 End(ResultCode::SUCCESS);
311 }
312
ConnectExtensionAbility(const AAFwk::Want & want,const std::string commandStr)313 int32_t WidgetContext::ConnectExtensionAbility(const AAFwk::Want &want, const std::string commandStr)
314 {
315 IAM_LOGI("ConnectExtensionAbility start");
316 if (connection_ != nullptr) {
317 IAM_LOGE("invalid connection_");
318 return ERR_INVALID_OPERATION;
319 }
320 connection_ = sptr<UIExtensionAbilityConnection>(new (std::nothrow) UIExtensionAbilityConnection(commandStr));
321 if (connection_ == nullptr) {
322 IAM_LOGE("new connection error.");
323 return ERR_NO_MEMORY;
324 }
325
326 std::string identity = IPCSkeleton::ResetCallingIdentity();
327 auto ret = AAFwk::ExtensionManagerClient::GetInstance().ConnectServiceExtensionAbility(want, connection_, nullptr,
328 DEFAULT_VALUE);
329 IPCSkeleton::SetCallingIdentity(identity);
330 IAM_LOGI("ConnectExtensionAbility errCode=%{public}d", ret);
331 return ret;
332 }
333
ConnectExtension()334 bool WidgetContext::ConnectExtension()
335 {
336 std::string tmp = BuildStartCommand();
337 IAM_LOGI("start command: %{public}s", tmp.c_str());
338
339 AAFwk::Want want;
340 std::string bundleName = "com.ohos.systemui";
341 std::string abilityName = "com.ohos.systemui.dialog";
342 want.SetElementName(bundleName, abilityName);
343 auto ret = ConnectExtensionAbility(want, tmp);
344 if (ret != ERR_OK) {
345 UserIam::UserAuth::ReportSystemFault(Common::GetNowTimeString(), "userauthservice");
346 IAM_LOGE("ConnectExtensionAbility failed.");
347 return false;
348 }
349 return true;
350 }
351
DisconnectExtension()352 bool WidgetContext::DisconnectExtension()
353 {
354 if (connection_ == nullptr) {
355 IAM_LOGE("invalid connection handle");
356 return false;
357 }
358 ErrCode ret = AAFwk::ExtensionManagerClient::GetInstance().DisconnectAbility(connection_);
359 if (ret != ERR_OK) {
360 IAM_LOGE("disconnect extension ability failed ret: %{public}d.", ret);
361 return false;
362 }
363 return true;
364 }
365
End(const ResultCode & resultCode)366 void WidgetContext::End(const ResultCode &resultCode)
367 {
368 IAM_LOGI("in End, resultCode: %{public}d", static_cast<int32_t>(resultCode));
369 WidgetClient::Instance().Reset();
370 StopAllRunTask();
371 if (resultCode != ResultCode::SUCCESS) {
372 IAM_LOGI("Try to disconnect extesnion");
373 if (!DisconnectExtension()) {
374 IAM_LOGE("failed to release launch widget.");
375 }
376 }
377 if (callback_ == nullptr) {
378 IAM_LOGE("invalid callback");
379 return;
380 }
381 Attributes attr;
382 if (resultCode == ResultCode::SUCCESS) {
383 if (!attr.SetInt32Value(Attributes::ATTR_AUTH_TYPE, authResultInfo_.authType)) {
384 IAM_LOGE("set auth type failed.");
385 callback_->OnResult(ResultCode::GENERAL_ERROR, attr);
386 return;
387 }
388 if (authResultInfo_.token.size() > 0) {
389 if (!attr.SetUint8ArrayValue(Attributes::ATTR_SIGNATURE, authResultInfo_.token)) {
390 IAM_LOGE("set signature token failed.");
391 callback_->OnResult(ResultCode::GENERAL_ERROR, attr);
392 return;
393 }
394 }
395 }
396 callback_->OnResult(resultCode, attr);
397 }
398
StopAllRunTask()399 void WidgetContext::StopAllRunTask()
400 {
401 std::lock_guard<std::recursive_mutex> lock(mutex_);
402 for (auto &taskInfo : runTaskInfoList_) {
403 IAM_LOGI("stop task");
404 taskInfo.task->Stop();
405 }
406 runTaskInfoList_.clear();
407 }
408
BuildStartCommand()409 std::string WidgetContext::BuildStartCommand()
410 {
411 WidgetCmdParameters widgetCmdParameters;
412 widgetCmdParameters.uiExtensionType = UI_EXTENSION_TYPE_SET;
413 widgetCmdParameters.useriamCmdData.widgetContextId = GetContextId();
414 widgetCmdParameters.useriamCmdData.title = para_.widgetParam.title;
415 widgetCmdParameters.useriamCmdData.windowModeType = WinModeType2Str(para_.widgetParam.windowMode);
416 widgetCmdParameters.useriamCmdData.navigationButtonText = para_.widgetParam.navigationButtonText;
417 auto it = para_.authProfileMap.find(AuthType::PIN);
418 if (it != para_.authProfileMap.end()) {
419 widgetCmdParameters.useriamCmdData.pinSubType = PinSubType2Str(static_cast<PinSubType>(it->second.pinSubType));
420 }
421 std::vector<std::string> typeList;
422 for (auto &item : para_.authProfileMap) {
423 auto &at = item.first;
424 auto &profile = item.second;
425 typeList.push_back(AuthType2Str(at));
426 WidgetCommand::Cmd cmd {
427 .event = CMD_NOTIFY_AUTH_START,
428 .version = NOTICE_VERSION_STR,
429 .type = AuthType2Str(at)
430 };
431 if (at == AuthType::FINGERPRINT && !profile.sensorInfo.empty()) {
432 cmd.sensorInfo = profile.sensorInfo;
433 }
434 cmd.remainAttempts = profile.remainTimes;
435 cmd.lockoutDuration = profile.freezingTime;
436 widgetCmdParameters.useriamCmdData.cmdList.push_back(cmd);
437 }
438 widgetCmdParameters.useriamCmdData.typeList = typeList;
439
440 nlohmann::json root = widgetCmdParameters;
441 std::string cmdData = root.dump();
442 return cmdData;
443 }
444 } // namespace UserAuth
445 } // namespace UserIam
446 } // namespace OHOS
447