| Index: chrome/browser/chromeos/arc/arc_opt_in_manager_impl.cc
|
| diff --git a/chrome/browser/chromeos/arc/arc_opt_in_manager_impl.cc b/chrome/browser/chromeos/arc/arc_opt_in_manager_impl.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f460abbbfe8ace81a5b86087267ec28b4d73f0f3
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/arc/arc_opt_in_manager_impl.cc
|
| @@ -0,0 +1,169 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "arc_opt_in_manager_impl.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| +#include "components/arc/arc_bridge_service.h"
|
| +#include "google_apis/gaia/gaia_constants.h"
|
| +#include "google_apis/gaia/gaia_urls.h"
|
| +#include "net/http/http_status_code.h"
|
| +#include "net/url_request/url_fetcher.h"
|
| +
|
| +namespace arc {
|
| +
|
| +namespace {
|
| +
|
| +const char kClientId[] =
|
| + "1070009224336-sdh77n7uot3oc99ais00jmuft6sk2fg9.apps.googleusercontent.com";
|
| +const char kCookiePartSecure[] = "secure";
|
| +const char kCookiePartHttpOnly[] = "httponly";
|
| +const char kCookiePartCodePrefix[] = "oauth_code=";
|
| +const int kCookiePartCodePrefixLength = arraysize(kCookiePartCodePrefix) - 1;
|
| +
|
| +static bool CookiePartsContains(const std::vector<std::string>& parts,
|
| + const char* part) {
|
| + for (std::vector<std::string>::const_iterator it = parts.begin();
|
| + it != parts.end(); ++it) {
|
| + if (base::LowerCaseEqualsASCII(*it, part))
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ArcOptInManagerImpl::ArcOptInManagerImpl() {}
|
| +
|
| +ArcOptInManagerImpl::~ArcOptInManagerImpl() {}
|
| +
|
| +ArcOptInManager::State ArcOptInManagerImpl::state() const {
|
| + return state_;
|
| +}
|
| +
|
| +void ArcOptInManagerImpl::SetProfile(Profile* profile) {
|
| + DCHECK(profile == nullptr || profile != profile_);
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + ArcBridgeService::Get()->Shutdown();
|
| + if (state_ != State::DISABLE) {
|
| + auth_fetcher_.reset();
|
| + state_ = State::DISABLE;
|
| + FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_));
|
| + }
|
| +
|
| + profile_ = profile;
|
| +
|
| + // TODO(khmel). At this moment UI to handle ARC OptIn is not ready yet. Assume
|
| + // we opted in by default. When UI is ready, this should be synced with
|
| + // user's prefs.
|
| + if (profile_ != nullptr)
|
| + FetchToken();
|
| +}
|
| +
|
| +void ArcOptInManagerImpl::AddObserver(Observer* observer) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + observer_list_.AddObserver(observer);
|
| +}
|
| +
|
| +void ArcOptInManagerImpl::RemoveObserver(Observer* observer) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + observer_list_.RemoveObserver(observer);
|
| +}
|
| +
|
| +std::string ArcOptInManagerImpl::GetAuthToken() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + std::string auth_token;
|
| + auth_token_.swap(auth_token);
|
| + return auth_token;
|
| +}
|
| +
|
| +void ArcOptInManagerImpl::SetAuthTokenAndStartArc(
|
| + const std::string auth_token) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!auth_token.empty());
|
| + DCHECK(state_ != State::ENABLE);
|
| +
|
| + auth_fetcher_.reset();
|
| + auth_token_ = auth_token;
|
| + state_ = State::ENABLE;
|
| +
|
| + ArcBridgeService::Get()->HandleStartup();
|
| + FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_));
|
| +}
|
| +
|
| +GURL ArcOptInManagerImpl::CreateURL(Profile* profile) {
|
| + DCHECK(profile != nullptr);
|
| +
|
| + std::string query_string = base::StringPrintf(
|
| + "?scope=%s&client_id=%s&email=%s", GaiaConstants::kOAuth1LoginScope,
|
| + kClientId, profile->GetProfileUserName().c_str());
|
| +
|
| + return GaiaUrls::GetInstance()->client_login_to_oauth2_url().Resolve(
|
| + query_string);
|
| +}
|
| +
|
| +void ArcOptInManagerImpl::FetchToken() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(state_ == State::DISABLE);
|
| +
|
| + auth_token_ = "";
|
| + state_ = State::FETCHING_TOKEN;
|
| + FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_));
|
| +
|
| + auth_fetcher_ =
|
| + net::URLFetcher::Create(CreateURL(profile_), net::URLFetcher::GET, this);
|
| + auth_fetcher_->SetRequestContext(profile_->GetRequestContext());
|
| + // Executed asynchronously.
|
| + auth_fetcher_->Start();
|
| +}
|
| +
|
| +bool ArcOptInManagerImpl::ParseAuthToken(const net::URLFetcher* source,
|
| + std::string* token) {
|
| + DCHECK(source != nullptr && token != nullptr);
|
| + net::ResponseCookies::const_iterator iter;
|
| + const net::ResponseCookies& cookies = source->GetCookies();
|
| + for (iter = cookies.begin(); iter != cookies.end(); ++iter) {
|
| + std::vector<std::string> parts = base::SplitString(
|
| + *iter, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
|
| + // Per documentation, the cookie should have Secure and HttpOnly.
|
| + if (!CookiePartsContains(parts, kCookiePartSecure) ||
|
| + !CookiePartsContains(parts, kCookiePartHttpOnly)) {
|
| + continue;
|
| + }
|
| +
|
| + std::vector<std::string>::const_iterator iter;
|
| + for (iter = parts.begin(); iter != parts.end(); ++iter) {
|
| + const std::string& part = *iter;
|
| + if (base::StartsWith(part, kCookiePartCodePrefix,
|
| + base::CompareCase::INSENSITIVE_ASCII)) {
|
| + *token = part.substr(kCookiePartCodePrefixLength);
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +void ArcOptInManagerImpl::OnURLFetchComplete(const net::URLFetcher* source) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + std::string auth_token;
|
| + if (!source->GetStatus().is_success() ||
|
| + source->GetResponseCode() != net::HTTP_OK ||
|
| + !ParseAuthToken(source, &auth_token)) {
|
| + state_ = State::NO_TOKEN;
|
| + // TODO(khmel). There is no UI currently available. So start bridge anyway.
|
| + // GMS won't be signed in automatically.
|
| + ArcBridgeService::Get()->HandleStartup();
|
| + FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInChanged(state_));
|
| + } else {
|
| + SetAuthTokenAndStartArc(auth_token);
|
| + }
|
| +}
|
| +
|
| +} // namespace arc
|
|
|