| OLD | NEW | 
|    1 // Copyright 2013 The Chromium Authors. All rights reserved. |    1 // Copyright 2013 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 "chrome/browser/extensions/install_signer.h" |    5 #include "chrome/browser/extensions/install_signer.h" | 
|    6  |    6  | 
|    7 #include "base/base64.h" |    7 #include "base/base64.h" | 
|    8 #include "base/bind.h" |    8 #include "base/bind.h" | 
|    9 #include "base/command_line.h" |    9 #include "base/command_line.h" | 
|   10 #include "base/json/json_reader.h" |   10 #include "base/json/json_reader.h" | 
|   11 #include "base/json/json_writer.h" |   11 #include "base/json/json_writer.h" | 
|   12 #include "base/lazy_instance.h" |  | 
|   13 #include "base/message_loop/message_loop.h" |   12 #include "base/message_loop/message_loop.h" | 
|   14 #include "base/metrics/histogram.h" |   13 #include "base/metrics/histogram.h" | 
|   15 #include "base/process/process_info.h" |  | 
|   16 #include "base/stl_util.h" |   14 #include "base/stl_util.h" | 
|   17 #include "base/strings/string_number_conversions.h" |   15 #include "base/strings/string_number_conversions.h" | 
|   18 #include "base/strings/string_split.h" |   16 #include "base/strings/string_split.h" | 
|   19 #include "base/strings/string_util.h" |   17 #include "base/strings/string_util.h" | 
|   20 #include "base/strings/stringprintf.h" |   18 #include "base/strings/stringprintf.h" | 
|   21 #include "base/time/time.h" |  | 
|   22 #include "base/values.h" |   19 #include "base/values.h" | 
|   23 #include "chrome/common/chrome_switches.h" |   20 #include "chrome/common/chrome_switches.h" | 
|   24 #include "chrome/common/extensions/extension_constants.h" |   21 #include "chrome/common/extensions/extension_constants.h" | 
|   25 #include "crypto/random.h" |   22 #include "crypto/random.h" | 
|   26 #include "crypto/secure_hash.h" |   23 #include "crypto/secure_hash.h" | 
|   27 #include "crypto/sha2.h" |   24 #include "crypto/sha2.h" | 
|   28 #include "crypto/signature_verifier.h" |   25 #include "crypto/signature_verifier.h" | 
|   29 #include "net/url_request/url_fetcher.h" |   26 #include "net/url_request/url_fetcher.h" | 
|   30 #include "net/url_request/url_fetcher_delegate.h" |   27 #include "net/url_request/url_fetcher_delegate.h" | 
|   31 #include "net/url_request/url_request_context_getter.h" |   28 #include "net/url_request/url_request_context_getter.h" | 
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  239   std::string value = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |  236   std::string value = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 
|  240       switches::kExtensionsNotWebstore); |  237       switches::kExtensionsNotWebstore); | 
|  241   if (value.empty()) |  238   if (value.empty()) | 
|  242     return ExtensionIdSet(); |  239     return ExtensionIdSet(); | 
|  243  |  240  | 
|  244   std::vector<std::string> ids; |  241   std::vector<std::string> ids; | 
|  245   base::SplitString(value, ',', &ids); |  242   base::SplitString(value, ',', &ids); | 
|  246   return ExtensionIdSet(ids.begin(), ids.end()); |  243   return ExtensionIdSet(ids.begin(), ids.end()); | 
|  247 } |  244 } | 
|  248  |  245  | 
|  249 namespace { |  | 
|  250  |  | 
|  251 static int g_request_count = 0; |  | 
|  252  |  | 
|  253 base::LazyInstance<base::TimeTicks> g_last_request_time = |  | 
|  254     LAZY_INSTANCE_INITIALIZER; |  | 
|  255  |  | 
|  256 base::LazyInstance<base::ThreadChecker> g_single_thread_checker = |  | 
|  257     LAZY_INSTANCE_INITIALIZER; |  | 
|  258  |  | 
|  259 void LogRequestStartHistograms() { |  | 
|  260   // Make sure we only ever call this from one thread, so that we don't have to |  | 
|  261   // worry about race conditions setting g_last_request_time. |  | 
|  262   DCHECK(g_single_thread_checker.Get().CalledOnValidThread()); |  | 
|  263  |  | 
|  264   const base::Time process_creation_time = |  | 
|  265       base::CurrentProcessInfo::CreationTime(); |  | 
|  266   UMA_HISTOGRAM_COUNTS("ExtensionInstallSigner.UptimeAtTimeOfRequest", |  | 
|  267                        (base::Time::Now() - process_creation_time).InSeconds()); |  | 
|  268  |  | 
|  269   base::TimeDelta delta; |  | 
|  270   base::TimeTicks now = base::TimeTicks::Now(); |  | 
|  271   if (!g_last_request_time.Get().is_null()) |  | 
|  272     delta = now - g_last_request_time.Get(); |  | 
|  273   g_last_request_time.Get() = now; |  | 
|  274   UMA_HISTOGRAM_COUNTS("ExtensionInstallSigner.SecondsSinceLastRequest", |  | 
|  275                        delta.InSeconds()); |  | 
|  276  |  | 
|  277   g_request_count += 1; |  | 
|  278   UMA_HISTOGRAM_COUNTS_100("ExtensionInstallSigner.RequestCount", |  | 
|  279                            g_request_count); |  | 
|  280 } |  | 
|  281  |  | 
|  282 }  // namespace |  | 
|  283  |  | 
|  284 void InstallSigner::GetSignature(const SignatureCallback& callback) { |  246 void InstallSigner::GetSignature(const SignatureCallback& callback) { | 
|  285   CHECK(!url_fetcher_.get()); |  247   CHECK(!url_fetcher_.get()); | 
|  286   CHECK(callback_.is_null()); |  248   CHECK(callback_.is_null()); | 
|  287   CHECK(salt_.empty()); |  249   CHECK(salt_.empty()); | 
|  288   callback_ = callback; |  250   callback_ = callback; | 
|  289  |  251  | 
|  290   // If the set of ids is empty, just return an empty signature and skip the |  252   // If the set of ids is empty, just return an empty signature and skip the | 
|  291   // call to the server. |  253   // call to the server. | 
|  292   if (ids_.empty()) { |  254   if (ids_.empty()) { | 
|  293     if (!callback_.is_null()) |  255     if (!callback_.is_null()) | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  332     id_list->AppendString(*i); |  294     id_list->AppendString(*i); | 
|  333   } |  295   } | 
|  334   dictionary.Set(kIdsKey, id_list.release()); |  296   dictionary.Set(kIdsKey, id_list.release()); | 
|  335   std::string json; |  297   std::string json; | 
|  336   base::JSONWriter::Write(&dictionary, &json); |  298   base::JSONWriter::Write(&dictionary, &json); | 
|  337   if (json.empty()) { |  299   if (json.empty()) { | 
|  338     ReportErrorViaCallback(); |  300     ReportErrorViaCallback(); | 
|  339     return; |  301     return; | 
|  340   } |  302   } | 
|  341   url_fetcher_->SetUploadData("application/json", json); |  303   url_fetcher_->SetUploadData("application/json", json); | 
|  342   LogRequestStartHistograms(); |  | 
|  343   url_fetcher_->Start(); |  304   url_fetcher_->Start(); | 
|  344 } |  305 } | 
|  345  |  306  | 
|  346 void InstallSigner::ReportErrorViaCallback() { |  307 void InstallSigner::ReportErrorViaCallback() { | 
|  347   InstallSignature* null_signature = NULL; |  308   InstallSignature* null_signature = NULL; | 
|  348   if (!callback_.is_null()) |  309   if (!callback_.is_null()) | 
|  349     callback_.Run(scoped_ptr<InstallSignature>(null_signature)); |  310     callback_.Run(scoped_ptr<InstallSignature>(null_signature)); | 
|  350 } |  311 } | 
|  351  |  312  | 
|  352 void InstallSigner::ParseFetchResponse() { |  313 void InstallSigner::ParseFetchResponse() { | 
|  353   bool fetch_success = url_fetcher_->GetStatus().is_success(); |  | 
|  354   UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.FetchSuccess", fetch_success); |  | 
|  355  |  | 
|  356   std::string response; |  314   std::string response; | 
|  357   if (fetch_success) { |  315   if (!url_fetcher_->GetStatus().is_success() || | 
|  358     if (!url_fetcher_->GetResponseAsString(&response)) |  316       !url_fetcher_->GetResponseAsString(&response) || | 
|  359       response.clear(); |  317       response.empty()) { | 
|  360   } |  | 
|  361   UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.GetResponseSuccess", |  | 
|  362                         !response.empty()); |  | 
|  363   if (!fetch_success || response.empty()) { |  | 
|  364     ReportErrorViaCallback(); |  318     ReportErrorViaCallback(); | 
|  365     return; |  319     return; | 
|  366   } |  320   } | 
|  367  |  321  | 
|  368   // The response is JSON of the form: |  322   // The response is JSON of the form: | 
|  369   // { |  323   // { | 
|  370   //   "protocol_version": "1", |  324   //   "protocol_version": "1", | 
|  371   //   "signature": "<base64-encoded signature>", |  325   //   "signature": "<base64-encoded signature>", | 
|  372   //   "expiry": "<date in YYYY-MM-DD form>", |  326   //   "expiry": "<date in YYYY-MM-DD form>", | 
|  373   //   "invalid_ids": [ "<id3>", "<id4>" ] |  327   //   "invalid_ids": [ "<id3>", "<id4>" ] | 
|  374   // } |  328   // } | 
|  375   // where |invalid_ids| is a list of ids from the original request that |  329   // where |invalid_ids| is a list of ids from the original request that | 
|  376   // could not be verified to be in the webstore. |  330   // could not be verified to be in the webstore. | 
|  377  |  331  | 
|  378   base::DictionaryValue* dictionary = NULL; |  332   base::DictionaryValue* dictionary = NULL; | 
|  379   scoped_ptr<base::Value> parsed(base::JSONReader::Read(response)); |  333   scoped_ptr<base::Value> parsed(base::JSONReader::Read(response)); | 
|  380   bool json_success = parsed.get() && parsed->GetAsDictionary(&dictionary); |  334   if (!parsed.get() || !parsed->GetAsDictionary(&dictionary)) { | 
|  381   UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.ParseJsonSuccess", |  | 
|  382                         json_success); |  | 
|  383   if (!json_success) { |  | 
|  384     ReportErrorViaCallback(); |  335     ReportErrorViaCallback(); | 
|  385     return; |  336     return; | 
|  386   } |  337   } | 
|  387  |  338  | 
|  388   int protocol_version = 0; |  339   int protocol_version = 0; | 
|  389   std::string signature_base64; |  340   std::string signature_base64; | 
|  390   std::string signature; |  341   std::string signature; | 
|  391   std::string expire_date; |  342   std::string expire_date; | 
|  392  |  343  | 
|  393   dictionary->GetInteger(kProtocolVersionKey, &protocol_version); |  344   dictionary->GetInteger(kProtocolVersionKey, &protocol_version); | 
|  394   dictionary->GetString(kSignatureKey, &signature_base64); |  345   dictionary->GetString(kSignatureKey, &signature_base64); | 
|  395   dictionary->GetString(kExpiryKey, &expire_date); |  346   dictionary->GetString(kExpiryKey, &expire_date); | 
|  396  |  347  | 
|  397   bool fields_success = |  348   if (protocol_version != 1 || signature_base64.empty() || | 
|  398       protocol_version == 1 && !signature_base64.empty() && |  349       !ValidateExpireDateFormat(expire_date) || | 
|  399       ValidateExpireDateFormat(expire_date) && |  350       !base::Base64Decode(signature_base64, &signature)) { | 
|  400       base::Base64Decode(signature_base64, &signature); |  | 
|  401   UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.ParseFieldsSuccess", |  | 
|  402                         fields_success); |  | 
|  403   if (!fields_success) { |  | 
|  404     ReportErrorViaCallback(); |  351     ReportErrorViaCallback(); | 
|  405     return; |  352     return; | 
|  406   } |  353   } | 
|  407  |  354  | 
|  408   ExtensionIdSet invalid_ids; |  355   ExtensionIdSet invalid_ids; | 
|  409   const base::ListValue* invalid_ids_list = NULL; |  356   const base::ListValue* invalid_ids_list = NULL; | 
|  410   if (dictionary->GetList(kInvalidIdsKey, &invalid_ids_list)) { |  357   if (dictionary->GetList(kInvalidIdsKey, &invalid_ids_list)) { | 
|  411     for (size_t i = 0; i < invalid_ids_list->GetSize(); i++) { |  358     for (size_t i = 0; i < invalid_ids_list->GetSize(); i++) { | 
|  412       std::string id; |  359       std::string id; | 
|  413       if (!invalid_ids_list->GetString(i, &id)) { |  360       if (!invalid_ids_list->GetString(i, &id)) { | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
|  441     if (!verified) |  388     if (!verified) | 
|  442       result.reset(); |  389       result.reset(); | 
|  443   } |  390   } | 
|  444  |  391  | 
|  445   if (!callback_.is_null()) |  392   if (!callback_.is_null()) | 
|  446     callback_.Run(result.Pass()); |  393     callback_.Run(result.Pass()); | 
|  447 } |  394 } | 
|  448  |  395  | 
|  449  |  396  | 
|  450 }  // namespace extensions |  397 }  // namespace extensions | 
| OLD | NEW |