OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/extensions/api/identity/extension_auth_flow.h" |
| 6 |
| 7 #include "base/location.h" |
| 8 #include "base/message_loop.h" |
| 9 #include "base/stringprintf.h" |
| 10 #include "base/string_util.h" |
| 11 #include "content/public/browser/invalidate_type.h" |
| 12 #include "content/public/browser/navigation_controller.h" |
| 13 #include "content/public/browser/web_contents.h" |
| 14 #include "ipc/ipc_message.h" |
| 15 #include "ui/views/controls/webview/webview.h" |
| 16 #include "ui/views/widget/widget.h" |
| 17 |
| 18 using content::BrowserContext; |
| 19 using content::WebContents; |
| 20 using content::WebContentsDelegate; |
| 21 using views::View; |
| 22 using views::WebView; |
| 23 using views::Widget; |
| 24 using views::WidgetDelegate; |
| 25 |
| 26 namespace { |
| 27 |
| 28 static const char kChromeExtensionSchemeUrlPattern[] = |
| 29 "chrome-extension://%s/"; |
| 30 static const char kChromiumDomainRedirectUrlPattern[] = |
| 31 "https://%s.chromiumapp.org/"; |
| 32 |
| 33 } // namespace |
| 34 |
| 35 namespace extensions { |
| 36 |
| 37 ExtensionAuthFlow::ExtensionAuthFlow( |
| 38 Delegate* delegate, |
| 39 content::BrowserContext* browser_context, |
| 40 const std::string& extension_id, |
| 41 const GURL& provider_url) |
| 42 : delegate_(delegate), |
| 43 browser_context_(browser_context), |
| 44 provider_url_(provider_url), |
| 45 contents_(NULL), |
| 46 widget_(NULL), |
| 47 web_view_(NULL) { |
| 48 InitValidRedirectUrlPrefixes(extension_id); |
| 49 } |
| 50 |
| 51 ExtensionAuthFlow::~ExtensionAuthFlow() { |
| 52 if (widget_) |
| 53 widget_->Close(); // Close() deletes the widget also. |
| 54 if (contents_) { |
| 55 contents_->SetDelegate(NULL); |
| 56 contents_->Stop(); |
| 57 // Tell message loop to delete contents_ instead of deleting it |
| 58 // directly since destructor can run in response to a callback from |
| 59 // contents_. |
| 60 MessageLoop::current()->DeleteSoon(FROM_HERE, contents_); |
| 61 } |
| 62 } |
| 63 |
| 64 void ExtensionAuthFlow::Start() { |
| 65 contents_ = CreateWebContents(); |
| 66 contents_->SetDelegate(this); |
| 67 contents_->GetController().LoadURL( |
| 68 provider_url_, |
| 69 content::Referrer(), |
| 70 content::PAGE_TRANSITION_START_PAGE, |
| 71 std::string()); |
| 72 } |
| 73 |
| 74 void ExtensionAuthFlow::LoadingStateChanged(WebContents* source) { |
| 75 if (source->IsLoading()) |
| 76 return; |
| 77 OnUrlLoaded(); |
| 78 } |
| 79 |
| 80 void ExtensionAuthFlow::NavigationStateChanged( |
| 81 const WebContents* source, unsigned changed_flags) { |
| 82 // If the URL has not changed, do not perform the check again (for |
| 83 // efficiency). |
| 84 if ((changed_flags & content::INVALIDATE_TYPE_URL) == 0) |
| 85 return; |
| 86 |
| 87 // If the URL is a valid extension redirect URL, capture the |
| 88 // results and end the flow. |
| 89 const GURL& url = source->GetURL(); |
| 90 |
| 91 if (IsValidRedirectUrl(url)) { |
| 92 ReportResult(url); |
| 93 return; |
| 94 } |
| 95 } |
| 96 |
| 97 WebContents* ExtensionAuthFlow::CreateWebContents() { |
| 98 return WebContents::Create( |
| 99 browser_context_, NULL, MSG_ROUTING_NONE, NULL, NULL); |
| 100 } |
| 101 |
| 102 void ExtensionAuthFlow::OnUrlLoaded() { |
| 103 const GURL& url = contents_->GetURL(); |
| 104 |
| 105 if (!widget_) { |
| 106 web_view_ = new WebView(browser_context_); |
| 107 web_view_->SetWebContents(contents_); |
| 108 widget_ = Widget::CreateWindow(this); |
| 109 // TODO(munjal): Make this configurable? |
| 110 widget_->CenterWindow(gfx::Size(1024, 768)); |
| 111 widget_->Show(); |
| 112 } |
| 113 } |
| 114 |
| 115 View* ExtensionAuthFlow::GetContentsView() { |
| 116 CHECK(web_view_); |
| 117 return web_view_; |
| 118 } |
| 119 |
| 120 Widget* ExtensionAuthFlow::GetWidget() { |
| 121 CHECK(widget_); |
| 122 return widget_; |
| 123 } |
| 124 |
| 125 const Widget* ExtensionAuthFlow::GetWidget() const { |
| 126 CHECK(widget_); |
| 127 return widget_; |
| 128 } |
| 129 |
| 130 View* ExtensionAuthFlow::GetInitiallyFocusedView() { |
| 131 CHECK(web_view_); |
| 132 return web_view_; |
| 133 } |
| 134 |
| 135 void ExtensionAuthFlow::DeleteDelegate() { |
| 136 ReportResult(GURL()); |
| 137 } |
| 138 |
| 139 void ExtensionAuthFlow::ReportResult(const GURL& result) { |
| 140 if (!delegate_) |
| 141 return; |
| 142 |
| 143 if (result.is_empty()) { |
| 144 delegate_->OnAuthFlowFailure(); |
| 145 } else { |
| 146 // TODO(munjal): Consider adding code to parse out access token |
| 147 // from some common places (e.g. URL fragment) so the apps don't |
| 148 // have to do that work. |
| 149 delegate_->OnAuthFlowSuccess(result.spec()); |
| 150 } |
| 151 |
| 152 // IMPORTANT: Do not access any members after calling the delegate |
| 153 // since the delegate can destroy |this| in the callback and hence |
| 154 // all data members are invalid after that. |
| 155 } |
| 156 |
| 157 void ExtensionAuthFlow::InitValidRedirectUrlPrefixes( |
| 158 const std::string& extension_id) { |
| 159 valid_prefixes_.push_back(base::StringPrintf( |
| 160 kChromeExtensionSchemeUrlPattern, extension_id.c_str())); |
| 161 valid_prefixes_.push_back(base::StringPrintf( |
| 162 kChromiumDomainRedirectUrlPattern, extension_id.c_str())); |
| 163 } |
| 164 |
| 165 bool ExtensionAuthFlow::IsValidRedirectUrl(const GURL& url) const { |
| 166 std::vector<std::string>::const_iterator iter; |
| 167 for (iter = valid_prefixes_.begin(); iter != valid_prefixes_.end(); ++iter) { |
| 168 if (StartsWithASCII(url.spec(), *iter, false)) |
| 169 return true; |
| 170 } |
| 171 return false; |
| 172 } |
| 173 |
| 174 } // namespace extensions |
OLD | NEW |