Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 1 | // Copyright 2024 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "components/manta/scanner_provider.h" |
| 6 | |
| 7 | #include <memory> |
| 8 | #include <string> |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 9 | #include <utility> |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 10 | |
| 11 | #include "base/check.h" |
| 12 | #include "base/functional/bind.h" |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 13 | #include "base/strings/strcat.h" |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 14 | #include "base/time/time.h" |
| 15 | #include "components/endpoint_fetcher/endpoint_fetcher.h" |
| 16 | #include "components/manta/base_provider.h" |
| 17 | #include "components/manta/features.h" |
| 18 | #include "components/manta/manta_service_callbacks.h" |
| 19 | #include "components/manta/manta_status.h" |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 20 | #include "components/manta/proto/common.pb.h" |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 21 | #include "components/manta/proto/manta.pb.h" |
| 22 | #include "components/manta/proto/scanner.pb.h" |
| 23 | #include "components/signin/public/identity_manager/identity_manager.h" |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 24 | |
| 25 | namespace manta { |
| 26 | |
| 27 | namespace { |
| 28 | |
| 29 | constexpr char kOauthConsumerName[] = "manta_scanner"; |
| 30 | constexpr base::TimeDelta kTimeout = base::Seconds(30); |
Callistus Tan | 550f53a6 | 2025-02-26 23:02:48 | [diff] [blame] | 31 | constexpr auto kTrafficAnnotation = |
| 32 | net::DefineNetworkTrafficAnnotation("chromeos_scanner_provider", R"( |
| 33 | semantics { |
| 34 | sender: "ChromeOS Scanner" |
| 35 | description: |
| 36 | "Requests extracted details for a selected region of their screen " |
| 37 | "from the Scanner service." |
| 38 | trigger: |
| 39 | "User selecting a region via the Scanner UI." |
| 40 | internal { |
| 41 | contacts { |
| 42 | email: "[email protected]" |
| 43 | } |
| 44 | } |
| 45 | user_data { |
| 46 | type: USER_CONTENT |
| 47 | } |
| 48 | data: |
| 49 | "A selected region of their screen." |
| 50 | destination: GOOGLE_OWNED_SERVICE |
| 51 | last_reviewed: "2025-02-25" |
| 52 | } |
| 53 | policy { |
| 54 | cookies_allowed: NO |
| 55 | setting: |
| 56 | "No setting. Users must take explicit action to trigger the feature." |
| 57 | policy_exception_justification: |
| 58 | "Not implemented, not considered useful. This request is part of a " |
| 59 | "flow which is user-initiated." |
| 60 | } |
| 61 | )"); |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 62 | |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 63 | bool IsValidScannerInput(const proto::ScannerInput& scanner_input) { |
| 64 | return scanner_input.image().size() > 0; |
| 65 | } |
| 66 | |
| 67 | std::unique_ptr<proto::ScannerOutput> GetScannerOutput( |
| 68 | const proto::Response& manta_response) { |
| 69 | // There should only be one output data. |
| 70 | if (manta_response.output_data_size() != 1) { |
| 71 | return nullptr; |
| 72 | } |
| 73 | const proto::OutputData& output_data = manta_response.output_data(0); |
| 74 | |
| 75 | // There should be a custom proto. |
| 76 | if (!output_data.has_custom()) { |
| 77 | return nullptr; |
| 78 | } |
| 79 | |
| 80 | // The custom proto should be a ScannerOutput. |
| 81 | if (output_data.custom().type_url() != kScannerOutputTypeUrl) { |
| 82 | return nullptr; |
| 83 | } |
| 84 | |
| 85 | const proto::Proto3Any& custom_data = output_data.custom(); |
| 86 | |
| 87 | auto scanner_output = std::make_unique<proto::ScannerOutput>(); |
| 88 | scanner_output->ParseFromString(custom_data.value()); |
| 89 | |
| 90 | return scanner_output; |
| 91 | } |
| 92 | |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 93 | void OnServerResponseOrErrorReceived( |
| 94 | ScannerProvider::ScannerProtoResponseCallback callback, |
| 95 | std::unique_ptr<proto::Response> manta_response, |
| 96 | MantaStatus manta_status) { |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 97 | // Check for Manta error status. |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 98 | if (manta_status.status_code != MantaStatusCode::kOk) { |
| 99 | std::move(callback).Run(nullptr, std::move(manta_status)); |
| 100 | return; |
| 101 | } |
| 102 | |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 103 | // Check for a valid Manta response. |
| 104 | if (manta_response == nullptr) { |
| 105 | std::move(callback).Run(nullptr, {MantaStatusCode::kMalformedResponse}); |
| 106 | return; |
| 107 | } |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 108 | |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 109 | // Check that the Manta response has output data. |
| 110 | if (manta_response->output_data_size() == 0) { |
| 111 | std::string message; |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 112 | |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 113 | // If there are no outputs, the response might have been filtered. |
| 114 | if (manta_response->filtered_data_size() > 0 && |
| 115 | manta_response->filtered_data(0).is_output_data()) { |
| 116 | message = base::StrCat({"filtered output for: ", |
| 117 | proto::FilteredReason_Name( |
| 118 | manta_response->filtered_data(0).reason())}); |
| 119 | } |
| 120 | std::move(callback).Run(nullptr, |
| 121 | {MantaStatusCode::kBlockedOutputs, message}); |
| 122 | return; |
| 123 | } |
| 124 | |
| 125 | // Try to extract a ScannerOutput object from the Manta response. |
| 126 | std::unique_ptr<proto::ScannerOutput> scanner_output = |
| 127 | GetScannerOutput(*manta_response); |
| 128 | if (scanner_output == nullptr) { |
| 129 | std::move(callback).Run(nullptr, {MantaStatusCode::kMalformedResponse}); |
| 130 | return; |
| 131 | } |
| 132 | |
| 133 | // All checks passed, run callback with valid ScannerOutput. |
| 134 | std::move(callback).Run(std::move(scanner_output), std::move(manta_status)); |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | } // namespace |
| 138 | |
| 139 | ScannerProvider::ScannerProvider( |
| 140 | scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| 141 | signin::IdentityManager* identity_manager, |
| 142 | const ProviderParams& provider_params) |
| 143 | : BaseProvider(url_loader_factory, identity_manager, provider_params) {} |
| 144 | |
| 145 | ScannerProvider::~ScannerProvider() = default; |
| 146 | |
| 147 | void ScannerProvider::Call( |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 148 | const manta::proto::ScannerInput& scanner_input, |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 149 | ScannerProvider::ScannerProtoResponseCallback done_callback) { |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 150 | // Check for valid ScannerInput. |
| 151 | if (!IsValidScannerInput(scanner_input)) { |
| 152 | std::move(done_callback).Run(nullptr, {MantaStatusCode::kInvalidInput}); |
| 153 | return; |
| 154 | } |
| 155 | // Populate Manta request with the specified ScannerInput as the custom input |
| 156 | // data. |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 157 | proto::Request request; |
| 158 | request.set_feature_name(proto::FeatureName::CHROMEOS_SCANNER); |
| 159 | |
Callistus Tan | 8f0d74d | 2024-10-14 03:35:05 | [diff] [blame] | 160 | proto::InputData* input_data = request.add_input_data(); |
| 161 | input_data->set_tag("scanner_input"); |
| 162 | |
| 163 | proto::Proto3Any& custom = *input_data->mutable_custom(); |
| 164 | custom.set_type_url(kScannerInputTypeUrl); |
| 165 | custom.set_value(scanner_input.SerializeAsString()); |
| 166 | |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 167 | RequestInternal( |
| 168 | GURL{GetProviderEndpoint(features::IsScannerUseProdServerEnabled())}, |
Callistus Tan | 550f53a6 | 2025-02-26 23:02:48 | [diff] [blame] | 169 | kOauthConsumerName, /*annotation_tag=*/kTrafficAnnotation, request, |
| 170 | MantaMetricType::kScanner, |
Callistus Tan | fa29be9 | 2024-10-08 01:13:37 | [diff] [blame] | 171 | base::BindOnce(&OnServerResponseOrErrorReceived, |
| 172 | std::move(done_callback)), |
| 173 | kTimeout); |
| 174 | } |
| 175 | |
| 176 | } // namespace manta |