mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Pure Refactor: move filtering logic into AdvertisementFilter class
- this decouples filtering logic from advertisement decoding logic in preparation for introducing a Rust backed impl of AdvertisementDecoder - this change is only a refactor and does not change functionality in any way PiperOrigin-RevId: 618978564
This commit is contained in:
@@ -54,6 +54,7 @@ cc_library(
|
||||
"action_factory.cc",
|
||||
"advertisement_decoder.cc",
|
||||
"advertisement_factory.cc",
|
||||
"advertisement_filter.cc",
|
||||
"base_broadcast_request.cc",
|
||||
"broadcast_manager.cc",
|
||||
"connection_authenticator_impl.cc",
|
||||
@@ -66,6 +67,7 @@ cc_library(
|
||||
"action_factory.h",
|
||||
"advertisement_decoder.h",
|
||||
"advertisement_factory.h",
|
||||
"advertisement_filter.h",
|
||||
"base_broadcast_request.h",
|
||||
"broadcast_manager.h",
|
||||
"connection_authenticator.h",
|
||||
@@ -180,6 +182,28 @@ cc_test(
|
||||
}),
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "advertisement_filter_test",
|
||||
size = "small",
|
||||
srcs = ["advertisement_filter_test.cc"],
|
||||
deps = [
|
||||
":internal",
|
||||
"//internal/platform:base",
|
||||
"//internal/proto:credential_cc_proto",
|
||||
"//presence:types",
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
] + select({
|
||||
"@platforms//os:windows": [
|
||||
"//internal/platform/implementation/windows",
|
||||
],
|
||||
"//conditions:default": [
|
||||
"//internal/platform/implementation/g3",
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "advertisement_factory_test",
|
||||
size = "small",
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include "presence/implementation/advertisement_decoder.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -154,36 +153,6 @@ absl::StatusOr<DataElement> ParseDataElement(const absl::string_view input,
|
||||
<< absl::BytesToHexString(input.substr(start, length));
|
||||
return DataElement(data_type, input.substr(start, length));
|
||||
}
|
||||
|
||||
bool Contains(const std::vector<DataElement>& data_elements,
|
||||
const DataElement& data_element) {
|
||||
return std::find(data_elements.begin(), data_elements.end(), data_element) !=
|
||||
data_elements.end();
|
||||
}
|
||||
|
||||
bool ContainsAll(const std::vector<DataElement>& data_elements,
|
||||
const std::vector<DataElement>& extended_properties) {
|
||||
for (const auto& filter_element : extended_properties) {
|
||||
if (!Contains(data_elements, filter_element)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContainsAny(const std::vector<DataElement>& data_elements,
|
||||
const std::vector<int>& actions) {
|
||||
if (actions.empty()) {
|
||||
return true;
|
||||
}
|
||||
for (int action : actions) {
|
||||
if (Contains(data_elements, DataElement(ActionBit(action)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AdvertisementDecoder::DecodeBaseAction(
|
||||
@@ -374,63 +343,5 @@ absl::StatusOr<Advertisement> AdvertisementDecoder::DecodeAdvertisement(
|
||||
return std::move(decoded_advertisement_);
|
||||
}
|
||||
|
||||
bool AdvertisementDecoder::MatchesScanFilter(
|
||||
const std::vector<DataElement>& data_elements) {
|
||||
// The advertisement matches the scan request when it matches at least
|
||||
// one of the filters in the request.
|
||||
if (scan_request_.scan_filters.empty()) {
|
||||
return true;
|
||||
}
|
||||
for (const auto& filter : scan_request_.scan_filters) {
|
||||
if (absl::holds_alternative<PresenceScanFilter>(filter)) {
|
||||
if (MatchesScanFilter(data_elements,
|
||||
absl::get<PresenceScanFilter>(filter))) {
|
||||
return true;
|
||||
}
|
||||
} else if (absl::holds_alternative<LegacyPresenceScanFilter>(filter)) {
|
||||
if (MatchesScanFilter(data_elements,
|
||||
absl::get<LegacyPresenceScanFilter>(filter))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdvertisementDecoder::MatchesScanFilter(
|
||||
const std::vector<DataElement>& data_elements,
|
||||
const PresenceScanFilter& filter) {
|
||||
// The advertisement must contain all Data Elements in scan request.
|
||||
return ContainsAll(data_elements, filter.extended_properties);
|
||||
}
|
||||
|
||||
bool AdvertisementDecoder::MatchesScanFilter(
|
||||
const std::vector<DataElement>& data_elements,
|
||||
const LegacyPresenceScanFilter& filter) {
|
||||
// The advertisement must:
|
||||
// * contain any Action from scan request,
|
||||
// * contain all Data Elements in scan request.
|
||||
return ContainsAny(data_elements, filter.actions) &&
|
||||
ContainsAll(data_elements, filter.extended_properties);
|
||||
}
|
||||
|
||||
std::vector<CredentialSelector> AdvertisementDecoder::GetCredentialSelectors(
|
||||
const ScanRequest& scan_request) {
|
||||
std::vector<IdentityType> all_types = {
|
||||
IdentityType::IDENTITY_TYPE_PRIVATE, IdentityType::IDENTITY_TYPE_TRUSTED,
|
||||
IdentityType::IDENTITY_TYPE_PUBLIC,
|
||||
IdentityType::IDENTITY_TYPE_PROVISIONED};
|
||||
std::vector<CredentialSelector> selectors;
|
||||
for (auto identity_type :
|
||||
(scan_request.identity_types.empty() ? all_types
|
||||
: scan_request.identity_types)) {
|
||||
selectors.push_back(
|
||||
CredentialSelector{.manager_app_id = scan_request.manager_app_id,
|
||||
.account_name = scan_request.account_name,
|
||||
.identity_type = identity_type});
|
||||
}
|
||||
return selectors;
|
||||
}
|
||||
|
||||
} // namespace presence
|
||||
} // namespace nearby
|
||||
|
||||
@@ -57,19 +57,12 @@ class AdvertisementDecoder {
|
||||
AddBannedDataTypes();
|
||||
}
|
||||
|
||||
static std::vector<CredentialSelector> GetCredentialSelectors(
|
||||
const ScanRequest& scan_request);
|
||||
|
||||
// Returns a list of Data Elements decoded from the advertisement.
|
||||
// Returns an error if the advertisement is misformatted or if it couldn't be
|
||||
// decrypted.
|
||||
absl::StatusOr<Advertisement> DecodeAdvertisement(
|
||||
absl::string_view advertisement);
|
||||
|
||||
// Returns true if the decoded advertisement in `data_elements` matches the
|
||||
// filters in `scan_request`.
|
||||
bool MatchesScanFilter(const std::vector<DataElement>& data_elements);
|
||||
|
||||
private:
|
||||
// Decrypts data elements stored inside encrypted `elem` and appends them to
|
||||
// `decoded_advertisement_`.
|
||||
@@ -81,10 +74,6 @@ class AdvertisementDecoder {
|
||||
const std::vector<internal::SharedCredential>& credentials,
|
||||
absl::string_view salt, absl::string_view data_elements);
|
||||
void AddBannedDataTypes();
|
||||
bool MatchesScanFilter(const std::vector<DataElement>& data_elements,
|
||||
const PresenceScanFilter& filter);
|
||||
bool MatchesScanFilter(const std::vector<DataElement>& data_elements,
|
||||
const LegacyPresenceScanFilter& filter);
|
||||
|
||||
ScanRequest scan_request_;
|
||||
absl::flat_hash_map<IdentityType, std::vector<internal::SharedCredential>>*
|
||||
|
||||
@@ -329,101 +329,6 @@ TEST(AdvertisementDecoder, UnsupportedAdvertisementVersion) {
|
||||
StatusIs(absl::StatusCode::kUnimplemented));
|
||||
}
|
||||
|
||||
TEST(AdvertisementDecoder, MatchesScanFilterNoFilterPasses) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
ScanRequest empty_scan_request = {};
|
||||
AdvertisementDecoder decoder(empty_scan_request);
|
||||
|
||||
// A scan request without scan filters matches any advertisement
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter(
|
||||
{DataElement(DataElement::kPrivateIdentityFieldType, "payload")}));
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter({}));
|
||||
}
|
||||
|
||||
TEST(AdvertisementDecoder, MatchesPresenceScanFilter) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
DataElement model_id =
|
||||
DataElement(DataElement::kModelIdFieldType, "model id");
|
||||
DataElement salt = DataElement(DataElement::kSaltFieldType, "salt");
|
||||
DataElement salt2 = DataElement(DataElement::kSaltFieldType, "salt 2");
|
||||
PresenceScanFilter filter = {.extended_properties = {model_id, salt}};
|
||||
|
||||
AdvertisementDecoder decoder(
|
||||
|
||||
ScanRequestBuilder().AddScanFilter(filter).Build());
|
||||
|
||||
EXPECT_FALSE(decoder.MatchesScanFilter({}));
|
||||
EXPECT_FALSE(decoder.MatchesScanFilter({salt}));
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter({salt, model_id}));
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter({salt, salt2, model_id}));
|
||||
EXPECT_FALSE(decoder.MatchesScanFilter({salt2, model_id}));
|
||||
}
|
||||
|
||||
TEST(AdvertisementDecoder, MatchesLegacyPresenceScanFilter) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
DataElement model_id =
|
||||
DataElement(DataElement::kModelIdFieldType, "model id");
|
||||
DataElement salt = DataElement(DataElement::kSaltFieldType, "salt");
|
||||
DataElement salt2 = DataElement(DataElement::kSaltFieldType, "salt 2");
|
||||
LegacyPresenceScanFilter filter = {.extended_properties = {model_id, salt}};
|
||||
|
||||
AdvertisementDecoder decoder(
|
||||
|
||||
ScanRequestBuilder().AddScanFilter(filter).Build());
|
||||
|
||||
EXPECT_FALSE(decoder.MatchesScanFilter({}));
|
||||
EXPECT_FALSE(decoder.MatchesScanFilter({salt}));
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter({salt, model_id}));
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter({salt, salt2, model_id}));
|
||||
EXPECT_FALSE(decoder.MatchesScanFilter({salt2, model_id}));
|
||||
}
|
||||
|
||||
TEST(AdvertisementDecoder, MatchesLegacyPresenceScanFilterWithActions) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
DataElement model_id =
|
||||
DataElement(DataElement::kModelIdFieldType, "model id");
|
||||
DataElement salt = DataElement(DataElement::kSaltFieldType, "salt");
|
||||
DataElement ttt_action = DataElement(ActionBit::kTapToTransferAction);
|
||||
LegacyPresenceScanFilter filter = {
|
||||
.actions = {static_cast<int>(ActionBit::kActiveUnlockAction),
|
||||
static_cast<int>(ActionBit::kTapToTransferAction)},
|
||||
.extended_properties = {model_id, salt}};
|
||||
|
||||
AdvertisementDecoder decoder(
|
||||
|
||||
ScanRequestBuilder().AddScanFilter(filter).Build());
|
||||
|
||||
EXPECT_FALSE(decoder.MatchesScanFilter({salt, model_id}));
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter({salt, ttt_action, model_id}));
|
||||
}
|
||||
|
||||
TEST(AdvertisementDecoder, MatchesMultipleFilters) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
DataElement model_id =
|
||||
DataElement(DataElement::kModelIdFieldType, "model id");
|
||||
DataElement salt = DataElement(DataElement::kSaltFieldType, "salt");
|
||||
DataElement ttt_action = DataElement(ActionBit::kTapToTransferAction);
|
||||
PresenceScanFilter presence_filter = {.extended_properties = {model_id}};
|
||||
LegacyPresenceScanFilter legacy_filter = {
|
||||
.actions = {static_cast<int>(ActionBit::kActiveUnlockAction),
|
||||
static_cast<int>(ActionBit::kTapToTransferAction)},
|
||||
.extended_properties = {salt}};
|
||||
|
||||
AdvertisementDecoder decoder(ScanRequestBuilder()
|
||||
.AddScanFilter(presence_filter)
|
||||
.AddScanFilter(legacy_filter)
|
||||
.Build());
|
||||
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter({model_id}));
|
||||
EXPECT_TRUE(decoder.MatchesScanFilter({salt, ttt_action}));
|
||||
EXPECT_FALSE(decoder.MatchesScanFilter({ttt_action}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace presence
|
||||
} // namespace nearby
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2024 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 "presence/implementation/advertisement_filter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/variant.h"
|
||||
#include "presence/data_element.h"
|
||||
#include "presence/scan_request.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace presence {
|
||||
|
||||
bool Contains(const std::vector<DataElement>& data_elements,
|
||||
const DataElement& data_element) {
|
||||
return std::find(data_elements.begin(), data_elements.end(), data_element) !=
|
||||
data_elements.end();
|
||||
}
|
||||
|
||||
bool ContainsAll(const std::vector<DataElement>& data_elements,
|
||||
const std::vector<DataElement>& extended_properties) {
|
||||
for (const auto& filter_element : extended_properties) {
|
||||
if (!Contains(data_elements, filter_element)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContainsAny(const std::vector<DataElement>& data_elements,
|
||||
const std::vector<int>& actions) {
|
||||
if (actions.empty()) {
|
||||
return true;
|
||||
}
|
||||
for (int action : actions) {
|
||||
if (Contains(data_elements, DataElement(ActionBit(action)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdvertisementFilter::MatchesScanFilter(
|
||||
const std::vector<DataElement>& data_elements) {
|
||||
// The advertisement matches the scan request when it matches at least
|
||||
// one of the filters in the request.
|
||||
if (scan_request_.scan_filters.empty()) {
|
||||
return true;
|
||||
}
|
||||
for (const auto& filter : scan_request_.scan_filters) {
|
||||
if (absl::holds_alternative<PresenceScanFilter>(filter)) {
|
||||
if (MatchesScanFilter(data_elements,
|
||||
absl::get<PresenceScanFilter>(filter))) {
|
||||
return true;
|
||||
}
|
||||
} else if (absl::holds_alternative<LegacyPresenceScanFilter>(filter)) {
|
||||
if (MatchesScanFilter(data_elements,
|
||||
absl::get<LegacyPresenceScanFilter>(filter))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdvertisementFilter::MatchesScanFilter(
|
||||
const std::vector<DataElement>& data_elements,
|
||||
const PresenceScanFilter& filter) {
|
||||
// The advertisement must contain all Data Elements in scan request.
|
||||
return ContainsAll(data_elements, filter.extended_properties);
|
||||
}
|
||||
|
||||
bool AdvertisementFilter::MatchesScanFilter(
|
||||
const std::vector<DataElement>& data_elements,
|
||||
const LegacyPresenceScanFilter& filter) {
|
||||
// The advertisement must:
|
||||
// * contain any Action from scan request,
|
||||
// * contain all Data Elements in scan request.
|
||||
return ContainsAny(data_elements, filter.actions) &&
|
||||
ContainsAll(data_elements, filter.extended_properties);
|
||||
}
|
||||
|
||||
} // namespace presence
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_FILTER_H_
|
||||
#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_FILTER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "presence/data_element.h"
|
||||
#include "presence/scan_request.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace presence {
|
||||
class AdvertisementFilter {
|
||||
public:
|
||||
explicit AdvertisementFilter(ScanRequest scan_request)
|
||||
: scan_request_(scan_request) {}
|
||||
|
||||
// Returns true if the decoded advertisement in `data_elements` matches the
|
||||
// filters in `scan_request`.
|
||||
bool MatchesScanFilter(const std::vector<DataElement>& data_elements);
|
||||
|
||||
private:
|
||||
bool MatchesScanFilter(const std::vector<DataElement>& data_elements,
|
||||
const PresenceScanFilter& filter);
|
||||
bool MatchesScanFilter(const std::vector<DataElement>& data_elements,
|
||||
const LegacyPresenceScanFilter& filter);
|
||||
ScanRequest scan_request_;
|
||||
};
|
||||
|
||||
} // namespace presence
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_FILTER_H_
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright 2024 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 "presence/implementation/advertisement_filter.h"
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "protobuf-matchers/protocol-buffer-matchers.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/proto/credential.pb.h"
|
||||
#include "presence/data_element.h"
|
||||
#include "presence/scan_request.h"
|
||||
#include "presence/scan_request_builder.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace presence {
|
||||
namespace {
|
||||
|
||||
TEST(AdvertisementFilter, MatchesScanFilterNoFilterPasses) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
ScanRequest empty_scan_request = {};
|
||||
AdvertisementFilter adv_filter(empty_scan_request);
|
||||
|
||||
// A scan request without scan filters matches any advertisement
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter(
|
||||
{DataElement(DataElement::kPrivateIdentityFieldType, "payload")}));
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter({}));
|
||||
}
|
||||
|
||||
TEST(AdvertisementFilter, MatchesPresenceScanFilter) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
DataElement model_id =
|
||||
DataElement(DataElement::kModelIdFieldType, "model id");
|
||||
DataElement salt = DataElement(DataElement::kSaltFieldType, "salt");
|
||||
DataElement salt2 = DataElement(DataElement::kSaltFieldType, "salt 2");
|
||||
PresenceScanFilter filter = {.extended_properties = {model_id, salt}};
|
||||
|
||||
AdvertisementFilter adv_filter(
|
||||
|
||||
ScanRequestBuilder().AddScanFilter(filter).Build());
|
||||
|
||||
EXPECT_FALSE(adv_filter.MatchesScanFilter({}));
|
||||
EXPECT_FALSE(adv_filter.MatchesScanFilter({salt}));
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter({salt, model_id}));
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter({salt, salt2, model_id}));
|
||||
EXPECT_FALSE(adv_filter.MatchesScanFilter({salt2, model_id}));
|
||||
}
|
||||
|
||||
TEST(AdvertisementFilter, MatchesLegacyPresenceScanFilter) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
DataElement model_id =
|
||||
DataElement(DataElement::kModelIdFieldType, "model id");
|
||||
DataElement salt = DataElement(DataElement::kSaltFieldType, "salt");
|
||||
DataElement salt2 = DataElement(DataElement::kSaltFieldType, "salt 2");
|
||||
LegacyPresenceScanFilter filter = {.extended_properties = {model_id, salt}};
|
||||
|
||||
AdvertisementFilter adv_filter(
|
||||
|
||||
ScanRequestBuilder().AddScanFilter(filter).Build());
|
||||
|
||||
EXPECT_FALSE(adv_filter.MatchesScanFilter({}));
|
||||
EXPECT_FALSE(adv_filter.MatchesScanFilter({salt}));
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter({salt, model_id}));
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter({salt, salt2, model_id}));
|
||||
EXPECT_FALSE(adv_filter.MatchesScanFilter({salt2, model_id}));
|
||||
}
|
||||
|
||||
TEST(AdvertisementFilter, MatchesLegacyPresenceScanFilterWithActions) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
DataElement model_id =
|
||||
DataElement(DataElement::kModelIdFieldType, "model id");
|
||||
DataElement salt = DataElement(DataElement::kSaltFieldType, "salt");
|
||||
DataElement ttt_action = DataElement(ActionBit::kTapToTransferAction);
|
||||
LegacyPresenceScanFilter filter = {
|
||||
.actions = {static_cast<int>(ActionBit::kActiveUnlockAction),
|
||||
static_cast<int>(ActionBit::kTapToTransferAction)},
|
||||
.extended_properties = {model_id, salt}};
|
||||
|
||||
AdvertisementFilter adv_filter(
|
||||
|
||||
ScanRequestBuilder().AddScanFilter(filter).Build());
|
||||
|
||||
EXPECT_FALSE(adv_filter.MatchesScanFilter({salt, model_id}));
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter({salt, ttt_action, model_id}));
|
||||
}
|
||||
|
||||
TEST(AdvertisementFilter, MatchesMultipleFilters) {
|
||||
std::vector<DataElement> adv = {
|
||||
DataElement(DataElement::kPrivateIdentityFieldType, "payload")};
|
||||
DataElement model_id =
|
||||
DataElement(DataElement::kModelIdFieldType, "model id");
|
||||
DataElement salt = DataElement(DataElement::kSaltFieldType, "salt");
|
||||
DataElement ttt_action = DataElement(ActionBit::kTapToTransferAction);
|
||||
PresenceScanFilter presence_filter = {.extended_properties = {model_id}};
|
||||
LegacyPresenceScanFilter legacy_filter = {
|
||||
.actions = {static_cast<int>(ActionBit::kActiveUnlockAction),
|
||||
static_cast<int>(ActionBit::kTapToTransferAction)},
|
||||
.extended_properties = {salt}};
|
||||
|
||||
AdvertisementFilter adv_filter(ScanRequestBuilder()
|
||||
.AddScanFilter(presence_filter)
|
||||
.AddScanFilter(legacy_filter)
|
||||
.Build());
|
||||
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter({model_id}));
|
||||
EXPECT_TRUE(adv_filter.MatchesScanFilter({salt, ttt_action}));
|
||||
EXPECT_FALSE(adv_filter.MatchesScanFilter({ttt_action}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace presence
|
||||
} // namespace nearby
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "internal/platform/implementation/credential_callbacks.h"
|
||||
#include "internal/platform/implementation/crypto.h"
|
||||
#include "internal/platform/uuid.h"
|
||||
#include "presence//implementation/advertisement_filter.h"
|
||||
#include "presence/data_types.h"
|
||||
#include "presence/implementation/advertisement_decoder.h"
|
||||
#include "presence/implementation/mediums/ble.h"
|
||||
@@ -49,35 +50,36 @@ ScanSessionId ScanManager::StartScan(ScanRequest scan_request,
|
||||
ScanSessionId id = nearby::RandData<ScanSessionId>();
|
||||
RunOnServiceControllerThread(
|
||||
"start-scan",
|
||||
[this, id, scan_request, scan_callback = std::move(cb)]()
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable {
|
||||
ScanningCallback callback = ScanningCallback{
|
||||
.start_scanning_result =
|
||||
[start_scan_client =
|
||||
std::move(scan_callback.start_scan_cb)](
|
||||
absl::Status ble_status) mutable {
|
||||
start_scan_client(ble_status);
|
||||
},
|
||||
.advertisement_found_cb =
|
||||
[this, id](BlePeripheral& peripheral,
|
||||
BleAdvertisementData data) {
|
||||
RunOnServiceControllerThread(
|
||||
"notify-found-ble",
|
||||
[this, id, data = std::move(data),
|
||||
address = peripheral.GetAddress()]()
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
|
||||
NotifyFoundBle(id, data, address);
|
||||
});
|
||||
}};
|
||||
FetchCredentials(id, scan_request);
|
||||
scan_sessions_.insert(
|
||||
{id, ScanSessionState{
|
||||
.request = scan_request,
|
||||
.callback = std::move(scan_callback),
|
||||
.decoder = AdvertisementDecoder(scan_request),
|
||||
.scanning_session = mediums_->GetBle().StartScanning(
|
||||
scan_request, std::move(callback))}});
|
||||
});
|
||||
[this, id, scan_request,
|
||||
scan_callback =
|
||||
std::move(cb)]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable {
|
||||
ScanningCallback callback = ScanningCallback{
|
||||
.start_scanning_result =
|
||||
[start_scan_client = std::move(scan_callback.start_scan_cb)](
|
||||
absl::Status ble_status) mutable {
|
||||
start_scan_client(ble_status);
|
||||
},
|
||||
.advertisement_found_cb =
|
||||
[this, id](BlePeripheral& peripheral,
|
||||
BleAdvertisementData data) {
|
||||
RunOnServiceControllerThread(
|
||||
"notify-found-ble",
|
||||
[this, id, data = std::move(data),
|
||||
address = peripheral.GetAddress()]()
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
|
||||
NotifyFoundBle(id, data, address);
|
||||
});
|
||||
}};
|
||||
FetchCredentials(id, scan_request);
|
||||
scan_sessions_.insert(
|
||||
{id, ScanSessionState{
|
||||
.request = scan_request,
|
||||
.callback = std::move(scan_callback),
|
||||
.decoder = AdvertisementDecoder(scan_request),
|
||||
.advertisement_filter = AdvertisementFilter(scan_request),
|
||||
.scanning_session = mediums_->GetBle().StartScanning(
|
||||
scan_request, std::move(callback))}});
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -111,7 +113,8 @@ void ScanManager::NotifyFoundBle(ScanSessionId id, BleAdvertisementData data,
|
||||
// This advertisement is not relevant to the current element, skip.
|
||||
return;
|
||||
}
|
||||
if (it->second.decoder.MatchesScanFilter(advert->data_elements)) {
|
||||
if (it->second.advertisement_filter.MatchesScanFilter(
|
||||
advert->data_elements)) {
|
||||
internal::DeviceIdentityMetaData device_identity_metadata;
|
||||
device_identity_metadata.set_bluetooth_mac_address(
|
||||
std::string(remote_address));
|
||||
@@ -132,10 +135,29 @@ void ScanManager::NotifyFoundBle(ScanSessionId id, BleAdvertisementData data,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CredentialSelector> GetCredentialSelectors(
|
||||
const ScanRequest& scan_request) {
|
||||
std::vector<nearby::internal::IdentityType> all_types = {
|
||||
nearby::internal::IdentityType::IDENTITY_TYPE_PRIVATE,
|
||||
nearby::internal::IdentityType::IDENTITY_TYPE_TRUSTED,
|
||||
nearby::internal::IdentityType::IDENTITY_TYPE_PUBLIC,
|
||||
nearby::internal::IdentityType::IDENTITY_TYPE_PROVISIONED};
|
||||
std::vector<CredentialSelector> selectors;
|
||||
for (auto identity_type :
|
||||
(scan_request.identity_types.empty() ? all_types
|
||||
: scan_request.identity_types)) {
|
||||
selectors.push_back(
|
||||
CredentialSelector{.manager_app_id = scan_request.manager_app_id,
|
||||
.account_name = scan_request.account_name,
|
||||
.identity_type = identity_type});
|
||||
}
|
||||
return selectors;
|
||||
}
|
||||
|
||||
void ScanManager::FetchCredentials(ScanSessionId id,
|
||||
const ScanRequest& scan_request) {
|
||||
std::vector<CredentialSelector> credential_selectors =
|
||||
AdvertisementDecoder::GetCredentialSelectors(scan_request);
|
||||
GetCredentialSelectors(scan_request);
|
||||
for (const CredentialSelector& selector : credential_selectors) {
|
||||
// Not fetching for PUBLIC.
|
||||
if (selector.identity_type == internal::IDENTITY_TYPE_UNSPECIFIED ||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "internal/proto/credential.pb.h"
|
||||
#include "presence/data_types.h"
|
||||
#include "presence/implementation/advertisement_decoder.h"
|
||||
#include "presence/implementation/advertisement_filter.h"
|
||||
#include "presence/implementation/credential_manager.h"
|
||||
#include "presence/implementation/mediums/mediums.h"
|
||||
#include "presence/scan_request.h"
|
||||
@@ -66,6 +67,7 @@ class ScanManager {
|
||||
absl::flat_hash_map<IdentityType, std::vector<SharedCredential>>
|
||||
credentials;
|
||||
AdvertisementDecoder decoder;
|
||||
AdvertisementFilter advertisement_filter;
|
||||
std::unique_ptr<ScanningSession> scanning_session;
|
||||
};
|
||||
void NotifyFoundBle(ScanSessionId id, BleAdvertisementData data,
|
||||
|
||||
Reference in New Issue
Block a user