Skip to content

Defang / Refang — JavaScript 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 JavaScript 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:   JavaScript (ES2021+, runs unmodified in Node 16+ and modern
 *             browsers - `replaceAll` is the ES2021 primitive this port uses)
 * 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 throws.
 *   - Functionally equivalent to the TS / Go reference: same inputs -> same outputs.
 *   - Self-contained: stdlib only (no npm dependencies).
 *
 * 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. `String.prototype.replaceAll` with a string argument
 * replaces every occurrence, matching the TS source one for one (this is the
 * canonical TS lib's own implementation, mirrored here verbatim).
 */

'use strict';

/**
 * 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.
 *
 * @param {string} text
 * @returns {string}
 */
function defang(text) {
  return text
    .replaceAll('https://', 'hxxps[://]')
    .replaceAll('http://', 'hxxp[://]')
    .replaceAll('.', '[.]')
    .replaceAll('@', '[@]');
}

/**
 * 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 `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.
 *
 * @param {string} text
 * @returns {string}
 */
function refang(text) {
  return text
    .replaceAll('hxxps[://]', 'https://')
    .replaceAll('hxxp[://]', 'http://')
    .replaceAll('[.]', '.')
    .replaceAll('[@]', '@');
}

// CommonJS export so the file is consumable from Node without a build step,
// while staying dependency-free and framework-agnostic.
module.exports = { defang, refang };

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 →