// 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 "chromeos/ash/components/network/hidden_network_handler.h"
#include "ash/constants/ash_switches.h"
#include "base/command_line.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/timer/timer.h"
#include "chromeos/ash/components/network/managed_network_configuration_handler.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/network_metadata_store.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "components/device_event_log/device_event_log.h"
namespace ash {
namespace {
constexpr char kRemoveAttemptResultHistogram[] =
"Network.Ash.WiFi.Hidden.RemovalAttempt.Result";
constexpr base::TimeDelta kDefaultOverrideInterval = base::Minutes(1);
constexpr base::TimeDelta kOneDay = base::Days(1);
constexpr base::TimeDelta kInitialDelay = base::Seconds(30);
void OnRemoveConfigurationSuccess(const std::string guid) {
base::UmaHistogramBoolean(kRemoveAttemptResultHistogram, true);
NET_LOG(EVENT) << "Successfully removed wrongly hidden network: " << guid;
}
void OnRemoveConfigurationFailure(const std::string guid,
const std::string& error_name) {
base::UmaHistogramBoolean(kRemoveAttemptResultHistogram, false);
NET_LOG(EVENT) << "Failed to remove wrongly hidden network: " << guid
<< ", error: " << error_name;
}
base::TimeDelta ComputeMigrationInterval() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kHiddenNetworkMigrationInterval)) {
return kOneDay;
}
int interval_in_seconds = -1;
const std::string ascii = command_line->GetSwitchValueASCII(
switches::kHiddenNetworkMigrationInterval);
if (ascii.empty() || !base::StringToInt(ascii, &interval_in_seconds) ||
interval_in_seconds < 1) {
return kDefaultOverrideInterval;
}
return base::Seconds(interval_in_seconds);
}
} // namespace
void HiddenNetworkHandler::Init(
ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
NetworkStateHandler* network_state_handler) {
DCHECK(NetworkHandler::IsInitialized());
network_state_handler_ = network_state_handler;
managed_network_configuration_handler_ =
managed_network_configuration_handler;
}
void HiddenNetworkHandler::SetNetworkMetadataStore(
NetworkMetadataStore* network_metadata_store) {
if (network_metadata_store_) {
initial_delay_timer_.Stop();
daily_event_timer_.Stop();
}
network_metadata_store_ = network_metadata_store;
if (!network_metadata_store_) {
return;
}
initial_delay_timer_.Start(
FROM_HERE, kInitialDelay,
base::BindOnce(&HiddenNetworkHandler::CleanHiddenNetworks,
base::Unretained(this)));
daily_event_timer_.Start(
FROM_HERE, ComputeMigrationInterval(),
base::BindRepeating(&HiddenNetworkHandler::CleanHiddenNetworks,
base::Unretained(this)));
}
void HiddenNetworkHandler::CleanHiddenNetworks() {
NetworkStateHandler::NetworkStateList state_list;
network_state_handler_->GetNetworkListByType(NetworkTypePattern::WiFi(),
/*configured_only=*/true,
/*visible_only=*/false,
/*limit=*/0, &state_list);
size_t remove_network_attempts = 0;
for (const NetworkState* state : state_list) {
if (!state->hidden_ssid() || state->IsManagedByPolicy()) {
continue;
}
// The last connected timestamp for a network will be zero if the network
// has never been connected to.
if (!network_metadata_store_->GetLastConnectedTimestamp(state->guid())
.is_zero()) {
continue;
}
// The WiFi timestamp will return UnixEpoch() if the network has
// existed for more than two weeks.
if (network_metadata_store_->UpdateAndRetrieveWiFiTimestamp(
state->guid()) != base::Time::UnixEpoch()) {
continue;
}
NET_LOG(EVENT) << "Attempting to remove network configuration with GUID: "
<< state->guid();
managed_network_configuration_handler_->RemoveConfiguration(
state->path(),
base::BindOnce(&OnRemoveConfigurationSuccess, state->guid()),
base::BindOnce(&OnRemoveConfigurationFailure, state->guid()));
remove_network_attempts++;
}
base::UmaHistogramCounts100("Network.Ash.WiFi.Hidden.RemovalAttempt",
remove_network_attempts);
}
} // namespace ash