diff --git a/src/main/kotlin/org/jitsi/xmpp/util/RedactColibriIp.kt b/src/main/kotlin/org/jitsi/xmpp/util/RedactColibriIp.kt new file mode 100644 index 0000000..b6ee6de --- /dev/null +++ b/src/main/kotlin/org/jitsi/xmpp/util/RedactColibriIp.kt @@ -0,0 +1,102 @@ +/* + * Copyright @ 2023 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jitsi.xmpp.util + +import java.io.StringReader +import java.io.StringWriter +import javax.xml.XMLConstants +import javax.xml.transform.Templates +import javax.xml.transform.TransformerFactory +import javax.xml.transform.stream.StreamResult +import javax.xml.transform.stream.StreamSource + +class RedactColibriIp { + companion object { + private val redactXslt = + """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + private val factory: TransformerFactory by lazy { + TransformerFactory.newInstance().also { + it.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true) + } + } + private val templates: Templates by lazy { + factory.newTemplates( + StreamSource(StringReader(redactXslt)) + ) + } + + fun redact(input: String): String { + val source = StreamSource(StringReader(input)) + val writer = StringWriter() + val result = StreamResult(writer) + val transformer = templates.newTransformer() + transformer.transform(source, result) + return writer.toString() + } + } +} diff --git a/src/test/kotlin/org/jitsi/xmpp/util/RedactColibriIpTest.kt b/src/test/kotlin/org/jitsi/xmpp/util/RedactColibriIpTest.kt new file mode 100644 index 0000000..69f66e1 --- /dev/null +++ b/src/test/kotlin/org/jitsi/xmpp/util/RedactColibriIpTest.kt @@ -0,0 +1,252 @@ +/* + * Copyright @ 2021 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jitsi.xmpp.util + +import io.kotest.assertions.asClue +import io.kotest.core.spec.style.ShouldSpec +import io.kotest.matchers.shouldBe +import org.jitsi.xmpp.util.RedactColibriIp.Companion.redact +import org.xmlunit.builder.DiffBuilder + +class RedactColibriIpTest : ShouldSpec() { + init { + context("Redacting an IPv4 address from a Colibri message") { + val sourceXml = + """ + + + + + + 31:D8:D0:A2:E8:2F:A6:43:5D:0C:69:BE:23:7A:0C:B1:4D:22:56:18:0B:5D:79:78:F6:E2:71:62:2E:46:45:E9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + val expectedXml = + """ + + + + + + 31:D8:D0:A2:E8:2F:A6:43:5D:0C:69:BE:23:7A:0C:B1:4D:22:56:18:0B:5D:79:78:F6:E2:71:62:2E:46:45:E9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + val redacted = redact(sourceXml) + + should("Convert to expected xml") { + val diff = DiffBuilder.compare(expectedXml).withTest(redacted) + .ignoreWhitespace() + .checkForIdentical().build() + + diff.asClue { + diff.hasDifferences() shouldBe false + } + } + } + + context("Redacting IPv6 addresses from a Colibri message") { + val sourceXml = + """ + + + + + + + + """ + val expectedXml = + """ + + + + + + + + """ + val redacted = redact(sourceXml) + + should("Convert to expected xml") { + val diff = DiffBuilder.compare(expectedXml).withTest(redacted) + .ignoreWhitespace() + .checkForIdentical().build() + + diff.asClue { + diff.hasDifferences() shouldBe false + } + } + } + + context("Turn candidates") { + val sourceXml = """ + + + + + + + + """ + + val redacted = redact(sourceXml) + + should("Be unchanged") { + val diff = DiffBuilder.compare(sourceXml).withTest(redacted) + .ignoreWhitespace() + .checkForIdentical().build() + + diff.asClue { + diff.hasDifferences() shouldBe false + } + } + } + context("Redacting related addresses") { + val sourceXml = """ + + + + + + + """ + val expectedXml = """ + + + + + + + """ + val redacted = redact(sourceXml) + + should("Convert to expected xml") { + val diff = DiffBuilder.compare(expectedXml).withTest(redacted) + .ignoreWhitespace() + .checkForIdentical().build() + + diff.asClue { + diff.hasDifferences() shouldBe false + } + } + } + context("Candidates of relays") { + val sourceXml = """ + + + + + + + E3:47:32:6B:70:67:56:EB:05:B3:B8:E2:95:E6:AD:A4:B7:5A:8D:CA:11:DF:5B:11:69:7C:C9:6E:4D:0B:E2:F4 + + + + + + + + """ + val redacted = redact(sourceXml) + + should("Be unchanged") { + val diff = DiffBuilder.compare(sourceXml).withTest(redacted) + .ignoreWhitespace() + .checkForIdentical().build() + + diff.asClue { + diff.hasDifferences() shouldBe false + } + } + } + } +}