• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     InfoLog("NdefHarDataParser::ParseHarPackage enter");
103     if (harPackages.size() <= 0) {
104         ErrorLog("NdefHarDataParser::ParseHarPackage harPackages is empty");
105         return false;
106     }
107     for (std::string harPackage : harPackages) {
108         if (ndefHarDispatch_ != nullptr
109             && ndefHarDispatch_->DispatchBundleAbility(harPackage, tagInfo, mimeType, uri)) {
110             return true;
111         }
112     }
113     ErrorLog("NdefHarDataParser::ParseHarPackage package not exist");
114     return false;
115 }
116 
117 /* Handle notepads, contacts, and mimetype app */
ParseOtherType(std::vector<std::shared_ptr<NdefRecord>> records,std::shared_ptr<KITS::TagInfo> tagInfo)118 bool NdefHarDataParser::ParseOtherType(
119     std::vector<std::shared_ptr<NdefRecord>> records, std::shared_ptr<KITS::TagInfo> tagInfo)
120 {
121     InfoLog("NdefHarDataParser::ParseOtherType enter");
122     if (records.size() <= 0 || records[0] == nullptr) {
123         ErrorLog("NdefHarDataParser::ParseOtherType records is empty");
124         return false;
125     }
126     NfcFailedParams err;
127     std::string type = ToMimeType(records[0]);
128     if (!type.empty()) {
129         if (type == TEXT_PLAIN) {
130             ErrorLog("NdefHarDataParser::ParseOtherType -> TEXT");
131             ExternalDepsProxy::GetInstance().BuildFailedParams(
132                 err, MainErrorCode::NDEF_TEXT_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
133             ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
134             return true;
135         } else if (type == TEXT_VCARD) {
136             ErrorLog("NdefHarDataParser::ParseOtherType -> VCARD");
137             ExternalDepsProxy::GetInstance().BuildFailedParams(
138                 err, MainErrorCode::NDEF_VCARD_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
139             ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
140             return true;
141         } else {
142             if (ndefHarDispatch_ != nullptr && ndefHarDispatch_->DispatchMimeType(type, tagInfo)) {
143                 return true;
144             }
145         }
146     }
147     InfoLog("NdefHarDataParser::ParseOtherType exit");
148     return false;
149 }
150 
151 /* URI parsing of phone, SMS, email, pull URI type app */
ParseUriLink(std::vector<std::shared_ptr<NdefRecord>> records)152 bool NdefHarDataParser::ParseUriLink(std::vector<std::shared_ptr<NdefRecord>> records)
153 {
154     InfoLog("NdefHarDataParser::ParseUriLink enter");
155     if (records.size() <= 0 || records[0] == nullptr) {
156         ErrorLog("NdefHarDataParser::ParseUriLink records is empty");
157         return false;
158     }
159     if (records[0]->tnf_ == static_cast<short>(NdefMessage::TNF_WELL_KNOWN)) {
160         std::string uri = GetUriPayload(records[0]);
161         InfoLog("NdefHarDataParser::ParseUriLink uri: %{public}s", NfcSdkCommon::CodeMiddlePart(uri).c_str());
162         Uri ndefUri(uri);
163         std::string scheme = ndefUri.GetScheme();
164         if (!scheme.empty()) {
165             NfcFailedParams err;
166             if ((scheme.size() >= 3) && (scheme.substr(0, 3) == TEL_PREFIX)) {  // 3 is tel length
167                 ErrorLog("NdefHarDataParser::ParseUriLink -> TEL");
168                 ExternalDepsProxy::GetInstance().BuildFailedParams(
169                     err, MainErrorCode::NDEF_TEL_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
170                 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
171                 return true;
172             } else if ((scheme.size() >= 3) && (scheme.substr(0, 3) == SMS_PREFIX)) {   // 3 is sms length
173                 ErrorLog("NdefHarDataParser::ParseUriLink -> SMS");
174                 ExternalDepsProxy::GetInstance().BuildFailedParams(
175                     err, MainErrorCode::NDEF_SMS_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
176                 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
177                 return true;
178             } else if ((scheme.size() >= 6) && (scheme.substr(0, 6) == MAIL_PREFIX)) {  // 6 is mailto length
179                 ErrorLog("NdefHarDataParser::ParseUriLink -> MAIL");
180                 ExternalDepsProxy::GetInstance().BuildFailedParams(
181                     err, MainErrorCode::NDEF_MAIL_EVENT, SubErrorCode::DEFAULT_ERR_DEF);
182                 ExternalDepsProxy::GetInstance().WriteNfcFailedHiSysEvent(&err);
183                 return true;
184             }
185         }
186         /* uri to package */
187         if (ndefHarDispatch_ != nullptr && ndefHarDispatch_->DispatchUriToBundleAbility(uri)) {
188             return true;
189         }
190     }
191     InfoLog("NdefHarDataParser::ParseUriLink exit");
192     return false;
193 }
194 
195 /* handle uri types */
ParseWebLink(std::vector<std::shared_ptr<NdefRecord>> records)196 bool NdefHarDataParser::ParseWebLink(std::vector<std::shared_ptr<NdefRecord>> records)
197 {
198     InfoLog("NdefHarDataParser::ParseWebLink enter");
199     if (records.size() <= 0) {
200         ErrorLog("NdefHarDataParser::ParseWebLink records is empty");
201         return false;
202     }
203     std::string uri = IsWebUri(records[0]);
204     if (!uri.empty()) {
205         if (nciTagProxy_.expired()) {
206             ErrorLog("NdefHarDataParser::ParseWebLink nciTagProxy_ is nullptr");
207             return false;
208         }
209         std::string browserBundleName = nciTagProxy_.lock()->GetVendorBrowserBundleName();
210         if (ndefHarDispatch_ == nullptr) {
211             ErrorLog("NdefHarDataParser::ParseWebLink ndefHarDispatch_ is nullptr");
212             return false;
213         }
214         if (ndefHarDispatch_->DispatchWebLink(uri, browserBundleName)) {
215             return true;
216         }
217     }
218     ErrorLog("NdefHarDataParser::ParseWebLink fail");
219     return false;
220 }
221 
222 /* Is it HTTP */
IsWebUri(std::shared_ptr<NdefRecord> record)223 std::string NdefHarDataParser::IsWebUri(std::shared_ptr<NdefRecord> record)
224 {
225     InfoLog("NdefHarDataParser::IsWebUri enter");
226     if (record == nullptr) {
227         ErrorLog("NdefHarDataParser::IsWebUri record is nullptr");
228         return "";
229     }
230     std::string uri = GetUriPayload(record);
231     InfoLog("NdefHarDataParser::IsWebUri is uri size: %{public}s", NfcSdkCommon::CodeMiddlePart(uri).c_str());
232     Uri ndefUri(uri);
233     std::string scheme = ndefUri.GetScheme();
234     if (!scheme.empty()) {
235         if ((scheme.size() >= 4) && (scheme.substr(0, 4) == HTTP_PREFIX)) { // 4 is http length
236             return uri;
237         }
238     }
239     ErrorLog("NdefHarDataParser::IsWebUri exit");
240     return "";
241 }
242 
243 /* get mimetype data */
ToMimeType(std::shared_ptr<NdefRecord> record)244 std::string NdefHarDataParser::ToMimeType(std::shared_ptr<NdefRecord> record)
245 {
246     InfoLog("NdefHarDataParser::ToMimeType enter");
247     if (record == nullptr) {
248         ErrorLog("NdefHarDataParser::ToMimeType record is nullptr");
249         return "";
250     }
251     std::string type = "";
252     InfoLog("NdefHarDataParser::ToMimeType record.tnf_: %{public}d", record->tnf_);
253     switch (record->tnf_) {
254         case NdefMessage::TNF_WELL_KNOWN:
255             if (record->tagRtdType_.compare(
256                 NfcSdkCommon::StringToHexString(NdefMessage::GetTagRtdType(NdefMessage::RTD_TEXT))) == 0) {
257                 return TEXT_PLAIN;
258             }
259             break;
260         case NdefMessage::TNF_MIME_MEDIA:
261             type = NfcSdkCommon::HexStringToAsciiString(record->tagRtdType_);
262             return type;
263     }
264     return type;
265 }
266 
GetUriPayload(std::shared_ptr<NdefRecord> record)267 std::string NdefHarDataParser::GetUriPayload(std::shared_ptr<NdefRecord> record)
268 {
269     if (record == nullptr) {
270         ErrorLog("NdefHarDataParser::GetUriPayload record is nullptr");
271         return "";
272     }
273     return GetUriPayload(record, false);
274 }
275 
276 /* get uri data */
GetUriPayload(std::shared_ptr<NdefRecord> record,bool isSmartPoster)277 std::string NdefHarDataParser::GetUriPayload(std::shared_ptr<NdefRecord> record, bool isSmartPoster)
278 {
279     InfoLog("NdefHarDataParser::GetUriPayload enter");
280     if (record == nullptr) {
281         ErrorLog("NdefHarDataParser::GetUriPayload record is nullptr");
282         return "";
283     }
284     std::string uri = "";
285     InfoLog("NdefHarDataParser::GetUriPayload record.tnf_: %{public}d", record->tnf_);
286     switch (record->tnf_) {
287         case NdefMessage::TNF_WELL_KNOWN:
288             InfoLog("GetUriPayload tagRtdType: %{public}s", NfcSdkCommon::CodeMiddlePart(record->tagRtdType_).c_str());
289             if ((record->tagRtdType_.compare(NfcSdkCommon::StringToHexString(
290                 NdefMessage::GetTagRtdType(NdefMessage::RTD_SMART_POSTER))) == 0) && !isSmartPoster) {
291                 std::shared_ptr<NdefMessage> nestMessage = NdefMessage::GetNdefMessage(record->payload_);
292                 InfoLog("GetUriPayload payload: %{public}s", NfcSdkCommon::CodeMiddlePart(record->payload_).c_str());
293                 if (nestMessage == nullptr) {
294                     ErrorLog("NdefHarDataParser::GetUriPayload nestMessage is nullptr");
295                     return "";
296                 }
297                 std::vector<std::shared_ptr<NdefRecord>> nestRecords = nestMessage->GetNdefRecords();
298                 for (std::shared_ptr<NdefRecord> nestRecord : nestRecords) {
299                     uri = GetUriPayload(nestRecord, true);
300                     return uri;
301                 }
302             } else if ((record->tagRtdType_.compare(NfcSdkCommon::StringToHexString(
303                 NdefMessage::GetTagRtdType(NdefMessage::RTD_URI))) == 0)) {
304                 uri = record->payload_;
305                 InfoLog("NdefHarDataParser::GetUriPayload uri: %{public}s", NfcSdkCommon::CodeMiddlePart(uri).c_str());
306                 if (uri.size() <= 2) {  // 2 is uri identifier length
307                     return NfcSdkCommon::HexStringToAsciiString(uri);
308                 }
309                 if (std::stoi(uri.substr(0, 2)) < 0 ||  // 2 is uri identifier length
310                     std::stoi(uri.substr(0, 2)) >= static_cast<int>(g_uriPrefix.size())) {
311                     return "";
312                 }
313                 std::string uriPrefix = g_uriPrefix[std::stoi(uri.substr(0, 2))];   // 2 is uri identifier length
314                 InfoLog("NdefHarDataParser::GetUriPayload uriPrefix = %{public}s", uriPrefix.c_str());
315                 return uriPrefix + NfcSdkCommon::HexStringToAsciiString(uri.substr(2));  // 2 is uri identifier length
316             }
317             break;
318         default:
319             break;
320     }
321     return uri;
322 }
323 
324 /* Package name resolution */
ExtractHarPackages(std::vector<std::shared_ptr<NdefRecord>> records)325 std::vector<std::string> NdefHarDataParser::ExtractHarPackages(std::vector<std::shared_ptr<NdefRecord>> records)
326 {
327     InfoLog("NdefHarDataParser::ExtractHarPackages enter");
328     std::vector<std::string> harPackages;
329     if (records.size() <= 0) {
330         ErrorLog("NdefHarDataParser::ExtractHarPackages records is empty");
331         return harPackages;
332     }
333     for (std::shared_ptr<NdefRecord> record : records) {
334         std::string bundle = CheckForHar(record);
335         if (!bundle.empty()) {
336             harPackages.push_back(bundle);
337         }
338     }
339     return harPackages;
340 }
341 
CheckForHar(std::shared_ptr<NdefRecord> record)342 std::string NdefHarDataParser::CheckForHar(std::shared_ptr<NdefRecord> record)
343 {
344     InfoLog("NdefHarDataParser:: CheckForHar enter");
345     if (record == nullptr) {
346         ErrorLog("NdefHarDataParser::CheckForHar record is nullptr");
347         return "";
348     }
349     std::string bundle = "";
350     /* app type judgment */
351     if (record->tnf_ == NdefMessage::TNF_EXTERNAL_TYPE &&
352         (IsOtherPlatformAppType(record->tagRtdType_) || record->tagRtdType_.compare(
353             NfcSdkCommon::StringToHexString(NdefMessage::GetTagRtdType(NdefMessage::RTD_OHOS_APP))) == 0)) {
354         return record->payload_;
355     }
356     return bundle;
357 }
358 
359 /* support parse and launch for other platform app type */
IsOtherPlatformAppType(const std::string & appType)360 bool NdefHarDataParser::IsOtherPlatformAppType(const std::string &appType)
361 {
362     const std::string OTHER_PLATFORM_APP_RECORD_TYPE = "android.com:pkg";
363     if (appType.compare(NfcSdkCommon::StringToHexString(OTHER_PLATFORM_APP_RECORD_TYPE)) == 0) {
364         return true;
365     }
366     InfoLog("NdefHarDataParser::IsOtherPlatformAppType exit");
367     return false;
368 }
369 } // namespace TAG
370 } // namespace NFC
371 } // namespace OHOS