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 "ipc/ipc_message.h" | |
14 | |
15 using content::BrowserContext; | |
16 using content::WebContents; | |
17 using content::WebContentsDelegate; | |
18 using views::View; | |
19 using views::WebView; | |
20 using views::Widget; | |
21 using views::WidgetDelegate; | |
22 | |
23 namespace { | |
24 | |
25 static const char kChromeExtensionSchemeUrlPattern[] = | |
26 "chrome-extension://%s/"; | |
27 static const char kChromiumDomainRedirectUrlPattern[] = | |
28 "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.
| |
29 | |
30 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.
| |
31 const std::string& extension_id, | |
32 std::vector<std::string>* list) { | |
33 CHECK(list); | |
34 list->push_back(base::StringPrintf(kChromeExtensionSchemeUrlPattern, | |
35 extension_id.c_str())); | |
36 list->push_back(base::StringPrintf(kChromiumDomainRedirectUrlPattern, | |
37 extension_id.c_str())); | |
38 } | |
39 | |
40 } // namespace | |
41 | |
42 namespace extensions { | |
43 | |
44 ExtensionAuthFlow::ExtensionAuthFlow( | |
45 Delegate* delegate, | |
46 content::BrowserContext* browser_context, | |
47 const std::string& extension_id, | |
48 const GURL& provider_url) | |
49 : delegate_(delegate), | |
50 browser_context_(browser_context), | |
51 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.
| |
52 provider_url_(provider_url), | |
53 contents_(NULL), | |
54 widget_(NULL), | |
55 web_view_(NULL) { | |
56 PopulateValidRedirectUrlPrefixes(extension_id_, &valid_prefixes_); | |
57 } | |
58 | |
59 ExtensionAuthFlow::~ExtensionAuthFlow() { | |
60 if (widget_) | |
61 widget_->Close(); // Close() deletes the widget also. | |
62 if (contents_) { | |
63 contents_->SetDelegate(NULL); | |
64 contents_->Stop(); | |
65 // Tell message loop to delete contents_ instead of deleting it | |
66 // directly since destructor can run in response to a callback from | |
67 // contents_. | |
68 MessageLoop::current()->DeleteSoon(FROM_HERE, contents_); | |
69 } | |
70 } | |
71 | |
72 void ExtensionAuthFlow::Start() { | |
73 contents_ = WebContents::Create( | |
74 browser_context_, NULL, MSG_ROUTING_NONE, NULL, NULL); | |
75 contents_->SetDelegate(this); | |
76 contents_->GetController().LoadURL( | |
77 provider_url_, | |
78 content::Referrer(), | |
79 content::PAGE_TRANSITION_START_PAGE, | |
80 std::string()); | |
81 } | |
82 | |
83 void ExtensionAuthFlow::LoadingStateChanged(WebContents* source) { | |
84 if (source->IsLoading()) | |
85 return; | |
86 OnUrlLoaded(); | |
87 } | |
88 | |
89 void ExtensionAuthFlow::NavigationStateChanged( | |
90 const WebContents* source, unsigned changed_flags) { | |
91 // If the URL has not changed, do not perform the check again (for | |
92 // efficiency). | |
93 if ((changed_flags & content::INVALIDATE_TYPE_URL) == 0) | |
94 return; | |
95 | |
96 const GURL& url = source->GetURL(); | |
97 | |
98 // If the URL being loaded is not from the provider host, then | |
99 // 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
| |
100 if (url.host() != provider_url_.host()) { | |
101 // The URL is either a valid extension redirect URL or an | |
102 // invalid URL. | |
103 if (IsValidExtensionRedirectUrl(url)) | |
104 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.
| |
105 | |
106 ReportResult(); | |
107 return; | |
108 } | |
109 } | |
110 | |
111 void ExtensionAuthFlow::OnUrlLoaded() { | |
112 const GURL& url = contents_->GetURL(); | |
113 CHECK_EQ(url.host(), provider_url_.host()); | |
114 | |
115 if (!widget_) { | |
116 web_view_ = new WebView(browser_context_); | |
117 web_view_->SetWebContents(contents_); | |
118 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
| |
119 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.
| |
120 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
| |
121 } | |
122 } | |
123 | |
124 View* ExtensionAuthFlow::GetContentsView() { | |
125 CHECK(web_view_); | |
126 return web_view_; | |
127 } | |
128 | |
129 Widget* ExtensionAuthFlow::GetWidget() { | |
130 CHECK(widget_); | |
131 return widget_; | |
132 } | |
133 | |
134 const Widget* ExtensionAuthFlow::GetWidget() const { | |
135 CHECK(widget_); | |
136 return widget_; | |
137 } | |
138 | |
139 View* ExtensionAuthFlow::GetInitiallyFocusedView() { | |
140 CHECK(web_view_); | |
141 return web_view_; | |
142 } | |
143 | |
144 void ExtensionAuthFlow::DeleteDelegate() { | |
145 ReportResult(); | |
146 } | |
147 | |
148 void ExtensionAuthFlow::ReportResult() { | |
149 if (!delegate_) | |
150 return; | |
151 | |
152 if (result_.is_empty()) { | |
153 delegate_->OnAuthFlowFailed(); | |
154 } else { | |
155 // TODO(munjal): Consider adding code to parse out access token | |
156 // from some common places (e.g. URL fragment) so the apps don't | |
157 // have to do that work. | |
158 delegate_->OnAuthFlowCompleted(result_.spec()); | |
159 } | |
160 | |
161 // IMPORTANT: Do not access any members after calling the delegate | |
162 // since the delegate can destroy |this| in the callback and hence | |
163 // all data members are invalid after that. | |
164 } | |
165 | |
166 bool ExtensionAuthFlow::IsValidExtensionRedirectUrl(const GURL& url) const { | |
167 std::vector<std::string>::const_iterator iter; | |
168 for (iter = valid_prefixes_.begin(); iter != valid_prefixes_.end(); ++iter) { | |
169 if (StartsWithASCII(url.spec(), *iter, false)) | |
170 return true; | |
171 } | |
172 return false; | |
173 } | |
174 | |
175 } // namespace extensions | |
OLD | NEW |