blob: 5f1fdea6f63dd7e9f9528e513d1b431efed3a10f [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "quick_start_decoder.h"
#include "base/base64.h"
#include "base/json/json_writer.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/values.h"
#include "chromeos/ash/components/quick_start/quick_start_message.h"
#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-forward.h"
#include "chromeos/ash/services/nearby/public/mojom/quick_start_decoder_types.mojom-shared.h"
#include "components/cbor/values.h"
#include "components/cbor/writer.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash::quick_start {
using QuickStartMessage = ash::quick_start::QuickStartMessage;
namespace {
constexpr char kCredentialIdKey[] = "id";
constexpr char kEntitiyIdMapKey[] = "id";
constexpr char kDeviceDetailsKey[] = "deviceDetails";
constexpr char kCryptauthDeviceIdKey[] = "cryptauthDeviceId";
constexpr char kExampleCryptauthDeviceId[] = "helloworld";
constexpr char kFidoMessageKey[] = "fidoMessage";
constexpr uint8_t kSuccess = 0x00;
constexpr uint8_t kCtap2ErrInvalidCBOR = 0x12;
constexpr int kCborDecoderErrorInvalidUtf8 = 6;
constexpr int kCborDecoderNoError = 0;
constexpr int kCborDecoderUnknownError = 14;
// Key in Wifi Information response containing information about the wifi
// network as a JSON Dictionary.
constexpr char kWifiNetworkInformationKey[] = "wifi_network";
// Key in wifi_network dictionary containing the SSID of the wifi network.
constexpr char kWifiNetworkSsidKey[] = "wifi_ssid";
// Key in wifi_network dictionary containing the password of the wifi network.
constexpr char kWifiNetworkPasswordKey[] = "wifi_pre_shared_key";
// Key in wifi_network dictionary containing the security type of the wifi
// network.
constexpr char kWifiNetworkSecurityTypeKey[] = "wifi_security_type";
// Key in wifi_network dictionary containing if the wifi network is hidden.
constexpr char kWifiNetworkIsHiddenKey[] = "wifi_hidden_ssid";
// Key in Notify Source of Update response containing bool acknowledging the
// message.
constexpr char kNotifySourceOfUpdateAckKey[] = "forced_update_acknowledged";
// Key in UserVerificationResult containing the result
constexpr char kUserVerificationResultKey[] = "user_verification_result";
// Key in UserVerificationResult indicating if this is the first user
// verification
constexpr char kIsFirstUserVerificationKey[] = "is_first_user_verification";
// Key in UserVerificationRequested indicating if user verification was
// requested
constexpr char kAwaitingUserVerificationKey[] = "await_user_verification";
constexpr int kUserVerifiedStatusCode = 0;
const std::vector<uint8_t> kValidCredentialId = {0x01, 0x02, 0x03};
const std::vector<uint8_t> kValidAuthData = {0x02, 0x03, 0x04};
const std::vector<uint8_t> kValidSignature = {0x03, 0x04, 0x05};
using GetAssertionStatus = mojom::GetAssertionResponse::GetAssertionStatus;
std::vector<uint8_t> BuildEncodedResponseData(
std::vector<uint8_t> credential_id,
std::vector<uint8_t> auth_data,
std::vector<uint8_t> signature,
std::vector<uint8_t> user_id,
uint8_t status) {
cbor::Value::MapValue cbor_map;
cbor::Value::MapValue credential_map;
credential_map[cbor::Value(kCredentialIdKey)] = cbor::Value(credential_id);
cbor_map[cbor::Value(1)] = cbor::Value(credential_map);
cbor_map[cbor::Value(2)] = cbor::Value(auth_data);
cbor_map[cbor::Value(3)] = cbor::Value(signature);
cbor::Value::MapValue user_map;
user_map[cbor::Value(kEntitiyIdMapKey)] = cbor::Value(user_id);
cbor_map[cbor::Value(4)] = cbor::Value(user_map);
absl::optional<std::vector<uint8_t>> cbor_bytes =
cbor::Writer::Write(cbor::Value(std::move(cbor_map)));
DCHECK(cbor_bytes);
std::vector<uint8_t> response_bytes = std::move(*cbor_bytes);
// Add the status byte to the beginning of this now fully encoded cbor bytes
// vector.
response_bytes.insert(response_bytes.begin(), status);
return response_bytes;
}
} // namespace
class QuickStartDecoderTest : public testing::Test {
public:
QuickStartDecoderTest() {
QuickStartMessage::DisableSandboxCheckForTesting();
decoder_ = std::make_unique<QuickStartDecoder>(
remote_.BindNewPipeAndPassReceiver(), base::DoNothing());
}
mojom::GetAssertionResponsePtr DoDecodeGetAssertionResponse(
const std::vector<uint8_t>& data) {
return decoder_->DoDecodeGetAssertionResponse(data);
}
void DoDecodeBootstrapConfigurations(
const std::vector<uint8_t>& data,
QuickStartDecoder::DecodeBootstrapConfigurationsCallback callback) {
return decoder_->DoDecodeBootstrapConfigurations(data, std::move(callback));
}
void DoDecodeWifiCredentialsResponse(
QuickStartMessage* message,
QuickStartDecoder::DecodeWifiCredentialsResponseCallback callback) {
return decoder_->DoDecodeWifiCredentialsResponse(
ConvertMessageToBytes(message), std::move(callback));
}
absl::optional<bool> DoDecodeNotifySourceOfUpdateResponse(
QuickStartMessage* message) {
return decoder_->DoDecodeNotifySourceOfUpdateResponse(
ConvertMessageToBytes(message));
}
absl::optional<std::vector<uint8_t>> ExtractFidoDataFromJsonResponse(
const std::vector<uint8_t>& data) {
return decoder_->ExtractFidoDataFromJsonResponse(data);
}
QuickStartDecoder* decoder() const { return decoder_.get(); }
protected:
base::test::SingleThreadTaskEnvironment task_environment_;
mojo::Remote<mojom::QuickStartDecoder> remote_;
std::unique_ptr<QuickStartDecoder> decoder_;
std::vector<uint8_t> ConvertMessageToBytes(QuickStartMessage* message) {
std::string json;
base::JSONWriter::Write(*message->GenerateEncodedMessage(), &json);
std::vector<uint8_t> payload(json.begin(), json.end());
return payload;
}
std::vector<uint8_t> BuildSecondDeviceAuthPayload(std::vector<uint8_t> data) {
// Package FIDO GetAssertion command bytes into MessagePayload.
QuickStartMessage message(QuickStartMessageType::kSecondDeviceAuthPayload);
message.GetPayload()->Set(kFidoMessageKey, base::Base64Encode(data));
return ConvertMessageToBytes(&message);
}
};
TEST_F(QuickStartDecoderTest, ConvertCtapDeviceResponseCodeTest_InRange) {
std::vector<uint8_t> credential_id = {0x01, 0x02, 0x03};
std::vector<uint8_t> auth_data = {};
std::vector<uint8_t> signature = {};
std::vector<uint8_t> user_id = {};
// kCtap2ErrActionTimeout
uint8_t status_code = 0x3A;
std::vector<uint8_t> data = BuildEncodedResponseData(
credential_id, auth_data, signature, user_id, status_code);
std::vector<uint8_t> message = BuildSecondDeviceAuthPayload(data);
mojom::GetAssertionResponsePtr response =
DoDecodeGetAssertionResponse(std::move(message));
EXPECT_EQ(response->ctap_device_response_code, status_code);
EXPECT_EQ(response->status, GetAssertionStatus::kCtapResponseError);
EXPECT_TRUE(response->credential_id.empty());
}
TEST_F(QuickStartDecoderTest, ConvertCtapDeviceRespnoseCodeTest_OutOfRange) {
std::vector<uint8_t> auth_data = {};
std::vector<uint8_t> signature = {};
std::vector<uint8_t> user_id = {};
// Unmapped error byte
uint8_t status_code = 0x07;
std::vector<uint8_t> data = BuildEncodedResponseData(
kValidCredentialId, auth_data, signature, user_id, status_code);
std::vector<uint8_t> message = BuildSecondDeviceAuthPayload(data);
mojom::GetAssertionResponsePtr response =
DoDecodeGetAssertionResponse(std::move(message));
EXPECT_EQ(response->ctap_device_response_code, status_code);
EXPECT_EQ(response->status, GetAssertionStatus::kCtapResponseError);
EXPECT_TRUE(response->credential_id.empty());
}
TEST_F(QuickStartDecoderTest, CborDecodeGetAssertionResponse_DecoderError) {
// UTF-8 validation should not stop at the first NUL character in the string.
// That is, a string with an invalid byte sequence should fail UTF-8
// validation even if the invalid character is located after one or more NUL
// characters. Here, 0xA6 is an unexpected continuation byte.
// Include 0x00 as first byte for kSuccess CtapDeviceResponse status.
std::vector<uint8_t> data = {0x00, 0x63, 0x00, 0x00, 0xA6};
std::vector<uint8_t> message = BuildSecondDeviceAuthPayload(data);
int expected = kCborDecoderErrorInvalidUtf8;
mojom::GetAssertionResponsePtr response =
DoDecodeGetAssertionResponse(std::move(message));
EXPECT_EQ(response->cbor_decoder_error, expected);
EXPECT_EQ(response->status, GetAssertionStatus::kCborDecoderError);
EXPECT_TRUE(response->credential_id.empty());
}
TEST_F(QuickStartDecoderTest, DecodeGetAssertionResponse_ResponseIsNotJson) {
std::vector<uint8_t> data;
uint8_t expected_device_response_code = kCtap2ErrInvalidCBOR;
int expected_decoder_error = kCborDecoderUnknownError;
mojom::GetAssertionResponsePtr response =
DoDecodeGetAssertionResponse(std::move(data));
EXPECT_EQ(response->ctap_device_response_code, expected_device_response_code);
EXPECT_EQ(response->cbor_decoder_error, expected_decoder_error);
EXPECT_EQ(response->status, GetAssertionStatus::kMessagePayloadParseError);
EXPECT_TRUE(response->credential_id.empty());
}
TEST_F(QuickStartDecoderTest, DecodeGetAssertionResponse_EmptyResponse) {
std::vector<uint8_t> data{};
uint8_t expected_device_response_code = kCtap2ErrInvalidCBOR;
int expected_decoder_error = kCborDecoderUnknownError;
std::vector<uint8_t> message = BuildSecondDeviceAuthPayload(data);
mojom::GetAssertionResponsePtr response =
DoDecodeGetAssertionResponse(std::move(message));
EXPECT_EQ(response->ctap_device_response_code, expected_device_response_code);
EXPECT_EQ(response->cbor_decoder_error, expected_decoder_error);
EXPECT_EQ(response->status, GetAssertionStatus::kCtapResponseError);
EXPECT_TRUE(response->credential_id.empty());
}
TEST_F(QuickStartDecoderTest, DecodeGetAssertionResponse_OnlyStatusCode) {
std::vector<uint8_t> data{0x00};
uint8_t expected_device_response_code = kCtap2ErrInvalidCBOR;
int expected_decoder_error = kCborDecoderUnknownError;
std::vector<uint8_t> message = BuildSecondDeviceAuthPayload(data);
mojom::GetAssertionResponsePtr response =
DoDecodeGetAssertionResponse(std::move(message));
EXPECT_EQ(response->ctap_device_response_code, expected_device_response_code);
EXPECT_EQ(response->cbor_decoder_error, expected_decoder_error);
EXPECT_EQ(response->status, GetAssertionStatus::kCtapResponseError);
EXPECT_TRUE(response->credential_id.empty());
}
TEST_F(QuickStartDecoderTest, DecodeGetAssertionResponse_Valid) {
std::string expected_credential_id(kValidCredentialId.begin(),
kValidCredentialId.end());
std::string email = "testcase@google.com";
std::vector<uint8_t> user_id(email.begin(), email.end());
// kSuccess
uint8_t status = kSuccess;
std::vector<uint8_t> data = BuildEncodedResponseData(
kValidCredentialId, kValidAuthData, kValidSignature, user_id, status);
std::vector<uint8_t> message = BuildSecondDeviceAuthPayload(data);
mojom::GetAssertionResponsePtr response =
DoDecodeGetAssertionResponse(std::move(message));
EXPECT_EQ(response->ctap_device_response_code, kSuccess);
EXPECT_EQ(response->cbor_decoder_error, kCborDecoderNoError);
EXPECT_EQ(response->status, GetAssertionStatus::kSuccess);
EXPECT_EQ(response->credential_id, expected_credential_id);
EXPECT_EQ(response->email, email);
EXPECT_EQ(response->auth_data, kValidAuthData);
EXPECT_EQ(response->signature, kValidSignature);
}
TEST_F(QuickStartDecoderTest, DecodeGetAssertionResponse_ValidEmptyValues) {
std::vector<uint8_t> credential_id = {};
std::string expected_credential_id(credential_id.begin(),
credential_id.end());
std::string email = "";
std::vector<uint8_t> user_id(email.begin(), email.end());
// kSuccess
uint8_t status = kSuccess;
std::vector<uint8_t> data = BuildEncodedResponseData(
credential_id, kValidAuthData, kValidSignature, user_id, status);
std::vector<uint8_t> message = BuildSecondDeviceAuthPayload(data);
mojom::GetAssertionResponsePtr response =
DoDecodeGetAssertionResponse(std::move(message));
EXPECT_EQ(response->ctap_device_response_code, kSuccess);
EXPECT_EQ(response->cbor_decoder_error, kCborDecoderNoError);
EXPECT_EQ(response->status, GetAssertionStatus::kSuccess);
EXPECT_EQ(response->credential_id, expected_credential_id);
EXPECT_EQ(response->email, email);
EXPECT_EQ(response->auth_data, kValidAuthData);
EXPECT_EQ(response->signature, kValidSignature);
}
TEST_F(QuickStartDecoderTest,
DecodeBootstrapConfigurations_EmptyMessagePayload) {
QuickStartMessage message(QuickStartMessageType::kBootstrapConfigurations);
base::test::TestFuture<
::ash::quick_start::mojom::BootstrapConfigurationsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeBootstrapConfigurations(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
DecodeBootstrapConfigurations_EmptyBootstrapConfigurations) {
QuickStartMessage message(QuickStartMessageType::kBootstrapConfigurations);
base::test::TestFuture<
::ash::quick_start::mojom::BootstrapConfigurationsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeBootstrapConfigurations(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
DecodeBootstrapConfigurations_EmptyDeviceDetails) {
base::Value::Dict device_details;
QuickStartMessage message(QuickStartMessageType::kBootstrapConfigurations);
message.GetPayload()->Set(kDeviceDetailsKey, std::move(device_details));
base::test::TestFuture<
::ash::quick_start::mojom::BootstrapConfigurationsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeBootstrapConfigurations(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_FALSE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<0>()->cryptauth_device_id, "");
EXPECT_EQ(future.Get<1>(), absl::nullopt);
}
TEST_F(QuickStartDecoderTest,
DecodeBootstrapConfigurations_EmptyCryptauthDeviceId) {
base::Value::Dict device_details;
device_details.Set(kCryptauthDeviceIdKey, "");
QuickStartMessage message(QuickStartMessageType::kBootstrapConfigurations);
message.GetPayload()->Set(kDeviceDetailsKey, std::move(device_details));
base::test::TestFuture<
::ash::quick_start::mojom::BootstrapConfigurationsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeBootstrapConfigurations(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_FALSE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<0>()->cryptauth_device_id, "");
EXPECT_EQ(future.Get<1>(), absl::nullopt);
}
TEST_F(QuickStartDecoderTest,
DecodeBootstrapConfigurations_ValidBootstrapConfigurations) {
base::Value::Dict device_details;
device_details.Set(kCryptauthDeviceIdKey, kExampleCryptauthDeviceId);
QuickStartMessage message(QuickStartMessageType::kBootstrapConfigurations);
message.GetPayload()->Set(kDeviceDetailsKey, std::move(device_details));
base::test::TestFuture<
::ash::quick_start::mojom::BootstrapConfigurationsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeBootstrapConfigurations(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_FALSE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<0>()->cryptauth_device_id, kExampleCryptauthDeviceId);
EXPECT_EQ(future.Get<1>(), absl::nullopt);
}
TEST_F(QuickStartDecoderTest, ExtractFidoDataFromValidJsonResponse) {
// Build a FIDO Message
std::string expected_credential_id(kValidCredentialId.begin(),
kValidCredentialId.end());
std::string email = "testcase@google.com";
std::vector<uint8_t> user_id(email.begin(), email.end());
// kSuccess
uint8_t status = kSuccess;
std::vector<uint8_t> data = BuildEncodedResponseData(
kValidCredentialId, kValidAuthData, kValidSignature, user_id, status);
std::vector<uint8_t> payload = BuildSecondDeviceAuthPayload(data);
absl::optional<std::vector<uint8_t>> result =
ExtractFidoDataFromJsonResponse(payload);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(result.value(), data);
}
TEST_F(QuickStartDecoderTest,
ExtractFidoDataFromJsonResponseFailsIfFidoDataMissingFromPayload) {
QuickStartMessage message(QuickStartMessageType::kSecondDeviceAuthPayload);
absl::optional<std::vector<uint8_t>> result =
ExtractFidoDataFromJsonResponse(ConvertMessageToBytes(&message));
EXPECT_FALSE(result.has_value());
}
TEST_F(QuickStartDecoderTest,
ExtractFidoDataFromJsonResponseFailsIfSecondDeviceAuthPayloadMissing) {
base::Value::Dict message_payload;
std::string json_serialized_payload;
base::JSONWriter::Write(message_payload, &json_serialized_payload);
std::vector<uint8_t> response_bytes(json_serialized_payload.begin(),
json_serialized_payload.end());
absl::optional<std::vector<uint8_t>> result =
ExtractFidoDataFromJsonResponse(response_bytes);
EXPECT_FALSE(result.has_value());
}
TEST_F(QuickStartDecoderTest,
ExtractFidoDataFromJsonResponseFailsIfPayloadIsNotJsonDictionary) {
std::string message_payload = "This is a JSON string";
std::string json_serialized_payload;
base::JSONWriter::Write(message_payload, &json_serialized_payload);
std::vector<uint8_t> response_bytes(json_serialized_payload.begin(),
json_serialized_payload.end());
absl::optional<std::vector<uint8_t>> result =
ExtractFidoDataFromJsonResponse(response_bytes);
EXPECT_FALSE(result.has_value());
}
TEST_F(QuickStartDecoderTest,
ExtractFidoDataFromJsonResponseFailsIfResponseIsNotJson) {
// This is just a random payload that is not a valid JSON.
std::vector<uint8_t> random_payload = {0x01, 0x02, 0x03};
absl::optional<std::vector<uint8_t>> result =
ExtractFidoDataFromJsonResponse(random_payload);
EXPECT_FALSE(result.has_value());
}
TEST_F(QuickStartDecoderTest, ExtractWifiInformationPassesOnValidResponse) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkPasswordKey, "password");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
ASSERT_FALSE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<0>()->ssid, "ssid");
EXPECT_EQ(future.Get<0>()->password, "password");
EXPECT_EQ(future.Get<0>()->security_type, mojom::WifiSecurityType::kPSK);
EXPECT_TRUE(future.Get<0>()->is_hidden);
EXPECT_EQ(future.Get<1>(), absl::nullopt);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationPassesWhenMissingPasswordAndOpenNetwork) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "Open");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
ASSERT_FALSE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<0>()->password, absl::nullopt);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenPasswordFoundAndOpenNetwork) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkPasswordKey, "password");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "Open");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenMissingPasswordAndNotOpenNetwork_PSK) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenMissingPasswordAndNotOpenNetwork_WEP) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "WEP");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenMissingPasswordAndNotOpenNetwork_EAP) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "EAP");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenMissingPasswordAndNotOpenNetwork_OWE) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "OWE");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenMissingPasswordAndNotOpenNetwork_SAE) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "SAE");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest, ExtractWifiInformationFailsIfSSIDLengthIsZero) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "");
wifi_information.Set(kWifiNetworkPasswordKey, "password");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest, ExtractWifiInformationFailsWhenMissingSSID) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkPasswordKey, "password");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenMissingSecurityType) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkPasswordKey, "password");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsOnInvalidSecurityType) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkPasswordKey, "password");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "invalid");
wifi_information.Set(kWifiNetworkIsHiddenKey, true);
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenMissingHiddenStatus) {
base::Value::Dict wifi_information;
wifi_information.Set(kWifiNetworkSsidKey, "ssid");
wifi_information.Set(kWifiNetworkPasswordKey, "password");
wifi_information.Set(kWifiNetworkSecurityTypeKey, "PSK");
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kWifiNetworkInformationKey,
std::move(wifi_information));
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
ExtractWifiInformationFailsWhenMissingWifiInformation) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
base::test::TestFuture<
::ash::quick_start::mojom::WifiCredentialsPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
DoDecodeWifiCredentialsResponse(&message, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest, DecodeNotifySourceOfUpdateResponseSuccess) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kNotifySourceOfUpdateAckKey, true);
EXPECT_TRUE(DoDecodeNotifySourceOfUpdateResponse(&message).has_value());
EXPECT_TRUE(DoDecodeNotifySourceOfUpdateResponse(&message).value());
message.GetPayload()->Set(kNotifySourceOfUpdateAckKey, false);
EXPECT_TRUE(DoDecodeNotifySourceOfUpdateResponse(&message).has_value());
EXPECT_FALSE(DoDecodeNotifySourceOfUpdateResponse(&message).value());
}
TEST_F(QuickStartDecoderTest,
DecodeNotifySourceOfUpdateResponseFailsWhenMissingValue) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
EXPECT_FALSE(DoDecodeNotifySourceOfUpdateResponse(&message).has_value());
}
TEST_F(QuickStartDecoderTest, DecodeUserVerificationResultSucceeds) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kUserVerificationResultKey,
kUserVerifiedStatusCode);
message.GetPayload()->Set(kIsFirstUserVerificationKey, true);
base::test::TestFuture<
::ash::quick_start::mojom::UserVerificationResponsePtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
decoder()->DecodeUserVerificationResult(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_TRUE(future.IsReady());
ASSERT_FALSE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<0>().get()->result,
mojom::UserVerificationResult::kUserVerified);
EXPECT_TRUE(future.Get<0>().get()->is_first_user_verification);
EXPECT_EQ(future.Get<1>(), absl::nullopt);
}
TEST_F(QuickStartDecoderTest,
DecodeUserVerificationResultFailsIfMessageIsNotJson) {
std::vector<uint8_t> message;
base::test::TestFuture<
::ash::quick_start::mojom::UserVerificationResponsePtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
decoder()->DecodeUserVerificationResult(message, future.GetCallback());
EXPECT_TRUE(future.IsReady());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kUnableToReadAsJSON);
}
TEST_F(QuickStartDecoderTest,
DecodeUserVerificationResultFailsIfMissingStatusCode) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kIsFirstUserVerificationKey, true);
base::test::TestFuture<
::ash::quick_start::mojom::UserVerificationResponsePtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
decoder()->DecodeUserVerificationResult(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_TRUE(future.IsReady());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
DecodeUserVerificationResultFailsIfMissingIsFirstUserVerification) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kUserVerificationResultKey,
kUserVerifiedStatusCode);
base::test::TestFuture<
::ash::quick_start::mojom::UserVerificationResponsePtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
decoder()->DecodeUserVerificationResult(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_TRUE(future.IsReady());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest,
DecodeUserVerificationResultFailsIfStatusCodeIsInvalid) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kUserVerificationResultKey, 5);
base::test::TestFuture<
::ash::quick_start::mojom::UserVerificationResponsePtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
decoder()->DecodeUserVerificationResult(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_TRUE(future.IsReady());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
TEST_F(QuickStartDecoderTest, DecodeUserVerificationRequestSucceeds) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
message.GetPayload()->Set(kAwaitingUserVerificationKey, true);
base::test::TestFuture<
::ash::quick_start::mojom::UserVerificationRequestedPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
decoder()->DecodeUserVerificationRequested(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_TRUE(future.IsReady());
ASSERT_FALSE(future.Get<0>().is_null());
EXPECT_TRUE(future.Get<0>().get()->is_awaiting_user_verification);
EXPECT_EQ(future.Get<1>(), absl::nullopt);
}
TEST_F(QuickStartDecoderTest, DecodeUserVerificationRequestFailsIfKeyMissing) {
QuickStartMessage message(QuickStartMessageType::kQuickStartPayload);
base::test::TestFuture<
::ash::quick_start::mojom::UserVerificationRequestedPtr,
absl::optional<::ash::quick_start::mojom::QuickStartDecoderError>>
future;
decoder()->DecodeUserVerificationRequested(ConvertMessageToBytes(&message),
future.GetCallback());
EXPECT_TRUE(future.IsReady());
EXPECT_TRUE(future.Get<0>().is_null());
EXPECT_EQ(future.Get<1>(),
mojom::QuickStartDecoderError::kMessageDoesNotMatchSchema);
}
} // namespace ash::quick_start