fix: sanitize custom IM type label before using as IMPP URI scheme#543
fix: sanitize custom IM type label before using as IMPP URI scheme#543faraz152 wants to merge 2 commits intoFossifyOrg:mainfrom
Conversation
Custom IM type labels are used as the URI scheme when building IMPP
properties (e.g. `a b:username`). URI schemes only allow the character
set [a-zA-Z][a-zA-Z0-9+-.]*; a label containing spaces or other
special characters caused ez-vcard's Impp constructor to throw an
IllegalArgumentException, which silently aborted the export and left
a 0-byte file on disk.
Fix: replace any character outside the valid URI-scheme set with a
hyphen before constructing the Impp object. Also guard against labels
that start with a non-letter (prefix "x-") or are empty ("x-custom").
Fixes FossifyOrg#499
|
Hey @faraz152 One small thing in the sanitization chain: val scheme = it.label
.replace(Regex("[^a-zA-Z0-9+\\-.]"), "-")
.let { s -> if (s.firstOrNull()?.isLetter() != true) "x-$s" else s }
.ifEmpty { "x-custom" }For an empty it.label, the let block prefixes "x-" first, so by the time .ifEmpty { "x-custom" } runs the string is "x-" (not empty) and the fallback never fires. The PR description says empty labels become "x-custom", but they actually become "x-". Reordering fixes it, and IMO reads more clearly as a when: val sanitized = it.label.replace(Regex("[^a-zA-Z0-9+\\-.]"), "-")
val scheme = when {
sanitized.isEmpty() -> "x-custom"
!sanitized.first().isLetter() -> "x-$sanitized"
else -> sanitized
}Also worth flagging for cross-PR awareness: #439 moves this exact line into CardPropertyAdderMain.kt, so whichever PR lands second will need a rebase that carries this sanitization across. PS: Little nitty site remark: Regex(...) is constructed per-IM: could be a top-level private val SCHEME_PATTERN = Regex(...) |
When it.label is empty, .replace() produces an empty string, then
the .let block prefixes 'x-' yielding 'x-' — which is not empty,
so .ifEmpty { 'x-custom' } never fires and 'x-' is used as the
URI scheme, which is invalid.
Replace the chained .let + .ifEmpty with a single when expression
that checks isEmpty() first, so empty labels always produce 'x-custom'.
|
good catch, pushed a fix. replaced the chained .let + .ifEmpty with a single when block that checks isEmpty() first, so empty labels always land on "x-custom" before the prefix logic runs. |
What
Fixes #499
A contact with a custom IM type containing a space (e.g.
"a b") caused sharing/export to fail silently — a 0-byte file was written and an error toast appeared.Root cause
VcfExporterpassesit.labeldirectly as the protocol argument to ez-vcard'sImpp(String protocol, String handle)constructor. That constructor builds ajava.net.URIusing the protocol string as the URI scheme. URI schemes only allow[a-zA-Z][a-zA-Z0-9+-.]*, so a label containing a space throwsIllegalArgumentException, which propagates up and aborts the export.Fix
Before constructing the
Imppproperty, replace any character outside the valid URI-scheme set with a hyphen. Two additional guards:"x-"(scheme must begin withALPHA)"x-custom"Testing
Manually verified:
"a b"with a username.IMPP:a-b:username.Compiled and linted against
fossDebugvariant — no errors or new warnings.Note on round-trip fidelity
Labels with spaces will be stored as hyphen-separated strings in the exported VCF (e.g.
"a b"→"a-b"). Preserving the original label through the URI scheme is not possible without a larger structural change (URI schemes forbid percent-encoding). This is a known limitation documented in the code comment.