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 #include "ndef_har_data_parser.h"
16
17 #include "ndef_har_dispatch.h"
18 #include "nfc_sdk_common.h"
19 #include "uri.h"
20 #include "loghelper.h"
21 #include "nfc_hisysevent.h"
22 #include "external_deps_proxy.h"
23
24 namespace OHOS {
25 namespace NFC {
26 namespace TAG {
27 const std::string HTTP_PREFIX = "http";
28 const std::string TEL_PREFIX = "tel";
29 const std::string SMS_PREFIX = "sms";
30 const std::string MAIL_PREFIX = "mailto";
31 const std::string TEXT_PLAIN = "text/plain";
32 const std::string TEXT_VCARD = "text/vcard";
33 const int MIME_MAX_LENGTH = 128;
34 const int URI_MAX_LENGTH = 2048;
35
36 using namespace OHOS::NFC::KITS;
37
NdefHarDataParser(std::weak_ptr<NCI::INciTagInterface> nciTagProxy)38 NdefHarDataParser::NdefHarDataParser(std::weak_ptr<NCI::INciTagInterface> nciTagProxy)
39 : nciTagProxy_(nciTagProxy)
40 {
41 ndefHarDispatch_ = std::make_shared<NdefHarDispatch>();
42 }
43
44 /* Ndef process function provided to HandleNdefDispatch */
TryNdef(const std::string & msg,std::shared_ptr<KITS::TagInfo> tagInfo)45 bool NdefHarDataParser::TryNdef(const std::string& msg, std::shared_ptr<KITS::TagInfo> tagInfo)
46 {
47 InfoLog("NdefHarDataParser::TryNdef enter");
48 if (msg.empty()) {
49 ErrorLog("NdefHarDataParser::TryNdef msg is empty");
50 return false;
51 }
52 std::shared_ptr<NdefMessage> ndef = NdefMessage::GetNdefMessage(msg);
53 if (ndef == nullptr) {
54 ErrorLog("NdefHarDataParser::TryNdef ndef is nullptr");
55 return false;
56 }
57 std::vector<std::shared_ptr<NdefRecord>> records = ndef->GetNdefRecords();
58 /* pull up app */
59 std::vector<std::string> harPackages = ExtractHarPackages(records);
60 if (harPackages.size() > 0) {
61 std::string mimeType = ToMimeType(records[0]);
62 if (mimeType.size() > MIME_MAX_LENGTH) {
63 ErrorLog("NdefHarDataParser::TryNdef mimeType too long");
64 mimeType = "";
65 }
66 std::string uri = GetUriPayload(records[0]);
67 if (uri.size() > URI_MAX_LENGTH) {
68 ErrorLog("NdefHarDataParser::TryNdef uri too long");
69 uri = "";
70 }
71 if (ParseHarPackage(harPackages, tagInfo, mimeType, uri)) {
72 InfoLog("NdefHarDataParser::TryNdef matched HAR to NDEF");
73 return true;
74 }
75 /* Handle uninstalled applications */
76 NfcFailedParams err;
77 ExternalDepsProxy::GetInstance().BuildFailedParams(
78 err, MainErrorCode::NDEF_APP_NOT_INSTALL, SubErrorCode::DEFAULT_ERR_DEF);
79 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
80 harPackages.clear();
81 }
82 /* Pull up browser */
83 if (ParseWebLink(records)) {
84 InfoLog("NdefHarDataParser::matched web link");
85 return true;
86 }
87 /* URI parsing of phone, SMS, email, pull URI type app */
88 if (ParseUriLink(records)) {
89 return true;
90 }
91 /* Handle notepads, contacts, and mimetype app */
92 if (ParseOtherType(records, tagInfo)) {
93 return true;
94 }
95 InfoLog("NdefHarDataParser::TryNdef exit");
96 return false;
97 }
98
ParseHarPackage(std::vector<std::string> harPackages,std::shared_ptr<KITS::TagInfo> tagInfo,const std::string & mimeType,const std::string & uri)99 bool NdefHarDataParser::ParseHarPackage(std::vector<std::string> harPackages, std::shared_ptr<KITS::TagInfo> tagInfo,
100 const std::string &mimeType, const std::string &uri)
101 {
102 if (ParseHarPackageInner(harPackages, tagInfo, mimeType, uri)) {
103 return true;
104 }
105 /* Try vendor parse harPackage */
106 if (nciTagProxy_.expired()) {
107 ErrorLog("NdefHarDataParser::TryNdef nciTagProxy_ is nullptr");
108 } else if (!nciTagProxy_.lock()->VendorParseHarPackage(harPackages)) {
109 return false;
110 }
111 /* Pull up vendor parsed harPackage */
112 if (ParseHarPackageInner(harPackages, tagInfo, mimeType, uri)) {
113 return true;
114 }
115 return false;
116 }
117
ParseHarPackageInner(std::vector<std::string> harPackages,std::shared_ptr<KITS::TagInfo> tagInfo,const std::string & mimeType,const std::string & uri)118 bool NdefHarDataParser::ParseHarPackageInner(std::vector<std::string> harPackages,
119 std::shared_ptr<KITS::TagInfo> tagInfo, const std::string &mimeType, const std::string &uri)
120 {
121 InfoLog("NdefHarDataParser::ParseHarPackage enter");
122 if (harPackages.size() <= 0) {
123 ErrorLog("NdefHarDataParser::ParseHarPackage harPackages is empty");
124 return false;
125 }
126 for (std::string harPackage : harPackages) {
127 if (ndefHarDispatch_ != nullptr
128 && ndefHarDispatch_->DispatchBundleAbility(harPackage, tagInfo, mimeType, uri)) {
129 return true;
130 }
131 }
132 ErrorLog("NdefHarDataParser::ParseHarPackage package not exist");
133 return false;
134 }
135
136 /* Handle notepads, contacts, and mimetype app */
ParseOtherType(std::vector<std::shared_ptr<NdefRecord>> records,std::shared_ptr<KITS::TagInfo> tagInfo)137 bool NdefHarDataParser::ParseOtherType(
138 std::vector<std::shared_ptr<NdefRecord>> records, std::shared_ptr<KITS::TagInfo> tagInfo)
139 {
140 InfoLog("NdefHarDataParser::ParseOtherType enter");
141 if (records.size() <= 0 || records[0] == nullptr) {
142 ErrorLog("NdefHarDataParser::ParseOtherType records is empty");
143 return false;
144 }
145 NfcFailedParams err;
146 std::string type = ToMimeType(records[0]);
147 if (!type.empty()) {
148 if (type == TEXT_PLAIN) {
149 ErrorLog("NdefHarDataParser::ParseOtherType -> TEXT");
150 ExternalDepsProxy::GetInstance().BuildFailedParams(
151 err, MainErrorCode::NDEF_TEXT_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
152 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
153 return true;
154 } else if (type == TEXT_VCARD) {
155 ErrorLog("NdefHarDataParser::ParseOtherType -> VCARD");
156 ExternalDepsProxy::GetInstance().BuildFailedParams(
157 err, MainErrorCode::NDEF_VCARD_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
158 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
159 return true;
160 } else {
161 if (ndefHarDispatch_ != nullptr && ndefHarDispatch_->DispatchMimeType(type, tagInfo)) {
162 return true;
163 }
164 }
165 }
166 InfoLog("NdefHarDataParser::ParseOtherType exit");
167 return false;
168 }
169
170 /* URI parsing of phone, SMS, email, pull URI type app */
ParseUriLink(std::vector<std::shared_ptr<NdefRecord>> records)171 bool NdefHarDataParser::ParseUriLink(std::vector<std::shared_ptr<NdefRecord>> records)
172 {
173 InfoLog("NdefHarDataParser::ParseUriLink enter");
174 if (records.size() <= 0 || records[0] == nullptr) {
175 ErrorLog("NdefHarDataParser::ParseUriLink records is empty");
176 return false;
177 }
178 if (records[0]->tnf_ == static_cast<short>(NdefMessage::TNF_WELL_KNOWN)) {
179 std::string uri = GetUriPayload(records[0]);
180 InfoLog("NdefHarDataParser::ParseUriLink uri: %{public}s", NfcSdkCommon::CodeMiddlePart(uri).c_str());
181 Uri ndefUri(uri);
182 std::string scheme = ndefUri.GetScheme();
183 if (!scheme.empty()) {
184 NfcFailedParams err;
185 if ((scheme.size() >= 3) && (scheme.substr(0, 3) == TEL_PREFIX)) { // 3 is tel length
186 ErrorLog("NdefHarDataParser::ParseUriLink -> TEL");
187 ExternalDepsProxy::GetInstance().BuildFailedParams(
188 err, MainErrorCode::NDEF_TEL_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
189 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
190 return true;
191 } else if ((scheme.size() >= 3) && (scheme.substr(0, 3) == SMS_PREFIX)) { // 3 is sms length
192 ErrorLog("NdefHarDataParser::ParseUriLink -> SMS");
193 ExternalDepsProxy::GetInstance().BuildFailedParams(
194 err, MainErrorCode::NDEF_SMS_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
195 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
196 return true;
197 } else if ((scheme.size() >= 6) && (scheme.substr(0, 6) == MAIL_PREFIX)) { // 6 is mailto length
198 ErrorLog("NdefHarDataParser::ParseUriLink -> MAIL");
199 ExternalDepsProxy::GetInstance().BuildFailedParams(
200 err, MainErrorCode::NDEF_MAIL_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
201 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
202 return true;
203 }
204 }
205 /* uri to package */
206 if (ndefHarDispatch_ != nullptr && ndefHarDispatch_->DispatchUriToBundleAbility(uri)) {
207 return true;
208 }
209 }
210 InfoLog("NdefHarDataParser::ParseUriLink exit");
211 return false;
212 }
213
214 /* handle uri types */
ParseWebLink(std::vector<std::shared_ptr<NdefRecord>> records)215 bool NdefHarDataParser::ParseWebLink(std::vector<std::shared_ptr<NdefRecord>> records)
216 {
217 InfoLog("NdefHarDataParser::ParseWebLink enter");
218 if (records.size() <= 0) {
219 ErrorLog("NdefHarDataParser::ParseWebLink records is empty");
220 return false;
221 }
222 std::string uri = IsWebUri(records[0]);
223 if (!uri.empty()) {
224 if (nciTagProxy_.expired()) {
225 ErrorLog("NdefHarDataParser::ParseWebLink nciTagProxy_ is nullptr");
226 return false;
227 }
228 std::string browserBundleName = nciTagProxy_.lock()->GetVendorBrowserBundleName();
229 if (ndefHarDispatch_ == nullptr) {
230 ErrorLog("NdefHarDataParser::ParseWebLink ndefHarDispatch_ is nullptr");
231 return false;
232 }
233 if (ndefHarDispatch_->DispatchWebLink(uri, browserBundleName)) {
234 return true;
235 }
236 }
237 ErrorLog("NdefHarDataParser::ParseWebLink fail");
238 return false;
239 }
240
241 /* Is it HTTP */
IsWebUri(std::shared_ptr<NdefRecord> record)242 std::string NdefHarDataParser::IsWebUri(std::shared_ptr<NdefRecord> record)
243 {
244 InfoLog("NdefHarDataParser::IsWebUri enter");
245 if (record == nullptr) {
246 ErrorLog("NdefHarDataParser::IsWebUri record is nullptr");
247 return "";
248 }
249 std::string uri = GetUriPayload(record);
250 InfoLog("NdefHarDataParser::IsWebUri is uri size: %{public}s", NfcSdkCommon::CodeMiddlePart(uri).c_str());
251 Uri ndefUri(uri);
252 std::string scheme = ndefUri.GetScheme();
253 if (!scheme.empty()) {
254 if ((scheme.size() >= 4) && (scheme.substr(0, 4) == HTTP_PREFIX)) { // 4 is http length
255 return uri;
256 }
257 }
258 ErrorLog("NdefHarDataParser::IsWebUri exit");
259 return "";
260 }
261
262 /* get mimetype data */
ToMimeType(std::shared_ptr<NdefRecord> record)263 std::string NdefHarDataParser::ToMimeType(std::shared_ptr<NdefRecord> record)
264 {
265 InfoLog("NdefHarDataParser::ToMimeType enter");
266 if (record == nullptr) {
267 ErrorLog("NdefHarDataParser::ToMimeType record is nullptr");
268 return "";
269 }
270 std::string type = "";
271 InfoLog("NdefHarDataParser::ToMimeType record.tnf_: %{public}d", record->tnf_);
272 switch (record->tnf_) {
273 case NdefMessage::TNF_WELL_KNOWN:
274 if (record->tagRtdType_.compare(
275 NfcSdkCommon::StringToHexString(NdefMessage::GetTagRtdType(NdefMessage::RTD_TEXT))) == 0) {
276 return TEXT_PLAIN;
277 }
278 break;
279 case NdefMessage::TNF_MIME_MEDIA:
280 type = NfcSdkCommon::HexStringToAsciiString(record->tagRtdType_);
281 return type;
282 }
283 return type;
284 }
285
GetUriPayload(std::shared_ptr<NdefRecord> record)286 std::string NdefHarDataParser::GetUriPayload(std::shared_ptr<NdefRecord> record)
287 {
288 if (record == nullptr) {
289 ErrorLog("NdefHarDataParser::GetUriPayload record is nullptr");
290 return "";
291 }
292 return GetUriPayload(record, false);
293 }
294
295 /* get uri data */
GetUriPayload(std::shared_ptr<NdefRecord> record,bool isSmartPoster)296 std::string NdefHarDataParser::GetUriPayload(std::shared_ptr<NdefRecord> record, bool isSmartPoster)
297 {
298 InfoLog("NdefHarDataParser::GetUriPayload enter");
299 if (record == nullptr) {
300 ErrorLog("NdefHarDataParser::GetUriPayload record is nullptr");
301 return "";
302 }
303 std::string uri = "";
304 InfoLog("NdefHarDataParser::GetUriPayload record.tnf_: %{public}d", record->tnf_);
305 switch (record->tnf_) {
306 case NdefMessage::TNF_WELL_KNOWN:
307 InfoLog("GetUriPayload tagRtdType: %{public}s", NfcSdkCommon::CodeMiddlePart(record->tagRtdType_).c_str());
308 if ((record->tagRtdType_.compare(NfcSdkCommon::StringToHexString(
309 NdefMessage::GetTagRtdType(NdefMessage::RTD_SMART_POSTER))) == 0) && !isSmartPoster) {
310 std::shared_ptr<NdefMessage> nestMessage = NdefMessage::GetNdefMessage(record->payload_);
311 InfoLog("GetUriPayload payload: %{public}s", NfcSdkCommon::CodeMiddlePart(record->payload_).c_str());
312 if (nestMessage == nullptr) {
313 ErrorLog("NdefHarDataParser::GetUriPayload nestMessage is nullptr");
314 return "";
315 }
316 std::vector<std::shared_ptr<NdefRecord>> nestRecords = nestMessage->GetNdefRecords();
317 for (std::shared_ptr<NdefRecord> nestRecord : nestRecords) {
318 uri = GetUriPayload(nestRecord, true);
319 return uri;
320 }
321 } else if ((record->tagRtdType_.compare(NfcSdkCommon::StringToHexString(
322 NdefMessage::GetTagRtdType(NdefMessage::RTD_URI))) == 0)) {
323 uri = record->payload_;
324 InfoLog("NdefHarDataParser::GetUriPayload uri: %{public}s", NfcSdkCommon::CodeMiddlePart(uri).c_str());
325 if (uri.size() <= 2) { // 2 is uri identifier length
326 return NfcSdkCommon::HexStringToAsciiString(uri);
327 }
328 if (std::stoi(uri.substr(0, 2)) < 0 || // 2 is uri identifier length
329 std::stoi(uri.substr(0, 2)) >= static_cast<int>(g_uriPrefix.size())) {
330 return "";
331 }
332 std::string uriPrefix = g_uriPrefix[std::stoi(uri.substr(0, 2))]; // 2 is uri identifier length
333 InfoLog("NdefHarDataParser::GetUriPayload uriPrefix = %{public}s", uriPrefix.c_str());
334 return uriPrefix + NfcSdkCommon::HexStringToAsciiString(uri.substr(2)); // 2 is uri identifier length
335 }
336 break;
337 default:
338 break;
339 }
340 return uri;
341 }
342
343 /* Package name resolution */
ExtractHarPackages(std::vector<std::shared_ptr<NdefRecord>> records)344 std::vector<std::string> NdefHarDataParser::ExtractHarPackages(std::vector<std::shared_ptr<NdefRecord>> records)
345 {
346 InfoLog("NdefHarDataParser::ExtractHarPackages enter");
347 std::vector<std::string> harPackages;
348 if (records.size() <= 0) {
349 ErrorLog("NdefHarDataParser::ExtractHarPackages records is empty");
350 return harPackages;
351 }
352 for (std::shared_ptr<NdefRecord> record : records) {
353 std::string bundle = CheckForHar(record);
354 if (!bundle.empty()) {
355 harPackages.push_back(bundle);
356 }
357 }
358 return harPackages;
359 }
360
CheckForHar(std::shared_ptr<NdefRecord> record)361 std::string NdefHarDataParser::CheckForHar(std::shared_ptr<NdefRecord> record)
362 {
363 InfoLog("NdefHarDataParser:: CheckForHar enter");
364 if (record == nullptr) {
365 ErrorLog("NdefHarDataParser::CheckForHar record is nullptr");
366 return "";
367 }
368 std::string bundle = "";
369 /* app type judgment */
370 if (record->tnf_ == NdefMessage::TNF_EXTERNAL_TYPE &&
371 (IsOtherPlatformAppType(record->tagRtdType_) || record->tagRtdType_.compare(
372 NfcSdkCommon::StringToHexString(NdefMessage::GetTagRtdType(NdefMessage::RTD_OHOS_APP))) == 0)) {
373 return record->payload_;
374 }
375 return bundle;
376 }
377
378 /* support parse and launch for other platform app type */
IsOtherPlatformAppType(const std::string & appType)379 bool NdefHarDataParser::IsOtherPlatformAppType(const std::string &appType)
380 {
381 const std::string OTHER_PLATFORM_APP_RECORD_TYPE = "android.com:pkg";
382 if (appType.compare(NfcSdkCommon::StringToHexString(OTHER_PLATFORM_APP_RECORD_TYPE)) == 0) {
383 return true;
384 }
385 InfoLog("NdefHarDataParser::IsOtherPlatformAppType exit");
386 return false;
387 }
388 } // namespace TAG
389 } // namespace NFC
390 } // namespace OHOS