diff options
Diffstat (limited to 'chromium/components/gcm_driver/instance_id/instance_id_impl.cc')
-rw-r--r-- | chromium/components/gcm_driver/instance_id/instance_id_impl.cc | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/chromium/components/gcm_driver/instance_id/instance_id_impl.cc b/chromium/components/gcm_driver/instance_id/instance_id_impl.cc new file mode 100644 index 00000000000..3f21ba69842 --- /dev/null +++ b/chromium/components/gcm_driver/instance_id/instance_id_impl.cc @@ -0,0 +1,275 @@ +// 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 "components/gcm_driver/instance_id/instance_id_impl.h" + +#include <stdint.h> + +#include <algorithm> +#include <memory> + +#include "base/base64.h" +#include "base/bind.h" +#include "base/containers/cxx20_erase.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/gcm_driver/gcm_driver.h" +#include "crypto/random.h" + +namespace instance_id { + +namespace { + +InstanceID::Result GCMClientResultToInstanceIDResult( + gcm::GCMClient::Result result) { + switch (result) { + case gcm::GCMClient::SUCCESS: + return InstanceID::SUCCESS; + case gcm::GCMClient::INVALID_PARAMETER: + return InstanceID::INVALID_PARAMETER; + case gcm::GCMClient::GCM_DISABLED: + return InstanceID::DISABLED; + case gcm::GCMClient::ASYNC_OPERATION_PENDING: + return InstanceID::ASYNC_OPERATION_PENDING; + case gcm::GCMClient::NETWORK_ERROR: + return InstanceID::NETWORK_ERROR; + case gcm::GCMClient::SERVER_ERROR: + return InstanceID::SERVER_ERROR; + case gcm::GCMClient::UNKNOWN_ERROR: + return InstanceID::UNKNOWN_ERROR; + case gcm::GCMClient::TTL_EXCEEDED: + NOTREACHED(); + break; + } + return InstanceID::UNKNOWN_ERROR; +} + +} // namespace + +// static +std::unique_ptr<InstanceID> InstanceID::CreateInternal( + const std::string& app_id, + gcm::GCMDriver* gcm_driver) { + return std::make_unique<InstanceIDImpl>(app_id, gcm_driver); +} + +InstanceIDImpl::InstanceIDImpl(const std::string& app_id, + gcm::GCMDriver* gcm_driver) + : InstanceID(app_id, gcm_driver) { + Handler()->GetInstanceIDData( + app_id, base::BindOnce(&InstanceIDImpl::GetInstanceIDDataCompleted, + weak_ptr_factory_.GetWeakPtr())); +} + +InstanceIDImpl::~InstanceIDImpl() { +} + +void InstanceIDImpl::GetID(GetIDCallback callback) { + RunWhenReady(base::BindOnce(&InstanceIDImpl::DoGetID, + weak_ptr_factory_.GetWeakPtr(), + std::move(callback))); +} + +void InstanceIDImpl::DoGetID(GetIDCallback callback) { + EnsureIDGenerated(); + std::move(callback).Run(id_); +} + +void InstanceIDImpl::GetCreationTime(GetCreationTimeCallback callback) { + RunWhenReady(base::BindOnce(&InstanceIDImpl::DoGetCreationTime, + weak_ptr_factory_.GetWeakPtr(), + std::move(callback))); +} + +void InstanceIDImpl::DoGetCreationTime(GetCreationTimeCallback callback) { + std::move(callback).Run(creation_time_); +} + +void InstanceIDImpl::GetToken(const std::string& authorized_entity, + const std::string& scope, + base::TimeDelta time_to_live, + std::set<Flags> flags, + GetTokenCallback callback) { + DCHECK(!authorized_entity.empty()); + DCHECK(!scope.empty()); + + RunWhenReady(base::BindOnce(&InstanceIDImpl::DoGetToken, + weak_ptr_factory_.GetWeakPtr(), authorized_entity, + scope, time_to_live, std::move(callback))); +} + +void InstanceIDImpl::DoGetToken( + const std::string& authorized_entity, + const std::string& scope, + base::TimeDelta time_to_live, + GetTokenCallback callback) { + EnsureIDGenerated(); + + Handler()->GetToken( + app_id(), authorized_entity, scope, time_to_live, + base::BindOnce(&InstanceIDImpl::OnGetTokenCompleted, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void InstanceIDImpl::ValidateToken(const std::string& authorized_entity, + const std::string& scope, + const std::string& token, + ValidateTokenCallback callback) { + DCHECK(!authorized_entity.empty()); + DCHECK(!scope.empty()); + DCHECK(!token.empty()); + + RunWhenReady(base::BindOnce(&InstanceIDImpl::DoValidateToken, + weak_ptr_factory_.GetWeakPtr(), authorized_entity, + scope, token, std::move(callback))); +} + +void InstanceIDImpl::DoValidateToken(const std::string& authorized_entity, + const std::string& scope, + const std::string& token, + ValidateTokenCallback callback) { + if (id_.empty()) { + std::move(callback).Run(false /* is_valid */); + return; + } + + Handler()->ValidateToken(app_id(), authorized_entity, scope, token, + std::move(callback)); +} + +void InstanceIDImpl::DeleteTokenImpl(const std::string& authorized_entity, + const std::string& scope, + DeleteTokenCallback callback) { + DCHECK(!authorized_entity.empty()); + DCHECK(!scope.empty()); + + RunWhenReady(base::BindOnce(&InstanceIDImpl::DoDeleteToken, + weak_ptr_factory_.GetWeakPtr(), authorized_entity, + scope, std::move(callback))); +} + +void InstanceIDImpl::DoDeleteToken(const std::string& authorized_entity, + const std::string& scope, + DeleteTokenCallback callback) { + // Nothing to delete if the ID has not been generated. + if (id_.empty()) { + std::move(callback).Run(InstanceID::INVALID_PARAMETER); + return; + } + + Handler()->DeleteToken( + app_id(), authorized_entity, scope, + base::BindOnce(&InstanceIDImpl::OnDeleteTokenCompleted, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void InstanceIDImpl::DeleteIDImpl(DeleteIDCallback callback) { + RunWhenReady(base::BindOnce(&InstanceIDImpl::DoDeleteID, + weak_ptr_factory_.GetWeakPtr(), + std::move(callback))); +} + +void InstanceIDImpl::DoDeleteID(DeleteIDCallback callback) { + // Nothing to do if ID has not been generated. + if (id_.empty()) { + std::move(callback).Run(InstanceID::SUCCESS); + return; + } + + Handler()->DeleteAllTokensForApp( + app_id(), + base::BindOnce(&InstanceIDImpl::OnDeleteIDCompleted, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + + Handler()->RemoveInstanceIDData(app_id()); + + id_.clear(); + creation_time_ = base::Time(); +} + +void InstanceIDImpl::OnGetTokenCompleted(GetTokenCallback callback, + const std::string& token, + gcm::GCMClient::Result result) { + std::move(callback).Run(token, GCMClientResultToInstanceIDResult(result)); +} + +void InstanceIDImpl::OnDeleteTokenCompleted(DeleteTokenCallback callback, + gcm::GCMClient::Result result) { + std::move(callback).Run(GCMClientResultToInstanceIDResult(result)); +} + +void InstanceIDImpl::OnDeleteIDCompleted(DeleteIDCallback callback, + gcm::GCMClient::Result result) { + std::move(callback).Run(GCMClientResultToInstanceIDResult(result)); +} + +void InstanceIDImpl::GetInstanceIDDataCompleted( + const std::string& instance_id, + const std::string& extra_data) { + id_ = instance_id; + + if (extra_data.empty()) { + creation_time_ = base::Time(); + } else { + int64_t time_internal = 0LL; + if (!base::StringToInt64(extra_data, &time_internal)) { + DVLOG(1) << "Failed to parse the time data: " + extra_data; + return; + } + creation_time_ = base::Time::FromInternalValue(time_internal); + } + + delayed_task_controller_.SetReady(); +} + +void InstanceIDImpl::EnsureIDGenerated() { + if (!id_.empty()) + return; + + // Now produce the ID in the following steps: + + // 1) Generates the random number in 8 bytes which is required by the server. + // We don't want to be strictly cryptographically secure. The server might + // reject the ID if there is a conflict or problem. + uint8_t bytes[kInstanceIDByteLength]; + crypto::RandBytes(bytes, sizeof(bytes)); + + // 2) Transforms the first 4 bits to 0x7. Note that this is required by the + // server. + bytes[0] &= 0x0f; + bytes[0] |= 0x70; + + // 3) Encode the value in Android-compatible base64 scheme: + // * URL safe: '/' replaced by '_' and '+' replaced by '-'. + // * No padding: any trailing '=' will be removed. + base::Base64Encode( + base::StringPiece(reinterpret_cast<const char*>(bytes), sizeof(bytes)), + &id_); + std::replace(id_.begin(), id_.end(), '+', '-'); + std::replace(id_.begin(), id_.end(), '/', '_'); + base::Erase(id_, '='); + + creation_time_ = base::Time::Now(); + + // Save to the persistent store. + Handler()->AddInstanceIDData( + app_id(), id_, base::NumberToString(creation_time_.ToInternalValue())); +} + +gcm::InstanceIDHandler* InstanceIDImpl::Handler() { + gcm::InstanceIDHandler* handler = + gcm_driver()->GetInstanceIDHandlerInternal(); + DCHECK(handler); + return handler; +} + +void InstanceIDImpl::RunWhenReady(base::OnceClosure task) { + if (!delayed_task_controller_.CanRunTaskWithoutDelay()) + delayed_task_controller_.AddTask(std::move(task)); + else + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task)); +} + +} // namespace instance_id |