blob: f7ba5716b367d46f2bb40b53801913c0958e24cc [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/page_info/android/connection_security_controller_android.h"
#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/strings/utf_string_conversions.h"
#include "components/page_info/page_info_ui.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "page_info_client.h"
// Must come after all headers that specialize FromJniType() / ToJniType()
#include "components/page_info/android/jni_headers/PageInfoConnectionSecurityController_jni.h"
#include "ui/base/l10n/l10n_util.h"
using base::android::ConvertUTF16ToJavaString;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using net::x509_util::CryptoBufferAsStringPiece;
// static
static jlong JNI_PageInfoConnectionSecurityController_Init(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& java_web_contents) {
content::WebContents* web_contents =
content::WebContents::FromJavaWebContents(java_web_contents);
return reinterpret_cast<intptr_t>(
new ConnectionSecurityControllerAndroid(env, obj, web_contents));
}
ConnectionSecurityControllerAndroid::ConnectionSecurityControllerAndroid(
JNIEnv* env,
const base::android::JavaRef<jobject>& java_controller_obj,
content::WebContents* web_contents) {
page_info_client_ = page_info::GetPageInfoClient();
DCHECK(page_info_client_);
content::NavigationEntry* nav_entry =
web_contents->GetController().GetVisibleEntry();
if (nav_entry->IsInitialEntry()) {
return;
}
controller_jobject_.Reset(env, java_controller_obj);
presenter_ = std::make_unique<PageInfo>(
page_info_client_->CreatePageInfoDelegate(web_contents), web_contents,
nav_entry->GetURL());
}
ConnectionSecurityControllerAndroid::~ConnectionSecurityControllerAndroid() =
default;
void ConnectionSecurityControllerAndroid::Destroy(JNIEnv* env) {
delete this;
}
void ConnectionSecurityControllerAndroid::LoadIdentityInfo(JNIEnv* env) {
// InitializeUiState will call PageInfoUI::SetIdentityInfo, which is
// implemented below to call setSecurityDescription on the Java controller
// with the relevant identity info.
presenter_->InitializeUiState(this, base::DoNothing());
}
ScopedJavaLocalRef<jobjectArray> CertToJavaArray(
JNIEnv* env,
const scoped_refptr<net::X509Certificate>& cert) {
std::vector<std::string> cert_chain;
if (cert) {
cert_chain.reserve(cert->cert_buffers().size());
for (const auto& handle : cert->cert_buffers()) {
cert_chain.emplace_back(CryptoBufferAsStringPiece(handle.get()));
}
}
return base::android::ToJavaArrayOfByteArray(env, cert_chain);
}
void ConnectionSecurityControllerAndroid::SetIdentityInfo(
const IdentityInfo& identity_info) {
JNIEnv* env = base::android::AttachCurrentThread();
std::unique_ptr<PageInfoUI::SecurityDescription> security_description =
GetSecurityDescription(identity_info);
int icon_id = page_info_client_->GetJavaResourceId(
PageInfoUI::GetIdentityIconID(identity_info.identity_status));
int icon_color_id = page_info_client_->GetJavaResourceId(
PageInfoUI::GetIdentityIconColorID(identity_info.identity_status));
scoped_refptr<net::X509Certificate> cert = identity_info.certificate;
auto cert_chain = CertToJavaArray(env, cert);
std::u16string qwac_identity;
// This matches the same check performed in
// PageInfoSecurityContentView::SetIdentityInfo.
bool is_1qwac = identity_info.identity_status ==
PageInfo::SITE_IDENTITY_STATUS_1QWAC_CERT &&
identity_info.connection_status ==
PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED;
auto two_qwac_chain = CertToJavaArray(env, identity_info.two_qwac);
scoped_refptr<net::X509Certificate> qwac_cert;
if (is_1qwac) {
qwac_cert = cert;
} else if (identity_info.two_qwac) {
qwac_cert = identity_info.two_qwac;
}
if (qwac_cert && !qwac_cert->subject().organization_names.empty() &&
!qwac_cert->subject().country_name.empty()) {
qwac_identity = l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_VERIFIED,
base::UTF8ToUTF16(qwac_cert->subject().organization_names[0]),
base::UTF8ToUTF16(qwac_cert->subject().country_name));
}
Java_PageInfoConnectionSecurityController_setSecurityDescription(
env, controller_jobject_, icon_id, icon_color_id,
ConvertUTF16ToJavaString(env, security_description->summary),
ConvertUTF16ToJavaString(env, security_description->details),
identity_info.show_ssl_decision_revoke_button, cert_chain, is_1qwac,
two_qwac_chain, ConvertUTF16ToJavaString(env, qwac_identity));
}
void ConnectionSecurityControllerAndroid::ResetCertDecisions(JNIEnv* env) {
presenter_->OnRevokeSSLErrorBypassButtonPressed();
}