1 // Copyright 2015 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 "components/gcm_driver/instance_id/instance_id_impl.h"
8 #include "base/base64.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "components/gcm_driver/gcm_driver_desktop.h"
15 #include "crypto/random.h"
17 namespace instance_id
{
21 InstanceID::Result
GCMClientResultToInstanceIDResult(
22 gcm::GCMClient::Result result
) {
24 case gcm::GCMClient::SUCCESS
:
25 return InstanceID::SUCCESS
;
26 case gcm::GCMClient::INVALID_PARAMETER
:
27 return InstanceID::INVALID_PARAMETER
;
28 case gcm::GCMClient::ASYNC_OPERATION_PENDING
:
29 return InstanceID::ASYNC_OPERATION_PENDING
;
30 case gcm::GCMClient::GCM_DISABLED
:
31 return InstanceID::DISABLED
;
32 case gcm::GCMClient::NETWORK_ERROR
:
33 return InstanceID::NETWORK_ERROR
;
34 case gcm::GCMClient::SERVER_ERROR
:
35 return InstanceID::SERVER_ERROR
;
36 case gcm::GCMClient::UNKNOWN_ERROR
:
37 return InstanceID::UNKNOWN_ERROR
;
39 NOTREACHED() << "Unexpected value of result cannot be converted: "
42 return InstanceID::UNKNOWN_ERROR
;
48 scoped_ptr
<InstanceID
> InstanceID::Create(const std::string
& app_id
,
49 gcm::GCMDriver
* gcm_driver
) {
50 return make_scoped_ptr(new InstanceIDImpl(app_id
, gcm_driver
));
53 InstanceIDImpl::InstanceIDImpl(const std::string
& app_id
,
54 gcm::GCMDriver
* gcm_driver
)
56 gcm_driver_(gcm_driver
),
57 load_from_store_(false),
58 weak_ptr_factory_(this) {
59 GetInstanceIDHandler()->GetInstanceIDData(
61 base::Bind(&InstanceIDImpl::GetInstanceIDDataCompleted
,
62 weak_ptr_factory_
.GetWeakPtr()));
65 InstanceIDImpl::~InstanceIDImpl() {
68 void InstanceIDImpl::GetID(const GetIDCallback
& callback
) {
69 if (!delayed_task_controller_
.CanRunTaskWithoutDelay()) {
70 delayed_task_controller_
.AddTask(
71 base::Bind(&InstanceIDImpl::DoGetID
,
72 weak_ptr_factory_
.GetWeakPtr(),
80 void InstanceIDImpl::DoGetID(const GetIDCallback
& callback
) {
85 void InstanceIDImpl::GetCreationTime(const GetCreationTimeCallback
& callback
) {
86 if (!delayed_task_controller_
.CanRunTaskWithoutDelay()) {
87 delayed_task_controller_
.AddTask(
88 base::Bind(&InstanceIDImpl::DoGetCreationTime
,
89 weak_ptr_factory_
.GetWeakPtr(),
94 DoGetCreationTime(callback
);
97 void InstanceIDImpl::DoGetCreationTime(
98 const GetCreationTimeCallback
& callback
) {
99 callback
.Run(creation_time_
);
102 void InstanceIDImpl::GetToken(
103 const std::string
& authorized_entity
,
104 const std::string
& scope
,
105 const std::map
<std::string
, std::string
>& options
,
106 const GetTokenCallback
& callback
) {
107 DCHECK(!authorized_entity
.empty());
108 DCHECK(!scope
.empty());
110 if (!delayed_task_controller_
.CanRunTaskWithoutDelay()) {
111 delayed_task_controller_
.AddTask(
112 base::Bind(&InstanceIDImpl::DoGetToken
,
113 weak_ptr_factory_
.GetWeakPtr(),
121 DoGetToken(authorized_entity
, scope
, options
, callback
);
124 void InstanceIDImpl::DoGetToken(
125 const std::string
& authorized_entity
,
126 const std::string
& scope
,
127 const std::map
<std::string
, std::string
>& options
,
128 const GetTokenCallback
& callback
) {
131 GetInstanceIDHandler()->GetToken(
136 base::Bind(&InstanceIDImpl::OnGetTokenCompleted
,
137 weak_ptr_factory_
.GetWeakPtr(),
141 void InstanceIDImpl::DeleteToken(const std::string
& authorized_entity
,
142 const std::string
& scope
,
143 const DeleteTokenCallback
& callback
) {
144 DCHECK(!authorized_entity
.empty());
145 DCHECK(!scope
.empty());
147 if (!delayed_task_controller_
.CanRunTaskWithoutDelay()) {
148 delayed_task_controller_
.AddTask(
149 base::Bind(&InstanceIDImpl::DoDeleteToken
,
150 weak_ptr_factory_
.GetWeakPtr(),
157 DoDeleteToken(authorized_entity
, scope
, callback
);
160 void InstanceIDImpl::DoDeleteToken(
161 const std::string
& authorized_entity
,
162 const std::string
& scope
,
163 const DeleteTokenCallback
& callback
) {
164 // Nothing to delete if the ID has not been generated.
166 callback
.Run(InstanceID::INVALID_PARAMETER
);
170 GetInstanceIDHandler()->DeleteToken(
174 base::Bind(&InstanceIDImpl::OnDeleteTokenCompleted
,
175 weak_ptr_factory_
.GetWeakPtr(),
179 void InstanceIDImpl::DeleteID(const DeleteIDCallback
& callback
) {
180 if (!delayed_task_controller_
.CanRunTaskWithoutDelay()) {
181 delayed_task_controller_
.AddTask(
182 base::Bind(&InstanceIDImpl::DoDeleteID
,
183 weak_ptr_factory_
.GetWeakPtr(),
188 DoDeleteID(callback
);
191 void InstanceIDImpl::DoDeleteID(const DeleteIDCallback
& callback
) {
192 // Nothing to do if ID has not been generated.
194 callback
.Run(InstanceID::SUCCESS
);
198 GetInstanceIDHandler()->DeleteAllTokensForApp(
200 base::Bind(&InstanceIDImpl::OnDeleteIDCompleted
,
201 weak_ptr_factory_
.GetWeakPtr(),
204 GetInstanceIDHandler()->RemoveInstanceIDData(app_id());
207 creation_time_
= base::Time();
210 void InstanceIDImpl::OnGetTokenCompleted(const GetTokenCallback
& callback
,
211 const std::string
& token
,
212 gcm::GCMClient::Result result
) {
213 callback
.Run(token
, GCMClientResultToInstanceIDResult(result
));
216 void InstanceIDImpl::OnDeleteTokenCompleted(
217 const DeleteTokenCallback
& callback
,
218 gcm::GCMClient::Result result
) {
219 callback
.Run(GCMClientResultToInstanceIDResult(result
));
222 void InstanceIDImpl::OnDeleteIDCompleted(
223 const DeleteIDCallback
& callback
,
224 gcm::GCMClient::Result result
) {
225 callback
.Run(GCMClientResultToInstanceIDResult(result
));
228 void InstanceIDImpl::GetInstanceIDDataCompleted(
229 const std::string
& instance_id
,
230 const std::string
& extra_data
) {
233 if (extra_data
.empty()) {
234 creation_time_
= base::Time();
236 int64 time_internal
= 0LL;
237 if (!base::StringToInt64(extra_data
, &time_internal
)) {
238 DVLOG(1) << "Failed to parse the time data: " + extra_data
;
241 creation_time_
= base::Time::FromInternalValue(time_internal
);
244 delayed_task_controller_
.SetReady();
247 gcm::InstanceIDHandler
* InstanceIDImpl::GetInstanceIDHandler() const {
248 gcm::InstanceIDHandler
* handler
= gcm_driver_
->GetInstanceIDHandler();
253 void InstanceIDImpl::EnsureIDGenerated() {
257 // Now produce the ID in the following steps:
259 // 1) Generates the random number in 8 bytes which is required by the server.
260 // We don't want to be strictly cryptographically secure. The server might
261 // reject the ID if there is a conflict or problem.
262 uint8 bytes
[kInstanceIDByteLength
];
263 crypto::RandBytes(bytes
, sizeof(bytes
));
265 // 2) Transforms the first 4 bits to 0x7. Note that this is required by the
270 // 3) Encode the value in Android-compatible base64 scheme:
271 // * URL safe: '/' replaced by '_' and '+' replaced by '-'.
272 // * No padding: any trailing '=' will be removed.
274 base::StringPiece(reinterpret_cast<const char*>(bytes
), sizeof(bytes
)),
276 std::replace(id_
.begin(), id_
.end(), '+', '-');
277 std::replace(id_
.begin(), id_
.end(), '/', '_');
278 id_
.erase(std::remove(id_
.begin(), id_
.end(), '='), id_
.end());
280 creation_time_
= base::Time::Now();
282 // Save to the persistent store.
283 GetInstanceIDHandler()->AddInstanceIDData(
286 base::Int64ToString(creation_time_
.ToInternalValue()));
289 } // namespace instance_id