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

Commit 80f31bbc authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Implement Nextcloud Login Flow

parent 4c229c81
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

package at.bitfire.davdroid.ui.setup

import android.content.Intent
import android.net.MailTo
import android.os.Bundle
import android.os.Handler
@@ -145,4 +146,11 @@ class DefaultLoginCredentialsFragment: Fragment() {
        return valid
    }


    class Factory: ILoginCredentialsFragment {

        override fun getFragment(intent: Intent) = DefaultLoginCredentialsFragment()

    }

}
+18 −0
Original line number Diff line number Diff line
/*
 * Copyright © Ricki Hirner (bitfire web engineering).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */

package at.bitfire.davdroid.ui.setup

import android.content.Intent
import androidx.fragment.app.Fragment

interface ILoginCredentialsFragment {

    fun getFragment(intent: Intent): Fragment?

}
 No newline at end of file
+16 −4
Original line number Diff line number Diff line
@@ -12,8 +12,10 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import at.bitfire.davdroid.App
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.UiUtils
import java.util.*

@@ -42,15 +44,25 @@ class LoginActivity: AppCompatActivity() {
        const val EXTRA_PASSWORD = "password"
    }

    private val loginFragmentLoader = ServiceLoader.load(ILoginCredentialsFragment::class.java)!!


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (savedInstanceState == null)
        if (savedInstanceState == null) {
            // first call, add first login fragment
            var fragment: Fragment? = null
            for (factory in loginFragmentLoader)
                fragment = fragment ?: factory.getFragment(intent)

            if (fragment != null) {
                supportFragmentManager.beginTransaction()
                    .replace(android.R.id.content, DefaultLoginCredentialsFragment())
                        .replace(android.R.id.content, fragment)
                        .commit()
            } else
                Logger.log.severe("Couldn't create LoginFragment")
        }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+96 −0
Original line number Diff line number Diff line
package at.bitfire.davdroid.ui.setup

import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.CookieManager
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.model.Credentials
import okhttp3.HttpUrl
import java.util.logging.Level

class NextcloudLoginFlowFragment: Fragment() {

    companion object {
        const val EXTRA_LOGIN_FLOW = "loginFlow"
        const val EXTRA_DAV_PATH = "davPath"
    }

    lateinit var loginModel: LoginModel

    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        loginModel = ViewModelProviders.of(requireActivity()).get(LoginModel::class.java)

        val webView = WebView(requireActivity())
        webView.settings.apply {
            javaScriptEnabled = true
            userAgentString = BuildConfig.userAgent
        }
        webView.loadUrl(
                requireActivity().intent.data.toString(),   // https://nextcloud.example.com/index.php/login/flow
                mapOf(Pair("OCS-APIREQUEST", "true"))
        )
        webView.webViewClient = object: WebViewClient() {
            override fun shouldOverrideUrlLoading(view: WebView, url: String) =
                    if (url.startsWith("nc://login")) {
                        onReceivedNcUrl(url)
                        true
                    } else {
                        Logger.log.info("Didn't handle $url")
                        false
                    }
        }
        return webView
    }

    private fun onReceivedNcUrl(url: String) {
        val format = Regex("^nc://login/server:(.+)&user:(.+)&password:(.+)$")
        val match = format.find(url)
        if (match != null) {
            // determine DAV URL from root URL
            try {
                val serverUrl = HttpUrl.get(match.groupValues[1])
                val davPath = requireActivity().intent.getStringExtra(EXTRA_DAV_PATH)
                loginModel.baseURI = if (davPath != null)
                    serverUrl.resolve(davPath)!!.uri()
                else
                    serverUrl.uri()

                loginModel.credentials = Credentials(
                        userName = match.groupValues[2],
                        password = match.groupValues[3]
                )

                // continue to next fragment
                requireFragmentManager().beginTransaction()
                        .replace(android.R.id.content, DetectConfigurationFragment(), null)
                        .addToBackStack(null)
                        .commit()
            } catch (e: IllegalArgumentException) {
                Logger.log.log(Level.SEVERE, "Couldn't parse server argument of nc URL: $url", e)
            }
        } else
            Logger.log.severe("Unknown format of nc URL: $url")
    }


    class Factory : ILoginCredentialsFragment {

        override fun getFragment(intent: Intent) =
                if (intent.hasExtra(EXTRA_LOGIN_FLOW))
                    NextcloudLoginFlowFragment()
                else
                    null

    }

}
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
at.bitfire.davdroid.ui.setup.NextcloudLoginFlowFragment$Factory
at.bitfire.davdroid.ui.setup.DefaultLoginCredentialsFragment$Factory
 No newline at end of file