Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8373c4cd authored by Mathew Smith's avatar Mathew Smith
Browse files

Add oauth2 support for gmail and outlook

parent 6077f0a0
Loading
Loading
Loading
Loading
+25 −5
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@ import com.fsck.k9.autodiscovery.api.DiscoveryResults
import com.fsck.k9.autodiscovery.api.DiscoveryTarget
import com.fsck.k9.helper.EmailHelper
import com.fsck.k9.mail.AuthType
import com.fsck.k9.mail.oauth.OAuth2Provider
import java.net.URI
import com.fsck.k9.mail.ConnectionSecurity
import com.fsck.k9.preferences.Protocols
import org.xmlpull.v1.XmlPullParser
@@ -90,13 +92,20 @@ class ProvidersXmlDiscovery(

        val username = incomingUsernameTemplate.fillInUsernameTemplate(email, user, domain)

        val xoauth2 = OAuth2Provider.isXOAuth2(domain)
        val xoauth2Label = if (xoauth2) AuthType.XOAUTH2.name else ""
        val xoauth2Colon = if (xoauth2) ":" else ""

        val security = when {
            incomingUriTemplate.startsWith("imap+ssl") -> ConnectionSecurity.SSL_TLS_REQUIRED
            incomingUriTemplate.startsWith("imap+tls") -> ConnectionSecurity.STARTTLS_REQUIRED
            else -> error("Connection security required")
        }
        
        val uri = Uri.parse(incomingUriTemplate)
        val incomingUri = with(URI(incomingUriTemplate)) {
            URI(scheme, "$xoauth2Label$xoauth2Colon$username", host, port, null, null, null).toString()
        }
        val uri = Uri.parse(incomingUri)
        val host = uri.host ?: error("Host name required")
        val port = if (uri.port == -1) {
            if (security == ConnectionSecurity.STARTTLS_REQUIRED) 143 else 993
@@ -104,13 +113,19 @@ class ProvidersXmlDiscovery(
            uri.port
        }

        return DiscoveredServerSettings(Protocols.IMAP, host, port, security, AuthType.PLAIN, username)
        val authType = if (xoauth2) AuthType.XOAUTH2 else AuthType.PLAIN
        return DiscoveredServerSettings(Protocols.IMAP, host, port, security, authType, username)
    }

    private fun Provider.toOutgoingServerSettings(email: String): DiscoveredServerSettings? {

        val user = EmailHelper.getLocalPartFromEmailAddress(email) ?: return null
        val domain = EmailHelper.getDomainFromEmailAddress(email) ?: return null

        val xoauth2 = OAuth2Provider.isXOAuth2(domain)
        val xoauth2Label = if (xoauth2) AuthType.XOAUTH2.name else ""
        val xoauth2Colon = if (xoauth2) ":" else ""

        val username = outgoingUsernameTemplate.fillInUsernameTemplate(email, user, domain)

        val security = when {
@@ -119,7 +134,11 @@ class ProvidersXmlDiscovery(
            else -> error("Connection security required")
        }

        val uri = Uri.parse(outgoingUriTemplate)
        val outgoingUri = with(URI(outgoingUriTemplate)) {
            URI(scheme, "$username$xoauth2Colon$xoauth2Label", host, port, null, null, null).toString()
        }

        val uri = Uri.parse(outgoingUri)
        val host = uri.host ?: error("Host name required")
        val port = if (uri.port == -1) {
            if (security == ConnectionSecurity.STARTTLS_REQUIRED) 587 else 465
@@ -127,7 +146,8 @@ class ProvidersXmlDiscovery(
            uri.port
        }

        return DiscoveredServerSettings(Protocols.SMTP, host, port, security, AuthType.PLAIN, username)
        val authType = if (xoauth2) AuthType.XOAUTH2 else AuthType.PLAIN
        return DiscoveredServerSettings(Protocols.SMTP, host, port, security, authType, username)
    }

    private fun String.fillInUsernameTemplate(email: String, user: String, domain: String): String {
+2 −2
Original line number Diff line number Diff line
@@ -20,13 +20,13 @@ class ProvidersXmlDiscoveryTest : RobolectricTest() {
        with(connectionSettings!!.incoming.first()) {
            assertThat(host).isEqualTo("imap.gmail.com")
            assertThat(security).isEqualTo(ConnectionSecurity.SSL_TLS_REQUIRED)
            assertThat(authType).isEqualTo(AuthType.PLAIN)
            assertThat(authType).isEqualTo(AuthType.XOAUTH2)
            assertThat(username).isEqualTo("user@gmail.com")
        }
        with(connectionSettings.outgoing.first()) {
            assertThat(host).isEqualTo("smtp.gmail.com")
            assertThat(security).isEqualTo(ConnectionSecurity.SSL_TLS_REQUIRED)
            assertThat(authType).isEqualTo(AuthType.PLAIN)
            assertThat(authType).isEqualTo(AuthType.XOAUTH2)
            assertThat(username).isEqualTo("user@gmail.com")
        }
    }
+3 −1
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import com.fsck.k9.backends.backendsModule
import com.fsck.k9.controller.ControllerExtension
import com.fsck.k9.crypto.EncryptionExtractor
import com.fsck.k9.crypto.openpgp.OpenPgpEncryptionExtractor
import com.fsck.k9.mail.oauth.oauth2Module
import com.fsck.k9.notification.notificationModule
import com.fsck.k9.preferences.K9StoragePersister
import com.fsck.k9.preferences.StoragePersister
@@ -38,5 +39,6 @@ val appModules = listOf(
    notificationModule,
    resourcesModule,
    backendsModule,
    storageModule
    storageModule,
    oauth2Module
)
+3 −4
Original line number Diff line number Diff line
@@ -19,7 +19,8 @@ class ImapBackendFactory(
    private val context: Context,
    private val powerManager: PowerManager,
    private val backendStorageFactory: K9BackendStorageFactory,
    private val trustedSocketFactory: TrustedSocketFactory
    private val trustedSocketFactory: TrustedSocketFactory,
    private val oAuth2TokenProvider: OAuth2TokenProvider
) : BackendFactory {
    override fun createBackend(account: Account): Backend {
        val accountName = account.displayName
@@ -30,7 +31,6 @@ class ImapBackendFactory(
    }

    private fun createImapStore(account: Account): ImapStore {
        val oAuth2TokenProvider: OAuth2TokenProvider? = null
        val config = createImapStoreConfig(account)
        return ImapStore(
            account.incomingServerSettings,
@@ -54,7 +54,6 @@ class ImapBackendFactory(

    private fun createSmtpTransport(account: Account): SmtpTransport {
        val serverSettings = account.outgoingServerSettings
        val oauth2TokenProvider: OAuth2TokenProvider? = null
        return SmtpTransport(serverSettings, trustedSocketFactory, oauth2TokenProvider)
        return SmtpTransport(serverSettings, trustedSocketFactory, oAuth2TokenProvider)
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ val backendsModule = module {
            )
        )
    }
    single { ImapBackendFactory(get(), get(), get(), get()) }
    single { ImapBackendFactory(get(), get(), get(), get(), get()) }
    single { Pop3BackendFactory(get(), get()) }
    single { WebDavBackendFactory(get(), get(), get()) }
}
Loading