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 "google_apis/gaia/gaia_auth_util.h"
6
7#include "base/json/json_reader.h"
8#include "base/logging.h"
9#include "base/strings/string_split.h"
10#include "base/strings/string_util.h"
11#include "base/values.h"
12#include "google_apis/gaia/gaia_urls.h"
13#include "url/gurl.h"
14
15namespace gaia {
16
17namespace {
18
19const char kGmailDomain[] = "gmail.com";
20const char kGooglemailDomain[] = "googlemail.com";
21
22std::string CanonicalizeEmailImpl(const std::string& email_address,
23                                  bool change_googlemail_to_gmail) {
24  std::vector<std::string> parts;
25  char at = '@';
26  base::SplitString(email_address, at, &parts);
27  if (parts.size() != 2U) {
28    NOTREACHED() << "expecting exactly one @, but got " << parts.size()-1 <<
29        " : " << email_address;
30  } else {
31    if (change_googlemail_to_gmail && parts[1] == kGooglemailDomain)
32      parts[1] = kGmailDomain;
33
34    if (parts[1] == kGmailDomain)  // only strip '.' for gmail accounts.
35      base::RemoveChars(parts[0], ".", &parts[0]);
36  }
37
38  std::string new_email = base::StringToLowerASCII(JoinString(parts, at));
39  VLOG(1) << "Canonicalized " << email_address << " to " << new_email;
40  return new_email;
41}
42
43}  // namespace
44
45std::string CanonicalizeEmail(const std::string& email_address) {
46  // CanonicalizeEmail() is called to process email strings that are eventually
47  // shown to the user, and may also be used in persisting email strings.  To
48  // avoid breaking this existing behavior, this function will not try to
49  // change googlemail to gmail.
50  return CanonicalizeEmailImpl(email_address, false);
51}
52
53std::string CanonicalizeDomain(const std::string& domain) {
54  // Canonicalization of domain names means lower-casing them. Make sure to
55  // update this function in sync with Canonicalize if this ever changes.
56  return base::StringToLowerASCII(domain);
57}
58
59std::string SanitizeEmail(const std::string& email_address) {
60  std::string sanitized(email_address);
61
62  // Apply a default domain if necessary.
63  if (sanitized.find('@') == std::string::npos) {
64    sanitized += '@';
65    sanitized += kGmailDomain;
66  }
67
68  return sanitized;
69}
70
71bool AreEmailsSame(const std::string& email1, const std::string& email2) {
72  return CanonicalizeEmailImpl(gaia::SanitizeEmail(email1), true) ==
73      CanonicalizeEmailImpl(gaia::SanitizeEmail(email2), true);
74}
75
76std::string ExtractDomainName(const std::string& email_address) {
77  // First canonicalize which will also verify we have proper domain part.
78  std::string email = CanonicalizeEmail(email_address);
79  size_t separator_pos = email.find('@');
80  if (separator_pos != email.npos && separator_pos < email.length() - 1)
81    return email.substr(separator_pos + 1);
82  else
83    NOTREACHED() << "Not a proper email address: " << email;
84  return std::string();
85}
86
87bool IsGaiaSignonRealm(const GURL& url) {
88  if (!url.SchemeIsSecure())
89    return false;
90
91  return url == GaiaUrls::GetInstance()->gaia_url();
92}
93
94
95bool ParseListAccountsData(
96    const std::string& data,
97    std::vector<std::pair<std::string, bool> >* accounts) {
98  accounts->clear();
99
100  // Parse returned data and make sure we have data.
101  scoped_ptr<base::Value> value(base::JSONReader::Read(data));
102  if (!value)
103    return false;
104
105  base::ListValue* list;
106  if (!value->GetAsList(&list) || list->GetSize() < 2)
107    return false;
108
109  // Get list of account info.
110  base::ListValue* account_list;
111  if (!list->GetList(1, &account_list) || accounts == NULL)
112    return false;
113
114  // Build a vector of accounts from the cookie.  Order is important: the first
115  // account in the list is the primary account.
116  for (size_t i = 0; i < account_list->GetSize(); ++i) {
117    base::ListValue* account;
118    if (account_list->GetList(i, &account) && account != NULL) {
119      std::string email;
120      // Canonicalize the email since ListAccounts returns "display email".
121      if (account->GetString(3, &email) && !email.empty()) {
122        // New version if ListAccounts indicates whether the email's session
123        // is still valid or not.  If this value is present and false, assume
124        // its invalid.  Otherwise assume it's valid to remain compatible with
125        // old version.
126        int is_email_valid = 1;
127        if (!account->GetInteger(9, &is_email_valid))
128          is_email_valid = 1;
129
130        accounts->push_back(
131            std::make_pair(CanonicalizeEmail(email), is_email_valid != 0));
132      }
133    }
134  }
135
136  return true;
137}
138
139}  // namespace gaia
140