Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / ui / webui / identity_internals_ui.cc
blob80052257c2ea0a7d78e270f3587fe827c4df821d
1 // Copyright 2013 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.
5 #include "chrome/browser/ui/webui/identity_internals_ui.h"
7 #include <set>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/i18n/time_formatting.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/api/identity/identity_api.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/common/url_constants.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "content/public/browser/web_ui.h"
20 #include "content/public/browser/web_ui_controller.h"
21 #include "content/public/browser/web_ui_data_source.h"
22 #include "content/public/browser/web_ui_message_handler.h"
23 #include "extensions/browser/extension_system.h"
24 #include "google_apis/gaia/gaia_auth_fetcher.h"
25 #include "google_apis/gaia/gaia_constants.h"
26 #include "grit/browser_resources.h"
27 #include "ui/base/l10n/l10n_util.h"
29 namespace {
31 // Properties of the Javascript object representing a token.
32 const char kExtensionId[] = "extensionId";
33 const char kExtensionName[] = "extensionName";
34 const char kScopes[] = "scopes";
35 const char kStatus[] = "status";
36 const char kTokenExpirationTime[] = "expirationTime";
37 const char kAccessToken[] = "accessToken";
39 // RevokeToken message parameter offsets.
40 const int kRevokeTokenExtensionOffset = 0;
41 const int kRevokeTokenTokenOffset = 1;
43 class IdentityInternalsTokenRevoker;
45 // Class acting as a controller of the chrome://identity-internals WebUI.
46 class IdentityInternalsUIMessageHandler : public content::WebUIMessageHandler {
47 public:
48 IdentityInternalsUIMessageHandler();
49 virtual ~IdentityInternalsUIMessageHandler();
51 // Ensures that a proper clean up happens after a token is revoked. That
52 // includes deleting the |token_revoker|, removing the token from Identity API
53 // cache and updating the UI that the token is gone.
54 void OnTokenRevokerDone(IdentityInternalsTokenRevoker* token_revoker);
56 // WebUIMessageHandler implementation.
57 virtual void RegisterMessages() override;
59 private:
60 // Gets the name of an extension referred to by |token_cache_key| as a string.
61 const std::string GetExtensionName(
62 const extensions::ExtensionTokenKey& token_cache_key);
64 // Gets a list of scopes specified in |token_cache_key| and returns a pointer
65 // to a ListValue containing the scopes. The caller gets ownership of the
66 // returned object.
67 base::ListValue* GetScopes(
68 const extensions::ExtensionTokenKey& token_cache_key);
70 // Gets a localized status of the access token in |token_cache_value|.
71 const base::string16 GetStatus(
72 const extensions::IdentityTokenCacheValue& token_cache_value);
74 // Gets a string representation of an expiration time of the access token in
75 // |token_cache_value|.
76 const std::string GetExpirationTime(
77 const extensions::IdentityTokenCacheValue& token_cache_value);
79 // Converts a pair of |token_cache_key| and |token_cache_value| to a
80 // DictionaryValue object with corresponding information in a localized and
81 // readable form and returns a pointer to created object. Caller gets the
82 // ownership of the returned object.
83 base::DictionaryValue* GetInfoForToken(
84 const extensions::ExtensionTokenKey& token_cache_key,
85 const extensions::IdentityTokenCacheValue& token_cache_value);
87 // Gets all of the tokens stored in IdentityAPI token cache and returns them
88 // to the caller using Javascript callback function
89 // |identity_internals.returnTokens()|.
90 void GetInfoForAllTokens(const base::ListValue* args);
92 // Initiates revoking of the token, based on the extension ID and token
93 // passed as entries in the |args| list. Updates the caller of completion
94 // using Javascript callback function |identity_internals.tokenRevokeDone()|.
95 void RevokeToken(const base::ListValue* args);
97 // A vector of token revokers that are currently revoking tokens.
98 ScopedVector<IdentityInternalsTokenRevoker> token_revokers_;
101 // Handles the revoking of an access token and helps performing the clean up
102 // after it is revoked by holding information about the access token and related
103 // extension ID.
104 class IdentityInternalsTokenRevoker : public GaiaAuthConsumer {
105 public:
106 // Revokes |access_token| from extension with |extension_id|.
107 // |profile| is required for its request context. |consumer| will be
108 // notified when revocation succeeds via |OnTokenRevokerDone()|.
109 IdentityInternalsTokenRevoker(const std::string& extension_id,
110 const std::string& access_token,
111 Profile* profile,
112 IdentityInternalsUIMessageHandler* consumer);
113 virtual ~IdentityInternalsTokenRevoker();
115 // Returns the access token being revoked.
116 const std::string& access_token() const { return access_token_; }
118 // Returns the ID of the extension the access token is related to.
119 const std::string& extension_id() const { return extension_id_; }
121 // GaiaAuthConsumer implementation.
122 virtual void OnOAuth2RevokeTokenCompleted() override;
124 private:
125 // An object used to start a token revoke request.
126 GaiaAuthFetcher fetcher_;
127 // An ID of an extension the access token is related to.
128 const std::string extension_id_;
129 // The access token to revoke.
130 const std::string access_token_;
131 // An object that needs to be notified once the access token is revoked.
132 IdentityInternalsUIMessageHandler* consumer_; // weak.
134 DISALLOW_COPY_AND_ASSIGN(IdentityInternalsTokenRevoker);
137 IdentityInternalsUIMessageHandler::IdentityInternalsUIMessageHandler() {}
139 IdentityInternalsUIMessageHandler::~IdentityInternalsUIMessageHandler() {}
141 void IdentityInternalsUIMessageHandler::OnTokenRevokerDone(
142 IdentityInternalsTokenRevoker* token_revoker) {
143 // Remove token from the cache.
144 extensions::IdentityAPI::GetFactoryInstance()
145 ->Get(Profile::FromWebUI(web_ui()))
146 ->EraseCachedToken(token_revoker->extension_id(),
147 token_revoker->access_token());
149 // Update view about the token being removed.
150 base::ListValue result;
151 result.AppendString(token_revoker->access_token());
152 web_ui()->CallJavascriptFunction("identity_internals.tokenRevokeDone",
153 result);
155 // Erase the revoker.
156 ScopedVector<IdentityInternalsTokenRevoker>::iterator iter =
157 std::find(token_revokers_.begin(), token_revokers_.end(), token_revoker);
158 DCHECK(iter != token_revokers_.end());
159 token_revokers_.erase(iter);
162 const std::string IdentityInternalsUIMessageHandler::GetExtensionName(
163 const extensions::ExtensionTokenKey& token_cache_key) {
164 ExtensionService* extension_service = extensions::ExtensionSystem::Get(
165 Profile::FromWebUI(web_ui()))->extension_service();
166 const extensions::Extension* extension =
167 extension_service->extensions()->GetByID(token_cache_key.extension_id);
168 if (!extension)
169 return std::string();
170 return extension->name();
173 base::ListValue* IdentityInternalsUIMessageHandler::GetScopes(
174 const extensions::ExtensionTokenKey& token_cache_key) {
175 base::ListValue* scopes_value = new base::ListValue();
176 for (std::set<std::string>::const_iterator
177 iter = token_cache_key.scopes.begin();
178 iter != token_cache_key.scopes.end(); ++iter) {
179 scopes_value->AppendString(*iter);
181 return scopes_value;
184 const base::string16 IdentityInternalsUIMessageHandler::GetStatus(
185 const extensions::IdentityTokenCacheValue& token_cache_value) {
186 switch (token_cache_value.status()) {
187 case extensions::IdentityTokenCacheValue::CACHE_STATUS_ADVICE:
188 // Fallthrough to NOT FOUND case, as ADVICE is short lived.
189 case extensions::IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND:
190 return l10n_util::GetStringUTF16(
191 IDS_IDENTITY_INTERNALS_TOKEN_NOT_FOUND);
192 case extensions::IdentityTokenCacheValue::CACHE_STATUS_TOKEN:
193 return l10n_util::GetStringUTF16(
194 IDS_IDENTITY_INTERNALS_TOKEN_PRESENT);
196 NOTREACHED();
197 return base::string16();
200 const std::string IdentityInternalsUIMessageHandler::GetExpirationTime(
201 const extensions::IdentityTokenCacheValue& token_cache_value) {
202 return base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
203 token_cache_value.expiration_time()));
206 base::DictionaryValue* IdentityInternalsUIMessageHandler::GetInfoForToken(
207 const extensions::ExtensionTokenKey& token_cache_key,
208 const extensions::IdentityTokenCacheValue& token_cache_value) {
209 base::DictionaryValue* token_data = new base::DictionaryValue();
210 token_data->SetString(kExtensionId, token_cache_key.extension_id);
211 token_data->SetString(kExtensionName, GetExtensionName(token_cache_key));
212 token_data->Set(kScopes, GetScopes(token_cache_key));
213 token_data->SetString(kStatus, GetStatus(token_cache_value));
214 token_data->SetString(kAccessToken, token_cache_value.token());
215 token_data->SetString(kTokenExpirationTime,
216 GetExpirationTime(token_cache_value));
217 return token_data;
220 void IdentityInternalsUIMessageHandler::GetInfoForAllTokens(
221 const base::ListValue* args) {
222 base::ListValue results;
223 extensions::IdentityAPI::CachedTokens tokens =
224 extensions::IdentityAPI::GetFactoryInstance()
225 ->Get(Profile::FromWebUI(web_ui()))
226 ->GetAllCachedTokens();
227 for (extensions::IdentityAPI::CachedTokens::const_iterator
228 iter = tokens.begin(); iter != tokens.end(); ++iter) {
229 results.Append(GetInfoForToken(iter->first, iter->second));
232 web_ui()->CallJavascriptFunction("identity_internals.returnTokens", results);
235 void IdentityInternalsUIMessageHandler::RegisterMessages() {
236 web_ui()->RegisterMessageCallback("identityInternalsGetTokens",
237 base::Bind(&IdentityInternalsUIMessageHandler::GetInfoForAllTokens,
238 base::Unretained(this)));
239 web_ui()->RegisterMessageCallback("identityInternalsRevokeToken",
240 base::Bind(&IdentityInternalsUIMessageHandler::RevokeToken,
241 base::Unretained(this)));
244 void IdentityInternalsUIMessageHandler::RevokeToken(
245 const base::ListValue* args) {
246 std::string extension_id;
247 std::string access_token;
248 args->GetString(kRevokeTokenExtensionOffset, &extension_id);
249 args->GetString(kRevokeTokenTokenOffset, &access_token);
250 token_revokers_.push_back(new IdentityInternalsTokenRevoker(
251 extension_id, access_token, Profile::FromWebUI(web_ui()), this));
254 IdentityInternalsTokenRevoker::IdentityInternalsTokenRevoker(
255 const std::string& extension_id,
256 const std::string& access_token,
257 Profile* profile,
258 IdentityInternalsUIMessageHandler* consumer)
259 : fetcher_(this, GaiaConstants::kChromeSource,
260 profile->GetRequestContext()),
261 extension_id_(extension_id),
262 access_token_(access_token),
263 consumer_(consumer) {
264 DCHECK(consumer_);
265 fetcher_.StartRevokeOAuth2Token(access_token);
268 IdentityInternalsTokenRevoker::~IdentityInternalsTokenRevoker() {}
270 void IdentityInternalsTokenRevoker::OnOAuth2RevokeTokenCompleted() {
271 consumer_->OnTokenRevokerDone(this);
274 } // namespace
276 IdentityInternalsUI::IdentityInternalsUI(content::WebUI* web_ui)
277 : content::WebUIController(web_ui) {
278 // chrome://identity-internals source.
279 content::WebUIDataSource* html_source =
280 content::WebUIDataSource::Create(chrome::kChromeUIIdentityInternalsHost);
282 // Localized strings
283 html_source->AddLocalizedString("tokenCacheHeader",
284 IDS_IDENTITY_INTERNALS_TOKEN_CACHE_TEXT);
285 html_source->AddLocalizedString("accessToken",
286 IDS_IDENTITY_INTERNALS_ACCESS_TOKEN);
287 html_source->AddLocalizedString("extensionName",
288 IDS_IDENTITY_INTERNALS_EXTENSION_NAME);
289 html_source->AddLocalizedString("extensionId",
290 IDS_IDENTITY_INTERNALS_EXTENSION_ID);
291 html_source->AddLocalizedString("tokenStatus",
292 IDS_IDENTITY_INTERNALS_TOKEN_STATUS);
293 html_source->AddLocalizedString("expirationTime",
294 IDS_IDENTITY_INTERNALS_EXPIRATION_TIME);
295 html_source->AddLocalizedString("scopes",
296 IDS_IDENTITY_INTERNALS_SCOPES);
297 html_source->AddLocalizedString("revoke",
298 IDS_IDENTITY_INTERNALS_REVOKE);
299 html_source->SetJsonPath("strings.js");
301 // Required resources
302 html_source->AddResourcePath("identity_internals.css",
303 IDR_IDENTITY_INTERNALS_CSS);
304 html_source->AddResourcePath("identity_internals.js",
305 IDR_IDENTITY_INTERNALS_JS);
306 html_source->SetDefaultResource(IDR_IDENTITY_INTERNALS_HTML);
308 content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
310 web_ui->AddMessageHandler(new IdentityInternalsUIMessageHandler());
313 IdentityInternalsUI::~IdentityInternalsUI() {}