Skip to content

Defang / Refang — Python source

Make URLs, IPs, and emails safe to paste by defanging indicators (https:// → hxxps[://], . → [.], @ → [@]) - and reverse refanged text back to its original form. Runs entirely in your browser, with a shareable link to your exact input and mode.

This is the Python implementation — the same logic the interactive tool runs, in a shareable, citable form.

"""defang-refang — make URLs, IPs, and emails safe to paste (and reverse it).

Language: Python (3.9+, standard library only)
Source:   CosmoDev polyglot showcase port of the Defang/Refang tool, ported from
          src/lib/defang.ts (the canonical TypeScript implementation) and held
          in lock-step with cli/defang-refang/defang-refang.go.
License:  display source — part of CosmoDev's polyglot tool pages.

Design goals:
  - Pure + deterministic; never raises.
  - Functionally equivalent to the TS / Go reference: same inputs -> same outputs.
  - Self-contained: stdlib only (str.replace is built into the language — no
    imports beyond ``annotations`` for forward-compat typing).

Algorithm: ``defang`` replaces ``https://`` / ``http://`` schemes with
``hxxps[://]`` / ``hxxp[://]``, then brackets EVERY dot as ``[.]`` and every
at-sign as ``[@]`` — the standard threat-intel indicator-defanging convention.
``refang`` is its exact inverse: scheme markers are restored first, then
``[.]`` / ``[@]`` are unbracketed, so ``refang(defang(x)) == x`` for typical
URLs, IPs, emails, and plain text.

Ordering note: scheme replacements run BEFORE dot/at bracketing so the dots and
colon inside the resulting ``[://]`` marker are not themselves re-bracketed
(which would corrupt the scheme marker). Note that EVERY dot is bracketed, not
just the domain separator — so defang is NOT idempotent by design: apply it
once to fresh text. ``str.replace`` replaces every occurrence by default,
matching the ``replaceAll`` semantics of the TS source.
"""

from __future__ import annotations

__all__ = ["defang", "refang"]


def defang(text: str) -> str:
    """Defang text so URLs, IPs, and emails are no longer clickable or auto-linked.

    Mirrors ``defang()`` in src/lib/defang.ts and ``Defang()`` in the Go twin,
    and must agree with both on every shared vector. Scheme replacements run
    first so the dots and colon inside the resulting ``[://]`` marker are not
    themselves re-bracketed. EVERY dot is bracketed, not just the domain
    separator. Empty input returns empty; text with no indicators passes through
    unchanged.
    """
    return (
        text.replace("https://", "hxxps[://]")
        .replace("http://", "hxxp[://]")
        .replace(".", "[.]")
        .replace("@", "[@]")
    )


def refang(text: str) -> str:
    """Reverse defanging — restore ``hxxps[://]`` / ``hxxp[://]`` to real schemes
    and unbracket ``[.]`` / ``[@]``. Mirrors ``refang()`` in src/lib/defang.ts
    and ``Refang()`` in the Go twin: the exact inverse of :func:`defang`.

    Scheme markers are restored before ``[.]`` / ``[@]`` are unbracketed, so a
    marker like ``hxxps[://]`` reassembles into ``https://`` rather than being
    split by an earlier dot/at substitution. Empty input returns empty.
    """
    return (
        text.replace("hxxps[://]", "https://")
        .replace("hxxp[://]", "http://")
        .replace("[.]", ".")
        .replace("[@]", "@")
    )

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →