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