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/push_messaging/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.
23 const char kPushMessagingApplicationIdPrefix
[] = "wp:";
26 void PushMessagingApplicationId::RegisterProfilePrefs(
27 user_prefs::PrefRegistrySyncable
* registry
) {
28 registry
->RegisterDictionaryPref(
29 prefs::kPushMessagingApplicationIdMap
,
30 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
34 PushMessagingApplicationId
PushMessagingApplicationId::Generate(
35 const GURL
& origin
, int64 service_worker_registration_id
)
37 // TODO(johnme): Does GenerateGUID produce good enough random numbers?
38 std::string guid
= base::GenerateGUID();
40 std::string app_id_guid
=
41 kPushMessagingApplicationIdPrefix
+ guid
;
43 PushMessagingApplicationId
application_id(app_id_guid
, origin
,
44 service_worker_registration_id
);
45 DCHECK(application_id
.IsValid());
46 return application_id
;
50 PushMessagingApplicationId
PushMessagingApplicationId::Get(
51 Profile
* profile
, const std::string
& app_id_guid
) {
52 // Workaround crbug.com/461867 in GCM where it converts subtypes to lowercase.
53 // TODO(johnme): Remove this when obsolete
54 const size_t prefix_len
= strlen(kPushMessagingApplicationIdPrefix
);
55 if (app_id_guid
.size() < prefix_len
)
56 return PushMessagingApplicationId();
57 std::string uppercase_app_id
=
58 app_id_guid
.substr(0, prefix_len
) +
59 StringToUpperASCII(app_id_guid
.substr(prefix_len
, std::string::npos
));
61 const base::DictionaryValue
* map
=
62 profile
->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap
);
64 std::string origin_and_sw_id
;
65 if (!map
->GetStringWithoutPathExpansion(uppercase_app_id
, &origin_and_sw_id
))
66 return PushMessagingApplicationId();
68 std::vector
<std::string
> parts
;
69 base::SplitString(origin_and_sw_id
, kSeparator
, &parts
);
70 if (parts
.size() != 2)
71 return PushMessagingApplicationId();
73 GURL origin
= GURL(parts
[0]);
75 int64 service_worker_registration_id
;
76 if (!base::StringToInt64(parts
[1], &service_worker_registration_id
))
77 return PushMessagingApplicationId();
79 PushMessagingApplicationId
application_id(uppercase_app_id
, origin
,
80 service_worker_registration_id
);
81 DCHECK(application_id
.IsValid());
82 return application_id
;
86 PushMessagingApplicationId
PushMessagingApplicationId::Get(
87 Profile
* profile
, const GURL
& origin
, int64 service_worker_registration_id
)
89 base::StringValue origin_and_sw_id
= base::StringValue(origin
.spec() +
90 kSeparator
+ base::Int64ToString(service_worker_registration_id
));
92 const base::DictionaryValue
* map
=
93 profile
->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap
);
94 for (auto it
= base::DictionaryValue::Iterator(*map
); !it
.IsAtEnd();
96 if (it
.value().Equals(&origin_and_sw_id
))
97 return Get(profile
, it
.key());
99 return PushMessagingApplicationId();
103 std::vector
<PushMessagingApplicationId
> PushMessagingApplicationId::GetAll(
105 std::vector
<PushMessagingApplicationId
> result
;
107 const base::DictionaryValue
* map
=
108 profile
->GetPrefs()->GetDictionary(prefs::kPushMessagingApplicationIdMap
);
109 for (auto it
= base::DictionaryValue::Iterator(*map
); !it
.IsAtEnd();
111 result
.push_back(Get(profile
, it
.key()));
117 void PushMessagingApplicationId::PersistToDisk(Profile
* profile
) const {
120 DictionaryPrefUpdate
update(profile
->GetPrefs(),
121 prefs::kPushMessagingApplicationIdMap
);
122 base::DictionaryValue
* map
= update
.Get();
124 // Delete any stale entry with the same origin and Service Worker
125 // registration id (hence we ensure there is a 1:1 not 1:many mapping).
126 PushMessagingApplicationId old
= Get(profile
, origin_
,
127 service_worker_registration_id_
);
129 map
->RemoveWithoutPathExpansion(old
.app_id_guid_
, nullptr);
131 std::string origin_and_sw_id
= origin_
.spec() + kSeparator
+
132 base::Int64ToString(service_worker_registration_id_
);
133 map
->SetStringWithoutPathExpansion(app_id_guid_
, origin_and_sw_id
);
136 void PushMessagingApplicationId::DeleteFromDisk(Profile
* profile
) const {
139 DictionaryPrefUpdate
update(profile
->GetPrefs(),
140 prefs::kPushMessagingApplicationIdMap
);
141 base::DictionaryValue
* map
= update
.Get();
142 map
->RemoveWithoutPathExpansion(app_id_guid_
, nullptr);
145 PushMessagingApplicationId::PushMessagingApplicationId()
146 : origin_(GURL::EmptyGURL()),
147 service_worker_registration_id_(-1) {
150 PushMessagingApplicationId::PushMessagingApplicationId(
151 const std::string
& app_id_guid
,
153 int64 service_worker_registration_id
)
154 : app_id_guid_(app_id_guid
),
156 service_worker_registration_id_(service_worker_registration_id
) {
159 PushMessagingApplicationId::~PushMessagingApplicationId() {
162 bool PushMessagingApplicationId::IsValid() const {
163 const size_t prefix_len
= strlen(kPushMessagingApplicationIdPrefix
);
164 return origin_
.is_valid() && origin_
.GetOrigin() == origin_
165 && service_worker_registration_id_
>= 0
166 && !app_id_guid_
.compare(0, prefix_len
, kPushMessagingApplicationIdPrefix
)
167 && base::IsValidGUID(app_id_guid_
.substr(prefix_len
, std::string::npos
));