aboutsummaryrefslogtreecommitdiff
path: root/nearby/presence/np_cpp_ffi/sample/main.cc
blob: a02a52391d2951741709adeccf0dcd8930ac62ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "nearby_protocol.h"

#include <bitset>
#include <iostream>

#include "absl/strings/escaping.h"

static void SamplePanicHandler(nearby_protocol::PanicReason reason);

void HandleAdvertisementResult(nearby_protocol::DeserializeAdvertisementResult);

void HandleV0Adv(nearby_protocol::DeserializedV0Advertisement);
void HandleLegibleV0Adv(nearby_protocol::LegibleDeserializedV0Advertisement);
void HandleV0IdentityKind(nearby_protocol::DeserializedV0IdentityKind);
void HandleDataElement(nearby_protocol::V0DataElement);

void HandleV1Adv(nearby_protocol::DeserializedV1Advertisement);
void HandleV1Section(nearby_protocol::DeserializedV1Section);
void HandleV1DataElement(nearby_protocol::V1DataElement);

int main() {
  auto result =
      nearby_protocol::GlobalConfig::SetPanicHandler(SamplePanicHandler);
  if (result) {
    std::cout << "Successfully registered panic handler\n";
  } else {
    std::cout << "Failed register panic handler\n";
    return -1;
  }
  nearby_protocol::GlobalConfig::SetNumShards(4);

  std::cout << "\n========= Example V0 Adv ==========\n";
  std::cout << "Hex bytes: 00031503260046\n\n";

  // Create an empty credential slab and verify that it is successful
  auto cred_slab_result = nearby_protocol::CredentialSlab::TryCreate();
  if (!cred_slab_result.ok()) {
    std::cout << cred_slab_result.status().ToString();
    return -1;
  }

  // Create an empty credential book from the empty slab, and verify success.
  auto cred_book_result = nearby_protocol::CredentialBook::TryCreateFromSlab(cred_slab_result.value());
  if (!cred_book_result.ok()) {
    std::cout << cred_book_result.status().ToString();
    return -1;
  }

  auto v0_byte_string = "00"      // Adv Header
                        "03"      // Public DE header
                        "1503"    // Length 1 Tx Power DE with value 3
                        "260046"; // Length 2 Actions

  auto v0_bytes = absl::HexStringToBytes(v0_byte_string);
  auto v0_buffer = nearby_protocol::ByteBuffer<255>::CopyFrom(v0_bytes);
  nearby_protocol::RawAdvertisementPayload v0_payload(v0_buffer.value());

  // Try to deserialize a V0 payload
  auto deserialize_v0_result =
      nearby_protocol::Deserializer::DeserializeAdvertisement(
          v0_payload, cred_book_result.value());
  HandleAdvertisementResult(std::move(deserialize_v0_result));

  std::cout << "\n========= Example V1 Adv ==========\n";
  std::cout << "Hex bytes: 20040326004603031505\n\n";

  auto v1_byte_string = "20"     // V1 Advertisement header
                        "04"     // Section Header
                        "03"     // Public Identity DE header
                        "260046" // Length 2 Actions DE
                        "03"     // Section Header
                        "03"     // Public Identity DE header
                        "1505";  // Length 1 Tx Power DE with value 5
  auto v1_bytes = absl::HexStringToBytes(v1_byte_string);
  auto v1_buffer = nearby_protocol::ByteBuffer<255>::CopyFrom(v1_bytes);
  nearby_protocol::RawAdvertisementPayload v1_payload(v1_buffer.value());

  // Try to deserialize a V1 payload
  auto deserialize_v1_result =
      nearby_protocol::Deserializer::DeserializeAdvertisement(
          v1_payload, cred_book_result.value());
  HandleAdvertisementResult(std::move(deserialize_v1_result));

  std::cout << "\n========= User input sample ==========\n\n";
  while (true) {
    std::string user_input;
    std::cout << "Enter the hex of the advertisement you would like to parse "
                 "(see above examples): ";
    std::cin >> user_input;
    auto bytes = absl::HexStringToBytes(user_input);
    auto buffer = nearby_protocol::ByteBuffer<255>::CopyFrom(bytes);
    if (!buffer.ok()) {
      std::cout << "Too many bytes provided, must fit into a max length 255 "
                   "byte BLE advertisement\n";
      continue;
    }
    nearby_protocol::RawAdvertisementPayload user_input_payload(buffer.value());

    // Try to deserialize user input
    auto user_input_result =
        nearby_protocol::Deserializer::DeserializeAdvertisement(
            user_input_payload, cred_book_result.value());
    HandleAdvertisementResult(std::move(user_input_result));

    char choice;
    do {
      std::cout << "Do you want to continue? (Y/N) ";
      std::cin >> choice;
    } while (choice != 'Y' && choice != 'N' && choice != 'n' && choice != 'y');

    if (choice == 'N' || choice == 'n') {
      return 0;
    }
  }
}

static void SamplePanicHandler(nearby_protocol::PanicReason reason) {
  std::cout << "Panicking! Reason: ";
  switch (reason) {
  case nearby_protocol::PanicReason::EnumCastFailed: {
    std::cout << "EnumCastFailed \n";
    break;
  }
  case nearby_protocol::PanicReason::AssertFailed: {
    std::cout << "AssertFailed \n";
    break;
  }
  case nearby_protocol::PanicReason::InvalidActionBits: {
    std::cout << "InvalidActionBits \n";
    break;
  }
  }
  std::abort();
}

