| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SERVICES_NETWORK_SCT_AUDITING_SCT_AUDITING_REPORTER_H_ |
| #define SERVICES_NETWORK_SCT_AUDITING_SCT_AUDITING_REPORTER_H_ |
| |
| #include <memory> |
| |
| #include "base/callback_forward.h" |
| #include "base/component_export.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "net/base/backoff_entry.h" |
| #include "net/base/hash_value.h" |
| #include "net/cert/signed_certificate_timestamp_and_status.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| #include "services/network/public/mojom/network_service.mojom-forward.h" |
| #include "services/network/public/mojom/url_loader_factory.mojom.h" |
| #include "services/network/public/proto/sct_audit_report.pb.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "url/gurl.h" |
| |
| namespace net { |
| class HttpResponseHeaders; |
| } |
| |
| namespace network { |
| |
| class NetworkContext; |
| class SimpleURLLoader; |
| |
| // Owns an SCT auditing report and handles sending it and retrying on failures. |
| // An SCTAuditingReporter begins trying to send the report to the report server |
| // on creation, retrying over time based on the backoff policy defined in |
| // `kBackoffPolicy`, and then runs the ReporterDoneCallback provided by the |
| // SCTAuditingHandler to notify the handler when it has completed (either |
| // success or running out of retries). If an SCTAuditingReporter instance is |
| // deleted, any outstanding requests are canceled, pending retry tasks will |
| // fail, and `done_callback` will not called. |
| // |
| // An SCTAuditingReporter instance is uniquely identified by its `reporter_key` |
| // hash, which is the SHA256HashValue of the set of SCTs included in the |
| // SCTClientReport that the reporter owns. |
| class COMPONENT_EXPORT(NETWORK_SERVICE) SCTAuditingReporter { |
| public: |
| // Callback to notify the SCTAuditingHandler that this reporter has completed. |
| // The SHA256HashValue `reporter_key` is passed to uniquely identify this |
| // reporter instance. |
| using ReporterDoneCallback = base::OnceCallback<void(net::HashValue)>; |
| // Callback to notify the SCTAuditingHandler that the reporter has updated |
| // (e.g., the retry counter has been incremented). |
| using ReporterUpdatedCallback = base::RepeatingCallback<void()>; |
| |
| // For hashdance requests, the client must select an SCT and set its metadata |
| // when building an SCTAuditingReporter. |
| struct COMPONENT_EXPORT(NETWORK_SERVICE) SCTHashdanceMetadata { |
| // Construct an SCTHashdanceMetadata from the given |value|. Returns |
| // absl::nullopt if |value| cannot be parsed into a valid |
| // SCTHashdanceMetadata. |
| static absl::optional<SCTHashdanceMetadata> FromValue( |
| const base::Value& value); |
| |
| SCTHashdanceMetadata(); |
| ~SCTHashdanceMetadata(); |
| SCTHashdanceMetadata(const SCTHashdanceMetadata&) = delete; |
| SCTHashdanceMetadata operator=(const SCTHashdanceMetadata&) = delete; |
| SCTHashdanceMetadata(SCTHashdanceMetadata&&); |
| SCTHashdanceMetadata& operator=(SCTHashdanceMetadata&&); |
| |
| // Returns a base::Value from which the SCTHashdanceMetadata can be |
| // reconstructed. |
| base::Value ToValue() const; |
| |
| // Merkle tree leaf hash. |
| std::string leaf_hash; |
| |
| // Date and time when this SCT was issued. |
| base::Time issued; |
| |
| // Corresponding CT Log ID. |
| std::string log_id; |
| |
| // Corresponding CT Log Maximum Merge Delay. |
| base::TimeDelta log_mmd; |
| |
| // The certificate expiry date. |
| base::Time certificate_expiry; |
| }; |
| |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| enum class LookupQueryResult { |
| // Indicates a network status other than 200 OK. |
| kHTTPError = 0, |
| |
| // The content returned by the server either did not parse as valid JSON or |
| // was missing required fields. |
| kInvalidJson = 1, |
| |
| // The server returned a `responseStatus` field other than "OK". |
| kStatusNotOk = 2, |
| |
| // The certificate has expired according to the timestamp returned by the |
| // server. |
| kCertificateExpired = 3, |
| |
| // The server does not know about the log corresponding to the SCT. |
| kLogNotFound = 4, |
| |
| // The log has not yet ingested the SCT. |
| kLogNotYetIngested = 5, |
| |
| // The SCT suffix was found in the suffix list, so it should not be |
| // reported. |
| kSCTSuffixFound = 6, |
| |
| // The SCT suffix was NOT found in the suffix list, so it should be |
| // reported. |
| kSCTSuffixNotFound = 7, |
| kMaxValue = kSCTSuffixNotFound, |
| }; |
| |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| enum class CompletionStatus { |
| kSuccessFirstTry = 0, |
| kSuccessAfterRetries = 1, |
| kRetriesExhausted = 2, |
| kMaxValue = kRetriesExhausted, |
| }; |
| |
| SCTAuditingReporter( |
| NetworkContext* owner_network_context_, |
| net::HashValue reporter_key, |
| std::unique_ptr<sct_auditing::SCTClientReport> report, |
| bool is_hashdance, |
| absl::optional<SCTHashdanceMetadata> hashdance_metadata, |
| mojom::SCTAuditingConfigurationPtr configuration, |
| mojom::URLLoaderFactory* url_loader_factory, |
| ReporterUpdatedCallback update_callback, |
| ReporterDoneCallback done_callback, |
| std::unique_ptr<net::BackoffEntry> backoff_entry = nullptr, |
| bool counted_towards_report_limit = false); |
| ~SCTAuditingReporter(); |
| |
| SCTAuditingReporter(const SCTAuditingReporter&) = delete; |
| SCTAuditingReporter& operator=(const SCTAuditingReporter&) = delete; |
| |
| static const net::BackoffEntry::Policy kDefaultBackoffPolicy; |
| |
| void Start(); |
| |
| net::HashValue key() { return reporter_key_; } |
| sct_auditing::SCTClientReport* report() { return report_.get(); } |
| net::BackoffEntry* backoff_entry() { return backoff_entry_.get(); } |
| const absl::optional<SCTHashdanceMetadata>& sct_hashdance_metadata() { |
| return sct_hashdance_metadata_; |
| } |
| bool counted_towards_report_limit() { return counted_towards_report_limit_; } |
| |
| static void SetRetryDelayForTesting(absl::optional<base::TimeDelta> delay); |
| |
| private: |
| void OnCheckReportAllowedStatusComplete(bool allowed); |
| // Schedules a |request| using the backoff delay or |minimum_delay|, whichever |
| // is greatest. |
| void ScheduleRequestWithBackoff(base::OnceClosure request, |
| base::TimeDelta minimum_delay); |
| void SendLookupQuery(); |
| void OnSendLookupQueryComplete(std::unique_ptr<std::string> response_body); |
| void SendReport(); |
| void OnSendReportComplete(scoped_refptr<net::HttpResponseHeaders> headers); |
| void MaybeRetryRequest(); |
| |
| // The NetworkContext which owns the SCTAuditingHandler that created this |
| // Reporter. |
| raw_ptr<NetworkContext> owner_network_context_; |
| |
| net::HashValue reporter_key_; |
| std::unique_ptr<sct_auditing::SCTClientReport> report_; |
| bool is_hashdance_; |
| // If |is_hashdance_| is true, |sct_hashdance_metadata_| will contain metadata |
| // for a randomly selected SCT from the report. |
| absl::optional<SCTHashdanceMetadata> sct_hashdance_metadata_; |
| mojo::Remote<mojom::URLLoaderFactory> url_loader_factory_remote_; |
| std::unique_ptr<SimpleURLLoader> url_loader_; |
| mojom::SCTAuditingConfigurationPtr configuration_; |
| ReporterUpdatedCallback update_callback_; |
| ReporterDoneCallback done_callback_; |
| |
| net::BackoffEntry::Policy backoff_policy_; |
| std::unique_ptr<net::BackoffEntry> backoff_entry_; |
| |
| int max_retries_; |
| |
| // Whether the report has been counted towards the max-reports limit. This is |
| // used to determine whether to notify the embedder that a new report is being |
| // sent by the client, to avoid overcounting how many unique reports have been |
| // sent. (Without this flag, this could happen on retries if the hashdance |
| // lookup query succeeds but then the full report upload fails.) |
| bool counted_towards_report_limit_; |
| |
| base::WeakPtrFactory<SCTAuditingReporter> weak_factory_{this}; |
| }; |
| |
| } // namespace network |
| |
| #endif // SERVICES_NETWORK_SCT_AUDITING_SCT_AUDITING_REPORTER_H_ |