Merge pull request #5 from CrazyWolf13/validation

add: extend header validation
This commit is contained in:
Tobias 2025-12-15 20:23:59 +01:00 committed by GitHub
commit 678747e783
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 38 additions and 2 deletions

View file

@ -11,6 +11,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
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
import io.heckel.ntfy.db.CustomHeader
import io.heckel.ntfy.util.AfterChangedTextWatcher
@ -25,6 +26,7 @@ class CustomHeaderFragment : DialogFragment() {
private lateinit var baseUrlView: TextInputEditText
private lateinit var headerNameView: TextInputEditText
private lateinit var headerValueView: TextInputEditText
private lateinit var headerNameLayout: TextInputLayout
private lateinit var positiveButton: Button
interface CustomHeaderDialogListener {
@ -60,6 +62,7 @@ class CustomHeaderFragment : DialogFragment() {
baseUrlView = view.findViewById(R.id.custom_header_dialog_base_url)
headerNameView = view.findViewById(R.id.custom_header_dialog_name)
headerValueView = view.findViewById(R.id.custom_header_dialog_value)
headerNameLayout = view.findViewById(R.id.custom_header_dialog_name_layout)
var title: String
if (header == null) {
@ -155,17 +158,32 @@ class CustomHeaderFragment : DialogFragment() {
val headerName = headerNameView.text?.toString()?.trim() ?: ""
val headerValue = headerValueView.text?.toString()?.trim() ?: ""
// Clear previous errors
headerNameLayout.error = null
// Validate header name
var isValid = true
if (headerName.isNotEmpty()) {
if (!validateHeaderName(headerName)) {
headerNameLayout.error = getString(R.string.custom_headers_invalid_name)
isValid = false
} else if (isReservedHeader(headerName)) {
headerNameLayout.error = getString(R.string.custom_headers_reserved_name)
isValid = false
}
}
if (header == null) {
// New header: baseUrl, name, and value required
positiveButton.isEnabled = validUrl(baseUrl)
&& headerName.isNotEmpty()
&& validateHeaderName(headerName)
&& headerValue.isNotEmpty()
&& isValid
} else {
// Editing header: name and value required
positiveButton.isEnabled = headerName.isNotEmpty()
&& validateHeaderName(headerName)
&& headerValue.isNotEmpty()
&& isValid
}
}
@ -178,6 +196,21 @@ class CustomHeaderFragment : DialogFragment() {
return regex.matches(name)
}
private fun isReservedHeader(name: String): Boolean {
// These headers are already set by ntfy and cannot be overridden
val nameLower = name.lowercase()
val reservedHeaders = setOf(
"user-agent",
"authorization",
"host",
"connection",
"upgrade",
"accept-encoding"
)
// Also block all WebSocket-related headers
return reservedHeaders.contains(nameLower) || nameLower.startsWith("sec-websocket-")
}
companion object {
const val TAG = "NtfyCustomHeaderFragment"
private const val BUNDLE_BASE_URL = "baseUrl"

View file

@ -43,6 +43,7 @@
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/custom_header_dialog_name_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="?dialogPreferredPadding"

View file

@ -371,6 +371,7 @@
<string name="custom_headers_delete">Löschen</string>
<string name="custom_headers_error_title">Ungültiger Header</string>
<string name="custom_headers_invalid_name">Ungültige Zeichen im Header-Namen</string>
<string name="custom_headers_reserved_name">Dieser Header ist reserviert und wird von ntfy gesetzt</string>
<string name="custom_headers_name_hint">Name (z.B. CF-Access-Client-Id)</string>
<string name="custom_headers_value_hint">Wert</string>
<string name="custom_header_dialog_description_add">Einen benutzerdefinierten HTTP-Header hinzufügen, der mit jeder Anfrage an den angegebenen Server gesendet wird.</string>

View file

@ -424,6 +424,7 @@
<string name="custom_headers_delete">Delete</string>
<string name="custom_headers_error_title">Invalid Header</string>
<string name="custom_headers_invalid_name">Header name contains invalid characters</string>
<string name="custom_headers_reserved_name">This header is reserved and set by ntfy</string>
<string name="custom_headers_name_hint">Name (e.g. CF-Access-Client-Id)</string>
<string name="custom_headers_value_hint">Value</string>
<string name="custom_header_dialog_description_add">Add a custom HTTP header that will be sent with every request to the specified server.</string>