1 // Copyright 2014 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/services/gcm/push_messaging_application_id.h"
8 #include "base/logging.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/common/pref_names.h"
17 #include "components/pref_registry/pref_registry_syncable.h"
20 const char kSeparator
= '#'; // Ok as only the origin of the url is used.
25 const char kPushMessagingApplicationIdPrefix
[] = "wp:";
28 void PushMessagingApplicationId::RegisterProfilePrefs(
29 user_prefs::PrefRegistrySyncable
* registry
) {
30 registry
->RegisterDictionaryPref(
31 prefs::kPushMessagingApplicationIdMap
,
32 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
36 PushMessagingApplicationId
PushMessagingApplicationId::Generate(
37 const GURL
& origin
, int64 service_worker_registration_id
)
39 // TODO(johnme): Does GenerateGUID produce good enough random numbers?
40 std::string guid
= base::GenerateGUID();
42 std::string app_id_guid
=
43 kPushMessagingApplicationIdPrefix
+ guid
;
45 PushMessagingApplicationId
application_id(app_id_guid
, origin
,
46 service_worker_registration_id
);
47 DCHECK(application_id
.IsValid());
48 return application_id
;
52 PushMessagingApplicationId
PushMessagingApplicationId::Get(
53 Profile
* profile
, const std::string
& app_id_guid
) {
54 // Workaround crbug.com/461867 in GCM where it converts subtypes to lowercase.
55 // TODO(johnme): Remove this when obsolete
56 const size_t prefix_len
= strlen(kPushMessagingApplicationIdPrefix
);
57 if (app_id_guid
.size() < prefix_len
)
58 return PushMessagingApplicationId();
59 std::string uppercase_app_id
=
60 app_id_guid
.substr(0, prefix_len
) +
61 StringToUpperASCII(app_id_guid
.substr(prefix_len
, std::string::npos
));
63 const base::DictionaryValue
* map
=
64 profile
->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap
);
66 std::string origin_and_sw_id
;
67 if (!map
->GetStringWithoutPathExpansion(uppercase_app_id
, &origin_and_sw_id
))
68 return PushMessagingApplicationId();
70 std::vector
<std::string
> parts
;
71 base::SplitString(origin_and_sw_id
, kSeparator
, &parts
);
72 if (parts
.size() != 2)
73 return PushMessagingApplicationId();
75 GURL origin
= GURL(parts
[0]);
77 int64 service_worker_registration_id
;
78 if (!base::StringToInt64(parts
[1], &service_worker_registration_id
))
79 return PushMessagingApplicationId();
81 PushMessagingApplicationId
application_id(uppercase_app_id
, origin
,
82 service_worker_registration_id
);
83 DCHECK(application_id
.IsValid());
84 return application_id
;
88 PushMessagingApplicationId
PushMessagingApplicationId::Get(
89 Profile
* profile
, const GURL
& origin
, int64 service_worker_registration_id
)
91 base::StringValue origin_and_sw_id
= base::StringValue(origin
.spec() +
92 kSeparator
+ base::Int64ToString(service_worker_registration_id
));
94 const base::DictionaryValue
* map
=
95 profile
->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap
);
96 for (auto it
= base::DictionaryValue::Iterator(*map
); !it
.IsAtEnd();
98 if (it
.value().Equals(&origin_and_sw_id
))
99 return Get(profile
, it
.key());
101 return PushMessagingApplicationId();
105 std::vector
<PushMessagingApplicationId
> PushMessagingApplicationId::GetAll(
107 std::vector
<PushMessagingApplicationId
> result
;
109 const base::DictionaryValue
* map
=
110 profile
->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap
);
111 for (auto it
= base::DictionaryValue::Iterator(*map
); !it
.IsAtEnd();
113 result
.push_back(Get(profile
, it
.key()));
119 void PushMessagingApplicationId::PersistToDisk(Profile
* profile
) const {
122 DictionaryPrefUpdate
update(profile
->GetPrefs(),
123 prefs::kPushMessagingApplicationIdMap
);
124 base::DictionaryValue
* map
= update
.Get();
126 // Delete any stale entry with the same origin and Service Worker
127 // registration id (hence we ensure there is a 1:1 not 1:many mapping).
128 PushMessagingApplicationId old
= Get(profile
, origin_
,
129 service_worker_registration_id_
);
131 map
->RemoveWithoutPathExpansion(old
.app_id_guid_
, nullptr);
133 std::string origin_and_sw_id
= origin_
.spec() + kSeparator
+
134 base::Int64ToString(service_worker_registration_id_
);
135 map
->SetStringWithoutPathExpansion(app_id_guid_
, origin_and_sw_id
);
138 void PushMessagingApplicationId::DeleteFromDisk(Profile
* profile
) const {
141 DictionaryPrefUpdate
update(profile
->GetPrefs(),
142 prefs::kPushMessagingApplicationIdMap
);
143 base::DictionaryValue
* map
= update
.Get();
144 map
->RemoveWithoutPathExpansion(app_id_guid_
, nullptr);
147 PushMessagingApplicationId::PushMessagingApplicationId()
148 : origin_(GURL::EmptyGURL()),
149 service_worker_registration_id_(-1) {
152 PushMessagingApplicationId::PushMessagingApplicationId(
153 const std::string
& app_id_guid
,
155 int64 service_worker_registration_id
)
156 : app_id_guid_(app_id_guid
),
158 service_worker_registration_id_(service_worker_registration_id
) {
161 PushMessagingApplicationId::~PushMessagingApplicationId() {
164 bool PushMessagingApplicationId::IsValid() const {
165 const size_t prefix_len
= strlen(kPushMessagingApplicationIdPrefix
);
166 return origin_
.is_valid() && origin_
.GetOrigin() == origin_
167 && service_worker_registration_id_
>= 0
168 && !app_id_guid_
.compare(0, prefix_len
, kPushMessagingApplicationIdPrefix
)
169 && base::IsValidGUID(app_id_guid_
.substr(prefix_len
, std::string::npos
));