• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "net/device_bound_sessions/session_challenge_param.h"
6 
7 #include "base/ranges/algorithm.h"
8 #include "net/http/http_response_headers.h"
9 #include "url/gurl.h"
10 
11 namespace {
12 // Sec-Session-Challenge header defined in
13 // https://github.com/WICG/dbsc/blob/main/README.md#high-level-overview
14 constexpr char kSessionChallengeHeaderName[] = "Sec-Session-Challenge";
15 constexpr char kSessionIdKey[] = "id";
16 }  // namespace
17 
18 namespace net::device_bound_sessions {
19 
20 SessionChallengeParam::SessionChallengeParam(
21     SessionChallengeParam&& other) noexcept = default;
22 
23 SessionChallengeParam& SessionChallengeParam::operator=(
24     SessionChallengeParam&& other) noexcept = default;
25 
26 SessionChallengeParam::~SessionChallengeParam() = default;
27 
SessionChallengeParam(std::optional<std::string> session_id,std::string challenge)28 SessionChallengeParam::SessionChallengeParam(
29     std::optional<std::string> session_id,
30     std::string challenge)
31     : session_id_(std::move(session_id)), challenge_(std::move(challenge)) {}
32 
33 // static
ParseItem(const structured_headers::ParameterizedMember & session_challenge)34 std::optional<SessionChallengeParam> SessionChallengeParam::ParseItem(
35     const structured_headers::ParameterizedMember& session_challenge) {
36   if (session_challenge.member_is_inner_list ||
37       session_challenge.member.empty()) {
38     return std::nullopt;
39   }
40 
41   const structured_headers::Item& item = session_challenge.member[0].item;
42   if (!item.is_string()) {
43     return std::nullopt;
44   }
45 
46   std::string challenge(item.GetString());
47   if (challenge.empty()) {
48     return std::nullopt;
49   }
50 
51   std::optional<std::string> session_id;
52   if (auto it = base::ranges::find(
53           session_challenge.params, kSessionIdKey,
54           &std::pair<std::string, structured_headers::Item>::first);
55       it != session_challenge.params.end()) {
56     const auto& param = it->second;
57     if (!param.is_string()) {
58       return std::nullopt;
59     }
60 
61     auto id = param.GetString();
62     if (!id.empty()) {
63       session_id = std::move(id);
64     }
65   }
66 
67   return SessionChallengeParam(std::move(session_id), std::move(challenge));
68 }
69 
70 // static
CreateIfValid(const GURL & request_url,const net::HttpResponseHeaders * headers)71 std::vector<SessionChallengeParam> SessionChallengeParam::CreateIfValid(
72     const GURL& request_url,
73     const net::HttpResponseHeaders* headers) {
74   std::vector<SessionChallengeParam> params;
75   if (!request_url.is_valid()) {
76     return params;
77   }
78 
79   if (!headers) {
80     return params;
81   }
82   std::optional<std::string> header_value =
83       headers->GetNormalizedHeader(kSessionChallengeHeaderName);
84   if (!header_value) {
85     return params;
86   }
87 
88   std::optional<structured_headers::List> list =
89       structured_headers::ParseList(*header_value);
90 
91   if (!list) {
92     return params;
93   }
94 
95   for (const auto& session_challenge : *list) {
96     std::optional<SessionChallengeParam> param = ParseItem(session_challenge);
97     if (param) {
98       params.push_back(std::move(*param));
99     }
100   }
101 
102   return params;
103 }
104 
105 }  // namespace net::device_bound_sessions
106