Skip to content

fix: sanitize custom IM type label before using as IMPP URI scheme#543

Open
faraz152 wants to merge 1 commit intoFossifyOrg:mainfrom
faraz152:fix/499-im-custom-type-space-export
Open

fix: sanitize custom IM type label before using as IMPP URI scheme#543
faraz152 wants to merge 1 commit intoFossifyOrg:mainfrom
faraz152:fix/499-im-custom-type-space-export

Conversation

@faraz152
Copy link
Copy Markdown

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

VcfExporter passes it.label directly as the protocol argument to ez-vcard's Impp(String protocol, String handle) constructor. That constructor builds a java.net.URI using the protocol string as the URI scheme. URI schemes only allow [a-zA-Z][a-zA-Z0-9+-.]*, so a label containing a space throws IllegalArgumentException, which propagates up and aborts the export.

Fix

Before constructing the Impp property, replace any character outside the valid URI-scheme set with a hyphen. Two additional guards:

  • Labels that start with a non-letter are prefixed with "x-" (scheme must begin with ALPHA)
  • Empty labels fall back to "x-custom"

Testing

Manually verified:

  1. Create a contact, set IM field to custom type "a b" with a username.
  2. Before fix: Export → 0-byte file, error toast.
  3. After fix: Export succeeds, IMPP line written as IMPP:a-b:username.

Compiled and linted against fossDebug variant — 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.

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
@faraz152 faraz152 requested a review from naveensingh as a code owner April 22, 2026 08:31
@Tchiller
Copy link
Copy Markdown

Tchiller commented May 7, 2026

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(...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Space in IM type field breaks export

2 participants