1 // Copyright 2023 Google LLC
2 //
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 // https://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 <bitset>
16 #include <iostream>
17 #include <string>
18 #include <utility>
19
20 #include "absl/strings/escaping.h"
21 #include "nearby_protocol.h"
22 #include "np_cpp_ffi_types.h"
23
24 void SamplePanicHandler(nearby_protocol::PanicReason reason);
25
26 void HandleAdvertisementResult(
27 nearby_protocol::DeserializeAdvertisementResult /*result*/);
28
29 void HandleV0Adv(nearby_protocol::DeserializedV0Advertisement /*result*/);
30 void HandleLegibleV0Adv(
31 nearby_protocol::LegibleDeserializedV0Advertisement /*legible_adv*/);
32 void HandleV0IdentityKind(
33 nearby_protocol::DeserializedV0IdentityKind /*identity*/);
34 void HandleDataElement(nearby_protocol::V0DataElement /*de*/);
35
36 void HandleV1Adv(nearby_protocol::DeserializedV1Advertisement /*adv*/);
37 void HandleV1Section(const nearby_protocol::DeserializedV1Section& /*section*/);
38 void HandleV1DataElement(nearby_protocol::V1DataElement /*de*/);
39
main()40 int main() {
41 auto result =
42 nearby_protocol::GlobalConfig::SetPanicHandler(SamplePanicHandler);
43 if (result) {
44 std::cout << "Successfully registered panic handler\n";
45 } else {
46 std::cout << "Failed register panic handler\n";
47 return -1;
48 }
49 nearby_protocol::GlobalConfig::SetNumShards(4);
50
51 std::cout << "\n========= Example V0 Adv ==========\n";
52 std::cout << "Hex bytes: 00031503260046\n\n";
53
54 nearby_protocol::CredentialSlab credential_slab;
55 nearby_protocol::CredentialBook credential_book(credential_slab);
56
57 const auto* v0_byte_string =
58 "00" // Adv Header
59 "03" // Public DE header
60 "1503" // Length 1 Tx Power DE with value 3
61 "260046"; // Length 2 Actions
62
63 std::string v0_bytes;
64 if (!absl::HexStringToBytes(v0_byte_string, &v0_bytes)) {
65 return -1;
66 }
67 auto v0_buffer = nearby_protocol::ByteBuffer<255>::TryFromString(v0_bytes);
68 nearby_protocol::RawAdvertisementPayload const v0_payload(v0_buffer.value());
69
70 // Try to deserialize a V0 payload
71 auto deserialize_v0_result =
72 nearby_protocol::Deserializer::DeserializeAdvertisement(v0_payload,
73 credential_book);
74 HandleAdvertisementResult(std::move(deserialize_v0_result));
75
76 std::cout << "\n========= Example V1 Adv ==========\n";
77 std::cout << "Hex bytes: 20040326004603031505\n\n";
78
79 const auto* v1_byte_string =
80 "20" // V1 Advertisement header
81 "04" // Section Header
82 "03" // Public Identity DE header
83 "260046"; // Length 2 Actions DE
84
85 std::string v1_bytes;
86 if (!absl::HexStringToBytes(v1_byte_string, &v1_bytes)) {
87 return -1;
88 }
89 auto v1_buffer = nearby_protocol::ByteBuffer<255>::TryFromString(v1_bytes);
90 nearby_protocol::RawAdvertisementPayload const v1_payload(v1_buffer.value());
91
92 // Try to deserialize a V1 payload
93 auto deserialize_v1_result =
94 nearby_protocol::Deserializer::DeserializeAdvertisement(v1_payload,
95 credential_book);
96 HandleAdvertisementResult(std::move(deserialize_v1_result));
97
98 std::cout << "\n========= User input sample ==========\n\n";
99 while (true) {
100 std::string user_input;
101 std::cout << "Enter the hex of the advertisement you would like to parse "
102 "(see above examples): ";
103 std::cin >> user_input;
104 std::string bytes;
105 auto hex_result = absl::HexStringToBytes(user_input, &bytes);
106 if (!hex_result) {
107 std::cout << "Provided string is not valid hex";
108 continue;
109 }
110 auto buffer = nearby_protocol::ByteBuffer<255>::TryFromString(bytes);
111 if (!buffer.ok()) {
112 std::cout << "Too many bytes provided, must fit into a max length 255 "
113 "byte BLE advertisement\n";
114 continue;
115 }
116 nearby_protocol::RawAdvertisementPayload const user_input_payload(
117 buffer.value());
118
119 // Try to deserialize user input
120 auto user_input_result =
121 nearby_protocol::Deserializer::DeserializeAdvertisement(
122 user_input_payload, credential_book);
123 HandleAdvertisementResult(std::move(user_input_result));
124
125 char choice;
126 do {
127 std::cout << "Do you want to continue? (Y/N) ";
128 std::cin >> choice;
129 } while (choice != 'Y' && choice != 'N' && choice != 'n' && choice != 'y');
130
131 if (choice == 'N' || choice == 'n') {
132 return 0;
133 }
134 }
135 }
136
SamplePanicHandler(nearby_protocol::PanicReason reason)137 void SamplePanicHandler(nearby_protocol::PanicReason reason) {
138 std::cout << "Panicking! Reason: ";
139 switch (reason) {
140 case nearby_protocol::PanicReason::EnumCastFailed: {
141 std::cout << "EnumCastFailed \n";
142 break;
143 }
144 case nearby_protocol::PanicReason::AssertFailed: {
145 std::cout << "AssertFailed \n";
146 break;
147 }
148 case nearby_protocol::PanicReason::InvalidStackDataStructure: {
149 std::cout << "InvalidStackDataStructure \n";
150 break;
151 }
152 case np_ffi::internal::PanicReason::ExceededMaxHandleAllocations:
153 std::cout << "ExceededMaxHandleAllocations \n";
154 break;
155 }
156 std::abort();
157 }
158
HandleAdvertisementResult(nearby_protocol::DeserializeAdvertisementResult result)159 void HandleAdvertisementResult(
160 nearby_protocol::DeserializeAdvertisementResult result) {
161 switch (result.GetKind()) {
162 case nearby_protocol::DeserializeAdvertisementResultKind::Error:
163 std::cout << "Error in deserializing advertisement!\n";
164 break;
165 case nearby_protocol::DeserializeAdvertisementResultKind::V0:
166 std::cout << "Successfully deserialized a V0 advertisement!\n";
167 HandleV0Adv(result.IntoV0());
168 break;
169 case nearby_protocol::DeserializeAdvertisementResultKind::V1:
170 std::cout << "Successfully deserialized a V1 advertisement\n";
171 HandleV1Adv(result.IntoV1());
172 break;
173 }
174 }
175
HandleV0Adv(nearby_protocol::DeserializedV0Advertisement result)176 void HandleV0Adv(nearby_protocol::DeserializedV0Advertisement result) {
177 switch (result.GetKind()) {
178 case nearby_protocol::DeserializedV0AdvertisementKind::Legible:
179 std::cout << "\tThe Advertisement is plaintext \n";
180 HandleLegibleV0Adv(result.IntoLegible());
181 break;
182 case nearby_protocol::DeserializedV0AdvertisementKind::
183 NoMatchingCredentials:
184 std::cout << "\tNo matching credentials found for this adv\n";
185 return;
186 }
187 }
188
HandleLegibleV0Adv(nearby_protocol::LegibleDeserializedV0Advertisement legible_adv)189 void HandleLegibleV0Adv(
190 nearby_protocol::LegibleDeserializedV0Advertisement legible_adv) {
191 HandleV0IdentityKind(legible_adv.GetIdentityKind());
192
193 auto num_des = legible_adv.GetNumberOfDataElements();
194 std::cout << "\t\tAdv contains " << static_cast<unsigned>(num_des)
195 << " data elements \n";
196 auto payload = legible_adv.IntoPayload();
197 for (int i = 0; i < num_des; i++) {
198 auto de_result = payload.TryGetDataElement(i);
199 if (!de_result.ok()) {
200 std::cout << "\t\tError getting DE at index: " << i << "\n";
201 return;
202 }
203 std::cout << "\t\tSuccessfully retrieved De at index " << i << "\n";
204 HandleDataElement(de_result.value());
205 }
206 }
207
HandleV0IdentityKind(nearby_protocol::DeserializedV0IdentityKind identity)208 void HandleV0IdentityKind(
209 nearby_protocol::DeserializedV0IdentityKind identity) {
210 switch (identity) {
211 case np_ffi::internal::DeserializedV0IdentityKind::Plaintext: {
212 std::cout << "\t\tIdentity is Plaintext\n";
213 break;
214 }
215 case np_ffi::internal::DeserializedV0IdentityKind::Decrypted: {
216 std::cout << "\t\tIdentity is Encrypted\n";
217 break;
218 }
219 }
220 }
221
HandleDataElement(nearby_protocol::V0DataElement de)222 void HandleDataElement(nearby_protocol::V0DataElement de) {
223 switch (de.GetKind()) {
224 case nearby_protocol::V0DataElementKind::TxPower: {
225 std::cout << "\t\t\tDE Type is TxPower\n";
226 auto tx_power = de.AsTxPower();
227 std::cout << "\t\t\tpower: " << static_cast<int>(tx_power.GetAsI8())
228 << "\n";
229 return;
230 }
231 case nearby_protocol::V0DataElementKind::Actions: {
232 std::cout << "\t\t\tDE Type is Actions\n";
233 auto actions = de.AsActions();
234 std::cout << "\t\t\tactions: " << std::bitset<32>(actions.GetAsU32())
235 << "\n";
236 return;
237 }
238 }
239 }
240
HandleV1Adv(nearby_protocol::DeserializedV1Advertisement adv)241 void HandleV1Adv(nearby_protocol::DeserializedV1Advertisement adv) {
242 auto legible_sections = adv.GetNumLegibleSections();
243 std::cout << "\tAdv has " << static_cast<unsigned>(legible_sections)
244 << " legible sections \n";
245
246 auto encrypted_sections = adv.GetNumUndecryptableSections();
247 std::cout << "\tAdv has " << static_cast<unsigned>(encrypted_sections)
248 << " undecryptable sections\n";
249
250 for (auto i = 0; i < legible_sections; i++) {
251 auto section_result = adv.TryGetSection(i);
252 if (!section_result.ok()) {
253 std::cout << "\tError getting Section at index: " << i << "\n";
254 return;
255 }
256 std::cout << "\tSuccessfully retrieved section at index " << i << "\n";
257 HandleV1Section(section_result.value());
258 }
259 }
260
HandleV1Section(const nearby_protocol::DeserializedV1Section & section)261 void HandleV1Section(const nearby_protocol::DeserializedV1Section& section) {
262 switch (section.GetIdentityKind()) {
263 case np_ffi::internal::DeserializedV1IdentityKind::Plaintext: {
264 std::cout << "\t\tIdentity is Plaintext\n";
265 break;
266 }
267 case np_ffi::internal::DeserializedV1IdentityKind::Decrypted: {
268 std::cout << "\t\tIdentity is Encrypted\n";
269 break;
270 }
271 }
272
273 auto num_des = section.NumberOfDataElements();
274 std::cout << "\t\tSection has " << static_cast<unsigned>(num_des)
275 << " data elements \n";
276 for (auto i = 0; i < num_des; i++) {
277 auto de_result = section.TryGetDataElement(i);
278 if (!de_result.ok()) {
279 std::cout << "\t\tError getting de at index: " << i << "\n";
280 return;
281 }
282 std::cout << "\t\tSuccessfully retrieved data element at index " << i
283 << "\n";
284 HandleV1DataElement(de_result.value());
285 }
286 }
287
HandleV1DataElement(nearby_protocol::V1DataElement de)288 void HandleV1DataElement(nearby_protocol::V1DataElement de) {
289 std::cout << "\t\t\tData Element type code: "
290 << static_cast<unsigned>(de.GetDataElementTypeCode()) << "\n";
291 std::cout << "\t\t\tPayload bytes as hex: "
292 << absl::BytesToHexString(de.GetPayload().ToString()) << "\n";
293 }
294