Index: chrome/browser/extensions/api/identity/extension_auth_flow.cc |
=================================================================== |
--- chrome/browser/extensions/api/identity/extension_auth_flow.cc (revision 0) |
+++ chrome/browser/extensions/api/identity/extension_auth_flow.cc (revision 0) |
@@ -0,0 +1,174 @@ |
+// Copyright (c) 2012 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 "chrome/browser/extensions/api/identity/extension_auth_flow.h" |
+ |
+#include "base/location.h" |
+#include "base/message_loop.h" |
+#include "base/stringprintf.h" |
+#include "base/string_util.h" |
+#include "content/public/browser/invalidate_type.h" |
+#include "content/public/browser/navigation_controller.h" |
+#include "content/public/browser/web_contents.h" |
+#include "ipc/ipc_message.h" |
+#include "ui/views/controls/webview/webview.h" |
+#include "ui/views/widget/widget.h" |
+ |
+using content::BrowserContext; |
+using content::WebContents; |
+using content::WebContentsDelegate; |
+using views::View; |
+using views::WebView; |
+using views::Widget; |
+using views::WidgetDelegate; |
+ |
+namespace { |
+ |
+static const char kChromeExtensionSchemeUrlPattern[] = |
+ "chrome-extension://%s/"; |
+static const char kChromiumDomainRedirectUrlPattern[] = |
+ "https://%s.chromiumapp.org/"; |
+ |
+} // namespace |
+ |
+namespace extensions { |
+ |
+ExtensionAuthFlow::ExtensionAuthFlow( |
+ Delegate* delegate, |
+ content::BrowserContext* browser_context, |
+ const std::string& extension_id, |
+ const GURL& provider_url) |
+ : delegate_(delegate), |
+ browser_context_(browser_context), |
+ provider_url_(provider_url), |
+ contents_(NULL), |
+ widget_(NULL), |
+ web_view_(NULL) { |
+ InitValidRedirectUrlPrefixes(extension_id); |
+} |
+ |
+ExtensionAuthFlow::~ExtensionAuthFlow() { |
+ if (widget_) |
+ widget_->Close(); // Close() deletes the widget also. |
+ if (contents_) { |
+ contents_->SetDelegate(NULL); |
+ contents_->Stop(); |
+ // Tell message loop to delete contents_ instead of deleting it |
+ // directly since destructor can run in response to a callback from |
+ // contents_. |
+ MessageLoop::current()->DeleteSoon(FROM_HERE, contents_); |
+ } |
+} |
+ |
+void ExtensionAuthFlow::Start() { |
+ contents_ = CreateWebContents(); |
+ contents_->SetDelegate(this); |
+ contents_->GetController().LoadURL( |
+ provider_url_, |
+ content::Referrer(), |
+ content::PAGE_TRANSITION_START_PAGE, |
+ std::string()); |
+} |
+ |
+void ExtensionAuthFlow::LoadingStateChanged(WebContents* source) { |
+ if (source->IsLoading()) |
+ return; |
+ OnUrlLoaded(); |
+} |
+ |
+void ExtensionAuthFlow::NavigationStateChanged( |
+ const WebContents* source, unsigned changed_flags) { |
+ // If the URL has not changed, do not perform the check again (for |
+ // efficiency). |
+ if ((changed_flags & content::INVALIDATE_TYPE_URL) == 0) |
+ return; |
+ |
+ // If the URL is a valid extension redirect URL, capture the |
+ // results and end the flow. |
+ const GURL& url = source->GetURL(); |
+ |
+ if (IsValidRedirectUrl(url)) { |
+ ReportResult(url); |
+ return; |
+ } |
+} |
+ |
+WebContents* ExtensionAuthFlow::CreateWebContents() { |
+ return WebContents::Create( |
+ browser_context_, NULL, MSG_ROUTING_NONE, NULL, NULL); |
+} |
+ |
+void ExtensionAuthFlow::OnUrlLoaded() { |
+ const GURL& url = contents_->GetURL(); |
+ |
+ if (!widget_) { |
+ web_view_ = new WebView(browser_context_); |
+ web_view_->SetWebContents(contents_); |
+ widget_ = Widget::CreateWindow(this); |
+ // TODO(munjal): Make this configurable? |
+ widget_->CenterWindow(gfx::Size(1024, 768)); |
+ widget_->Show(); |
+ } |
+} |
+ |
+View* ExtensionAuthFlow::GetContentsView() { |
+ CHECK(web_view_); |
+ return web_view_; |
+} |
+ |
+Widget* ExtensionAuthFlow::GetWidget() { |
+ CHECK(widget_); |
+ return widget_; |
+} |
+ |
+const Widget* ExtensionAuthFlow::GetWidget() const { |
+ CHECK(widget_); |
+ return widget_; |
+} |
+ |
+View* ExtensionAuthFlow::GetInitiallyFocusedView() { |
+ CHECK(web_view_); |
+ return web_view_; |
+} |
+ |
+void ExtensionAuthFlow::DeleteDelegate() { |
+ ReportResult(GURL()); |
+} |
+ |
+void ExtensionAuthFlow::ReportResult(const GURL& result) { |
+ if (!delegate_) |
+ return; |
+ |
+ if (result.is_empty()) { |
+ delegate_->OnAuthFlowFailure(); |
+ } else { |
+ // TODO(munjal): Consider adding code to parse out access token |
+ // from some common places (e.g. URL fragment) so the apps don't |
+ // have to do that work. |
+ delegate_->OnAuthFlowSuccess(result.spec()); |
+ } |
+ |
+ // IMPORTANT: Do not access any members after calling the delegate |
+ // since the delegate can destroy |this| in the callback and hence |
+ // all data members are invalid after that. |
+} |
+ |
+void ExtensionAuthFlow::InitValidRedirectUrlPrefixes( |
+ const std::string& extension_id) { |
+ valid_prefixes_.push_back(base::StringPrintf( |
+ kChromeExtensionSchemeUrlPattern, extension_id.c_str())); |
+ valid_prefixes_.push_back(base::StringPrintf( |
+ kChromiumDomainRedirectUrlPattern, extension_id.c_str())); |
+} |
+ |
+bool ExtensionAuthFlow::IsValidRedirectUrl(const GURL& url) const { |
+ std::vector<std::string>::const_iterator iter; |
+ for (iter = valid_prefixes_.begin(); iter != valid_prefixes_.end(); ++iter) { |
+ if (StartsWithASCII(url.spec(), *iter, false)) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+} // namespace extensions |