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