chromium/chromeos/ash/services/device_sync/cryptauth_feature_type.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/services/device_sync/cryptauth_feature_type.h"

#include "ash/constants/ash_features.h"
#include "base/base64url.h"
#include "base/containers/flat_map.h"
#include "base/no_destructor.h"
#include "crypto/sha2.h"

namespace ash {

namespace device_sync {

namespace {

const char kBetterTogetherHostSupportedString[] =
    "BETTER_TOGETHER_HOST_SUPPORTED";
const char kBetterTogetherClientSupportedString[] =
    "BETTER_TOGETHER_CLIENT_SUPPORTED";
const char kEasyUnlockHostSupportedString[] = "EASY_UNLOCK_HOST_SUPPORTED";
const char kEasyUnlockClientSupportedString[] = "EASY_UNLOCK_CLIENT_SUPPORTED";
const char kMagicTetherHostSupportedString[] = "MAGIC_TETHER_HOST_SUPPORTED";
const char kMagicTetherClientSupportedString[] =
    "MAGIC_TETHER_CLIENT_SUPPORTED";
const char kSmsConnectHostSupportedString[] = "SMS_CONNECT_HOST_SUPPORTED";
const char kSmsConnectClientSupportedString[] = "SMS_CONNECT_CLIENT_SUPPORTED";
const char kPhoneHubHostSupportedString[] = "PHONE_HUB_HOST_SUPPORTED";
const char kPhoneHubClientSupportedString[] = "PHONE_HUB_CLIENT_SUPPORTED";
const char kWifiSyncHostSupportedString[] = "WIFI_SYNC_HOST_SUPPORTED";
const char kWifiSyncClientSupportedString[] = "WIFI_SYNC_CLIENT_SUPPORTED";
const char kEcheHostSupportedString[] = "EXO_HOST_SUPPORTED";
const char kEcheClientSupportedString[] = "EXO_CLIENT_SUPPORTED";
const char kPhoneHubCameraRollHostSupportedString[] =
    "PHONE_HUB_CAMERA_ROLL_HOST_SUPPORTED";
const char kPhoneHubCameraRollClientSupportedString[] =
    "PHONE_HUB_CAMERA_ROLL_CLIENT_SUPPORTED";

const char kBetterTogetherHostEnabledString[] = "BETTER_TOGETHER_HOST";
const char kBetterTogetherClientEnabledString[] = "BETTER_TOGETHER_CLIENT";
const char kEasyUnlockHostEnabledString[] = "EASY_UNLOCK_HOST";
const char kEasyUnlockClientEnabledString[] = "EASY_UNLOCK_CLIENT";
const char kMagicTetherHostEnabledString[] = "MAGIC_TETHER_HOST";
const char kMagicTetherClientEnabledString[] = "MAGIC_TETHER_CLIENT";
const char kSmsConnectHostEnabledString[] = "SMS_CONNECT_HOST";
const char kSmsConnectClientEnabledString[] = "SMS_CONNECT_CLIENT";
const char kPhoneHubHostEnabledString[] = "PHONE_HUB_HOST";
const char kPhoneHubClientEnabledString[] = "PHONE_HUB_CLIENT";
const char kWifiSyncHostEnabledString[] = "WIFI_SYNC_HOST";
const char kWifiSyncClientEnabledString[] = "WIFI_SYNC_CLIENT";
const char kEcheHostEnabledString[] = "EXO_HOST";
const char kEcheClientEnabledString[] = "EXO_CLIENT";
const char kPhoneHubCameraRollHostEnabledString[] =
    "PHONE_HUB_CAMERA_ROLL_HOST";
const char kPhoneHubCameraRollClientEnabledString[] =
    "PHONE_HUB_CAMERA_ROLL_CLIENT";

}  // namespace

const base::flat_set<CryptAuthFeatureType>& GetAllCryptAuthFeatureTypes() {
  static const base::NoDestructor<base::flat_set<CryptAuthFeatureType>>
      feature_set([] {
        base::flat_set<CryptAuthFeatureType> feature_set{
            CryptAuthFeatureType::kBetterTogetherHostSupported,
            CryptAuthFeatureType::kBetterTogetherClientSupported,
            CryptAuthFeatureType::kEasyUnlockHostSupported,
            CryptAuthFeatureType::kEasyUnlockClientSupported,
            CryptAuthFeatureType::kMagicTetherHostSupported,
            CryptAuthFeatureType::kMagicTetherClientSupported,
            CryptAuthFeatureType::kSmsConnectHostSupported,
            CryptAuthFeatureType::kSmsConnectClientSupported,
            CryptAuthFeatureType::kBetterTogetherHostEnabled,
            CryptAuthFeatureType::kBetterTogetherClientEnabled,
            CryptAuthFeatureType::kEasyUnlockHostEnabled,
            CryptAuthFeatureType::kEasyUnlockClientEnabled,
            CryptAuthFeatureType::kMagicTetherHostEnabled,
            CryptAuthFeatureType::kMagicTetherClientEnabled,
            CryptAuthFeatureType::kSmsConnectHostEnabled,
            CryptAuthFeatureType::kSmsConnectClientEnabled};
        if (features::IsPhoneHubEnabled()) {
          feature_set.insert(CryptAuthFeatureType::kPhoneHubClientSupported);
          feature_set.insert(CryptAuthFeatureType::kPhoneHubClientEnabled);
          feature_set.insert(CryptAuthFeatureType::kPhoneHubHostSupported);
          feature_set.insert(CryptAuthFeatureType::kPhoneHubHostEnabled);
        }
        if (features::IsWifiSyncAndroidEnabled()) {
          feature_set.insert(CryptAuthFeatureType::kWifiSyncClientSupported);
          feature_set.insert(CryptAuthFeatureType::kWifiSyncClientEnabled);
          feature_set.insert(CryptAuthFeatureType::kWifiSyncHostSupported);
          feature_set.insert(CryptAuthFeatureType::kWifiSyncHostEnabled);
        }
        if (features::IsEcheSWAEnabled()) {
          feature_set.insert(CryptAuthFeatureType::kEcheClientSupported);
          feature_set.insert(CryptAuthFeatureType::kEcheClientEnabled);
          feature_set.insert(CryptAuthFeatureType::kEcheHostSupported);
          feature_set.insert(CryptAuthFeatureType::kEcheHostEnabled);
        }
        if (features::IsPhoneHubCameraRollEnabled()) {
          feature_set.insert(
              CryptAuthFeatureType::kPhoneHubCameraRollClientSupported);
          feature_set.insert(
              CryptAuthFeatureType::kPhoneHubCameraRollClientEnabled);
          feature_set.insert(
              CryptAuthFeatureType::kPhoneHubCameraRollHostSupported);
          feature_set.insert(
              CryptAuthFeatureType::kPhoneHubCameraRollHostEnabled);
        }
        return feature_set;
      }());

  return *feature_set;
}

const base::flat_set<CryptAuthFeatureType>&
GetSupportedCryptAuthFeatureTypes() {
  static const base::NoDestructor<base::flat_set<CryptAuthFeatureType>>
      supported_set([] {
        base::flat_set<CryptAuthFeatureType> supported_set{
            CryptAuthFeatureType::kBetterTogetherHostSupported,
            CryptAuthFeatureType::kBetterTogetherClientSupported,
            CryptAuthFeatureType::kEasyUnlockHostSupported,
            CryptAuthFeatureType::kEasyUnlockClientSupported,
            CryptAuthFeatureType::kMagicTetherHostSupported,
            CryptAuthFeatureType::kMagicTetherClientSupported,
            CryptAuthFeatureType::kSmsConnectHostSupported,
            CryptAuthFeatureType::kSmsConnectClientSupported};
        if (features::IsPhoneHubEnabled()) {
          supported_set.insert(CryptAuthFeatureType::kPhoneHubHostSupported);
          supported_set.insert(CryptAuthFeatureType::kPhoneHubClientSupported);
        }
        if (features::IsWifiSyncAndroidEnabled()) {
          supported_set.insert(CryptAuthFeatureType::kWifiSyncHostSupported);
          supported_set.insert(CryptAuthFeatureType::kWifiSyncClientSupported);
        }
        if (features::IsEcheSWAEnabled()) {
          supported_set.insert(CryptAuthFeatureType::kEcheHostSupported);
          supported_set.insert(CryptAuthFeatureType::kEcheClientSupported);
        }
        if (features::IsPhoneHubCameraRollEnabled()) {
          supported_set.insert(
              CryptAuthFeatureType::kPhoneHubCameraRollHostSupported);
          supported_set.insert(
              CryptAuthFeatureType::kPhoneHubCameraRollClientSupported);
        }
        return supported_set;
      }());

  return *supported_set;
}

const base::flat_set<CryptAuthFeatureType>& GetEnabledCryptAuthFeatureTypes() {
  static const base::NoDestructor<base::flat_set<CryptAuthFeatureType>>
      enabled_set([] {
        base::flat_set<CryptAuthFeatureType> enabled_set{
            CryptAuthFeatureType::kBetterTogetherHostEnabled,
            CryptAuthFeatureType::kBetterTogetherClientEnabled,
            CryptAuthFeatureType::kEasyUnlockHostEnabled,
            CryptAuthFeatureType::kEasyUnlockClientEnabled,
            CryptAuthFeatureType::kMagicTetherHostEnabled,
            CryptAuthFeatureType::kMagicTetherClientEnabled,
            CryptAuthFeatureType::kSmsConnectHostEnabled,
            CryptAuthFeatureType::kSmsConnectClientEnabled};
        if (features::IsPhoneHubEnabled()) {
          enabled_set.insert(CryptAuthFeatureType::kPhoneHubHostEnabled);
          enabled_set.insert(CryptAuthFeatureType::kPhoneHubClientEnabled);
        }
        if (features::IsWifiSyncAndroidEnabled()) {
          enabled_set.insert(CryptAuthFeatureType::kWifiSyncHostEnabled);
          enabled_set.insert(CryptAuthFeatureType::kWifiSyncClientEnabled);
        }
        if (features::IsEcheSWAEnabled()) {
          enabled_set.insert(CryptAuthFeatureType::kEcheHostEnabled);
          enabled_set.insert(CryptAuthFeatureType::kEcheClientEnabled);
        }
        if (features::IsPhoneHubCameraRollEnabled()) {
          enabled_set.insert(
              CryptAuthFeatureType::kPhoneHubCameraRollHostEnabled);
          enabled_set.insert(
              CryptAuthFeatureType::kPhoneHubCameraRollClientEnabled);
        }
        return enabled_set;
      }());

  return *enabled_set;
}

const base::flat_set<std::string>& GetAllCryptAuthFeatureTypeStrings() {
  static const base::NoDestructor<base::flat_set<std::string>>
      feature_string_set([] {
        base::flat_set<std::string> feature_string_set;
        for (CryptAuthFeatureType feature_type : GetAllCryptAuthFeatureTypes())
          feature_string_set.insert(CryptAuthFeatureTypeToString(feature_type));

        return feature_string_set;
      }());
  return *feature_string_set;
}

const char* CryptAuthFeatureTypeToString(CryptAuthFeatureType feature_type) {
  switch (feature_type) {
    case CryptAuthFeatureType::kBetterTogetherHostSupported:
      return kBetterTogetherHostSupportedString;
    case CryptAuthFeatureType::kBetterTogetherHostEnabled:
      return kBetterTogetherHostEnabledString;
    case CryptAuthFeatureType::kBetterTogetherClientSupported:
      return kBetterTogetherClientSupportedString;
    case CryptAuthFeatureType::kBetterTogetherClientEnabled:
      return kBetterTogetherClientEnabledString;
    case CryptAuthFeatureType::kEasyUnlockHostSupported:
      return kEasyUnlockHostSupportedString;
    case CryptAuthFeatureType::kEasyUnlockHostEnabled:
      return kEasyUnlockHostEnabledString;
    case CryptAuthFeatureType::kEasyUnlockClientSupported:
      return kEasyUnlockClientSupportedString;
    case CryptAuthFeatureType::kEasyUnlockClientEnabled:
      return kEasyUnlockClientEnabledString;
    case CryptAuthFeatureType::kMagicTetherHostSupported:
      return kMagicTetherHostSupportedString;
    case CryptAuthFeatureType::kMagicTetherHostEnabled:
      return kMagicTetherHostEnabledString;
    case CryptAuthFeatureType::kMagicTetherClientSupported:
      return kMagicTetherClientSupportedString;
    case CryptAuthFeatureType::kMagicTetherClientEnabled:
      return kMagicTetherClientEnabledString;
    case CryptAuthFeatureType::kSmsConnectHostSupported:
      return kSmsConnectHostSupportedString;
    case CryptAuthFeatureType::kSmsConnectHostEnabled:
      return kSmsConnectHostEnabledString;
    case CryptAuthFeatureType::kSmsConnectClientSupported:
      return kSmsConnectClientSupportedString;
    case CryptAuthFeatureType::kSmsConnectClientEnabled:
      return kSmsConnectClientEnabledString;
    case CryptAuthFeatureType::kPhoneHubHostSupported:
      return kPhoneHubHostSupportedString;
    case CryptAuthFeatureType::kPhoneHubHostEnabled:
      return kPhoneHubHostEnabledString;
    case CryptAuthFeatureType::kPhoneHubClientSupported:
      return kPhoneHubClientSupportedString;
    case CryptAuthFeatureType::kPhoneHubClientEnabled:
      return kPhoneHubClientEnabledString;
    case CryptAuthFeatureType::kWifiSyncHostSupported:
      return kWifiSyncHostSupportedString;
    case CryptAuthFeatureType::kWifiSyncHostEnabled:
      return kWifiSyncHostEnabledString;
    case CryptAuthFeatureType::kWifiSyncClientSupported:
      return kWifiSyncClientSupportedString;
    case CryptAuthFeatureType::kWifiSyncClientEnabled:
      return kWifiSyncClientEnabledString;
    case CryptAuthFeatureType::kEcheHostSupported:
      return kEcheHostSupportedString;
    case CryptAuthFeatureType::kEcheHostEnabled:
      return kEcheHostEnabledString;
    case CryptAuthFeatureType::kEcheClientSupported:
      return kEcheClientSupportedString;
    case CryptAuthFeatureType::kEcheClientEnabled:
      return kEcheClientEnabledString;
    case CryptAuthFeatureType::kPhoneHubCameraRollHostSupported:
      return kPhoneHubCameraRollHostSupportedString;
    case CryptAuthFeatureType::kPhoneHubCameraRollHostEnabled:
      return kPhoneHubCameraRollHostEnabledString;
    case CryptAuthFeatureType::kPhoneHubCameraRollClientSupported:
      return kPhoneHubCameraRollClientSupportedString;
    case CryptAuthFeatureType::kPhoneHubCameraRollClientEnabled:
      return kPhoneHubCameraRollClientEnabledString;
  }
}

std::optional<CryptAuthFeatureType> CryptAuthFeatureTypeFromString(
    const std::string& feature_type_string) {
  if (feature_type_string == kBetterTogetherHostSupportedString)
    return CryptAuthFeatureType::kBetterTogetherHostSupported;
  if (feature_type_string == kBetterTogetherHostEnabledString)
    return CryptAuthFeatureType::kBetterTogetherHostEnabled;
  if (feature_type_string == kBetterTogetherClientSupportedString)
    return CryptAuthFeatureType::kBetterTogetherClientSupported;
  if (feature_type_string == kBetterTogetherClientEnabledString)
    return CryptAuthFeatureType::kBetterTogetherClientEnabled;
  if (feature_type_string == kEasyUnlockHostSupportedString)
    return CryptAuthFeatureType::kEasyUnlockHostSupported;
  if (feature_type_string == kEasyUnlockHostEnabledString)
    return CryptAuthFeatureType::kEasyUnlockHostEnabled;
  if (feature_type_string == kEasyUnlockClientSupportedString)
    return CryptAuthFeatureType::kEasyUnlockClientSupported;
  if (feature_type_string == kEasyUnlockClientEnabledString)
    return CryptAuthFeatureType::kEasyUnlockClientEnabled;
  if (feature_type_string == kMagicTetherHostSupportedString)
    return CryptAuthFeatureType::kMagicTetherHostSupported;
  if (feature_type_string == kMagicTetherHostEnabledString)
    return CryptAuthFeatureType::kMagicTetherHostEnabled;
  if (feature_type_string == kMagicTetherClientSupportedString)
    return CryptAuthFeatureType::kMagicTetherClientSupported;
  if (feature_type_string == kMagicTetherClientEnabledString)
    return CryptAuthFeatureType::kMagicTetherClientEnabled;
  if (feature_type_string == kSmsConnectHostSupportedString)
    return CryptAuthFeatureType::kSmsConnectHostSupported;
  if (feature_type_string == kSmsConnectHostEnabledString)
    return CryptAuthFeatureType::kSmsConnectHostEnabled;
  if (feature_type_string == kSmsConnectClientSupportedString)
    return CryptAuthFeatureType::kSmsConnectClientSupported;
  if (feature_type_string == kSmsConnectClientEnabledString)
    return CryptAuthFeatureType::kSmsConnectClientEnabled;
  if (feature_type_string == kPhoneHubHostSupportedString)
    return CryptAuthFeatureType::kPhoneHubHostSupported;
  if (feature_type_string == kPhoneHubHostEnabledString)
    return CryptAuthFeatureType::kPhoneHubHostEnabled;
  if (feature_type_string == kPhoneHubClientSupportedString)
    return CryptAuthFeatureType::kPhoneHubClientSupported;
  if (feature_type_string == kPhoneHubClientEnabledString)
    return CryptAuthFeatureType::kPhoneHubClientEnabled;
  if (feature_type_string == kWifiSyncHostSupportedString)
    return CryptAuthFeatureType::kWifiSyncHostSupported;
  if (feature_type_string == kWifiSyncHostEnabledString)
    return CryptAuthFeatureType::kWifiSyncHostEnabled;
  if (feature_type_string == kWifiSyncClientSupportedString)
    return CryptAuthFeatureType::kWifiSyncClientSupported;
  if (feature_type_string == kWifiSyncClientEnabledString)
    return CryptAuthFeatureType::kWifiSyncClientEnabled;
  if (feature_type_string == kEcheHostSupportedString)
    return CryptAuthFeatureType::kEcheHostSupported;
  if (feature_type_string == kEcheHostEnabledString)
    return CryptAuthFeatureType::kEcheHostEnabled;
  if (feature_type_string == kEcheClientSupportedString)
    return CryptAuthFeatureType::kEcheClientSupported;
  if (feature_type_string == kEcheClientEnabledString)
    return CryptAuthFeatureType::kEcheClientEnabled;
  if (feature_type_string == kPhoneHubCameraRollHostSupportedString)
    return CryptAuthFeatureType::kPhoneHubCameraRollHostSupported;
  if (feature_type_string == kPhoneHubCameraRollHostEnabledString)
    return CryptAuthFeatureType::kPhoneHubCameraRollHostEnabled;
  if (feature_type_string == kPhoneHubCameraRollClientSupportedString)
    return CryptAuthFeatureType::kPhoneHubCameraRollClientSupported;
  if (feature_type_string == kPhoneHubCameraRollClientEnabledString)
    return CryptAuthFeatureType::kPhoneHubCameraRollClientEnabled;

  return std::nullopt;
}

// Computes the base64url-encoded, SHA-256 8-byte hash of the
// CryptAuthFeatureType string.
std::string CryptAuthFeatureTypeToGcmHash(CryptAuthFeatureType feature_type) {
  std::string hash_8_bytes(8, 0);
  crypto::SHA256HashString(CryptAuthFeatureTypeToString(feature_type),
                           std::data(hash_8_bytes), 8u);

  std::string hash_base64url;
  base::Base64UrlEncode(hash_8_bytes, base::Base64UrlEncodePolicy::OMIT_PADDING,
                        &hash_base64url);

  return hash_base64url;
}

std::optional<CryptAuthFeatureType> CryptAuthFeatureTypeFromGcmHash(
    const std::string& feature_type_hash) {
  // The map from the feature type hash value that CryptAuth sends in GCM
  // messages to the CryptAuthFeatureType enum.
  static const base::NoDestructor<
      base::flat_map<std::string, CryptAuthFeatureType>>
      hash_to_feature_map([] {
        base::flat_map<std::string, CryptAuthFeatureType> hash_to_feature_map;
        for (const CryptAuthFeatureType& feature_type :
             GetAllCryptAuthFeatureTypes()) {
          hash_to_feature_map.insert_or_assign(
              CryptAuthFeatureTypeToGcmHash(feature_type), feature_type);
        }

        return hash_to_feature_map;
      }());

  auto it = hash_to_feature_map->find(feature_type_hash);

  if (it == hash_to_feature_map->end())
    return std::nullopt;

  return it->second;
}

multidevice::SoftwareFeature CryptAuthFeatureTypeToSoftwareFeature(
    CryptAuthFeatureType feature_type) {
  switch (feature_type) {
    case CryptAuthFeatureType::kBetterTogetherHostSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kBetterTogetherHostEnabled:
      return multidevice::SoftwareFeature::kBetterTogetherHost;

    case CryptAuthFeatureType::kBetterTogetherClientSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kBetterTogetherClientEnabled:
      return multidevice::SoftwareFeature::kBetterTogetherClient;

    case CryptAuthFeatureType::kEasyUnlockHostSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kEasyUnlockHostEnabled:
      return multidevice::SoftwareFeature::kSmartLockHost;

    case CryptAuthFeatureType::kEasyUnlockClientSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kEasyUnlockClientEnabled:
      return multidevice::SoftwareFeature::kSmartLockClient;

    case CryptAuthFeatureType::kMagicTetherHostSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kMagicTetherHostEnabled:
      return multidevice::SoftwareFeature::kInstantTetheringHost;

    case CryptAuthFeatureType::kMagicTetherClientSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kMagicTetherClientEnabled:
      return multidevice::SoftwareFeature::kInstantTetheringClient;

    case CryptAuthFeatureType::kSmsConnectHostSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kSmsConnectHostEnabled:
      return multidevice::SoftwareFeature::kMessagesForWebHost;

    case CryptAuthFeatureType::kSmsConnectClientSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kSmsConnectClientEnabled:
      return multidevice::SoftwareFeature::kMessagesForWebClient;

    case CryptAuthFeatureType::kPhoneHubHostSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kPhoneHubHostEnabled:
      return multidevice::SoftwareFeature::kPhoneHubHost;

    case CryptAuthFeatureType::kPhoneHubClientSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kPhoneHubClientEnabled:
      return multidevice::SoftwareFeature::kPhoneHubClient;

    case CryptAuthFeatureType::kWifiSyncHostSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kWifiSyncHostEnabled:
      return multidevice::SoftwareFeature::kWifiSyncHost;

    case CryptAuthFeatureType::kWifiSyncClientSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kWifiSyncClientEnabled:
      return multidevice::SoftwareFeature::kWifiSyncClient;

    case CryptAuthFeatureType::kEcheHostSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kEcheHostEnabled:
      return multidevice::SoftwareFeature::kEcheHost;

    case CryptAuthFeatureType::kEcheClientSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kEcheClientEnabled:
      return multidevice::SoftwareFeature::kEcheClient;

    case CryptAuthFeatureType::kPhoneHubCameraRollHostSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kPhoneHubCameraRollHostEnabled:
      return multidevice::SoftwareFeature::kPhoneHubCameraRollHost;

    case CryptAuthFeatureType::kPhoneHubCameraRollClientSupported:
      [[fallthrough]];
    case CryptAuthFeatureType::kPhoneHubCameraRollClientEnabled:
      return multidevice::SoftwareFeature::kPhoneHubCameraRollClient;
  }
}

CryptAuthFeatureType CryptAuthFeatureTypeFromSoftwareFeature(
    multidevice::SoftwareFeature software_feature) {
  switch (software_feature) {
    case multidevice::SoftwareFeature::kBetterTogetherHost:
      return CryptAuthFeatureType::kBetterTogetherHostEnabled;
    case multidevice::SoftwareFeature::kBetterTogetherClient:
      return CryptAuthFeatureType::kBetterTogetherClientEnabled;
    case multidevice::SoftwareFeature::kSmartLockHost:
      return CryptAuthFeatureType::kEasyUnlockHostEnabled;
    case multidevice::SoftwareFeature::kSmartLockClient:
      return CryptAuthFeatureType::kEasyUnlockClientEnabled;
    case multidevice::SoftwareFeature::kInstantTetheringHost:
      return CryptAuthFeatureType::kMagicTetherHostEnabled;
    case multidevice::SoftwareFeature::kInstantTetheringClient:
      return CryptAuthFeatureType::kMagicTetherClientEnabled;
    case multidevice::SoftwareFeature::kMessagesForWebHost:
      return CryptAuthFeatureType::kSmsConnectHostEnabled;
    case multidevice::SoftwareFeature::kMessagesForWebClient:
      return CryptAuthFeatureType::kSmsConnectClientEnabled;
    case multidevice::SoftwareFeature::kPhoneHubHost:
      return CryptAuthFeatureType::kPhoneHubHostEnabled;
    case multidevice::SoftwareFeature::kPhoneHubClient:
      return CryptAuthFeatureType::kPhoneHubClientEnabled;
    case multidevice::SoftwareFeature::kWifiSyncHost:
      return CryptAuthFeatureType::kWifiSyncHostEnabled;
    case multidevice::SoftwareFeature::kWifiSyncClient:
      return CryptAuthFeatureType::kWifiSyncClientEnabled;
    case multidevice::SoftwareFeature::kEcheHost:
      return CryptAuthFeatureType::kEcheHostEnabled;
    case multidevice::SoftwareFeature::kEcheClient:
      return CryptAuthFeatureType::kEcheClientEnabled;
    case multidevice::SoftwareFeature::kPhoneHubCameraRollHost:
      return CryptAuthFeatureType::kPhoneHubCameraRollHostEnabled;
    case multidevice::SoftwareFeature::kPhoneHubCameraRollClient:
      return CryptAuthFeatureType::kPhoneHubCameraRollClientEnabled;
  }
}

std::ostream& operator<<(std::ostream& stream,
                         CryptAuthFeatureType feature_type) {
  stream << CryptAuthFeatureTypeToString(feature_type);
  return stream;
}

}  // namespace device_sync

}  // namespace ash