Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: content/common/origin_trials/trial_token.cc

Issue 1909633003: Collect UMA data for Origin Trials (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/common/origin_trials/trial_token.h" 5 #include "content/common/origin_trials/trial_token.h"
6 6
7 #include <openssl/curve25519.h> 7 #include <openssl/curve25519.h>
8 8
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/base64.h" 11 #include "base/base64.h"
12 #include "base/big_endian.h" 12 #include "base/big_endian.h"
13 #include "base/json/json_reader.h" 13 #include "base/json/json_reader.h"
14 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "base/strings/string_piece.h" 16 #include "base/strings/string_piece.h"
17 #include "base/time/time.h" 17 #include "base/time/time.h"
18 #include "base/values.h" 18 #include "base/values.h"
19 #include "third_party/WebKit/public/platform/WebOriginTrialTokenStatus.h"
19 #include "url/gurl.h" 20 #include "url/gurl.h"
20 #include "url/origin.h" 21 #include "url/origin.h"
21 22
22 namespace content { 23 namespace content {
23 24
24 namespace { 25 namespace {
25 26
26 // Version is a 1-byte field at offset 0. 27 // Version is a 1-byte field at offset 0.
27 const size_t kVersionOffset = 0; 28 const size_t kVersionOffset = 0;
28 const size_t kVersionSize = 1; 29 const size_t kVersionSize = 1;
29 30
30 // These constants define the Version 2 field sizes and offsets. 31 // These constants define the Version 2 field sizes and offsets.
31 const size_t kSignatureOffset = kVersionOffset + kVersionSize; 32 const size_t kSignatureOffset = kVersionOffset + kVersionSize;
32 const size_t kSignatureSize = 64; 33 const size_t kSignatureSize = 64;
33 const size_t kPayloadLengthOffset = kSignatureOffset + kSignatureSize; 34 const size_t kPayloadLengthOffset = kSignatureOffset + kSignatureSize;
34 const size_t kPayloadLengthSize = 4; 35 const size_t kPayloadLengthSize = 4;
35 const size_t kPayloadOffset = kPayloadLengthOffset + kPayloadLengthSize; 36 const size_t kPayloadOffset = kPayloadLengthOffset + kPayloadLengthSize;
36 37
37 // Version 2 is the only token version currently supported. Version 1 was 38 // Version 2 is the only token version currently supported. Version 1 was
38 // introduced in Chrome M50, and removed in M51. There were no experiments 39 // introduced in Chrome M50, and removed in M51. There were no experiments
39 // enabled in the stable M50 release which would have used those tokens. 40 // enabled in the stable M50 release which would have used those tokens.
40 const uint8_t kVersion2 = 2; 41 const uint8_t kVersion2 = 2;
41 42
42 } // namespace 43 } // namespace
43 44
44 TrialToken::~TrialToken() {} 45 TrialToken::~TrialToken() {}
45 46
46 // static 47 // static
47 std::unique_ptr<TrialToken> TrialToken::From(const std::string& token_text, 48 std::unique_ptr<TrialToken> TrialToken::From(
48 base::StringPiece public_key) { 49 const std::string& token_text,
49 std::unique_ptr<std::string> token_payload = Extract(token_text, public_key); 50 base::StringPiece public_key,
50 if (!token_payload) { 51 blink::WebOriginTrialTokenStatus* out_status) {
52 DCHECK(out_status);
53 std::string token_payload;
54 *out_status = Extract(token_text, public_key, &token_payload);
55 if (*out_status != blink::WebOriginTrialTokenStatus::Success) {
51 return nullptr; 56 return nullptr;
52 } 57 }
53 return Parse(*token_payload); 58 std::unique_ptr<TrialToken> token = Parse(token_payload);
59 *out_status = token ? blink::WebOriginTrialTokenStatus::Success
60 : blink::WebOriginTrialTokenStatus::Malformed;
61 return token;
54 } 62 }
55 63
56 bool TrialToken::IsValidForFeature(const url::Origin& origin, 64 blink::WebOriginTrialTokenStatus TrialToken::IsValidForFeature(
57 base::StringPiece feature_name, 65 const url::Origin& origin,
58 const base::Time& now) const { 66 base::StringPiece feature_name,
59 return ValidateOrigin(origin) && ValidateFeatureName(feature_name) && 67 const base::Time& now) const {
60 ValidateDate(now); 68 // The order of these checks is intentional. For example, will only report a
69 // token as expired if it is valid for the origin + feature combination.
70 if (!ValidateOrigin(origin)) {
71 return blink::WebOriginTrialTokenStatus::WrongOrigin;
72 }
73 if (!ValidateFeatureName(feature_name)) {
74 return blink::WebOriginTrialTokenStatus::WrongFeature;
75 }
76 if (!ValidateDate(now)) {
77 return blink::WebOriginTrialTokenStatus::Expired;
78 }
79 return blink::WebOriginTrialTokenStatus::Success;
61 } 80 }
62 81
63 std::unique_ptr<std::string> TrialToken::Extract( 82 // static
64 const std::string& token_payload, 83 blink::WebOriginTrialTokenStatus TrialToken::Extract(
65 base::StringPiece public_key) { 84 const std::string& token_text,
66 if (token_payload.empty()) { 85 base::StringPiece public_key,
67 return nullptr; 86 std::string* out_token_payload) {
87 if (token_text.empty()) {
88 return blink::WebOriginTrialTokenStatus::Malformed;
68 } 89 }
69 90
70 // Token is base64-encoded; decode first. 91 // Token is base64-encoded; decode first.
71 std::string token_contents; 92 std::string token_contents;
72 if (!base::Base64Decode(token_payload, &token_contents)) { 93 if (!base::Base64Decode(token_text, &token_contents)) {
73 return nullptr; 94 return blink::WebOriginTrialTokenStatus::Malformed;
74 } 95 }
75 96
76 // Only version 2 currently supported. 97 // Only version 2 currently supported.
77 if (token_contents.length() < (kVersionOffset + kVersionSize)) { 98 if (token_contents.length() < (kVersionOffset + kVersionSize)) {
78 return nullptr; 99 return blink::WebOriginTrialTokenStatus::Malformed;
79 } 100 }
80 uint8_t version = token_contents[kVersionOffset]; 101 uint8_t version = token_contents[kVersionOffset];
81 if (version != kVersion2) { 102 if (version != kVersion2) {
82 return nullptr; 103 return blink::WebOriginTrialTokenStatus::WrongVersion;
83 } 104 }
84 105
85 // Token must be large enough to contain a version, signature, and payload 106 // Token must be large enough to contain a version, signature, and payload
86 // length. 107 // length.
87 if (token_contents.length() < (kPayloadLengthOffset + kPayloadLengthSize)) { 108 if (token_contents.length() < (kPayloadLengthOffset + kPayloadLengthSize)) {
88 return nullptr; 109 return blink::WebOriginTrialTokenStatus::Malformed;
89 } 110 }
90 111
91 // Extract the length of the signed data (Big-endian). 112 // Extract the length of the signed data (Big-endian).
92 uint32_t payload_length; 113 uint32_t payload_length;
93 base::ReadBigEndian(&(token_contents[kPayloadLengthOffset]), &payload_length); 114 base::ReadBigEndian(&(token_contents[kPayloadLengthOffset]), &payload_length);
94 115
95 // Validate that the stated length matches the actual payload length. 116 // Validate that the stated length matches the actual payload length.
96 if (payload_length != token_contents.length() - kPayloadOffset) { 117 if (payload_length != token_contents.length() - kPayloadOffset) {
97 return nullptr; 118 return blink::WebOriginTrialTokenStatus::Malformed;
98 } 119 }
99 120
100 // Extract the version-specific contents of the token. 121 // Extract the version-specific contents of the token.
101 const char* token_bytes = token_contents.data(); 122 const char* token_bytes = token_contents.data();
102 base::StringPiece version_piece(token_bytes + kVersionOffset, kVersionSize); 123 base::StringPiece version_piece(token_bytes + kVersionOffset, kVersionSize);
103 base::StringPiece signature(token_bytes + kSignatureOffset, kSignatureSize); 124 base::StringPiece signature(token_bytes + kSignatureOffset, kSignatureSize);
104 base::StringPiece payload_piece(token_bytes + kPayloadLengthOffset, 125 base::StringPiece payload_piece(token_bytes + kPayloadLengthOffset,
105 kPayloadLengthSize + payload_length); 126 kPayloadLengthSize + payload_length);
106 127
107 // The data which is covered by the signature is (version + length + payload). 128 // The data which is covered by the signature is (version + length + payload).
108 std::string signed_data = 129 std::string signed_data =
109 version_piece.as_string() + payload_piece.as_string(); 130 version_piece.as_string() + payload_piece.as_string();
110 131
111 // Validate the signature on the data before proceeding. 132 // Validate the signature on the data before proceeding.
112 if (!TrialToken::ValidateSignature(signature, signed_data, public_key)) { 133 if (!TrialToken::ValidateSignature(signature, signed_data, public_key)) {
113 return nullptr; 134 return blink::WebOriginTrialTokenStatus::InvalidSignature;
114 } 135 }
115 136
116 // Return just the payload, as a new string. 137 // Return just the payload, as a new string.
117 return base::WrapUnique( 138 *out_token_payload = token_contents.substr(kPayloadOffset, payload_length);
118 new std::string(token_contents, kPayloadOffset, payload_length)); 139 return blink::WebOriginTrialTokenStatus::Success;
119 } 140 }
120 141
121 std::unique_ptr<TrialToken> TrialToken::Parse(const std::string& token_json) { 142 // static
143 std::unique_ptr<TrialToken> TrialToken::Parse(
144 const std::string& token_payload) {
122 std::unique_ptr<base::DictionaryValue> datadict = 145 std::unique_ptr<base::DictionaryValue> datadict =
123 base::DictionaryValue::From(base::JSONReader::Read(token_json)); 146 base::DictionaryValue::From(base::JSONReader::Read(token_payload));
124 if (!datadict) { 147 if (!datadict) {
125 return nullptr; 148 return nullptr;
126 } 149 }
127 150
128 std::string origin_string; 151 std::string origin_string;
129 std::string feature_name; 152 std::string feature_name;
130 int expiry_timestamp = 0; 153 int expiry_timestamp = 0;
131 datadict->GetString("origin", &origin_string); 154 datadict->GetString("origin", &origin_string);
132 datadict->GetString("feature", &feature_name); 155 datadict->GetString("feature", &feature_name);
133 datadict->GetInteger("expiry", &expiry_timestamp); 156 datadict->GetInteger("expiry", &expiry_timestamp);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 } 207 }
185 208
186 TrialToken::TrialToken(const url::Origin& origin, 209 TrialToken::TrialToken(const url::Origin& origin,
187 const std::string& feature_name, 210 const std::string& feature_name,
188 uint64_t expiry_timestamp) 211 uint64_t expiry_timestamp)
189 : origin_(origin), 212 : origin_(origin),
190 feature_name_(feature_name), 213 feature_name_(feature_name),
191 expiry_time_(base::Time::FromDoubleT(expiry_timestamp)) {} 214 expiry_time_(base::Time::FromDoubleT(expiry_timestamp)) {}
192 215
193 } // namespace content 216 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698