blob: 05b00e493038fe2e1bff5dc4000f24322164cb68 [file] [log] [blame]
Callistus Tanfa29be92024-10-08 01:13:371// 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 Tan8f0d74d2024-10-14 03:35:059#include <utility>
Callistus Tanfa29be92024-10-08 01:13:3710
11#include "base/check.h"
12#include "base/functional/bind.h"
Callistus Tan8f0d74d2024-10-14 03:35:0513#include "base/strings/strcat.h"
Callistus Tanfa29be92024-10-08 01:13:3714#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 Tan8f0d74d2024-10-14 03:35:0520#include "components/manta/proto/common.pb.h"
Callistus Tanfa29be92024-10-08 01:13:3721#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 Tanfa29be92024-10-08 01:13:3724
25namespace manta {
26
27namespace {
28
29constexpr char kOauthConsumerName[] = "manta_scanner";
30constexpr base::TimeDelta kTimeout = base::Seconds(30);
Callistus Tan550f53a62025-02-26 23:02:4831constexpr 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 Tanfa29be92024-10-08 01:13:3762
Callistus Tan8f0d74d2024-10-14 03:35:0563bool IsValidScannerInput(const proto::ScannerInput& scanner_input) {
64 return scanner_input.image().size() > 0;
65}
66
67std::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 Tanfa29be92024-10-08 01:13:3793void OnServerResponseOrErrorReceived(
94 ScannerProvider::ScannerProtoResponseCallback callback,
95 std::unique_ptr<proto::Response> manta_response,
96 MantaStatus manta_status) {
Callistus Tan8f0d74d2024-10-14 03:35:0597 // Check for Manta error status.
Callistus Tanfa29be92024-10-08 01:13:3798 if (manta_status.status_code != MantaStatusCode::kOk) {
99 std::move(callback).Run(nullptr, std::move(manta_status));
100 return;
101 }
102
Callistus Tan8f0d74d2024-10-14 03:35:05103 // Check for a valid Manta response.
104 if (manta_response == nullptr) {
105 std::move(callback).Run(nullptr, {MantaStatusCode::kMalformedResponse});
106 return;
107 }
Callistus Tanfa29be92024-10-08 01:13:37108
Callistus Tan8f0d74d2024-10-14 03:35:05109 // Check that the Manta response has output data.
110 if (manta_response->output_data_size() == 0) {
111 std::string message;
Callistus Tanfa29be92024-10-08 01:13:37112
Callistus Tan8f0d74d2024-10-14 03:35:05113 // 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 Tanfa29be92024-10-08 01:13:37135}
136
137} // namespace
138
139ScannerProvider::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
145ScannerProvider::~ScannerProvider() = default;
146
147void ScannerProvider::Call(
Callistus Tan8f0d74d2024-10-14 03:35:05148 const manta::proto::ScannerInput& scanner_input,
Callistus Tanfa29be92024-10-08 01:13:37149 ScannerProvider::ScannerProtoResponseCallback done_callback) {
Callistus Tan8f0d74d2024-10-14 03:35:05150 // 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 Tanfa29be92024-10-08 01:13:37157 proto::Request request;
158 request.set_feature_name(proto::FeatureName::CHROMEOS_SCANNER);
159
Callistus Tan8f0d74d2024-10-14 03:35:05160 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 Tanfa29be92024-10-08 01:13:37167 RequestInternal(
168 GURL{GetProviderEndpoint(features::IsScannerUseProdServerEnabled())},
Callistus Tan550f53a62025-02-26 23:02:48169 kOauthConsumerName, /*annotation_tag=*/kTrafficAnnotation, request,
170 MantaMetricType::kScanner,
Callistus Tanfa29be92024-10-08 01:13:37171 base::BindOnce(&OnServerResponseOrErrorReceived,
172 std::move(done_callback)),
173 kTimeout);
174}
175
176} // namespace manta