| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/printing/ipp_client_info_calculator.h" |
| |
| #include <cstdint> |
| #include <memory> |
| |
| #include "base/check.h" |
| #include "base/functional/bind.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_piece.h" |
| #include "base/system/sys_info.h" |
| #include "chrome/browser/ash/policy/core/device_attributes.h" |
| #include "chrome/browser/ash/policy/core/device_attributes_impl.h" |
| #include "chrome/browser/ash/settings/cros_settings.h" |
| #include "chromeos/ash/components/settings/cros_settings_names.h" |
| #include "components/version_info/version_info.h" |
| #include "printing/mojom/print.mojom.h" |
| |
| namespace ash::printing { |
| |
| namespace { |
| |
| using ::printing::mojom::IppClientInfo; |
| using ::printing::mojom::IppClientInfoPtr; |
| |
| constexpr char kOsInfoClientName[] = "ChromeOS"; |
| constexpr char kDeviceDirectoryApiIdPlaceholder[] = |
| "${DEVICE_DIRECTORY_API_ID}"; |
| constexpr char kDeviceSerialNumberPlaceholder[] = "${DEVICE_SERIAL_NUMBER}"; |
| constexpr char kDeviceAssetIdPlaceholder[] = "${DEVICE_ASSET_ID}"; |
| constexpr char kDeviceAnnotatedLocationPlaceholder[] = |
| "${DEVICE_ANNOTATED_LOCATION}"; |
| |
| // Replace device variables found in `str` with the provided values. |
| std::string ReplaceDeviceVariables(std::string template_with_vars, |
| base::StringPiece api_id, |
| base::StringPiece serial, |
| base::StringPiece asset_id, |
| base::StringPiece location) { |
| base::ReplaceSubstringsAfterOffset(&template_with_vars, 0, |
| kDeviceDirectoryApiIdPlaceholder, api_id); |
| base::ReplaceSubstringsAfterOffset(&template_with_vars, 0, |
| kDeviceSerialNumberPlaceholder, serial); |
| base::ReplaceSubstringsAfterOffset(&template_with_vars, 0, |
| kDeviceAssetIdPlaceholder, asset_id); |
| base::ReplaceSubstringsAfterOffset( |
| &template_with_vars, 0, kDeviceAnnotatedLocationPlaceholder, location); |
| return template_with_vars; |
| } |
| |
| class IppClientInfoCalculatorImpl : public IppClientInfoCalculator { |
| public: |
| IppClientInfoCalculatorImpl( |
| std::unique_ptr<policy::DeviceAttributes> device_attributes, |
| const std::string& chrome_milestone) |
| : cros_settings_(CrosSettings::Get()), |
| device_attributes_(std::move(device_attributes)) { |
| // Calculate the initial client-info values. The admin-configured |
| // `client-info` value with device information can change later if the |
| // `kDevicePrintingClientNameTemplate` setting changes. |
| CalculateClientInfoWithDeviceValues(); |
| CalculateClientInfoWithOSVersion(chrome_milestone); |
| |
| // Recalculate `client-info` with device information when |
| // `kDevicePrintingClientNameTemplate` setting changes. |
| // base::Unretained(this) is safe here because the subscription is scoped to |
| // the lifetime of `this` already. |
| auto callback = base::BindRepeating( |
| &IppClientInfoCalculatorImpl::CalculateClientInfoWithDeviceValues, |
| base::Unretained(this)); |
| client_name_template_subscription_ = |
| CrosSettings::Get()->AddSettingsObserver( |
| kDevicePrintingClientNameTemplate, std::move(callback)); |
| } |
| |
| private: |
| IppClientInfoPtr GetOsInfo() const override { |
| DCHECK(os_info_); |
| return os_info_.Clone(); |
| } |
| |
| IppClientInfoPtr GetDeviceInfo() const override { |
| return device_info_.Clone(); |
| } |
| |
| void CalculateClientInfoWithDeviceValues() { |
| std::string client_name_template = GetClientNameTemplateFromCrosSettings(); |
| if (client_name_template.empty()) { |
| return; |
| } |
| std::string serial = device_attributes_->GetDeviceSerialNumber(); |
| std::string asset_id = device_attributes_->GetDeviceAssetID(); |
| std::string location = device_attributes_->GetDeviceAnnotatedLocation(); |
| std::string directory_api_id = device_attributes_->GetDirectoryApiID(); |
| std::string client_name = |
| ReplaceDeviceVariables(std::move(client_name_template), |
| directory_api_id, serial, asset_id, location); |
| device_info_ = IppClientInfo::New(IppClientInfo::ClientType::kOther, |
| std::move(client_name), |
| /*client_patches=*/absl::nullopt, |
| /*client_string_version=*/std::string(), |
| /*client_version=*/absl::nullopt); |
| } |
| |
| void CalculateClientInfoWithOSVersion(const std::string& chrome_milestone) { |
| DCHECK(base::SysInfo::IsRunningOnChromeOS()); |
| os_info_ = IppClientInfo::New( |
| IppClientInfo::ClientType::kOperatingSystem, kOsInfoClientName, |
| base::SysInfo::OperatingSystemVersion(), chrome_milestone, |
| /*client_version=*/absl::nullopt); |
| } |
| |
| std::string GetClientNameTemplateFromCrosSettings() { |
| std::string client_name_template; |
| cros_settings_->GetString(kDevicePrintingClientNameTemplate, |
| &client_name_template); |
| return client_name_template; |
| } |
| |
| raw_ptr<const CrosSettings> cros_settings_; |
| std::unique_ptr<policy::DeviceAttributes> device_attributes_; |
| IppClientInfoPtr device_info_; |
| IppClientInfoPtr os_info_; |
| base::CallbackListSubscription client_name_template_subscription_; |
| }; |
| |
| } // namespace |
| |
| std::unique_ptr<IppClientInfoCalculator> IppClientInfoCalculator::Create() { |
| return std::make_unique<IppClientInfoCalculatorImpl>( |
| std::make_unique<policy::DeviceAttributesImpl>(), |
| version_info::GetMajorVersionNumber()); |
| } |
| |
| std::unique_ptr<IppClientInfoCalculator> |
| IppClientInfoCalculator::CreateForTesting( |
| std::unique_ptr<policy::DeviceAttributes> device_attributes, |
| const std::string& chrome_milestone) { |
| return std::make_unique<IppClientInfoCalculatorImpl>( |
| std::move(device_attributes), chrome_milestone); |
| } |
| |
| } // namespace ash::printing |