Looks great now
This commit is contained in:
parent
eb3b01da48
commit
adeb8ebfbd
6 changed files with 91 additions and 41 deletions
|
|
@ -169,7 +169,7 @@ class CertificateSettingsFragment : BasePreferenceFragment(),
|
|||
it.readBytes()
|
||||
}
|
||||
if (data != null && data.isNotEmpty()) {
|
||||
ClientCertificateFragment.newInstance(data)
|
||||
ClientCertificateFragment.newInstanceAdd(data)
|
||||
.show(childFragmentManager, ClientCertificateFragment.TAG)
|
||||
} else {
|
||||
Toast.makeText(context, R.string.settings_advanced_certificates_error_invalid_p12, Toast.LENGTH_SHORT).show()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import androidx.core.view.isVisible
|
|||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import io.heckel.ntfy.R
|
||||
|
|
@ -64,6 +63,7 @@ class ClientCertificateFragment : DialogFragment() {
|
|||
|
||||
// Page 2 views
|
||||
private lateinit var page2Layout: LinearLayout
|
||||
private lateinit var descriptionPage2Text: TextView
|
||||
private lateinit var baseUrlValueText: TextView
|
||||
private lateinit var subjectText: TextView
|
||||
private lateinit var issuerText: TextView
|
||||
|
|
@ -143,7 +143,7 @@ class ClientCertificateFragment : DialogFragment() {
|
|||
true
|
||||
}
|
||||
R.id.client_certificate_action_delete -> {
|
||||
confirmDeleteCertificate()
|
||||
deleteCertificate()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
|
|
@ -163,6 +163,7 @@ class ClientCertificateFragment : DialogFragment() {
|
|||
|
||||
// Page 2 views
|
||||
page2Layout = view.findViewById(R.id.client_certificate_page2)
|
||||
descriptionPage2Text = view.findViewById(R.id.client_certificate_description_page2)
|
||||
baseUrlValueText = view.findViewById(R.id.client_certificate_base_url_value)
|
||||
subjectText = view.findViewById(R.id.client_certificate_subject)
|
||||
issuerText = view.findViewById(R.id.client_certificate_issuer)
|
||||
|
|
@ -197,7 +198,7 @@ class ClientCertificateFragment : DialogFragment() {
|
|||
deleteMenuItem.isVisible = true
|
||||
|
||||
// Hide description for view mode
|
||||
view?.findViewById<TextView>(R.id.client_certificate_description_page2)?.isVisible = false
|
||||
descriptionPage2Text.isVisible = false
|
||||
|
||||
// Load certificate from repository
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
|
|
@ -301,22 +302,16 @@ class ClientCertificateFragment : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun confirmDeleteCertificate() {
|
||||
private fun deleteCertificate() {
|
||||
val url = baseUrl ?: return
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setMessage(R.string.client_certificate_dialog_delete_confirm)
|
||||
.setPositiveButton(R.string.client_certificate_dialog_button_delete) { _, _ ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
repository.removeClientCertificate(url)
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(context, R.string.client_certificate_dialog_deleted_toast, Toast.LENGTH_SHORT).show()
|
||||
listener?.onCertificateDeleted()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
repository.removeClientCertificate(url)
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(context, R.string.client_certificate_dialog_deleted_toast, Toast.LENGTH_SHORT).show()
|
||||
listener?.onCertificateDeleted()
|
||||
dismiss()
|
||||
}
|
||||
.setNegativeButton(R.string.client_certificate_dialog_button_cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBack() {
|
||||
|
|
@ -357,7 +352,7 @@ class ClientCertificateFragment : DialogFragment() {
|
|||
/**
|
||||
* Create fragment for ADD mode - two-page flow to add a client certificate
|
||||
*/
|
||||
fun newInstance(pkcs12Data: ByteArray): ClientCertificateFragment {
|
||||
fun newInstanceAdd(pkcs12Data: ByteArray): ClientCertificateFragment {
|
||||
return ClientCertificateFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(ARG_MODE, Mode.ADD.name)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ class TrustedCertificateFragment : DialogFragment() {
|
|||
private lateinit var fingerprintText: TextView
|
||||
private lateinit var validFromText: TextView
|
||||
private lateinit var validUntilText: TextView
|
||||
private lateinit var caText: TextView
|
||||
private lateinit var caInfoText: TextView
|
||||
|
||||
interface TrustedCertificateListener {
|
||||
fun onCertificateTrusted(certificate: X509Certificate)
|
||||
|
|
@ -145,6 +147,8 @@ class TrustedCertificateFragment : DialogFragment() {
|
|||
fingerprintText = view.findViewById(R.id.trusted_certificate_fingerprint)
|
||||
validFromText = view.findViewById(R.id.trusted_certificate_valid_from)
|
||||
validUntilText = view.findViewById(R.id.trusted_certificate_valid_until)
|
||||
caText = view.findViewById(R.id.trusted_certificate_ca)
|
||||
caInfoText = view.findViewById(R.id.trusted_certificate_ca_info)
|
||||
|
||||
when (mode) {
|
||||
Mode.UNKNOWN -> setupUnknownMode()
|
||||
|
|
@ -211,6 +215,11 @@ class TrustedCertificateFragment : DialogFragment() {
|
|||
validFromText.text = dateFormat.format(certificate.notBefore)
|
||||
validUntilText.text = dateFormat.format(certificate.notAfter)
|
||||
|
||||
// Determine if this is a CA certificate (self-signed)
|
||||
val isCa = certificate.subjectX500Principal == certificate.issuerX500Principal
|
||||
caText.text = if (isCa) getString(R.string.common_yes) else getString(R.string.common_no)
|
||||
caInfoText.isVisible = isCa
|
||||
|
||||
// Show warning if certificate is expired or not yet valid
|
||||
val now = Date()
|
||||
when {
|
||||
|
|
|
|||
|
|
@ -63,10 +63,26 @@
|
|||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/client_certificate_base_url_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/client_certificate_dialog_base_url_hint"
|
||||
app:placeholderText="@string/client_certificate_dialog_base_url_placeholder">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/client_certificate_base_url_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textUri" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/client_certificate_password_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/client_certificate_dialog_password_hint"
|
||||
app:passwordToggleEnabled="true">
|
||||
|
||||
|
|
@ -78,21 +94,6 @@
|
|||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/client_certificate_base_url_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/client_certificate_dialog_base_url_hint">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/client_certificate_base_url_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textUri" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/client_certificate_error_text"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -208,6 +208,48 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintWidth_percent="0.5" />
|
||||
|
||||
<!-- Certificate Authority -->
|
||||
<TextView
|
||||
android:id="@+id/trusted_certificate_ca_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/trusted_certificate_dialog_ca"
|
||||
android:textSize="12sp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/trusted_certificate_valid_from"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/trusted_certificate_ca"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/trusted_certificate_ca_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<!-- CA Info (only shown for CA certificates) -->
|
||||
<TextView
|
||||
android:id="@+id/trusted_certificate_ca_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/trusted_certificate_dialog_ca_info"
|
||||
android:textSize="14sp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/trusted_certificate_ca"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
tools:ignore="MissingTranslation">
|
||||
|
||||
<!-- Common strings -->
|
||||
<string name="common_yes">Yes</string>
|
||||
<string name="common_no">No</string>
|
||||
<string name="common_copied_to_clipboard">Copied to clipboard</string>
|
||||
|
||||
<!-- Notification channels -->
|
||||
|
|
@ -424,8 +426,8 @@
|
|||
<string name="settings_advanced_exact_alarms_true">ntfy can schedule exact alarms. Exact alarms are required to reconnect WebSockets in the background. Click to revoke the permission.</string>
|
||||
<string name="settings_advanced_exact_alarms_false">ntfy cannot schedule exact alarms. Exact alarms are required to reconnect WebSockets in the background. Click to grant the permission.</string>
|
||||
<string name="settings_advanced_certificates_title">Manage certificates</string>
|
||||
<string name="settings_advanced_certificates_summary">Trust self-signed server certificates and manage client certificates for mTLS</string>
|
||||
<string name="settings_advanced_certificates_trusted_header">Trusted server certificates</string>
|
||||
<string name="settings_advanced_certificates_summary">Add certificates to the trust store and manage client certificates for mTLS</string>
|
||||
<string name="settings_advanced_certificates_trusted_header">Trusted certificates</string>
|
||||
<string name="settings_advanced_certificates_trusted_item_summary_leaf">Leaf certificate, issued by %1$s\nExpires %2$s</string>
|
||||
<string name="settings_advanced_certificates_trusted_item_summary_leaf_expired">Leaf certificate, issued by %1$s\nExpired</string>
|
||||
<string name="settings_advanced_certificates_trusted_item_summary_ca">CA certificate, self-signed\nExpires %1$s</string>
|
||||
|
|
@ -434,7 +436,7 @@
|
|||
<string name="settings_advanced_certificates_trusted_add_summary">Import a certificate into the trust store (PEM). HTTPS and WebSocket connections will trust this certificate.</string>
|
||||
<string name="settings_advanced_certificates_client_header">Client certificates (mTLS)</string>
|
||||
<string name="settings_advanced_certificates_client_item_summary">Client certificate, issued by %1$s\nExpires %2$s, used by %3$s</string>
|
||||
<string name="settings_advanced_certificates_client_item_summary_expired">EClient certificate, issued by %1$s\nExpired, used by %2$s</string>
|
||||
<string name="settings_advanced_certificates_client_item_summary_expired">Client certificate, issued by %1$s\nExpired, used by %2$s</string>
|
||||
<string name="settings_advanced_certificates_client_add_title">Add a client certificate</string>
|
||||
<string name="settings_advanced_certificates_client_add_summary">Import certificate for mutual TLS authentication (PKCS#12). This certificate will be used when connecting to the server.</string>
|
||||
<string name="settings_advanced_certificates_error_invalid_cert">Invalid certificate file</string>
|
||||
|
|
@ -511,6 +513,8 @@
|
|||
<string name="trusted_certificate_dialog_fingerprint">SHA-256 fingerprint</string>
|
||||
<string name="trusted_certificate_dialog_valid_from">Valid from</string>
|
||||
<string name="trusted_certificate_dialog_valid_until">Valid until</string>
|
||||
<string name="trusted_certificate_dialog_ca">Certificate Authority (CA)</string>
|
||||
<string name="trusted_certificate_dialog_ca_info">All certificates signed by this Certificate Authority will be trusted.</string>
|
||||
<string name="trusted_certificate_dialog_expired_warning">Warning: This certificate has expired.</string>
|
||||
<string name="trusted_certificate_dialog_not_yet_valid_warning">Warning: This certificate is not yet valid.</string>
|
||||
<string name="trusted_certificate_dialog_button_trust">Trust</string>
|
||||
|
|
@ -521,10 +525,11 @@
|
|||
<!-- Client certificate dialog (ClientCertificateFragment) -->
|
||||
<string name="client_certificate_dialog_title">Client certificate</string>
|
||||
<string name="client_certificate_dialog_title_add">Add client certificate</string>
|
||||
<string name="client_certificate_dialog_description_page1">Enter the password for the PKCS#12 file and the server URL this certificate should be used for.</string>
|
||||
<string name="client_certificate_dialog_description_page1">Enter the service URL this certificate should be used for, and the password for the PKCS#12 file.</string>
|
||||
<string name="client_certificate_dialog_description_page2">Review the certificate details and save to add this client certificate.</string>
|
||||
<string name="client_certificate_dialog_password_hint">Password</string>
|
||||
<string name="client_certificate_dialog_base_url_hint">Server URL (e.g. https://example.com)</string>
|
||||
<string name="client_certificate_dialog_base_url_hint">Service URL</string>
|
||||
<string name="client_certificate_dialog_base_url_placeholder">e.g. https://ntfy.example.com</string>
|
||||
<string name="client_certificate_dialog_subject">Subject</string>
|
||||
<string name="client_certificate_dialog_issuer">Issuer</string>
|
||||
<string name="client_certificate_dialog_fingerprint">SHA-256 Fingerprint</string>
|
||||
|
|
@ -533,8 +538,6 @@
|
|||
<string name="client_certificate_dialog_button_next">Next</string>
|
||||
<string name="client_certificate_dialog_button_save">Save</string>
|
||||
<string name="client_certificate_dialog_button_delete">Delete</string>
|
||||
<string name="client_certificate_dialog_button_cancel">Cancel</string>
|
||||
<string name="client_certificate_dialog_delete_confirm">Delete this certificate?</string>
|
||||
<string name="client_certificate_dialog_added_toast">Certificate added</string>
|
||||
<string name="client_certificate_dialog_deleted_toast">Certificate deleted</string>
|
||||
<string name="client_certificate_dialog_error_wrong_password">Wrong password or invalid PKCS#12 file</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue