1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
// Copyright 2015 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 "ios/chrome/browser/browser_state/chrome_browser_state_removal_controller.h"
#import <Foundation/Foundation.h>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "components/prefs/pref_service.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/browser_state/browser_state_info_cache.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h"
#include "ios/chrome/browser/chrome_constants.h"
#include "ios/chrome/browser/chrome_paths_internal.h"
#include "ios/chrome/browser/pref_names.h"
#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
#include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
#include "ios/web/public/web_thread.h"
namespace {
ChromeBrowserStateRemovalController* g_chrome_browser_state_removal_helper =
nullptr;
NSString* const kPathToBrowserStateToKeepKey = @"PathToBrowserStateToKeep";
NSString* const kHasBrowserStateBeenRemovedKey = @"HasBrowserStateBeenRemoved";
const char kGmailDomain[] = "gmail.com";
// Removes from disk the directories used by the browser states in
// |browser_states_paths|.
void NukeBrowserStates(const std::vector<base::FilePath>& browser_states_path) {
for (const base::FilePath& browser_state_path : browser_states_path) {
// Delete both the browser state directory and its corresponding cache.
base::FilePath cache_path;
ios::GetUserCacheDirectory(browser_state_path, &cache_path);
base::DeleteFile(browser_state_path, true);
base::DeleteFile(cache_path, true);
}
}
// Returns the GAIA Id of the given |browser_state_path| using the |info_cache|.
std::string GetGaiaIdForBrowserState(const std::string& browser_state_path,
BrowserStateInfoCache* info_cache) {
base::FilePath path = info_cache->GetUserDataDir().Append(browser_state_path);
size_t index = info_cache->GetIndexOfBrowserStateWithPath(path);
if (index > info_cache->GetNumberOfBrowserStates())
return std::string();
return info_cache->GetGAIAIdOfBrowserStateAtIndex(index);
}
// Returns the email's domain of the identity associated with |gaia_id|.
std::string GetDomainForGaiaId(const std::string& gaia_id) {
ChromeIdentity* identity = ios::GetChromeBrowserProvider()
->GetChromeIdentityService()
->GetIdentityWithGaiaID(gaia_id);
if (![identity userEmail])
return std::string();
return gaia::ExtractDomainName(
gaia::SanitizeEmail(base::SysNSStringToUTF8([identity userEmail])));
}
}
ChromeBrowserStateRemovalController::ChromeBrowserStateRemovalController()
: has_changed_last_used_browser_state_(false) {}
ChromeBrowserStateRemovalController*
ChromeBrowserStateRemovalController::GetInstance() {
if (!g_chrome_browser_state_removal_helper) {
g_chrome_browser_state_removal_helper =
new ChromeBrowserStateRemovalController();
}
return g_chrome_browser_state_removal_helper;
}
void ChromeBrowserStateRemovalController::RemoveBrowserStatesIfNecessary() {
ApplicationContext* application_context = GetApplicationContext();
DCHECK(application_context);
ios::ChromeBrowserStateManager* manager =
application_context->GetChromeBrowserStateManager();
DCHECK(manager);
BrowserStateInfoCache* info_cache = manager->GetBrowserStateInfoCache();
DCHECK(info_cache);
std::string browser_state_to_keep = GetBrowserStatePathToKeep();
std::string browser_state_last_used = GetLastBrowserStatePathUsed();
if (browser_state_to_keep.empty()) {
// If no browser state was marked as to keep, keep the last used one.
browser_state_to_keep = browser_state_last_used;
}
if (browser_state_to_keep.empty()) {
browser_state_to_keep = kIOSChromeInitialBrowserState;
}
if (browser_state_to_keep != browser_state_last_used) {
std::string gaia_id =
GetGaiaIdForBrowserState(browser_state_to_keep, info_cache);
std::string last_used_gaia_id =
GetGaiaIdForBrowserState(browser_state_last_used, info_cache);
std::string last_used_domain = GetDomainForGaiaId(last_used_gaia_id);
if (gaia_id.empty() && last_used_domain == kGmailDomain) {
// If browser state to keep is not the last used one, wasn't
// authenticated, and the last used browser state was a normal account
// (domain starts with "gmail"), keep the last used browser state instead.
browser_state_to_keep = browser_state_last_used;
}
}
bool is_removing_browser_states = false;
std::vector<base::FilePath> browser_states_to_nuke;
for (size_t index = 0; index < info_cache->GetNumberOfBrowserStates();
++index) {
base::FilePath path = info_cache->GetPathOfBrowserStateAtIndex(index);
if (path.BaseName().MaybeAsASCII() == browser_state_to_keep) {
continue;
}
is_removing_browser_states = true;
// Note: if there is more than 2 browser states (which should never be the
// case), this might show the wrong GAIA Id. However, in this unlikely case,
// there isn't really more that can be done.
removed_browser_state_gaia_id_ =
info_cache->GetGAIAIdOfBrowserStateAtIndex(index);
browser_states_to_nuke.push_back(path);
info_cache->RemoveBrowserState(path);
}
// Update the last used browser state if the old one was removed.
if (browser_state_to_keep != browser_state_last_used) {
has_changed_last_used_browser_state_ = true;
SetLastBrowserStatePathUsed(browser_state_to_keep);
}
if (is_removing_browser_states) {
SetHasBrowserStateBeenRemoved(true);
web::WebThread::PostBlockingPoolTask(
FROM_HERE, base::Bind(&NukeBrowserStates, browser_states_to_nuke));
}
}
bool ChromeBrowserStateRemovalController::HasBrowserStateBeenRemoved() {
return [[NSUserDefaults standardUserDefaults]
boolForKey:kHasBrowserStateBeenRemovedKey];
}
void ChromeBrowserStateRemovalController::SetHasBrowserStateBeenRemoved(
bool value) {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:value forKey:kHasBrowserStateBeenRemovedKey];
[defaults synchronize];
}
std::string ChromeBrowserStateRemovalController::GetBrowserStatePathToKeep() {
return base::SysNSStringToUTF8([[NSUserDefaults standardUserDefaults]
stringForKey:kPathToBrowserStateToKeepKey]);
}
std::string ChromeBrowserStateRemovalController::GetLastBrowserStatePathUsed() {
return GetApplicationContext()->GetLocalState()->GetString(
prefs::kBrowserStateLastUsed);
}
void ChromeBrowserStateRemovalController::SetLastBrowserStatePathUsed(
const std::string& browser_state_path) {
GetApplicationContext()->GetLocalState()->SetString(
prefs::kBrowserStateLastUsed, browser_state_path);
}
|