// Copyright 2021 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/password_entry_edit/android/credential_edit_bridge.h"
#include <jni.h>
#include <memory>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/memory/ptr_util.h"
#include "chrome/grit/generated_resources.h"
#include "components/affiliations/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
#include "components/url_formatter/url_formatter.h"
#include "ui/base/l10n/l10n_util.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/password_entry_edit/android/internal/jni/CredentialEditBridge_jni.h"
std::unique_ptr<CredentialEditBridge> CredentialEditBridge::MaybeCreate(
const password_manager::CredentialUIEntry credential,
IsInsecureCredential is_insecure_credential,
std::vector<std::u16string> existing_usernames,
password_manager::SavedPasswordsPresenter* saved_passwords_presenter,
base::OnceClosure dismissal_callback,
const base::android::JavaRef<jobject>& context) {
base::android::ScopedJavaGlobalRef<jobject> java_bridge;
java_bridge.Reset(Java_CredentialEditBridge_maybeCreate(
base::android::AttachCurrentThread()));
if (!java_bridge) {
return nullptr;
}
return base::WrapUnique(new CredentialEditBridge(
std::move(credential), is_insecure_credential,
std::move(existing_usernames), saved_passwords_presenter,
std::move(dismissal_callback), context, std::move(java_bridge)));
}
CredentialEditBridge::CredentialEditBridge(
const password_manager::CredentialUIEntry credential,
IsInsecureCredential is_insecure_credential,
std::vector<std::u16string> existing_usernames,
password_manager::SavedPasswordsPresenter* saved_passwords_presenter,
base::OnceClosure dismissal_callback,
const base::android::JavaRef<jobject>& context,
base::android::ScopedJavaGlobalRef<jobject> java_bridge)
: credential_(std::move(credential)),
is_insecure_credential_(is_insecure_credential),
existing_usernames_(std::move(existing_usernames)),
saved_passwords_presenter_(saved_passwords_presenter),
dismissal_callback_(std::move(dismissal_callback)),
java_bridge_(java_bridge) {
Java_CredentialEditBridge_initAndLaunchUi(
base::android::AttachCurrentThread(), java_bridge_,
reinterpret_cast<intptr_t>(this), context, credential.blocked_by_user,
credential.federation_origin.IsValid());
}
CredentialEditBridge::~CredentialEditBridge() {
Java_CredentialEditBridge_destroy(base::android::AttachCurrentThread(),
java_bridge_);
}
void CredentialEditBridge::GetCredential(JNIEnv* env) {
Java_CredentialEditBridge_setCredential(
env, java_bridge_,
base::android::ConvertUTF16ToJavaString(env, GetDisplayURLOrAppName()),
base::android::ConvertUTF16ToJavaString(env, credential_.username),
base::android::ConvertUTF16ToJavaString(env, credential_.password),
base::android::ConvertUTF16ToJavaString(env,
GetDisplayFederationOrigin()),
is_insecure_credential_.value());
}
void CredentialEditBridge::GetExistingUsernames(JNIEnv* env) {
Java_CredentialEditBridge_setExistingUsernames(
env, java_bridge_,
base::android::ToJavaArrayOfStrings(env, existing_usernames_));
}
void CredentialEditBridge::SaveChanges(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& username,
const base::android::JavaParamRef<jstring>& password) {
password_manager::CredentialUIEntry updated_credential = credential_;
updated_credential.username =
base::android::ConvertJavaStringToUTF16(username);
updated_credential.password =
base::android::ConvertJavaStringToUTF16(password);
saved_passwords_presenter_->EditSavedCredentials(credential_,
updated_credential);
}
void CredentialEditBridge::DeleteCredential(JNIEnv* env) {
saved_passwords_presenter_->RemoveCredential(credential_);
std::move(dismissal_callback_).Run();
}
void CredentialEditBridge::OnUIDismissed(JNIEnv* env) {
std::move(dismissal_callback_).Run();
}
std::u16string CredentialEditBridge::GetDisplayURLOrAppName() {
auto facet = affiliations::FacetURI::FromPotentiallyInvalidSpec(
credential_.GetFirstSignonRealm());
std::string display_name = credential_.GetDisplayName();
if (facet.IsValidAndroidFacetURI()) {
if (display_name.empty()) {
// In case no affiliation information could be obtained show the
// formatted package name to the user.
return l10n_util::GetStringFUTF16(
IDS_SETTINGS_PASSWORDS_ANDROID_APP,
base::UTF8ToUTF16(facet.android_package_name()));
}
return base::UTF8ToUTF16(display_name);
}
return url_formatter::FormatUrl(
credential_.GetURL().DeprecatedGetOriginAsURL(),
url_formatter::kFormatUrlOmitDefaults |
url_formatter::kFormatUrlOmitHTTPS |
url_formatter::kFormatUrlOmitTrivialSubdomains |
url_formatter::kFormatUrlTrimAfterHost,
base::UnescapeRule::SPACES, nullptr, nullptr, nullptr);
}
std::u16string CredentialEditBridge::GetDisplayFederationOrigin() {
return credential_.federation_origin.IsValid()
? url_formatter::FormatUrl(
credential_.federation_origin.GetURL(),
url_formatter::kFormatUrlOmitDefaults |
url_formatter::kFormatUrlOmitHTTPS |
url_formatter::kFormatUrlOmitTrivialSubdomains |
url_formatter::kFormatUrlTrimAfterHost,
base::UnescapeRule::SPACES, nullptr, nullptr, nullptr)
: std::u16string();
}