From 7e74265aa937c4ab7672d461ebbac2e17309402b Mon Sep 17 00:00:00 2001 From: Priveetee Date: Mon, 13 Apr 2026 13:39:25 +0200 Subject: [PATCH] fix: repair collapsed scheme in subscriptions delete --- .../typetype/server/routes/SubscriptionsRoutes.kt | 6 ++++++ .../server/SubscriptionsDeleteProxyRoutesTest.kt | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/dev/typetype/server/routes/SubscriptionsRoutes.kt b/src/main/kotlin/dev/typetype/server/routes/SubscriptionsRoutes.kt index 646a30e..9d9c6f6 100644 --- a/src/main/kotlin/dev/typetype/server/routes/SubscriptionsRoutes.kt +++ b/src/main/kotlin/dev/typetype/server/routes/SubscriptionsRoutes.kt @@ -64,5 +64,11 @@ private fun ApplicationCall.extractDeleteChannelUrl(): String? { if (rawTail.isBlank()) return null return runCatching { URLDecoder.decode(rawTail, StandardCharsets.UTF_8) } .getOrDefault(rawTail) + .restoreCollapsedScheme() .takeIf { it.isNotBlank() } } + +private fun String.restoreCollapsedScheme(): String { + val match = Regex("^([A-Za-z][A-Za-z0-9+.-]*):/([^/].*)$").matchEntire(this) ?: return this + return "${match.groupValues[1]}://${match.groupValues[2]}" +} diff --git a/src/test/kotlin/dev/typetype/server/SubscriptionsDeleteProxyRoutesTest.kt b/src/test/kotlin/dev/typetype/server/SubscriptionsDeleteProxyRoutesTest.kt index 7b56ffc..c00c144 100644 --- a/src/test/kotlin/dev/typetype/server/SubscriptionsDeleteProxyRoutesTest.kt +++ b/src/test/kotlin/dev/typetype/server/SubscriptionsDeleteProxyRoutesTest.kt @@ -61,9 +61,9 @@ class SubscriptionsDeleteProxyRoutesTest { } @Test - fun `DELETE subscriptions uses query url when path is proxy-decoded`() = withApp { + fun `DELETE subscriptions repairs proxy-decoded path`() = withApp { service.add(TEST_USER_ID, SubscriptionItem(channelUrl = "https://www.youtube.com/channel/UC123", name = "T", avatarUrl = "")) - val response = client.delete("/subscriptions/https:/www.youtube.com/channel/UC123?url=https%3A%2F%2Fwww.youtube.com%2Fchannel%2FUC123") { + val response = client.delete("/subscriptions/https:/www.youtube.com/channel/UC123") { headers.append(HttpHeaders.Authorization, "Bearer test-jwt") } assertEquals(HttpStatusCode.NoContent, response.status) @@ -72,4 +72,13 @@ class SubscriptionsDeleteProxyRoutesTest { }.bodyAsText() assertFalse(body.contains("UC123")) } + + @Test + fun `DELETE subscriptions accepts query url when provided`() = withApp { + service.add(TEST_USER_ID, SubscriptionItem(channelUrl = "https://www.youtube.com/channel/UC123", name = "T", avatarUrl = "")) + val response = client.delete("/subscriptions/https:/www.youtube.com/channel/UC123?url=https%3A%2F%2Fwww.youtube.com%2Fchannel%2FUC123") { + headers.append(HttpHeaders.Authorization, "Bearer test-jwt") + } + assertEquals(HttpStatusCode.NoContent, response.status) + } }