Merge pull request #6860 from thundernest/autoconfig_provider

Change autoconfig code to match Thunderbird's current behavior
This commit is contained in:
cketti 2023-05-03 16:53:18 +02:00 committed by GitHub
commit 1de820571a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 145 additions and 47 deletions

View file

@ -1,47 +1,7 @@
package app.k9mail.autodiscovery.autoconfig
import com.fsck.k9.helper.EmailHelper
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
class AutoconfigUrlProvider {
fun getAutoconfigUrls(email: String): List<HttpUrl> {
val domain = EmailHelper.getDomainFromEmailAddress(email)
requireNotNull(domain) { "Couldn't extract domain from email address: $email" }
return listOf(
createProviderUrl(domain, email),
createDomainUrl(scheme = "https", domain),
createDomainUrl(scheme = "http", domain),
createIspDbUrl(domain),
)
}
private fun createProviderUrl(domain: String?, email: String): HttpUrl {
// https://autoconfig.{domain}/mail/config-v1.1.xml?emailaddress={email}
return HttpUrl.Builder()
.scheme("https")
.host("autoconfig.$domain")
.addEncodedPathSegments("mail/config-v1.1.xml")
.addQueryParameter("emailaddress", email)
.build()
}
private fun createDomainUrl(scheme: String, domain: String): HttpUrl {
// https://{domain}/.well-known/autoconfig/mail/config-v1.1.xml
// http://{domain}/.well-known/autoconfig/mail/config-v1.1.xml
return HttpUrl.Builder()
.scheme(scheme)
.host(domain)
.addEncodedPathSegments(".well-known/autoconfig/mail/config-v1.1.xml")
.build()
}
private fun createIspDbUrl(domain: String): HttpUrl {
// https://autoconfig.thunderbird.net/v1.1/{domain}
return "https://autoconfig.thunderbird.net/v1.1/".toHttpUrl()
.newBuilder()
.addPathSegment(domain)
.build()
}
interface AutoconfigUrlProvider {
fun getAutoconfigUrls(email: String): List<HttpUrl>
}

View file

@ -0,0 +1,22 @@
package app.k9mail.autodiscovery.autoconfig
import com.fsck.k9.helper.EmailHelper
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
class IspDbAutoconfigUrlProvider : AutoconfigUrlProvider {
override fun getAutoconfigUrls(email: String): List<HttpUrl> {
val domain = EmailHelper.getDomainFromEmailAddress(email)
requireNotNull(domain) { "Couldn't extract domain from email address: $email" }
return listOf(createIspDbUrl(domain))
}
private fun createIspDbUrl(domain: String): HttpUrl {
// https://autoconfig.thunderbird.net/v1.1/{domain}
return "https://autoconfig.thunderbird.net/v1.1/".toHttpUrl()
.newBuilder()
.addPathSegment(domain)
.build()
}
}

View file

@ -0,0 +1,56 @@
package app.k9mail.autodiscovery.autoconfig
import com.fsck.k9.helper.EmailHelper
import okhttp3.HttpUrl
class ProviderAutoconfigUrlProvider(private val config: AutoconfigUrlConfig) : AutoconfigUrlProvider {
override fun getAutoconfigUrls(email: String): List<HttpUrl> {
val domain = EmailHelper.getDomainFromEmailAddress(email)
requireNotNull(domain) { "Couldn't extract domain from email address: $email" }
return buildList {
add(createProviderUrl(domain, email, useHttps = true))
add(createDomainUrl(domain, email, useHttps = true))
if (!config.httpsOnly) {
add(createProviderUrl(domain, email, useHttps = false))
add(createDomainUrl(domain, email, useHttps = false))
}
}
}
private fun createProviderUrl(domain: String, email: String, useHttps: Boolean): HttpUrl {
// https://autoconfig.{domain}/mail/config-v1.1.xml?emailaddress={email}
// http://autoconfig.{domain}/mail/config-v1.1.xml?emailaddress={email}
return HttpUrl.Builder()
.scheme(if (useHttps) "https" else "http")
.host("autoconfig.$domain")
.addEncodedPathSegments("mail/config-v1.1.xml")
.apply {
if (config.includeEmailAddress) {
addQueryParameter("emailaddress", email)
}
}
.build()
}
private fun createDomainUrl(domain: String, email: String, useHttps: Boolean): HttpUrl {
// https://{domain}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={email}
// http://{domain}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={email}
return HttpUrl.Builder()
.scheme(if (useHttps) "https" else "http")
.host(domain)
.addEncodedPathSegments(".well-known/autoconfig/mail/config-v1.1.xml")
.apply {
if (config.includeEmailAddress) {
addQueryParameter("emailaddress", email)
}
}
.build()
}
}
data class AutoconfigUrlConfig(
val httpsOnly: Boolean,
val includeEmailAddress: Boolean,
)

View file

@ -4,17 +4,14 @@ import assertk.assertThat
import assertk.assertions.containsExactly
import org.junit.Test
class AutoconfigUrlProviderTest {
private val urlProvider = AutoconfigUrlProvider()
class IspDbAutoconfigUrlProviderTest {
private val urlProvider = IspDbAutoconfigUrlProvider()
@Test
fun `getAutoconfigUrls with ASCII email address`() {
val autoconfigUrls = urlProvider.getAutoconfigUrls("test@domain.example")
assertThat(autoconfigUrls.map { it.toString() }).containsExactly(
"https://autoconfig.domain.example/mail/config-v1.1.xml?emailaddress=test%40domain.example",
"https://domain.example/.well-known/autoconfig/mail/config-v1.1.xml",
"http://domain.example/.well-known/autoconfig/mail/config-v1.1.xml",
"https://autoconfig.thunderbird.net/v1.1/domain.example",
)
}

View file

@ -0,0 +1,63 @@
package app.k9mail.autodiscovery.autoconfig
import assertk.assertThat
import assertk.assertions.containsExactly
import org.junit.Test
class ProviderAutoconfigUrlProviderTest {
@Test
fun `getAutoconfigUrls with http allowed and email address included`() {
val urlProvider = ProviderAutoconfigUrlProvider(
AutoconfigUrlConfig(httpsOnly = false, includeEmailAddress = true),
)
val autoconfigUrls = urlProvider.getAutoconfigUrls("test@domain.example")
assertThat(autoconfigUrls.map { it.toString() }).containsExactly(
"https://autoconfig.domain.example/mail/config-v1.1.xml?emailaddress=test%40domain.example",
"https://domain.example/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=test%40domain.example",
"http://autoconfig.domain.example/mail/config-v1.1.xml?emailaddress=test%40domain.example",
"http://domain.example/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=test%40domain.example",
)
}
@Test
fun `getAutoconfigUrls with only https and email address included`() {
val urlProvider = ProviderAutoconfigUrlProvider(
AutoconfigUrlConfig(httpsOnly = true, includeEmailAddress = true),
)
val autoconfigUrls = urlProvider.getAutoconfigUrls("test@domain.example")
assertThat(autoconfigUrls.map { it.toString() }).containsExactly(
"https://autoconfig.domain.example/mail/config-v1.1.xml?emailaddress=test%40domain.example",
"https://domain.example/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=test%40domain.example",
)
}
@Test
fun `getAutoconfigUrls with only https and email address not included`() {
val urlProvider = ProviderAutoconfigUrlProvider(
AutoconfigUrlConfig(httpsOnly = true, includeEmailAddress = false),
)
val autoconfigUrls = urlProvider.getAutoconfigUrls("test@domain.example")
assertThat(autoconfigUrls.map { it.toString() }).containsExactly(
"https://autoconfig.domain.example/mail/config-v1.1.xml",
"https://domain.example/.well-known/autoconfig/mail/config-v1.1.xml",
)
}
@Test
fun `getAutoconfigUrls with http allowed and email address not included`() {
val urlProvider = ProviderAutoconfigUrlProvider(
AutoconfigUrlConfig(httpsOnly = false, includeEmailAddress = false),
)
val autoconfigUrls = urlProvider.getAutoconfigUrls("test@domain.example")
assertThat(autoconfigUrls.map { it.toString() }).containsExactly(
"https://autoconfig.domain.example/mail/config-v1.1.xml",
"https://domain.example/.well-known/autoconfig/mail/config-v1.1.xml",
"http://autoconfig.domain.example/mail/config-v1.1.xml",
"http://domain.example/.well-known/autoconfig/mail/config-v1.1.xml",
)
}
}