blob: 510844ac8343c733fb3f6233f579ebf47a72a0ec [file] [log] [blame]
// 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
//
// http://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 <array>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <span>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "np_cpp_ffi_functions.h"
#include "np_cpp_ffi_types.h"
namespace nearby_protocol {
void panic_handler(PanicReason reason);
struct PanicHandler {
void (*handler)(PanicReason);
bool set_by_client;
};
PanicHandler gPanicHandler = PanicHandler{panic_handler, false};
// C++ layer internal panic handler
void panic_handler(PanicReason reason) {
// Give clients a chance to use their own panic handler, but if they don't
// terminate the process we will make sure it happens.
if (gPanicHandler.set_by_client) {
gPanicHandler.handler(reason);
}
std::abort();
}
void _assert_panic(bool condition, const char* func, const char* file,
int line) {
if (!condition) {
std::cout << "Assert failed: \n function: " << func << "\n file: " << file
<< "\n line: " << line << "\n";
panic_handler(PanicReason::AssertFailed);
}
}
#define assert_panic(e) _assert_panic(e, __func__, __FILE__, __LINE__)
bool GlobalConfig::SetPanicHandler(void (*handler)(PanicReason)) {
if (!gPanicHandler.set_by_client) {
gPanicHandler.handler = handler;
gPanicHandler.set_by_client = true;
return np_ffi::internal::np_ffi_global_config_panic_handler(panic_handler);
}
return false;
}
void GlobalConfig::SetNumShards(const uint8_t num_shards) {
np_ffi::internal::np_ffi_global_config_set_num_shards(num_shards);
}
CurrentHandleAllocations GlobalConfig::GetCurrentHandleAllocationCount() {
return np_ffi::internal::np_ffi_global_config_get_current_allocation_count();
}
CredentialSlab::CredentialSlab() {
this->credential_slab_ = np_ffi::internal::np_ffi_create_credential_slab();
this->moved_ = false;
}
CredentialSlab::~CredentialSlab() {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_credential_slab(credential_slab_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
}
CredentialSlab::CredentialSlab(CredentialSlab&& other) noexcept
: credential_slab_(other.credential_slab_), moved_(other.moved_) {
other.credential_slab_ = {};
other.moved_ = true;
}
CredentialSlab& CredentialSlab::operator=(CredentialSlab&& other) noexcept {
if (this != &other) {
if (!this->moved_) {
auto result = np_ffi::internal::np_ffi_deallocate_credential_slab(
this->credential_slab_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
this->credential_slab_ = other.credential_slab_;
this->moved_ = other.moved_;
other.credential_slab_ = {};
other.moved_ = true;
}
return *this;
}
void CredentialSlab::AddV0Credential(const V0MatchableCredential v0_cred) {
assert_panic(!this->moved_);
auto result = np_ffi::internal::np_ffi_CredentialSlab_add_v0_credential(
this->credential_slab_, v0_cred.internal_);
// Add V0 is infallible since the handle is guaranteed to be correct by the
// C++ wrapper
assert_panic(result == AddV0CredentialToSlabResult::Success);
}
absl::Status CredentialSlab::AddV1Credential(
const V1MatchableCredential v1_cred) {
assert_panic(!this->moved_);
auto result = np_ffi::internal::np_ffi_CredentialSlab_add_v1_credential(
this->credential_slab_, v1_cred.internal_);
switch (result) {
case AddV1CredentialToSlabResult::Success: {
return absl::OkStatus();
}
case AddV1CredentialToSlabResult::InvalidHandle: {
return absl::InvalidArgumentError(
"invalid credential slab handle provided");
}
case AddV1CredentialToSlabResult::InvalidPublicKeyBytes: {
return absl::InvalidArgumentError(
"Invalid public key bytes in credential");
}
}
}
CredentialBook::CredentialBook(CredentialSlab& slab) {
assert_panic(!slab.moved_);
auto result = np_ffi::internal::np_ffi_create_credential_book_from_slab(
slab.credential_slab_);
auto kind = np_ffi::internal::np_ffi_CreateCredentialBookResult_kind(result);
// Handle is guaranteed to be valid by the C++ wrapper
assert_panic(kind == CreateCredentialBookResultKind::Success);
slab.moved_ = true;
this->credential_book_ =
np_ffi::internal::np_ffi_CreateCredentialBookResult_into_SUCCESS(result);
this->moved_ = false;
}
CredentialBook::~CredentialBook() {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_credential_book(credential_book_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
}
CredentialBook::CredentialBook(CredentialBook&& other) noexcept
: credential_book_(other.credential_book_), moved_(other.moved_) {
other.credential_book_ = {};
other.moved_ = true;
}
CredentialBook& CredentialBook::operator=(CredentialBook&& other) noexcept {
if (this != &other) {
if (!this->moved_) {
auto result = np_ffi::internal::np_ffi_deallocate_credential_book(
this->credential_book_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
this->credential_book_ = other.credential_book_;
this->moved_ = other.moved_;
other.credential_book_ = {};
other.moved_ = true;
}
return *this;
}
DeserializeAdvertisementResult Deserializer::DeserializeAdvertisement(
const RawAdvertisementPayload& payload,
const CredentialBook& credential_book) {
assert_panic(!credential_book.moved_);
auto result = np_ffi::internal::np_ffi_deserialize_advertisement(
{payload.buffer_.internal_}, credential_book.credential_book_);
return DeserializeAdvertisementResult(result);
}
DeserializeAdvertisementResultKind DeserializeAdvertisementResult::GetKind()
const {
assert_panic(!this->moved_);
return np_ffi::internal::np_ffi_DeserializeAdvertisementResult_kind(result_);
}
DeserializedV0Advertisement DeserializeAdvertisementResult::IntoV0() {
assert_panic(!this->moved_);
auto result =
np_ffi::internal::np_ffi_DeserializeAdvertisementResult_into_V0(result_);
this->moved_ = true;
return DeserializedV0Advertisement(result);
}
DeserializedV1Advertisement DeserializeAdvertisementResult::IntoV1() {
assert_panic(!this->moved_);
auto v1_adv =
np_ffi::internal::np_ffi_DeserializeAdvertisementResult_into_V1(result_);
this->moved_ = true;
return DeserializedV1Advertisement(v1_adv);
}
DeserializeAdvertisementResult::~DeserializeAdvertisementResult() {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_deserialize_advertisement_result(
result_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
}
DeserializeAdvertisementResult::DeserializeAdvertisementResult(
DeserializeAdvertisementResult&& other) noexcept
: result_(other.result_), moved_(other.moved_) {
other.result_ = {};
other.moved_ = true;
}
DeserializeAdvertisementResult& DeserializeAdvertisementResult::operator=(
DeserializeAdvertisementResult&& other) noexcept {
if (this != &other) {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_deserialize_advertisement_result(
result_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
this->result_ = other.result_;
this->moved_ = other.moved_;
other.result_ = {};
other.moved_ = true;
}
return *this;
}
// V0 Stuff
DeserializedV0Advertisement::DeserializedV0Advertisement(
DeserializedV0Advertisement&& other) noexcept
: v0_advertisement_(other.v0_advertisement_), moved_(other.moved_) {
other.v0_advertisement_ = {};
other.moved_ = true;
}
DeserializedV0Advertisement& DeserializedV0Advertisement::operator=(
DeserializedV0Advertisement&& other) noexcept {
if (this != &other) {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_deserialized_V0_advertisement(
v0_advertisement_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
this->v0_advertisement_ = other.v0_advertisement_;
this->moved_ = other.moved_;
other.v0_advertisement_ = {};
other.moved_ = true;
}
return *this;
}
DeserializedV0Advertisement::~DeserializedV0Advertisement() {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_deserialized_V0_advertisement(
v0_advertisement_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
}
np_ffi::internal::DeserializedV0AdvertisementKind
DeserializedV0Advertisement::GetKind() const {
assert_panic(!this->moved_);
return np_ffi::internal::np_ffi_DeserializedV0Advertisement_kind(
v0_advertisement_);
}
LegibleDeserializedV0Advertisement DeserializedV0Advertisement::IntoLegible() {
assert_panic(!this->moved_);
auto result =
np_ffi::internal::np_ffi_DeserializedV0Advertisement_into_LEGIBLE(
v0_advertisement_);
this->moved_ = true;
this->v0_advertisement_ = {};
return LegibleDeserializedV0Advertisement(result);
}
LegibleDeserializedV0Advertisement::LegibleDeserializedV0Advertisement(
LegibleDeserializedV0Advertisement&& other) noexcept
: legible_v0_advertisement_(other.legible_v0_advertisement_),
moved_(other.moved_) {
other.moved_ = true;
other.legible_v0_advertisement_ = {};
}
LegibleDeserializedV0Advertisement&
LegibleDeserializedV0Advertisement::operator=(
LegibleDeserializedV0Advertisement&& other) noexcept {
if (this != &other) {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_legible_v0_advertisement(
this->legible_v0_advertisement_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
this->legible_v0_advertisement_ = other.legible_v0_advertisement_;
this->moved_ = other.moved_;
other.moved_ = true;
other.legible_v0_advertisement_ = {};
}
return *this;
}
LegibleDeserializedV0Advertisement::~LegibleDeserializedV0Advertisement() {
if (!this->moved_) {
auto result = np_ffi::internal::np_ffi_deallocate_legible_v0_advertisement(
this->legible_v0_advertisement_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
}
DeserializedV0IdentityKind LegibleDeserializedV0Advertisement::GetIdentityKind()
const {
assert_panic(!this->moved_);
auto result = np_ffi::internal::
np_ffi_LegibleDeserializedV0Advertisement_get_identity_kind(
legible_v0_advertisement_);
return result;
}
uint8_t LegibleDeserializedV0Advertisement::GetNumberOfDataElements() const {
assert_panic(!this->moved_);
return np_ffi::internal::
np_ffi_LegibleDeserializedV0Advertisement_get_num_des(
legible_v0_advertisement_);
}
V0Payload LegibleDeserializedV0Advertisement::IntoPayload() {
assert_panic(!this->moved_);
auto result = np_ffi_LegibleDeserializedV0Advertisement_into_payload(
legible_v0_advertisement_);
this->moved_ = true;
return V0Payload(result);
}
V0Payload::V0Payload(V0Payload&& other) noexcept
: v0_payload_(other.v0_payload_), moved_(other.moved_) {
other.v0_payload_ = {};
other.moved_ = true;
}
V0Payload& V0Payload::operator=(V0Payload&& other) noexcept {
if (this != &other) {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_v0_payload(this->v0_payload_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
this->v0_payload_ = other.v0_payload_;
this->moved_ = other.moved_;
other.moved_ = true;
other.v0_payload_ = {};
}
return *this;
}
V0Payload::~V0Payload() {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_v0_payload(this->v0_payload_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
}
absl::StatusOr<V0DataElement> V0Payload::TryGetDataElement(
const uint8_t index) const {
assert_panic(!this->moved_);
auto result = np_ffi::internal::np_ffi_V0Payload_get_de(v0_payload_, index);
auto kind = np_ffi::internal::np_ffi_GetV0DEResult_kind(result);
switch (kind) {
case GetV0DEResultKind::Success: {
auto de = np_ffi_GetV0DEResult_into_SUCCESS(result);
return V0DataElement(de);
}
case GetV0DEResultKind::Error: {
return absl::OutOfRangeError("Invalid Data Element index");
}
}
}
absl::StatusOr<std::vector<uint8_t>> MetadataResultToVec(
np_ffi::internal::DecryptMetadataResult decrypt_result) {
auto kind =
np_ffi::internal::np_ffi_DecryptMetadataResult_kind(decrypt_result);
switch (kind) {
case np_ffi::internal::DecryptMetadataResultKind::Success: {
auto metadata =
np_ffi::internal::np_ffi_DecryptMetadataResult_into_SUCCESS(
decrypt_result);
auto parts_result =
np_ffi::internal::np_ffi_DecryptedMetadata_get_metadata_buffer_parts(
metadata);
// The handle is guaranteed to be valid by the C++ wrapper so this should
// never fail
assert_panic(np_ffi::internal::np_ffi_GetMetadataBufferPartsResult_kind(
parts_result) ==
np_ffi::internal::GetMetadataBufferPartsResultKind::Success);
auto parts =
np_ffi::internal::np_ffi_GetMetadataBufferPartsResult_into_SUCCESS(
parts_result);
std::vector<uint8_t> result(parts.ptr, parts.ptr + parts.len);
// Now that the contents have been copied into the vec, the underlying
// handle can be de-allocated
auto deallocate_result =
np_ffi::internal::np_ffi_deallocate_DecryptedMetadata(metadata);
assert_panic(deallocate_result ==
np_ffi::internal::DeallocateResult::Success);
return result;
}
case np_ffi::internal::DecryptMetadataResultKind::Error: {
return absl::InvalidArgumentError(
"Decrypt attempt failed, identity is missing or invalid");
}
}
}
absl::StatusOr<DeserializedV0IdentityDetails> V0Payload::TryGetIdentityDetails()
const {
assert_panic(!this->moved_);
auto result = np_ffi::internal::np_ffi_V0Payload_get_identity_details(
this->v0_payload_);
auto kind = np_ffi::internal::np_ffi_GetV0IdentityDetailsResult_kind(result);
switch (kind) {
case np_ffi::internal::GetV0IdentityDetailsResultKind::Error: {
return absl::InvalidArgumentError(
"Identity details not available for public advertisements");
}
case np_ffi::internal::GetV0IdentityDetailsResultKind::Success: {
return np_ffi::internal::np_ffi_GetV0IdentityDetailsResult_into_SUCCESS(
result);
}
}
}
absl::StatusOr<std::vector<uint8_t>> V0Payload::TryDecryptMetadata() const {
assert_panic(!this->moved_);
auto decrypt_result =
np_ffi::internal::np_ffi_V0Payload_decrypt_metadata(this->v0_payload_);
return MetadataResultToVec(decrypt_result);
}
V0DataElementKind V0DataElement::GetKind() const {
return np_ffi::internal::np_ffi_V0DataElement_kind(v0_data_element_);
}
TxPower V0DataElement::AsTxPower() const {
return TxPower(
np_ffi::internal::np_ffi_V0DataElement_into_TX_POWER(v0_data_element_));
}
V0Actions V0DataElement::AsActions() const {
auto internal =
np_ffi::internal::np_ffi_V0DataElement_into_ACTIONS(v0_data_element_);
return V0Actions(internal);
}
V0DataElement::V0DataElement(TxPower tx_power) {
v0_data_element_ =
np_ffi::internal::np_ffi_TxPower_into_V0DataElement(tx_power.tx_power_);
}
V0DataElement::V0DataElement(V0Actions actions) {
v0_data_element_ =
np_ffi::internal::np_ffi_V0Actions_into_V0DataElement(actions.actions_);
}
uint32_t V0Actions::GetAsU32() const {
return np_ffi::internal::np_ffi_V0Actions_as_u32(actions_);
}
bool V0Actions::HasAction(ActionType action) const {
return np_ffi::internal::np_ffi_V0Actions_has_action(actions_, action);
}
absl::Status V0Actions::TrySetAction(ActionType action, bool value) {
auto result =
np_ffi::internal::np_ffi_V0Actions_set_action(actions_, action, value);
auto kind = np_ffi::internal::np_ffi_SetV0ActionResult_kind(result);
switch (kind) {
case np_ffi::internal::SetV0ActionResultKind::Success: {
actions_ =
np_ffi::internal::np_ffi_SetV0ActionResult_into_SUCCESS(result);
return absl::OkStatus();
}
case np_ffi::internal::SetV0ActionResultKind::Error: {
actions_ = np_ffi::internal::np_ffi_SetV0ActionResult_into_ERROR(result);
return absl::InvalidArgumentError(
"The requested action bit may not be set for the requested adv "
"encoding");
}
}
}
V0Actions V0Actions::BuildNewZeroed(AdvertisementBuilderKind kind) {
auto actions = np_ffi::internal::np_ffi_build_new_zeroed_V0Actions(kind);
return V0Actions(actions);
}
int8_t TxPower::GetAsI8() const {
return np_ffi::internal::np_ffi_TxPower_as_signed_byte(tx_power_);
}
absl::StatusOr<TxPower> TxPower::TryBuildFromI8(int8_t value) {
auto result = np_ffi::internal::np_ffi_TxPower_build_from_signed_byte(value);
auto kind = np_ffi::internal::np_ffi_BuildTxPowerResult_kind(result);
switch (kind) {
case np_ffi::internal::BuildTxPowerResultKind::Success: {
return TxPower(
np_ffi::internal::np_ffi_BuildTxPowerResult_into_SUCCESS(result));
}
case np_ffi::internal::BuildTxPowerResultKind::OutOfRange: {
return absl::InvalidArgumentError(
"Could not build a tx power for the requested byte value.");
}
}
}
// This is called after all references to the shared_ptr have gone out of
// scope
auto DeallocateV1Adv(
np_ffi::internal::DeserializedV1Advertisement* v1_advertisement) {
auto result =
np_ffi::internal::np_ffi_deallocate_deserialized_V1_advertisement(
*v1_advertisement);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
delete v1_advertisement;
}
DeserializedV1Advertisement::DeserializedV1Advertisement(
np_ffi::internal::DeserializedV1Advertisement v1_advertisement) {
v1_advertisement_ =
std::shared_ptr<np_ffi::internal::DeserializedV1Advertisement>(
new np_ffi::internal::DeserializedV1Advertisement(v1_advertisement),
DeallocateV1Adv);
}
DeserializedV1Advertisement::DeserializedV1Advertisement(
DeserializedV1Advertisement&& other) noexcept
: v1_advertisement_(std::move(other.v1_advertisement_)) {}
DeserializedV1Advertisement& DeserializedV1Advertisement::operator=(
DeserializedV1Advertisement&& other) noexcept {
if (this != &other) {
this->v1_advertisement_ = std::move(other.v1_advertisement_);
}
return *this;
}
// V1 Stuff
uint8_t DeserializedV1Advertisement::GetNumLegibleSections() const {
assert_panic(this->v1_advertisement_ != nullptr);
return np_ffi::internal::
np_ffi_DeserializedV1Advertisement_get_num_legible_sections(
*v1_advertisement_);
}
uint8_t DeserializedV1Advertisement::GetNumUndecryptableSections() const {
assert_panic(this->v1_advertisement_ != nullptr);
return np_ffi::internal::
np_ffi_DeserializedV1Advertisement_get_num_undecryptable_sections(
*v1_advertisement_);
}
absl::StatusOr<DeserializedV1Section>
DeserializedV1Advertisement::TryGetSection(const uint8_t section_index) const {
assert_panic(this->v1_advertisement_ != nullptr);
auto result =
np_ffi::internal::np_ffi_DeserializedV1Advertisement_get_section(
*v1_advertisement_, section_index);
auto kind = np_ffi::internal::np_ffi_GetV1SectionResult_kind(result);
switch (kind) {
case np_ffi::internal::GetV1SectionResultKind::Error: {
return absl::OutOfRangeError("Invalid section index");
}
case np_ffi::internal::GetV1SectionResultKind::Success: {
auto section =
np_ffi::internal::np_ffi_GetV1SectionResult_into_SUCCESS(result);
return DeserializedV1Section(section, v1_advertisement_);
}
}
}
uint8_t DeserializedV1Section::NumberOfDataElements() const {
return np_ffi::internal::np_ffi_DeserializedV1Section_get_num_des(section_);
}
DeserializedV1IdentityKind DeserializedV1Section::GetIdentityKind() const {
return np_ffi::internal::np_ffi_DeserializedV1Section_get_identity_kind(
section_);
}
absl::StatusOr<V1DataElement> DeserializedV1Section::TryGetDataElement(
const uint8_t index) const {
auto result =
np_ffi::internal::np_ffi_DeserializedV1Section_get_de(section_, index);
auto kind = np_ffi::internal::np_ffi_GetV1DEResult_kind(result);
switch (kind) {
case np_ffi::internal::GetV1DEResultKind::Error: {
return absl::OutOfRangeError(
"Invalid data element index for this section");
}
case np_ffi::internal::GetV1DEResultKind::Success: {
return V1DataElement(
np_ffi::internal::np_ffi_GetV1DEResult_into_SUCCESS(result));
}
}
}
absl::StatusOr<std::vector<uint8_t>> DeserializedV1Section::TryDecryptMetadata()
const {
assert_panic(this->owning_v1_advertisement_ != nullptr);
auto decrypt_result =
np_ffi::internal::np_ffi_DeserializedV1Section_decrypt_metadata(
this->section_);
return MetadataResultToVec(decrypt_result);
}
absl::StatusOr<DeserializedV1IdentityDetails>
DeserializedV1Section::GetIdentityDetails() const {
assert_panic(this->owning_v1_advertisement_ != nullptr);
auto result =
np_ffi::internal::np_ffi_DeserializedV1Section_get_identity_details(
this->section_);
auto kind = np_ffi::internal::np_ffi_GetV1IdentityDetailsResult_kind(result);
switch (kind) {
case np_ffi::internal::GetV1IdentityDetailsResultKind::Error: {
return absl::InvalidArgumentError(
"Identity details are not available for public advertisements");
}
case np_ffi::internal::GetV1IdentityDetailsResultKind::Success: {
return np_ffi::internal::np_ffi_GetV1IdentityDetailsResult_into_SUCCESS(
result);
}
}
}
absl::StatusOr<std::array<uint8_t, DERIVED_SALT_SIZE>>
DeserializedV1Section::DeriveSaltForOffset(const uint8_t offset) const {
auto result = np_ffi::internal::
np_ffi_DeserializedV1Section_derive_16_byte_salt_for_offset(
this->section_, offset);
auto kind = np_ffi::internal::np_ffi_GetV1DE16ByteSaltResult_kind(result);
switch (kind) {
case np_ffi::internal::GetV1DE16ByteSaltResultKind::Error: {
return absl::InvalidArgumentError("Failed to derive salt for offset");
}
case np_ffi::internal::GetV1DE16ByteSaltResultKind::Success: {
auto buffer =
np_ffi::internal::np_ffi_GetV1DE16ByteSaltResult_into_SUCCESS(result);
return std::to_array(buffer._0);
}
}
}
uint32_t V1DataElement::GetDataElementTypeCode() const {
return np_ffi::internal::np_ffi_V1DEType_to_uint32_t(
np_ffi::internal::np_ffi_V1DataElement_to_generic(this->v1_data_element_)
.de_type);
}
ByteBuffer<MAX_V1_DE_PAYLOAD_SIZE> V1DataElement::GetPayload() const {
return ByteBuffer(
np_ffi::internal::np_ffi_V1DataElement_to_generic(this->v1_data_element_)
.payload);
}
uint8_t V1DataElement::GetOffset() const {
return np_ffi::internal::np_ffi_V1DataElement_to_generic(
this->v1_data_element_)
.offset;
}
MatchedCredentialData::MatchedCredentialData(
const uint32_t cred_id, std::span<const uint8_t> metadata_bytes) {
this->data_ = {cred_id, metadata_bytes.data(), metadata_bytes.size()};
}
template <typename T, size_t N>
void CopyToRawArray(T (&dest)[N], const std::array<T, N>& src) {
memcpy(dest, src.data(), sizeof(T) * N);
}
V0MatchableCredential::V0MatchableCredential(
const std::array<uint8_t, 32> key_seed,
const std::array<uint8_t, 32> legacy_metadata_key_hmac,
const MatchedCredentialData matched_credential_data) {
np_ffi::internal::V0DiscoveryCredential discovery_cred{};
CopyToRawArray(discovery_cred.key_seed, key_seed);
CopyToRawArray(discovery_cred.identity_token_hmac, legacy_metadata_key_hmac);
this->internal_ = {discovery_cred, matched_credential_data.data_};
}
V1MatchableCredential::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) {
np_ffi::internal::V1DiscoveryCredential discovery_cred{};
CopyToRawArray(discovery_cred.key_seed, key_seed);
CopyToRawArray(discovery_cred.expected_mic_extended_salt_identity_token_hmac,
expected_mic_extended_salt_identity_token_hmac);
CopyToRawArray(discovery_cred.expected_signature_identity_token_hmac,
expected_signature_identity_token_hmac);
CopyToRawArray(discovery_cred.pub_key, pub_key);
this->internal_ = {discovery_cred, matched_credential_data.data_};
}
V0BroadcastCredential::V0BroadcastCredential(
std::array<uint8_t, 32> key_seed, std::array<uint8_t, 14> identity_token) {
CopyToRawArray(internal_.key_seed, key_seed);
CopyToRawArray(internal_.identity_token, identity_token);
}
V0AdvertisementBuilder::~V0AdvertisementBuilder() {
if (!this->moved_) {
auto result = np_ffi::internal::np_ffi_deallocate_v0_advertisement_builder(
adv_builder_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
}
V0AdvertisementBuilder::V0AdvertisementBuilder(
V0AdvertisementBuilder&& other) noexcept
: adv_builder_(other.adv_builder_), moved_(other.moved_) {
other.adv_builder_ = {};
other.moved_ = true;
}
V0AdvertisementBuilder& V0AdvertisementBuilder::operator=(
V0AdvertisementBuilder&& other) noexcept {
if (this != &other) {
if (!this->moved_) {
auto result =
np_ffi::internal::np_ffi_deallocate_v0_advertisement_builder(
this->adv_builder_);
assert_panic(result == np_ffi::internal::DeallocateResult::Success);
}
this->adv_builder_ = other.adv_builder_;
this->moved_ = other.moved_;
other.adv_builder_ = {};
other.moved_ = true;
}
return *this;
}
absl::Status V0AdvertisementBuilder::TryAddDE(V0DataElement de) {
assert_panic(!this->moved_);
auto result = np_ffi::internal::np_ffi_V0AdvertisementBuilder_add_de(
this->adv_builder_, de.v0_data_element_);
switch (result) {
case AddV0DEResult::Success: {
return absl::OkStatus();
}
case AddV0DEResult::InvalidAdvertisementBuilderHandle: {
return absl::InvalidArgumentError(
"invalid v0 advertisement builder handle provided");
}
case AddV0DEResult::InsufficientAdvertisementSpace: {
return absl::ResourceExhaustedError(
"insufficient advertisement space to add DE");
}
case AddV0DEResult::InvalidIdentityTypeForDataElement: {
return absl::InvalidArgumentError(
"the DE may not be added to this advertisement builder due to an "
"identity type mismatch");
}
}
}
[[nodiscard]] absl::StatusOr<ByteBuffer<24>>
V0AdvertisementBuilder::TrySerialize() {
assert_panic(!this->moved_);
auto result =
np_ffi::internal::np_ffi_V0AdvertisementBuilder_into_advertisement(
this->adv_builder_);
auto kind =
np_ffi::internal::np_ffi_SerializeV0AdvertisementResult_kind(result);
// Regardless of what happens, we've invalidated the original adv builder.
this->moved_ = true;
switch (kind) {
case SerializeV0AdvertisementResultKind::Success: {
auto bytes =
np_ffi::internal::np_ffi_SerializeV0AdvertisementResult_into_SUCCESS(
result);
return ByteBuffer(bytes);
}
case SerializeV0AdvertisementResultKind::LdtError: {
return absl::OutOfRangeError(
"The advertisement contents were not of a proper size for LDT "
"encryption");
}
case SerializeV0AdvertisementResultKind::UnencryptedError: {
return absl::OutOfRangeError(
"The advertisement contents did not meet the length requirements");
}
case SerializeV0AdvertisementResultKind::
InvalidAdvertisementBuilderHandle: {
return absl::InvalidArgumentError(
"The advertisement builder handle was invalid");
}
}
}
[[nodiscard]] V0AdvertisementBuilder V0AdvertisementBuilder::CreatePublic() {
auto result =
np_ffi::internal::np_ffi_create_v0_public_advertisement_builder();
return V0AdvertisementBuilder(result);
}
template <uintptr_t N>
[[nodiscard]] np_ffi::internal::FixedSizeArray<N> ToFFIArray(
std::array<uint8_t, N> value) {
np_ffi::internal::FixedSizeArray<N> result;
std::copy(std::begin(value), std::end(value), result._0);
return result;
}
[[nodiscard]] V0AdvertisementBuilder V0AdvertisementBuilder::CreateEncrypted(
V0BroadcastCredential broadcast_cred, std::array<uint8_t, 2> salt) {
auto result =
np_ffi::internal::np_ffi_create_v0_encrypted_advertisement_builder(
broadcast_cred.internal_, ToFFIArray(salt));
return V0AdvertisementBuilder(result);
}
} // namespace nearby_protocol