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 //      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 "nearby_protocol.h"
16 
17 #include <array>
18 #include <cstddef>
19 #include <cstdint>
20 #include <cstdlib>
21 #include <iostream>
22 #include <memory>
23 #include <span>
24 #include <utility>
25 #include <vector>
26 
27 #include "absl/status/status.h"
28 #include "absl/status/statusor.h"
29 #include "np_cpp_ffi_functions.h"
30 #include "np_cpp_ffi_types.h"
31 
32 namespace nearby_protocol {
33 
34 void panic_handler(PanicReason reason);
35 
36 struct PanicHandler {
37   void (*handler)(PanicReason);
38   bool set_by_client;
39 };
40 
41 PanicHandler gPanicHandler = PanicHandler{panic_handler, false};
42 
43 // C++ layer internal panic handler
panic_handler(PanicReason reason)44 void panic_handler(PanicReason reason) {
45   // Give clients a chance to use their own panic handler, but if they don't
46   // terminate the process we will make sure it happens.
47   if (gPanicHandler.set_by_client) {
48     gPanicHandler.handler(reason);
49   }
50   std::abort();
51 }
52 
_assert_panic(bool condition,const char * func,const char * file,int line)53 void _assert_panic(bool condition, const char* func, const char* file,
54                    int line) {
55   if (!condition) {
56     std::cout << "Assert failed: \n function: " << func << "\n file: " << file
57               << "\n line: " << line << "\n";
58     panic_handler(PanicReason::AssertFailed);
59   }
60 }
61 
62 #define assert_panic(e) _assert_panic(e, __func__, __FILE__, __LINE__)
63 
SetPanicHandler(void (* handler)(PanicReason))64 bool GlobalConfig::SetPanicHandler(void (*handler)(PanicReason)) {
65   if (!gPanicHandler.set_by_client) {
66     gPanicHandler.handler = handler;
67     gPanicHandler.set_by_client = true;
68     return np_ffi::internal::np_ffi_global_config_panic_handler(panic_handler);
69   }
70   return false;
71 }
72 
SetNumShards(const uint8_t num_shards)73 void GlobalConfig::SetNumShards(const uint8_t num_shards) {
74   np_ffi::internal::np_ffi_global_config_set_num_shards(num_shards);
75 }
76 
GetCurrentHandleAllocationCount()77 CurrentHandleAllocations GlobalConfig::GetCurrentHandleAllocationCount() {
78   return np_ffi::internal::np_ffi_global_config_get_current_allocation_count();
79 }
80 
CredentialSlab()81 CredentialSlab::CredentialSlab() {
82   this->credential_slab_ = np_ffi::internal::np_ffi_create_credential_slab();
83   this->moved_ = false;
84 }
85 
~CredentialSlab()86 CredentialSlab::~CredentialSlab() {
87   if (!this->moved_) {
88     auto result =
89         np_ffi::internal::np_ffi_deallocate_credential_slab(credential_slab_);
90     assert_panic(result == np_ffi::internal::DeallocateResult::Success);
91   }
92 }
93 
CredentialSlab(CredentialSlab && other)94 CredentialSlab::CredentialSlab(CredentialSlab&& other) noexcept
95     : credential_slab_(other.credential_slab_), moved_(other.moved_) {
96   other.credential_slab_ = {};
97   other.moved_ = true;
98 }
99 
operator =(CredentialSlab && other)100 CredentialSlab& CredentialSlab::operator=(CredentialSlab&& other) noexcept {
101   if (this != &other) {
102     if (!this->moved_) {
103       auto result = np_ffi::internal::np_ffi_deallocate_credential_slab(
104           this->credential_slab_);
105       assert_panic(result == np_ffi::internal::DeallocateResult::Success);
106     }
107 
108     this->credential_slab_ = other.credential_slab_;
109     this->moved_ = other.moved_;
110 
111     other.credential_slab_ = {};
112     other.moved_ = true;
113   }
114   return *this;
115 }
116 
AddV0Credential(const V0MatchableCredential v0_cred)117 void CredentialSlab::AddV0Credential(const V0MatchableCredential v0_cred) {
118   assert_panic(!this->moved_);
119   auto result = np_ffi::internal::np_ffi_CredentialSlab_add_v0_credential(
120       this->credential_slab_, v0_cred.internal_);
121   // Add V0 is infallible since the handle is guaranteed to be correct by the
122   // C++ wrapper
123   assert_panic(result == AddV0CredentialToSlabResult::Success);
124 }
125 
AddV1Credential(const V1MatchableCredential v1_cred)126 absl::Status CredentialSlab::AddV1Credential(
127     const V1MatchableCredential v1_cred) {
128   assert_panic(!this->moved_);
129   auto result = np_ffi::internal::np_ffi_CredentialSlab_add_v1_credential(
130       this->credential_slab_, v1_cred.internal_);
131   switch (result) {
132     case AddV1CredentialToSlabResult::Success: {
133       return absl::OkStatus();
134     }
135     case AddV1CredentialToSlabResult::InvalidHandle: {
136       return absl::InvalidArgumentError(
137           "invalid credential slab handle provided");
138     }
139     case AddV1CredentialToSlabResult::InvalidPublicKeyBytes: {
140       return absl::InvalidArgumentError(
141           "Invalid public key bytes in credential");
142     }
143   }
144 }
145 
CredentialBook(CredentialSlab & slab)146 CredentialBook::CredentialBook(CredentialSlab& slab) {
147   assert_panic(!slab.moved_);
148   auto result = np_ffi::internal::np_ffi_create_credential_book_from_slab(
149       slab.credential_slab_);
150   auto kind = np_ffi::internal::np_ffi_CreateCredentialBookResult_kind(result);
151   // Handle is guaranteed to be valid by the C++ wrapper
152   assert_panic(kind == CreateCredentialBookResultKind::Success);
153   slab.moved_ = true;
154   this->credential_book_ =
155       np_ffi::internal::np_ffi_CreateCredentialBookResult_into_SUCCESS(result);
156   this->moved_ = false;
157 }
158 
~CredentialBook()159 CredentialBook::~CredentialBook() {
160   if (!this->moved_) {
161     auto result =
162         np_ffi::internal::np_ffi_deallocate_credential_book(credential_book_);
163     assert_panic(result == np_ffi::internal::DeallocateResult::Success);
164   }
165 }
166 
CredentialBook(CredentialBook && other)167 CredentialBook::CredentialBook(CredentialBook&& other) noexcept
168     : credential_book_(other.credential_book_), moved_(other.moved_) {
169   other.credential_book_ = {};
170   other.moved_ = true;
171 }
172 
operator =(CredentialBook && other)173 CredentialBook& CredentialBook::operator=(CredentialBook&& other) noexcept {
174   if (this != &other) {
175     if (!this->moved_) {
176       auto result = np_ffi::internal::np_ffi_deallocate_credential_book(
177           this->credential_book_);
178       assert_panic(result == np_ffi::internal::DeallocateResult::Success);
179     }
180 
181     this->credential_book_ = other.credential_book_;
182     this->moved_ = other.moved_;
183 
184     other.credential_book_ = {};
185     other.moved_ = true;
186   }
187   return *this;
188 }
189 
DeserializeAdvertisement(const RawAdvertisementPayload & payload,const CredentialBook & credential_book)190 DeserializeAdvertisementResult Deserializer::DeserializeAdvertisement(
191     const RawAdvertisementPayload& payload,
192     const CredentialBook& credential_book) {
193   assert_panic(!credential_book.moved_);
194   auto result = np_ffi::internal::np_ffi_deserialize_advertisement(
195       {payload.buffer_.internal_}, credential_book.credential_book_);
196   return DeserializeAdvertisementResult(result);
197 }
198 
GetKind() const199 DeserializeAdvertisementResultKind DeserializeAdvertisementResult::GetKind()
200     const {
201   assert_panic(!this->moved_);
202   return np_ffi::internal::np_ffi_DeserializeAdvertisementResult_kind(result_);
203 }
204 
IntoV0()205 DeserializedV0Advertisement DeserializeAdvertisementResult::IntoV0() {
206   assert_panic(!this->moved_);
207   auto result =
208       np_ffi::internal::np_ffi_DeserializeAdvertisementResult_into_V0(result_);
209   this->moved_ = true;
210   return DeserializedV0Advertisement(result);
211 }
212 
IntoV1()213 DeserializedV1Advertisement DeserializeAdvertisementResult::IntoV1() {
214   assert_panic(!this->moved_);
215   auto v1_adv =
216       np_ffi::internal::np_ffi_DeserializeAdvertisementResult_into_V1(result_);
217   this->moved_ = true;
218   return DeserializedV1Advertisement(v1_adv);
219 }
220 
~DeserializeAdvertisementResult()221 DeserializeAdvertisementResult::~DeserializeAdvertisementResult() {
222   if (!this->moved_) {
223     auto result =
224         np_ffi::internal::np_ffi_deallocate_deserialize_advertisement_result(
225             result_);
226     assert_panic(result == np_ffi::internal::DeallocateResult::Success);
227   }
228 }
229 
DeserializeAdvertisementResult(DeserializeAdvertisementResult && other)230 DeserializeAdvertisementResult::DeserializeAdvertisementResult(
231     DeserializeAdvertisementResult&& other) noexcept
232     : result_(other.result_), moved_(other.moved_) {
233   other.result_ = {};
234   other.moved_ = true;
235 }
236 
operator =(DeserializeAdvertisementResult && other)237 DeserializeAdvertisementResult& DeserializeAdvertisementResult::operator=(
238     DeserializeAdvertisementResult&& other) noexcept {
239   if (this != &other) {
240     if (!this->moved_) {
241       auto result =
242           np_ffi::internal::np_ffi_deallocate_deserialize_advertisement_result(
243               result_);
244       assert_panic(result == np_ffi::internal::DeallocateResult::Success);
245     }
246     this->result_ = other.result_;
247     this->moved_ = other.moved_;
248 
249     other.result_ = {};
250     other.moved_ = true;
251   }
252   return *this;
253 }
254 
255 // V0 Stuff
DeserializedV0Advertisement(DeserializedV0Advertisement && other)256 DeserializedV0Advertisement::DeserializedV0Advertisement(
257     DeserializedV0Advertisement&& other) noexcept
258     : v0_advertisement_(other.v0_advertisement_), moved_(other.moved_) {
259   other.v0_advertisement_ = {};
260   other.moved_ = true;
261 }
262 
operator =(DeserializedV0Advertisement && other)263 DeserializedV0Advertisement& DeserializedV0Advertisement::operator=(
264     DeserializedV0Advertisement&& other) noexcept {
265   if (this != &other) {
266     if (!this->moved_) {
267       auto result =
268           np_ffi::internal::np_ffi_deallocate_deserialized_V0_advertisement(
269               v0_advertisement_);
270       assert_panic(result == np_ffi::internal::DeallocateResult::Success);
271     }
272     this->v0_advertisement_ = other.v0_advertisement_;
273     this->moved_ = other.moved_;
274 
275     other.v0_advertisement_ = {};
276     other.moved_ = true;
277   }
278   return *this;
279 }
280 
~DeserializedV0Advertisement()281 DeserializedV0Advertisement::~DeserializedV0Advertisement() {
282   if (!this->moved_) {
283     auto result =
284         np_ffi::internal::np_ffi_deallocate_deserialized_V0_advertisement(
285             v0_advertisement_);
286     assert_panic(result == np_ffi::internal::DeallocateResult::Success);
287   }
288 }
289 
290 np_ffi::internal::DeserializedV0AdvertisementKind
GetKind() const291 DeserializedV0Advertisement::GetKind() const {
292   assert_panic(!this->moved_);
293   return np_ffi::internal::np_ffi_DeserializedV0Advertisement_kind(
294       v0_advertisement_);
295 }
296 
IntoLegible()297 LegibleDeserializedV0Advertisement DeserializedV0Advertisement::IntoLegible() {
298   assert_panic(!this->moved_);
299   auto result =
300       np_ffi::internal::np_ffi_DeserializedV0Advertisement_into_LEGIBLE(
301           v0_advertisement_);
302   this->moved_ = true;
303   this->v0_advertisement_ = {};
304   return LegibleDeserializedV0Advertisement(result);
305 }
306 
LegibleDeserializedV0Advertisement(LegibleDeserializedV0Advertisement && other)307 LegibleDeserializedV0Advertisement::LegibleDeserializedV0Advertisement(
308     LegibleDeserializedV0Advertisement&& other) noexcept
309     : legible_v0_advertisement_(other.legible_v0_advertisement_),
310       moved_(other.moved_) {
311   other.moved_ = true;
312   other.legible_v0_advertisement_ = {};
313 }
314 
315 LegibleDeserializedV0Advertisement&
operator =(LegibleDeserializedV0Advertisement && other)316 LegibleDeserializedV0Advertisement::operator=(
317     LegibleDeserializedV0Advertisement&& other) noexcept {
318   if (this != &other) {
319     if (!this->moved_) {
320       auto result =
321           np_ffi::internal::np_ffi_deallocate_legible_v0_advertisement(
322               this->legible_v0_advertisement_);
323       assert_panic(result == np_ffi::internal::DeallocateResult::Success);
324     }
325     this->legible_v0_advertisement_ = other.legible_v0_advertisement_;
326     this->moved_ = other.moved_;
327 
328     other.moved_ = true;
329     other.legible_v0_advertisement_ = {};
330   }
331   return *this;
332 }
333 
~LegibleDeserializedV0Advertisement()334 LegibleDeserializedV0Advertisement::~LegibleDeserializedV0Advertisement() {
335   if (!this->moved_) {
336     auto result = np_ffi::internal::np_ffi_deallocate_legible_v0_advertisement(
337         this->legible_v0_advertisement_);
338     assert_panic(result == np_ffi::internal::DeallocateResult::Success);
339   }
340 }
341 
GetIdentityKind() const342 DeserializedV0IdentityKind LegibleDeserializedV0Advertisement::GetIdentityKind()
343     const {
344   assert_panic(!this->moved_);
345   auto result = np_ffi::internal::
346       np_ffi_LegibleDeserializedV0Advertisement_get_identity_kind(
347           legible_v0_advertisement_);
348   return result;
349 }
350 
GetNumberOfDataElements() const351 uint8_t LegibleDeserializedV0Advertisement::GetNumberOfDataElements() const {
352   assert_panic(!this->moved_);
353   return np_ffi::internal::
354       np_ffi_LegibleDeserializedV0Advertisement_get_num_des(
355           legible_v0_advertisement_);
356 }
357 
IntoPayload()358 V0Payload LegibleDeserializedV0Advertisement::IntoPayload() {
359   assert_panic(!this->moved_);
360   auto result = np_ffi_LegibleDeserializedV0Advertisement_into_payload(
361       legible_v0_advertisement_);
362   this->moved_ = true;
363   return V0Payload(result);
364 }
365 
V0Payload(V0Payload && other)366 V0Payload::V0Payload(V0Payload&& other) noexcept
367     : v0_payload_(other.v0_payload_), moved_(other.moved_) {
368   other.v0_payload_ = {};
369   other.moved_ = true;
370 }
371 
operator =(V0Payload && other)372 V0Payload& V0Payload::operator=(V0Payload&& other) noexcept {
373   if (this != &other) {
374     if (!this->moved_) {
375       auto result =
376           np_ffi::internal::np_ffi_deallocate_v0_payload(this->v0_payload_);
377       assert_panic(result == np_ffi::internal::DeallocateResult::Success);
378     }
379     this->v0_payload_ = other.v0_payload_;
380     this->moved_ = other.moved_;
381 
382     other.moved_ = true;
383     other.v0_payload_ = {};
384   }
385   return *this;
386 }
387 
~V0Payload()388 V0Payload::~V0Payload() {
389   if (!this->moved_) {
390     auto result =
391         np_ffi::internal::np_ffi_deallocate_v0_payload(this->v0_payload_);
392     assert_panic(result == np_ffi::internal::DeallocateResult::Success);
393   }
394 }
395 
TryGetDataElement(const uint8_t index) const396 absl::StatusOr<V0DataElement> V0Payload::TryGetDataElement(
397     const uint8_t index) const {
398   assert_panic(!this->moved_);
399   auto result = np_ffi::internal::np_ffi_V0Payload_get_de(v0_payload_, index);
400   auto kind = np_ffi::internal::np_ffi_GetV0DEResult_kind(result);
401   switch (kind) {
402     case GetV0DEResultKind::Success: {
403       auto de = np_ffi_GetV0DEResult_into_SUCCESS(result);
404       return V0DataElement(de);
405     }
406     case GetV0DEResultKind::Error: {
407       return absl::OutOfRangeError("Invalid Data Element index");
408     }
409   }
410 }
411 
MetadataResultToVec(np_ffi::internal::DecryptMetadataResult decrypt_result)412 absl::StatusOr<std::vector<uint8_t>> MetadataResultToVec(
413     np_ffi::internal::DecryptMetadataResult decrypt_result) {
414   auto kind =
415       np_ffi::internal::np_ffi_DecryptMetadataResult_kind(decrypt_result);
416   switch (kind) {
417     case np_ffi::internal::DecryptMetadataResultKind::Success: {
418       auto metadata =
419           np_ffi::internal::np_ffi_DecryptMetadataResult_into_SUCCESS(
420               decrypt_result);
421       auto parts_result =
422           np_ffi::internal::np_ffi_DecryptedMetadata_get_metadata_buffer_parts(
423               metadata);
424       // The handle is guaranteed to be valid by the C++ wrapper so this should
425       // never fail
426       assert_panic(np_ffi::internal::np_ffi_GetMetadataBufferPartsResult_kind(
427                        parts_result) ==
428                    np_ffi::internal::GetMetadataBufferPartsResultKind::Success);
429       auto parts =
430           np_ffi::internal::np_ffi_GetMetadataBufferPartsResult_into_SUCCESS(
431               parts_result);
432       std::vector<uint8_t> result(parts.ptr, parts.ptr + parts.len);
433 
434       // Now that the contents have been copied into the vec, the underlying
435       // handle can be de-allocated
436       auto deallocate_result =
437           np_ffi::internal::np_ffi_deallocate_DecryptedMetadata(metadata);
438       assert_panic(deallocate_result ==
439                    np_ffi::internal::DeallocateResult::Success);
440       return result;
441     }
442     case np_ffi::internal::DecryptMetadataResultKind::Error: {
443       return absl::InvalidArgumentError(
444           "Decrypt attempt failed, identity is missing or invalid");
445     }
446   }
447 }
448 
TryGetIdentityDetails() const449 absl::StatusOr<DeserializedV0IdentityDetails> V0Payload::TryGetIdentityDetails()
450     const {
451   assert_panic(!this->moved_);
452   auto result = np_ffi::internal::np_ffi_V0Payload_get_identity_details(
453       this->v0_payload_);
454   auto kind = np_ffi::internal::np_ffi_GetV0IdentityDetailsResult_kind(result);
455   switch (kind) {
456     case np_ffi::internal::GetV0IdentityDetailsResultKind::Error: {
457       return absl::InvalidArgumentError(
458           "Identity details not available for public advertisements");
459     }
460     case np_ffi::internal::GetV0IdentityDetailsResultKind::Success: {
461       return np_ffi::internal::np_ffi_GetV0IdentityDetailsResult_into_SUCCESS(
462           result);
463     }
464   }
465 }
466 
TryDecryptMetadata() const467 absl::StatusOr<std::vector<uint8_t>> V0Payload::TryDecryptMetadata() const {
468   assert_panic(!this->moved_);
469   auto decrypt_result =
470       np_ffi::internal::np_ffi_V0Payload_decrypt_metadata(this->v0_payload_);
471   return MetadataResultToVec(decrypt_result);
472 }
473 
GetKind() const474 V0DataElementKind V0DataElement::GetKind() const {
475   return np_ffi::internal::np_ffi_V0DataElement_kind(v0_data_element_);
476 }
477 
AsTxPower() const478 TxPower V0DataElement::AsTxPower() const {
479   return TxPower(
480       np_ffi::internal::np_ffi_V0DataElement_into_TX_POWER(v0_data_element_));
481 }
482 
AsActions() const483 V0Actions V0DataElement::AsActions() const {
484   auto internal =
485       np_ffi::internal::np_ffi_V0DataElement_into_ACTIONS(v0_data_element_);
486   return V0Actions(internal);
487 }
488 
V0DataElement(TxPower tx_power)489 V0DataElement::V0DataElement(TxPower tx_power) {
490   v0_data_element_ =
491       np_ffi::internal::np_ffi_TxPower_into_V0DataElement(tx_power.tx_power_);
492 }
493 
V0DataElement(V0Actions actions)494 V0DataElement::V0DataElement(V0Actions actions) {
495   v0_data_element_ =
496       np_ffi::internal::np_ffi_V0Actions_into_V0DataElement(actions.actions_);
497 }
498 
GetAsU32() const499 uint32_t V0Actions::GetAsU32() const {
500   return np_ffi::internal::np_ffi_V0Actions_as_u32(actions_);
501 }
502 
HasAction(ActionType action) const503 bool V0Actions::HasAction(ActionType action) const {
504   return np_ffi::internal::np_ffi_V0Actions_has_action(actions_, action);
505 }
506 
TrySetAction(ActionType action,bool value)507 absl::Status V0Actions::TrySetAction(ActionType action, bool value) {
508   auto result =
509       np_ffi::internal::np_ffi_V0Actions_set_action(actions_, action, value);
510   auto kind = np_ffi::internal::np_ffi_SetV0ActionResult_kind(result);
511   switch (kind) {
512     case np_ffi::internal::SetV0ActionResultKind::Success: {
513       actions_ =
514           np_ffi::internal::np_ffi_SetV0ActionResult_into_SUCCESS(result);
515       return absl::OkStatus();
516     }
517     case np_ffi::internal::SetV0ActionResultKind::Error: {
518       actions_ = np_ffi::internal::np_ffi_SetV0ActionResult_into_ERROR(result);
519       return absl::InvalidArgumentError(
520           "The requested action bit may not be set for the requested adv "
521           "encoding");
522     }
523   }
524 }
525 
BuildNewZeroed(AdvertisementBuilderKind kind)526 V0Actions V0Actions::BuildNewZeroed(AdvertisementBuilderKind kind) {
527   auto actions = np_ffi::internal::np_ffi_build_new_zeroed_V0Actions(kind);
528   return V0Actions(actions);
529 }
530 
GetAsI8() const531 int8_t TxPower::GetAsI8() const {
532   return np_ffi::internal::np_ffi_TxPower_as_signed_byte(tx_power_);
533 }
534 
TryBuildFromI8(int8_t value)535 absl::StatusOr<TxPower> TxPower::TryBuildFromI8(int8_t value) {
536   auto result = np_ffi::internal::np_ffi_TxPower_build_from_signed_byte(value);
537   auto kind = np_ffi::internal::np_ffi_BuildTxPowerResult_kind(result);
538   switch (kind) {
539     case np_ffi::internal::BuildTxPowerResultKind::Success: {
540       return TxPower(
541           np_ffi::internal::np_ffi_BuildTxPowerResult_into_SUCCESS(result));
542     }
543     case np_ffi::internal::BuildTxPowerResultKind::OutOfRange: {
544       return absl::InvalidArgumentError(
545           "Could not build a tx power for the requested byte value.");
546     }
547   }
548 }
549 
550 // This is called after all references to the shared_ptr have gone out of
551 // scope
DeallocateV1Adv(np_ffi::internal::DeserializedV1Advertisement * v1_advertisement)552 auto DeallocateV1Adv(
553     np_ffi::internal::DeserializedV1Advertisement* v1_advertisement) {
554   auto result =
555       np_ffi::internal::np_ffi_deallocate_deserialized_V1_advertisement(
556           *v1_advertisement);
557   assert_panic(result == np_ffi::internal::DeallocateResult::Success);
558   delete v1_advertisement;
559 }
560 
DeserializedV1Advertisement(np_ffi::internal::DeserializedV1Advertisement v1_advertisement)561 DeserializedV1Advertisement::DeserializedV1Advertisement(
562     np_ffi::internal::DeserializedV1Advertisement v1_advertisement) {
563   v1_advertisement_ =
564       std::shared_ptr<np_ffi::internal::DeserializedV1Advertisement>(
565           new np_ffi::internal::DeserializedV1Advertisement(v1_advertisement),
566           DeallocateV1Adv);
567 }
568 
DeserializedV1Advertisement(DeserializedV1Advertisement && other)569 DeserializedV1Advertisement::DeserializedV1Advertisement(
570     DeserializedV1Advertisement&& other) noexcept
571     : v1_advertisement_(std::move(other.v1_advertisement_)) {}
572 
operator =(DeserializedV1Advertisement && other)573 DeserializedV1Advertisement& DeserializedV1Advertisement::operator=(
574     DeserializedV1Advertisement&& other) noexcept {
575   if (this != &other) {
576     this->v1_advertisement_ = std::move(other.v1_advertisement_);
577   }
578   return *this;
579 }
580 
581 // V1 Stuff
GetNumLegibleSections() const582 uint8_t DeserializedV1Advertisement::GetNumLegibleSections() const {
583   assert_panic(this->v1_advertisement_ != nullptr);
584   return np_ffi::internal::
585       np_ffi_DeserializedV1Advertisement_get_num_legible_sections(
586           *v1_advertisement_);
587 }
588 
GetNumUndecryptableSections() const589 uint8_t DeserializedV1Advertisement::GetNumUndecryptableSections() const {
590   assert_panic(this->v1_advertisement_ != nullptr);
591   return np_ffi::internal::
592       np_ffi_DeserializedV1Advertisement_get_num_undecryptable_sections(
593           *v1_advertisement_);
594 }
595 
596 absl::StatusOr<DeserializedV1Section>
TryGetSection(const uint8_t section_index) const597 DeserializedV1Advertisement::TryGetSection(const uint8_t section_index) const {
598   assert_panic(this->v1_advertisement_ != nullptr);
599   auto result =
600       np_ffi::internal::np_ffi_DeserializedV1Advertisement_get_section(
601           *v1_advertisement_, section_index);
602   auto kind = np_ffi::internal::np_ffi_GetV1SectionResult_kind(result);
603   switch (kind) {
604     case np_ffi::internal::GetV1SectionResultKind::Error: {
605       return absl::OutOfRangeError("Invalid section index");
606     }
607     case np_ffi::internal::GetV1SectionResultKind::Success: {
608       auto section =
609           np_ffi::internal::np_ffi_GetV1SectionResult_into_SUCCESS(result);
610       return DeserializedV1Section(section, v1_advertisement_);
611     }
612   }
613 }
614 
NumberOfDataElements() const615 uint8_t DeserializedV1Section::NumberOfDataElements() const {
616   return np_ffi::internal::np_ffi_DeserializedV1Section_get_num_des(section_);
617 }
618 
GetIdentityKind() const619 DeserializedV1IdentityKind DeserializedV1Section::GetIdentityKind() const {
620   return np_ffi::internal::np_ffi_DeserializedV1Section_get_identity_kind(
621       section_);
622 }
623 
TryGetDataElement(const uint8_t index) const624 absl::StatusOr<V1DataElement> DeserializedV1Section::TryGetDataElement(
625     const uint8_t index) const {
626   auto result =
627       np_ffi::internal::np_ffi_DeserializedV1Section_get_de(section_, index);
628   auto kind = np_ffi::internal::np_ffi_GetV1DEResult_kind(result);
629   switch (kind) {
630     case np_ffi::internal::GetV1DEResultKind::Error: {
631       return absl::OutOfRangeError(
632           "Invalid data element index for this section");
633     }
634     case np_ffi::internal::GetV1DEResultKind::Success: {
635       return V1DataElement(
636           np_ffi::internal::np_ffi_GetV1DEResult_into_SUCCESS(result));
637     }
638   }
639 }
640 
TryDecryptMetadata() const641 absl::StatusOr<std::vector<uint8_t>> DeserializedV1Section::TryDecryptMetadata()
642     const {
643   assert_panic(this->owning_v1_advertisement_ != nullptr);
644   auto decrypt_result =
645       np_ffi::internal::np_ffi_DeserializedV1Section_decrypt_metadata(
646           this->section_);
647   return MetadataResultToVec(decrypt_result);
648 }
649 
650 absl::StatusOr<DeserializedV1IdentityDetails>
GetIdentityDetails() const651 DeserializedV1Section::GetIdentityDetails() const {
652   assert_panic(this->owning_v1_advertisement_ != nullptr);
653   auto result =
654       np_ffi::internal::np_ffi_DeserializedV1Section_get_identity_details(
655           this->section_);
656   auto kind = np_ffi::internal::np_ffi_GetV1IdentityDetailsResult_kind(result);
657   switch (kind) {
658     case np_ffi::internal::GetV1IdentityDetailsResultKind::Error: {
659       return absl::InvalidArgumentError(
660           "Identity details are not available for public advertisements");
661     }
662     case np_ffi::internal::GetV1IdentityDetailsResultKind::Success: {
663       return np_ffi::internal::np_ffi_GetV1IdentityDetailsResult_into_SUCCESS(
664           result);
665     }
666   }
667 }
668 
669 absl::StatusOr<std::array<uint8_t, DERIVED_SALT_SIZE>>
DeriveSaltForOffset(const uint8_t offset) const670 DeserializedV1Section::DeriveSaltForOffset(const uint8_t offset) const {
671   auto result = np_ffi::internal::
672       np_ffi_DeserializedV1Section_derive_16_byte_salt_for_offset(
673           this->section_, offset);
674   auto kind = np_ffi::internal::np_ffi_GetV1DE16ByteSaltResult_kind(result);
675   switch (kind) {
676     case np_ffi::internal::GetV1DE16ByteSaltResultKind::Error: {
677       return absl::InvalidArgumentError("Failed to derive salt for offset");
678     }
679     case np_ffi::internal::GetV1DE16ByteSaltResultKind::Success: {
680       auto buffer =
681           np_ffi::internal::np_ffi_GetV1DE16ByteSaltResult_into_SUCCESS(result);
682       return std::to_array(buffer._0);
683     }
684   }
685 }
686 
GetDataElementTypeCode() const687 uint32_t V1DataElement::GetDataElementTypeCode() const {
688   return np_ffi::internal::np_ffi_V1DEType_to_uint32_t(
689       np_ffi::internal::np_ffi_V1DataElement_to_generic(this->v1_data_element_)
690           .de_type);
691 }
692 
GetPayload() const693 ByteBuffer<MAX_V1_DE_PAYLOAD_SIZE> V1DataElement::GetPayload() const {
694   return ByteBuffer(
695       np_ffi::internal::np_ffi_V1DataElement_to_generic(this->v1_data_element_)
696           .payload);
697 }
698 
GetOffset() const699 uint8_t V1DataElement::GetOffset() const {
700   return np_ffi::internal::np_ffi_V1DataElement_to_generic(
701              this->v1_data_element_)
702       .offset;
703 }
704 
MatchedCredentialData(const uint32_t cred_id,std::span<const uint8_t> metadata_bytes)705 MatchedCredentialData::MatchedCredentialData(
706     const uint32_t cred_id, std::span<const uint8_t> metadata_bytes) {
707   this->data_ = {cred_id, metadata_bytes.data(), metadata_bytes.size()};
708 }
709 
710 template <typename T, size_t N>
CopyToRawArray(T (& dest)[N],const std::array<T,N> & src)711 void CopyToRawArray(T (&dest)[N], const std::array<T, N>& src) {
712   memcpy(dest, src.data(), sizeof(T) * N);
713 }
714 
V0MatchableCredential(const std::array<uint8_t,32> key_seed,const std::array<uint8_t,32> legacy_metadata_key_hmac,const MatchedCredentialData matched_credential_data)715 V0MatchableCredential::V0MatchableCredential(
716     const std::array<uint8_t, 32> key_seed,
717     const std::array<uint8_t, 32> legacy_metadata_key_hmac,
718     const MatchedCredentialData matched_credential_data) {
719   np_ffi::internal::V0DiscoveryCredential discovery_cred{};
720   CopyToRawArray(discovery_cred.key_seed, key_seed);
721   CopyToRawArray(discovery_cred.identity_token_hmac, legacy_metadata_key_hmac);
722   this->internal_ = {discovery_cred, matched_credential_data.data_};
723 }
724 
V1MatchableCredential(const std::array<uint8_t,32> key_seed,const std::array<uint8_t,32> expected_mic_extended_salt_identity_token_hmac,const std::array<uint8_t,32> expected_signature_identity_token_hmac,const std::array<uint8_t,32> pub_key,const MatchedCredentialData matched_credential_data)725 V1MatchableCredential::V1MatchableCredential(
726     const std::array<uint8_t, 32> key_seed,
727     const std::array<uint8_t, 32>
728         expected_mic_extended_salt_identity_token_hmac,
729     const std::array<uint8_t, 32> expected_signature_identity_token_hmac,
730     const std::array<uint8_t, 32> pub_key,
731     const MatchedCredentialData matched_credential_data) {
732   np_ffi::internal::V1DiscoveryCredential discovery_cred{};
733   CopyToRawArray(discovery_cred.key_seed, key_seed);
734   CopyToRawArray(discovery_cred.expected_mic_extended_salt_identity_token_hmac,
735                  expected_mic_extended_salt_identity_token_hmac);
736   CopyToRawArray(discovery_cred.expected_signature_identity_token_hmac,
737                  expected_signature_identity_token_hmac);
738   CopyToRawArray(discovery_cred.pub_key, pub_key);
739   this->internal_ = {discovery_cred, matched_credential_data.data_};
740 }
741 
V0BroadcastCredential(std::array<uint8_t,32> key_seed,std::array<uint8_t,14> identity_token)742 V0BroadcastCredential::V0BroadcastCredential(
743     std::array<uint8_t, 32> key_seed, std::array<uint8_t, 14> identity_token) {
744   CopyToRawArray(internal_.key_seed, key_seed);
745   CopyToRawArray(internal_.identity_token, identity_token);
746 }
747 
~V0AdvertisementBuilder()748 V0AdvertisementBuilder::~V0AdvertisementBuilder() {
749   if (!this->moved_) {
750     auto result = np_ffi::internal::np_ffi_deallocate_v0_advertisement_builder(
751         adv_builder_);
752     assert_panic(result == np_ffi::internal::DeallocateResult::Success);
753   }
754 }
755 
V0AdvertisementBuilder(V0AdvertisementBuilder && other)756 V0AdvertisementBuilder::V0AdvertisementBuilder(
757     V0AdvertisementBuilder&& other) noexcept
758     : adv_builder_(other.adv_builder_), moved_(other.moved_) {
759   other.adv_builder_ = {};
760   other.moved_ = true;
761 }
762 
operator =(V0AdvertisementBuilder && other)763 V0AdvertisementBuilder& V0AdvertisementBuilder::operator=(
764     V0AdvertisementBuilder&& other) noexcept {
765   if (this != &other) {
766     if (!this->moved_) {
767       auto result =
768           np_ffi::internal::np_ffi_deallocate_v0_advertisement_builder(
769               this->adv_builder_);
770       assert_panic(result == np_ffi::internal::DeallocateResult::Success);
771     }
772 
773     this->adv_builder_ = other.adv_builder_;
774     this->moved_ = other.moved_;
775 
776     other.adv_builder_ = {};
777     other.moved_ = true;
778   }
779   return *this;
780 }
781 
TryAddDE(V0DataElement de)782 absl::Status V0AdvertisementBuilder::TryAddDE(V0DataElement de) {
783   assert_panic(!this->moved_);
784   auto result = np_ffi::internal::np_ffi_V0AdvertisementBuilder_add_de(
785       this->adv_builder_, de.v0_data_element_);
786   switch (result) {
787     case AddV0DEResult::Success: {
788       return absl::OkStatus();
789     }
790     case AddV0DEResult::InvalidAdvertisementBuilderHandle: {
791       return absl::InvalidArgumentError(
792           "invalid v0 advertisement builder handle provided");
793     }
794     case AddV0DEResult::InsufficientAdvertisementSpace: {
795       return absl::ResourceExhaustedError(
796           "insufficient advertisement space to add DE");
797     }
798     case AddV0DEResult::InvalidIdentityTypeForDataElement: {
799       return absl::InvalidArgumentError(
800           "the DE may not be added to this advertisement builder due to an "
801           "identity type mismatch");
802     }
803   }
804 }
805 
806 [[nodiscard]] absl::StatusOr<ByteBuffer<24>>
TrySerialize()807 V0AdvertisementBuilder::TrySerialize() {
808   assert_panic(!this->moved_);
809   auto result =
810       np_ffi::internal::np_ffi_V0AdvertisementBuilder_into_advertisement(
811           this->adv_builder_);
812   auto kind =
813       np_ffi::internal::np_ffi_SerializeV0AdvertisementResult_kind(result);
814   // Regardless of what happens, we've invalidated the original adv builder.
815   this->moved_ = true;
816 
817   switch (kind) {
818     case SerializeV0AdvertisementResultKind::Success: {
819       auto bytes =
820           np_ffi::internal::np_ffi_SerializeV0AdvertisementResult_into_SUCCESS(
821               result);
822       return ByteBuffer(bytes);
823     }
824     case SerializeV0AdvertisementResultKind::LdtError: {
825       return absl::OutOfRangeError(
826           "The advertisement contents were not of a proper size for LDT "
827           "encryption");
828     }
829     case SerializeV0AdvertisementResultKind::UnencryptedError: {
830       return absl::OutOfRangeError(
831           "The advertisement contents did not meet the length requirements");
832     }
833     case SerializeV0AdvertisementResultKind::
834         InvalidAdvertisementBuilderHandle: {
835       return absl::InvalidArgumentError(
836           "The advertisement builder handle was invalid");
837     }
838   }
839 }
840 
CreatePublic()841 [[nodiscard]] V0AdvertisementBuilder V0AdvertisementBuilder::CreatePublic() {
842   auto result =
843       np_ffi::internal::np_ffi_create_v0_public_advertisement_builder();
844   return V0AdvertisementBuilder(result);
845 }
846 
847 template <uintptr_t N>
ToFFIArray(std::array<uint8_t,N> value)848 [[nodiscard]] np_ffi::internal::FixedSizeArray<N> ToFFIArray(
849     std::array<uint8_t, N> value) {
850   np_ffi::internal::FixedSizeArray<N> result;
851   std::copy(std::begin(value), std::end(value), result._0);
852   return result;
853 }
854 
CreateEncrypted(V0BroadcastCredential broadcast_cred,std::array<uint8_t,2> salt)855 [[nodiscard]] V0AdvertisementBuilder V0AdvertisementBuilder::CreateEncrypted(
856     V0BroadcastCredential broadcast_cred, std::array<uint8_t, 2> salt) {
857   auto result =
858       np_ffi::internal::np_ffi_create_v0_encrypted_advertisement_builder(
859           broadcast_cred.internal_, ToFFIArray(salt));
860   return V0AdvertisementBuilder(result);
861 }
862 
863 }  // namespace nearby_protocol
864