Defang / Refang — Java 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 Java 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: Java (Java 17, 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 throws.
// - Functionally equivalent to the TS / Go reference: same inputs -> same outputs.
// - Self-contained: String.replace(CharSequence, CharSequence) replaces
// every occurrence — the closest one-call equivalent of the TS replaceAll.
//
// 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.
/**
* Make URLs, IPs, and emails safe to paste (and reverse it).
*
* <p>The class is package-private so this showcase file compiles standalone
* under its snippet filename ({@code java.java}); in a project, drop it in as
* {@code DefangRefang.java} and mark it {@code public} to export it.</p>
*/
final class DefangRefang {
private DefangRefang() {
}
/**
* Defang text so URLs, IPs, and emails are no longer clickable or auto-linked.
*
* <p>Mirrors {@code defang()} in src/lib/defang.ts and {@code 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 {@code [://]} 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.</p>
*
* @param text the text to defang
* @return the defanged text
*/
static String defang(String text) {
return text.replace("https://", "hxxps[://]")
.replace("http://", "hxxp[://]")
.replace(".", "[.]")
.replace("@", "[@]");
}
/**
* Reverse defanging — restore {@code hxxps[://]} / {@code hxxp[://]} to real
* schemes and unbracket {@code [.]} / {@code [@]}. Mirrors {@code refang()}
* in src/lib/defang.ts and {@code Refang()} in the Go twin: the exact inverse
* of {@link #defang(String)}.
*
* <p>Scheme markers are restored before {@code [.]} / {@code [@]} are
* unbracketed, so a marker like {@code hxxps[://]} reassembles into
* {@code https://} rather than being split by an earlier dot/at substitution.
* Empty input returns empty.</p>
*
* @param text the defanged text
* @return the text with real schemes and separators restored
*/
static String refang(String text) {
return text.replace("hxxps[://]", "https://")
.replace("hxxp[://]", "http://")
.replace("[.]", ".")
.replace("[@]", "@");
}
// ---------- tests (showcase-only; the canonical suite lives in src/lib) ----------
private static int failures = 0;
private static void expect(String got, String want, String label) {
if (!got.equals(want)) {
System.err.printf("FAIL %s:%n got \"%s\"%n want \"%s\"%n", label, got, want);
failures++;
}
}
/** Runs the showcase checks mirrored from the Rust/Python reference snippets. */
public static void main(String[] args) {
// defangs url, email, and ip
expect(defang("https://example.com"), "hxxps[://]example[.]com", "defang url");
expect(defang("user@example.com"), "user[@]example[.]com", "defang email");
expect(defang("192.168.1.1"), "192[.]168[.]1[.]1", "defang ip");
// defangs mixed text
expect(defang("contact admin@site.co.uk or visit http://site.co.uk"),
"contact admin[@]site[.]co[.]uk or visit hxxp[://]site[.]co[.]uk",
"defang mixed");
// applies scheme replacement before dot bracketing
String got = defang("https://a.com");
expect(got, "hxxps[://]a[.]com", "scheme first");
if (got.contains("https[://]") || got.contains("hxxps://")) {
System.err.println("FAIL scheme marker corrupted: \"" + got + "\"");
failures++;
}
// refangs and round-trips
expect(refang("hxxps[://]example[.]com"), "https://example.com", "refang https");
expect(refang("hxxp[://]single[.]com"), "http://single.com", "refang http");
// hxxp and hxxps are distinct markers — never confused.
expect(refang("hxxps[://]secure[.]com"), "https://secure.com", "refang hxxps distinct");
// Round-trip identity for typical URLs, IPs, emails, and plain text.
String[] roundTrips = {
"https://sub.example.com/path?q=1&a=b",
"first.last@sub.example.co.uk",
"172.16.254.1",
"just a sentence with no indicators",
};
for (String x : roundTrips) {
expect(refang(defang(x)), x, "round trip");
}
// empty and passthrough
expect(defang(""), "", "defang empty");
expect(refang(""), "", "refang empty");
expect(defang("nothing to transform here"), "nothing to transform here", "defang passthrough");
expect(refang("no indicators here"), "no indicators here", "refang passthrough");
if (failures > 0) {
System.err.println(failures + " check(s) failed");
System.exit(1);
}
System.out.println("all checks passed");
}
}
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 →