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,175 @@ |
+// 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 "ipc/ipc_message.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.ext.chromium.org/"; |
Mihai Parparita -not on Chrome
2012/05/04 22:37:18
I would prefer not use chromium.org, since it's st
Munjal (Google)
2012/05/08 19:26:35
Done.
|
+ |
+static void PopulateValidRedirectUrlPrefixes( |
Mihai Parparita -not on Chrome
2012/05/04 22:37:18
Not sure I see the benefit of making this into a s
Munjal (Google)
2012/05/08 19:26:35
Done.
|
+ const std::string& extension_id, |
+ std::vector<std::string>* list) { |
+ CHECK(list); |
+ list->push_back(base::StringPrintf(kChromeExtensionSchemeUrlPattern, |
+ extension_id.c_str())); |
+ list->push_back(base::StringPrintf(kChromiumDomainRedirectUrlPattern, |
+ extension_id.c_str())); |
+} |
+ |
+} // 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), |
+ extension_id_(extension_id), |
Mihai Parparita -not on Chrome
2012/05/04 22:37:18
The extension_id_ member is otherwise unused, you
Munjal (Google)
2012/05/08 19:26:35
Done.
Munjal (Google)
2012/05/08 19:26:35
Done.
|
+ provider_url_(provider_url), |
+ contents_(NULL), |
+ widget_(NULL), |
+ web_view_(NULL) { |
+ PopulateValidRedirectUrlPrefixes(extension_id_, &valid_prefixes_); |
+} |
+ |
+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_ = WebContents::Create( |
+ browser_context_, NULL, MSG_ROUTING_NONE, NULL, NULL); |
+ 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; |
+ |
+ const GURL& url = source->GetURL(); |
+ |
+ // If the URL being loaded is not from the provider host, then |
+ // we are done with the flow. |
Mihai Parparita -not on Chrome
2012/05/04 22:37:18
I don't think this is quite true. If I'm not signe
Munjal (Google)
2012/05/08 19:26:35
I put in some thought into this but not enough to
|
+ if (url.host() != provider_url_.host()) { |
+ // The URL is either a valid extension redirect URL or an |
+ // invalid URL. |
+ if (IsValidExtensionRedirectUrl(url)) |
+ result_ = url; |
Mihai Parparita -not on Chrome
2012/05/04 22:37:18
I don't think result_ should be a member, instead
Munjal (Google)
2012/05/08 19:26:35
Done.
|
+ |
+ ReportResult(); |
+ return; |
+ } |
+} |
+ |
+void ExtensionAuthFlow::OnUrlLoaded() { |
+ const GURL& url = contents_->GetURL(); |
+ CHECK_EQ(url.host(), provider_url_.host()); |
+ |
+ if (!widget_) { |
+ web_view_ = new WebView(browser_context_); |
+ web_view_->SetWebContents(contents_); |
+ widget_ = Widget::CreateWindow(this); |
Avi (use Gerrit)
2012/05/07 23:31:13
This is just a floating window, popup-like without
Munjal (Google)
2012/05/08 19:26:35
I am not aware of what is the difference between a
|
+ widget_->CenterWindow(gfx::Size(1024, 768)); |
Mihai Parparita -not on Chrome
2012/05/04 22:37:18
TODO about making this configurable?
Munjal (Google)
2012/05/08 19:26:35
Done.
I suppose you meant the size of the window.
|
+ widget_->Show(); |
Mihai Parparita -not on Chrome
2012/05/04 22:37:18
So we only show the window once the initial URL ha
Munjal (Google)
2012/05/08 19:26:35
Yes, this is actually intentional. We will not sho
|
+ } |
+} |
+ |
+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(); |
+} |
+ |
+void ExtensionAuthFlow::ReportResult() { |
+ if (!delegate_) |
+ return; |
+ |
+ if (result_.is_empty()) { |
+ delegate_->OnAuthFlowFailed(); |
+ } 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_->OnAuthFlowCompleted(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. |
+} |
+ |
+bool ExtensionAuthFlow::IsValidExtensionRedirectUrl(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 |