void HandleAdvertisementResult(
    nearby_protocol::DeserializeAdvertisementResult result) {
  switch (result.GetKind()) {
  case nearby_protocol::DeserializeAdvertisementResultKind::Error:
    std::cout << "Error in deserializing advertisement!\n";
    break;
  case nearby_protocol::DeserializeAdvertisementResultKind::V0:
    std::cout << "Successfully deserialized a V0 advertisement!\n";
    HandleV0Adv(result.IntoV0());
    break;
  case nearby_protocol::DeserializeAdvertisementResultKind::V1:
    std::cout << "Successfully deserialized a V1 advertisement\n";
    HandleV1Adv(result.IntoV1());
    break;
  }
}

void HandleV0Adv(nearby_protocol::DeserializedV0Advertisement result) {
  switch (result.GetKind()) {
  case nearby_protocol::DeserializedV0AdvertisementKind::Legible:
    std::cout << "\tThe Advertisement is plaintext \n";
    HandleLegibleV0Adv(result.IntoLegible());
    break;
  case nearby_protocol::DeserializedV0AdvertisementKind::NoMatchingCredentials:
    std::cout << "\tNo matching credentials found for this adv\n";
    return;
  }
}

void HandleLegibleV0Adv(
    nearby_protocol::LegibleDeserializedV0Advertisement legible_adv) {
  HandleV0IdentityKind(legible_adv.GetIdentityKind());

  auto num_des = legible_adv.GetNumberOfDataElements();
  std::cout << "\t\tAdv contains " << unsigned(num_des) << " data elements \n";
  auto payload = legible_adv.IntoPayload();
  for (int i = 0; i < num_des; i++) {
    auto de_result = payload.TryGetDataElement(i);
    if (!de_result.ok()) {
      std::cout << "\t\tError getting DE at index: " << i << "\n";
      return;
    }
    std::cout << "\t\tSuccessfully retrieved De at index " << i << "\n";
    HandleDataElement(de_result.value());
  }
}

void HandleV0IdentityKind(nearby_protocol::DeserializedV0IdentityKind identity) {
  switch (identity) {
  case np_ffi::internal::DeserializedV0IdentityKind::Plaintext: {
    std::cout << "\t\tIdentity is Plaintext\n";
    break;
  }
  case np_ffi::internal::DeserializedV0IdentityKind::Decrypted: {
    std::cout << "\t\tIdentity is Encrypted\n";
    break;
  }
  }
}

void HandleDataElement(nearby_protocol::V0DataElement de) {
  switch (de.GetKind()) {
  case nearby_protocol::V0DataElementKind::TxPower: {
    std::cout << "\t\t\tDE Type is TxPower\n";
    auto tx_power = de.AsTxPower();
    std::cout << "\t\t\tpower: " << int(tx_power.tx_power) << "\n";
    return;
  }
  case nearby_protocol::V0DataElementKind::Actions: {
    std::cout << "\t\t\tDE Type is Actions\n";
    auto actions = de.AsActions();
    std::cout << "\t\t\tactions: " << std::bitset<32>(actions.GetAsU32())
              << "\n";
    return;
  }
  }
}

void HandleV1Adv(nearby_protocol::DeserializedV1Advertisement adv) {
  auto legible_sections = adv.GetNumLegibleSections();
  std::cout << "\tAdv has " << unsigned(legible_sections)
            << " legible sections \n";

  auto encrypted_sections = adv.GetNumUndecryptableSections();
  std::cout << "\tAdv has " << unsigned(encrypted_sections)
            << " undecryptable sections\n";

  for (auto i = 0; i < legible_sections; i++) {
    auto section_result = adv.TryGetSection(i);
    if (!section_result.ok()) {
      std::cout << "\tError getting Section at index: " << i << "\n";
      return;
    }
    std::cout << "\tSuccessfully retrieved section at index " << i << "\n";
    HandleV1Section(section_result.value());
  }
}

void HandleV1Section(nearby_protocol::DeserializedV1Section section) {
  switch (section.GetIdentityKind()) {
  case np_ffi::internal::DeserializedV1IdentityKind::Plaintext: {
    std::cout << "\t\tIdentity is Plaintext\n";
    break;
  }
  case np_ffi::internal::DeserializedV1IdentityKind::Decrypted: {
    std::cout << "\t\tIdentity is Encrypted\n";
    break;
  }
  }

  auto num_des = section.NumberOfDataElements();
  std::cout << "\t\tSection has " << unsigned(num_des) << " data elements \n";
  for (auto i = 0; i < num_des; i++) {
    auto de_result = section.TryGetDataElement(i);
    if (!de_result.ok()) {
      std::cout << "\t\tError getting de at index: " << i << "\n";
      return;
    }
    std::cout << "\t\tSuccessfully retrieved data element at index " << i
              << "\n";
    HandleV1DataElement(de_result.value());
  }
}

void HandleV1DataElement(nearby_protocol::V1DataElement de) {
  std::cout << "\t\t\tData Element type code: "
            << unsigned(de.GetDataElementTypeCode()) << "\n";
  std::cout << "\t\t\tPayload bytes as hex: "
            << absl::BytesToHexString(de.GetPayload().ToString()) << "\n";
}