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

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: Address some comments Created 4 years, 8 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
(...skipping 25 matching lines...) Expand all
36 36
37 // Version 2 is the only token version currently supported. Version 1 was 37 // 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 38 // 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. 39 // enabled in the stable M50 release which would have used those tokens.
40 const uint8_t kVersion2 = 2; 40 const uint8_t kVersion2 = 2;
41 41
42 } // namespace 42 } // namespace
43 43
44 TrialToken::~TrialToken() {} 44 TrialToken::~TrialToken() {}
45 45
46 // static 46 // Static
Marijn Kruisselbrink 2016/04/22 21:51:06 the lowercase version of this comment is vastly mo
chasej 2016/04/25 20:32:52 Done.
47 std::unique_ptr<TrialToken> TrialToken::From(const std::string& token_text, 47 std::unique_ptr<TrialToken> TrialToken::From(const std::string& token_text,
48 base::StringPiece public_key) { 48 base::StringPiece public_key,
49 std::unique_ptr<std::string> token_payload = Extract(token_text, public_key); 49 TrialTokenStatus* out_status) {
50 if (!token_payload) { 50 DCHECK(out_status);
51 std::string token_payload;
52 *out_status = Extract(token_text, public_key, &token_payload);
53 if (*out_status != TRIAL_TOKEN_STATUS_SUCCESS) {
51 return nullptr; 54 return nullptr;
52 } 55 }
53 return Parse(*token_payload); 56 std::unique_ptr<TrialToken> token = Parse(token_payload);
57 *out_status =
58 token ? TRIAL_TOKEN_STATUS_SUCCESS : TRIAL_TOKEN_STATUS_MALFORMED;
59 return token;
54 } 60 }
55 61
56 bool TrialToken::IsValidForFeature(const url::Origin& origin, 62 TrialTokenStatus TrialToken::IsValidForFeature(const url::Origin& origin,
57 base::StringPiece feature_name, 63 base::StringPiece feature_name,
58 const base::Time& now) const { 64 const base::Time& now) const {
59 return ValidateOrigin(origin) && ValidateFeatureName(feature_name) && 65 // The order of these checks is intentional. For example, will only report a
60 ValidateDate(now); 66 // token as expired if it is valid for the origin + feature combination.
67 if (!ValidateOrigin(origin)) {
68 return TRIAL_TOKEN_STATUS_WRONG_ORIGIN;
69 }
70 if (!ValidateFeatureName(feature_name)) {
71 return TRIAL_TOKEN_STATUS_WRONG_FEATURE;
72 }
73 if (!ValidateDate(now)) {
74 return TRIAL_TOKEN_STATUS_EXPIRED;
75 }
76 return TRIAL_TOKEN_STATUS_SUCCESS;
61 } 77 }
62 78
63 std::unique_ptr<std::string> TrialToken::Extract( 79 TrialTokenStatus TrialToken::Extract(const std::string& token_payload,
64 const std::string& token_payload, 80 base::StringPiece public_key,
65 base::StringPiece public_key) { 81 std::string* out_token_json) {
66 if (token_payload.empty()) { 82 if (token_payload.empty()) {
67 return nullptr; 83 return TRIAL_TOKEN_STATUS_MALFORMED;
68 } 84 }
69 85
70 // Token is base64-encoded; decode first. 86 // Token is base64-encoded; decode first.
71 std::string token_contents; 87 std::string token_contents;
72 if (!base::Base64Decode(token_payload, &token_contents)) { 88 if (!base::Base64Decode(token_payload, &token_contents)) {
73 return nullptr; 89 return TRIAL_TOKEN_STATUS_MALFORMED;
74 } 90 }
75 91
76 // Only version 2 currently supported. 92 // Only version 2 currently supported.
77 if (token_contents.length() < (kVersionOffset + kVersionSize)) { 93 if (token_contents.length() < (kVersionOffset + kVersionSize)) {
78 return nullptr; 94 return TRIAL_TOKEN_STATUS_MALFORMED;
79 } 95 }
80 uint8_t version = token_contents[kVersionOffset]; 96 uint8_t version = token_contents[kVersionOffset];
81 if (version != kVersion2) { 97 if (version != kVersion2) {
82 return nullptr; 98 return TRIAL_TOKEN_STATUS_MALFORMED;
83 } 99 }
84 100
85 // Token must be large enough to contain a version, signature, and payload 101 // Token must be large enough to contain a version, signature, and payload
86 // length. 102 // length.
87 if (token_contents.length() < (kPayloadLengthOffset + kPayloadLengthSize)) { 103 if (token_contents.length() < (kPayloadLengthOffset + kPayloadLengthSize)) {
88 return nullptr; 104 return TRIAL_TOKEN_STATUS_MALFORMED;
89 } 105 }
90 106
91 // Extract the length of the signed data (Big-endian). 107 // Extract the length of the signed data (Big-endian).
92 uint32_t payload_length; 108 uint32_t payload_length;
93 base::ReadBigEndian(&(token_contents[kPayloadLengthOffset]), &payload_length); 109 base::ReadBigEndian(&(token_contents[kPayloadLengthOffset]), &payload_length);
94 110
95 // Validate that the stated length matches the actual payload length. 111 // Validate that the stated length matches the actual payload length.
96 if (payload_length != token_contents.length() - kPayloadOffset) { 112 if (payload_length != token_contents.length() - kPayloadOffset) {
97 return nullptr; 113 return TRIAL_TOKEN_STATUS_MALFORMED;
98 } 114 }
99 115
100 // Extract the version-specific contents of the token. 116 // Extract the version-specific contents of the token.
101 const char* token_bytes = token_contents.data(); 117 const char* token_bytes = token_contents.data();
102 base::StringPiece version_piece(token_bytes + kVersionOffset, kVersionSize); 118 base::StringPiece version_piece(token_bytes + kVersionOffset, kVersionSize);
103 base::StringPiece signature(token_bytes + kSignatureOffset, kSignatureSize); 119 base::StringPiece signature(token_bytes + kSignatureOffset, kSignatureSize);
104 base::StringPiece payload_piece(token_bytes + kPayloadLengthOffset, 120 base::StringPiece payload_piece(token_bytes + kPayloadLengthOffset,
105 kPayloadLengthSize + payload_length); 121 kPayloadLengthSize + payload_length);
106 122
107 // The data which is covered by the signature is (version + length + payload). 123 // The data which is covered by the signature is (version + length + payload).
108 std::string signed_data = 124 std::string signed_data =
109 version_piece.as_string() + payload_piece.as_string(); 125 version_piece.as_string() + payload_piece.as_string();
110 126
111 // Validate the signature on the data before proceeding. 127 // Validate the signature on the data before proceeding.
112 if (!TrialToken::ValidateSignature(signature, signed_data, public_key)) { 128 if (!TrialToken::ValidateSignature(signature, signed_data, public_key)) {
113 return nullptr; 129 return TRIAL_TOKEN_STATUS_INVALID_SIGNATURE;
114 } 130 }
115 131
116 // Return just the payload, as a new string. 132 // Return just the payload, as a new string.
117 return base::WrapUnique( 133 *out_token_json = token_contents.substr(kPayloadOffset, payload_length);
118 new std::string(token_contents, kPayloadOffset, payload_length)); 134 return TRIAL_TOKEN_STATUS_SUCCESS;
119 } 135 }
120 136
121 std::unique_ptr<TrialToken> TrialToken::Parse(const std::string& token_json) { 137 std::unique_ptr<TrialToken> TrialToken::Parse(const std::string& token_json) {
122 std::unique_ptr<base::DictionaryValue> datadict = 138 std::unique_ptr<base::DictionaryValue> datadict =
123 base::DictionaryValue::From(base::JSONReader::Read(token_json)); 139 base::DictionaryValue::From(base::JSONReader::Read(token_json));
124 if (!datadict) { 140 if (!datadict) {
125 return nullptr; 141 return nullptr;
126 } 142 }
127 143
128 std::string origin_string; 144 std::string origin_string;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 } 200 }
185 201
186 TrialToken::TrialToken(const url::Origin& origin, 202 TrialToken::TrialToken(const url::Origin& origin,
187 const std::string& feature_name, 203 const std::string& feature_name,
188 uint64_t expiry_timestamp) 204 uint64_t expiry_timestamp)
189 : origin_(origin), 205 : origin_(origin),
190 feature_name_(feature_name), 206 feature_name_(feature_name),
191 expiry_time_(base::Time::FromDoubleT(expiry_timestamp)) {} 207 expiry_time_(base::Time::FromDoubleT(expiry_timestamp)) {}
192 208
193 } // namespace content 209 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698