| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/trusted_vault/trusted_vault_client_android.h" |
| |
| #include <utility> |
| #include <variant> |
| |
| #include "base/android/jni_android.h" |
| #include "base/check_op.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/not_fatal_until.h" |
| #include "base/notreached.h" |
| #include "components/sync/service/sync_service_utils.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "google_apis/gaia/gaia_id.h" |
| |
| // Must come after all headers that specialize FromJniType() / ToJniType(). |
| #include "chrome/android/chrome_jni_headers/TrustedVaultClient_jni.h" |
| |
| TrustedVaultClientAndroid::OngoingFetchKeys::OngoingFetchKeys( |
| const CoreAccountInfo& account_info, |
| base::OnceCallback<void(const std::vector<std::vector<uint8_t>>&)> callback) |
| : account_info(account_info), callback(std::move(callback)) {} |
| |
| TrustedVaultClientAndroid::OngoingFetchKeys::OngoingFetchKeys( |
| OngoingFetchKeys&&) = default; |
| |
| TrustedVaultClientAndroid::OngoingFetchKeys::~OngoingFetchKeys() = default; |
| |
| TrustedVaultClientAndroid::OngoingMarkLocalKeysAsStale:: |
| OngoingMarkLocalKeysAsStale(base::OnceCallback<void(bool)> callback) |
| : callback(std::move(callback)) {} |
| |
| TrustedVaultClientAndroid::OngoingMarkLocalKeysAsStale:: |
| OngoingMarkLocalKeysAsStale(OngoingMarkLocalKeysAsStale&&) = default; |
| |
| TrustedVaultClientAndroid::OngoingMarkLocalKeysAsStale:: |
| ~OngoingMarkLocalKeysAsStale() = default; |
| |
| TrustedVaultClientAndroid::OngoingGetIsRecoverabilityDegraded:: |
| OngoingGetIsRecoverabilityDegraded(base::OnceCallback<void(bool)> callback) |
| : callback(std::move(callback)) {} |
| |
| TrustedVaultClientAndroid::OngoingGetIsRecoverabilityDegraded:: |
| OngoingGetIsRecoverabilityDegraded(OngoingGetIsRecoverabilityDegraded&&) = |
| default; |
| |
| TrustedVaultClientAndroid::OngoingGetIsRecoverabilityDegraded:: |
| ~OngoingGetIsRecoverabilityDegraded() = default; |
| |
| TrustedVaultClientAndroid::OngoingAddTrustedRecoveryMethod:: |
| OngoingAddTrustedRecoveryMethod(base::OnceClosure callback) |
| : callback(std::move(callback)) {} |
| |
| TrustedVaultClientAndroid::OngoingAddTrustedRecoveryMethod:: |
| OngoingAddTrustedRecoveryMethod(OngoingAddTrustedRecoveryMethod&&) = |
| default; |
| |
| TrustedVaultClientAndroid::OngoingAddTrustedRecoveryMethod:: |
| ~OngoingAddTrustedRecoveryMethod() = default; |
| |
| TrustedVaultClientAndroid::TrustedVaultClientAndroid( |
| const GetAccountInfoByGaiaIdCallback& gaia_account_info_by_gaia_id_cb) |
| : gaia_account_info_by_gaia_id_cb_(gaia_account_info_by_gaia_id_cb) { |
| JNIEnv* const env = base::android::AttachCurrentThread(); |
| Java_TrustedVaultClient_registerNative(env, reinterpret_cast<intptr_t>(this)); |
| } |
| |
| TrustedVaultClientAndroid::~TrustedVaultClientAndroid() { |
| JNIEnv* const env = base::android::AttachCurrentThread(); |
| Java_TrustedVaultClient_unregisterNative(env, |
| reinterpret_cast<intptr_t>(this)); |
| } |
| |
| void TrustedVaultClientAndroid::FetchKeysCompleted( |
| JNIEnv* env, |
| jint request_id, |
| std::string& gaia_id, |
| const base::android::JavaParamRef<jobjectArray>& keys) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| OngoingRequest ongoing_request = GetAndUnregisterOngoingRequest(request_id); |
| OngoingFetchKeys& ongoing_fetch_keys = |
| std::get<OngoingFetchKeys>(ongoing_request); |
| |
| DCHECK_EQ(ongoing_fetch_keys.account_info.gaia, GaiaId(gaia_id)) |
| << "User mismatch in FetchKeys() response"; |
| |
| std::vector<std::vector<uint8_t>> converted_keys; |
| base::android::JavaArrayOfByteArrayToBytesVector(env, keys, &converted_keys); |
| std::move(ongoing_fetch_keys.callback).Run(converted_keys); |
| } |
| |
| void TrustedVaultClientAndroid::MarkLocalKeysAsStaleCompleted( |
| JNIEnv* env, |
| jint request_id, |
| jboolean succeeded) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| OngoingRequest ongoing_request = GetAndUnregisterOngoingRequest(request_id); |
| |
| std::move(std::get<OngoingMarkLocalKeysAsStale>(ongoing_request).callback) |
| .Run(!!succeeded); |
| } |
| |
| void TrustedVaultClientAndroid::GetIsRecoverabilityDegradedCompleted( |
| JNIEnv* env, |
| jint request_id, |
| jboolean is_degraded) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| OngoingRequest ongoing_request = GetAndUnregisterOngoingRequest(request_id); |
| |
| std::move( |
| std::get<OngoingGetIsRecoverabilityDegraded>(ongoing_request).callback) |
| .Run(!!is_degraded); |
| } |
| |
| void TrustedVaultClientAndroid::AddTrustedRecoveryMethodCompleted( |
| JNIEnv* env, |
| jint request_id) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| OngoingRequest ongoing_request = GetAndUnregisterOngoingRequest(request_id); |
| |
| std::move(std::get<OngoingAddTrustedRecoveryMethod>(ongoing_request).callback) |
| .Run(); |
| } |
| |
| void TrustedVaultClientAndroid::NotifyKeysChanged(JNIEnv* env) { |
| for (Observer& observer : observer_list_) { |
| observer.OnTrustedVaultKeysChanged(); |
| } |
| } |
| |
| void TrustedVaultClientAndroid::NotifyRecoverabilityChanged(JNIEnv* env) { |
| for (Observer& observer : observer_list_) { |
| observer.OnTrustedVaultRecoverabilityChanged(); |
| } |
| } |
| |
| void TrustedVaultClientAndroid::AddObserver(Observer* observer) { |
| observer_list_.AddObserver(observer); |
| } |
| |
| void TrustedVaultClientAndroid::RemoveObserver(Observer* observer) { |
| observer_list_.RemoveObserver(observer); |
| } |
| |
| void TrustedVaultClientAndroid::FetchKeys( |
| const CoreAccountInfo& account_info, |
| base::OnceCallback<void(const std::vector<std::vector<uint8_t>>&)> cb) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| // Store for later completion when Java invokes FetchKeysCompleted(). |
| const RequestId request_id = |
| RegisterNewOngoingRequest(OngoingFetchKeys(account_info, std::move(cb))); |
| |
| // Trigger the fetching keys from the implementation in Java, which will |
| // eventually call FetchKeysCompleted(). |
| Java_TrustedVaultClient_fetchKeys(base::android::AttachCurrentThread(), |
| reinterpret_cast<intptr_t>(this), |
| request_id, account_info); |
| } |
| |
| void TrustedVaultClientAndroid::StoreKeys( |
| const GaiaId& gaia_id, |
| const std::vector<std::vector<uint8_t>>& keys, |
| int last_key_version) { |
| // Not supported on Android, where keys are fetched outside the browser. |
| NOTREACHED(); |
| } |
| |
| void TrustedVaultClientAndroid::MarkLocalKeysAsStale( |
| const CoreAccountInfo& account_info, |
| base::OnceCallback<void(bool)> cb) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| DCHECK(cb); |
| |
| // Store for later completion when Java invokes |
| // MarkLocalKeysAsStaleCompleted(). |
| const RequestId request_id = |
| RegisterNewOngoingRequest(OngoingMarkLocalKeysAsStale(std::move(cb))); |
| |
| // The Java implementation will eventually call |
| // MarkLocalKeysAsStaleCompleted(). |
| Java_TrustedVaultClient_markLocalKeysAsStale( |
| base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this), |
| request_id, account_info); |
| } |
| |
| void TrustedVaultClientAndroid::GetIsRecoverabilityDegraded( |
| const CoreAccountInfo& account_info, |
| base::OnceCallback<void(bool)> cb) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| DCHECK(cb); |
| |
| // Store for later completion when Java invokes |
| // GetIsRecoverabilityDegradedCompleted(). |
| const RequestId request_id = RegisterNewOngoingRequest( |
| OngoingGetIsRecoverabilityDegraded(std::move(cb))); |
| |
| // The Java implementation will eventually call |
| // MarkLocalKeysAsStaleCompleted(). |
| Java_TrustedVaultClient_getIsRecoverabilityDegraded( |
| base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this), |
| request_id, account_info); |
| } |
| |
| void TrustedVaultClientAndroid::AddTrustedRecoveryMethod( |
| const GaiaId& gaia_id, |
| const std::vector<uint8_t>& public_key, |
| int method_type_hint, |
| base::OnceClosure cb) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| DCHECK(cb); |
| |
| const CoreAccountInfo account_info = |
| gaia_account_info_by_gaia_id_cb_.Run(gaia_id); |
| |
| base::UmaHistogramBoolean( |
| "Sync.TrustedVaultJavascriptAddRecoveryMethodUserKnown", |
| account_info != CoreAccountInfo()); |
| |
| if (account_info == CoreAccountInfo()) { |
| std::move(cb).Run(); |
| return; |
| } |
| |
| // Store for later completion when Java invokes |
| // AddTrustedRecoveryMethodCompleted(). |
| const RequestId request_id = |
| RegisterNewOngoingRequest(OngoingAddTrustedRecoveryMethod(std::move(cb))); |
| |
| JNIEnv* const env = base::android::AttachCurrentThread(); |
| const base::android::ScopedJavaLocalRef<jbyteArray> java_public_key = |
| base::android::ToJavaByteArray(env, public_key); |
| |
| // The Java implementation will eventually call |
| // AddTrustedRecoveryMethodCompleted(). |
| Java_TrustedVaultClient_addTrustedRecoveryMethod( |
| env, reinterpret_cast<intptr_t>(this), request_id, account_info, |
| java_public_key, method_type_hint); |
| } |
| |
| void TrustedVaultClientAndroid::ClearLocalDataForAccount( |
| const CoreAccountInfo& account_info) { |
| // Not relevant for Android implementation. |
| } |
| |
| TrustedVaultClientAndroid::RequestId |
| TrustedVaultClientAndroid::RegisterNewOngoingRequest(OngoingRequest request) { |
| ongoing_requests_.emplace(++last_request_id_, std::move(request)); |
| return last_request_id_; |
| } |
| |
| TrustedVaultClientAndroid::OngoingRequest |
| TrustedVaultClientAndroid::GetAndUnregisterOngoingRequest(RequestId id) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| auto it = ongoing_requests_.find(id); |
| CHECK(it != ongoing_requests_.end(), base::NotFatalUntil::M130); |
| |
| OngoingRequest request = std::move(it->second); |
| ongoing_requests_.erase(it); |
| return request; |
| } |
| |
| static void JNI_TrustedVaultClient_RecordKeyRetrievalTrigger(JNIEnv* env, |
| int trigger) { |
| syncer::RecordKeyRetrievalTrigger( |
| static_cast<syncer::TrustedVaultUserActionTriggerForUMA>(trigger)); |
| } |
| |
| static void JNI_TrustedVaultClient_RecordRecoverabilityDegradedFixTrigger( |
| JNIEnv* env, |
| int trigger) { |
| syncer::RecordRecoverabilityDegradedFixTrigger( |
| static_cast<syncer::TrustedVaultUserActionTriggerForUMA>(trigger)); |
| } |