Loading app/build.gradle +1 −1 Original line number Diff line number Diff line Loading @@ -66,7 +66,7 @@ android { defaultConfig { manifestPlaceholders = [ 'appAuthRedirectScheme': 'com.googleusercontent.apps.628867657910-7ade6gut5rhabdgjq6k4rln9i1u9ppca' 'appAuthRedirectScheme': 'net.openid.appauthdemo' ] testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } Loading app/src/main/AndroidManifest.xml +1 −20 Original line number Diff line number Diff line Loading @@ -254,29 +254,10 @@ <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="net.openid.appauth.demo" /> <data android:scheme="net.openid.appauthdemo" /> <data android:scheme="com.googleusercontent.apps.628867657910-7ade6gut5rhabdgjq6k4rln9i1u9ppca" /> </intent-filter> <!-- for up-to-date Chrome browsers we can intercept the OAuth2 callback directly, if a secure assertion is found on the site matching this app: https://appauth.demo-app.io/.well-known/assetlinks.json The source for this file can also be found in web/.well-known/assetlinks.json --> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="appauth.demo-app.io" android:path="/oauth2redirect" android:scheme="https" /> </intent-filter> </activity> </application> Loading app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java +13 −1 Original line number Diff line number Diff line Loading @@ -52,8 +52,20 @@ public class IdentityProvider R.string.google_scope_string, R.string.google_name); public static final IdentityProvider EELO = new IdentityProvider( "eelo", R.string.eelo_discovery_uri, NOT_SPECIFIED, // auth endpoint is discovered NOT_SPECIFIED, // token endpoint is discovered R.string.eelo_client_id, NOT_SPECIFIED, // client secret is not required for Google R.string.eelo_auth_redirect_uri, R.string.eelo_scope_string, R.string.eelo_name); public static final List<IdentityProvider> PROVIDERS = Arrays.asList( GOOGLE); GOOGLE, EELO); public static List<IdentityProvider> getEnabledProviders(Context context) { Loading app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt 0 → 100644 +392 −0 Original line number Diff line number Diff line package at.bitfire.davdroid.ui.setup import android.app.Activity import android.app.PendingIntent import android.content.Context import android.content.Intent import android.net.Uri import android.os.* import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import at.bitfire.dav4android.Constants import at.bitfire.davdroid.authorization.IdentityProvider import at.bitfire.davdroid.R import kotlinx.android.synthetic.main.login_credentials_fragment.view.* import net.openid.appauth.* import org.json.JSONException import org.json.JSONObject import java.io.BufferedReader import java.io.IOException import java.io.InputStream import java.io.InputStreamReader import java.net.* import java.util.HashMap import java.util.logging.Level import android.net.ConnectivityManager import android.widget.Toast class EeloAuthenticatorFragment : Fragment(), AuthorizationService.TokenResponseCallback { private val extraAuthServiceDiscovery = "authServiceDiscovery" private val extraClientSecret = "clientSecret" private var authState: AuthState? = null private var authorizationService: AuthorizationService? = null private val bufferSize = 1024 private var userInfoJson: JSONObject? = null private fun isNetworkAvailable(): Boolean { val connectivityManager = activity!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetworkInfo = connectivityManager.activeNetworkInfo return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_eelo_authenticator, container, false) if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } // Initialise the authorization service authorizationService = AuthorizationService(context!!) activity?.intent?.let { if (!it.getBooleanExtra(LoginActivity.ACCOUNT_PROVIDER_EELO_AUTH_COMPLETE, false)) { // Get all the account providers val providers = IdentityProvider.getEnabledProviders(context) // Iterate over the account providers for (idp in providers) { val retrieveCallback = AuthorizationServiceConfiguration.RetrieveConfigurationCallback { serviceConfiguration, ex -> if (ex == null && serviceConfiguration != null) { makeAuthRequest(serviceConfiguration, idp) } else { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } } if (idp.name == getString(R.string.eelo_name)) { // Get configurations for the eelo account provider idp.retrieveConfig(context, retrieveCallback) } } } else { val response = AuthorizationResponse.fromIntent(activity!!.intent) val ex = AuthorizationException.fromIntent(activity!!.intent) authState = AuthState(response, ex) if (response != null) { exchangeAuthorizationCode(response) } else { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } } } return view } private fun makeAuthRequest( serviceConfig: AuthorizationServiceConfiguration, idp: IdentityProvider) { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } val authRequest = AuthorizationRequest.Builder( serviceConfig, idp.clientId, ResponseTypeValues.CODE, idp.redirectUri) .setScope(idp.scope) .build() authorizationService?.performAuthorizationRequest( authRequest, createPostAuthorizationIntent( context!!, authRequest, serviceConfig.discoveryDoc, idp.clientSecret), authorizationService?.createCustomTabsIntentBuilder()!! .build()) requireActivity().setResult(Activity.RESULT_OK) requireActivity().finish() } private fun createPostAuthorizationIntent( context: Context, request: AuthorizationRequest, discoveryDoc: AuthorizationServiceDiscovery?, clientSecret: String?): PendingIntent { val intent = Intent(context, LoginActivity::class.java) if (discoveryDoc != null) { intent.putExtra(extraAuthServiceDiscovery, discoveryDoc.docJson.toString()) } if (clientSecret != null) { intent.putExtra(extraClientSecret, clientSecret) } intent.putExtra(LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE, LoginActivity.ACCOUNT_PROVIDER_EELO) intent.putExtra(LoginActivity.ACCOUNT_PROVIDER_EELO_AUTH_COMPLETE, true) return PendingIntent.getActivity(context, request.hashCode(), intent, 0) } private fun exchangeAuthorizationCode(authorizationResponse: AuthorizationResponse) { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } val additionalParams = HashMap<String, String?>() if (getClientSecretFromIntent(activity!!.intent) != null) { additionalParams["client_secret"] = getClientSecretFromIntent(activity!!.intent) } performTokenRequest(authorizationResponse.createTokenExchangeRequest(additionalParams)) } private fun getClientSecretFromIntent(intent: Intent): String? { return if (!intent.hasExtra(extraClientSecret)) { null } else intent.getStringExtra(extraClientSecret) } private fun performTokenRequest(request: TokenRequest) { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } authorizationService?.performTokenRequest( request, this) } override fun onTokenRequestCompleted(response: TokenResponse?, ex: AuthorizationException?) { authState?.update(response, ex) // TODO Get the userId for future requests //getAccountInfo() } private fun getAccountInfo() { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } val discoveryDoc = getDiscoveryDocFromIntent(activity!!.intent) if (!authState!!.isAuthorized || discoveryDoc == null || discoveryDoc.userinfoEndpoint == null) { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } else { object : AsyncTask<Void, Void, Void>() { override fun doInBackground(vararg params: Void): Void? { if (fetchUserInfo()) { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } return null } }.execute() } } private fun getDiscoveryDocFromIntent(intent: Intent): AuthorizationServiceDiscovery? { if (!intent.hasExtra(extraAuthServiceDiscovery)) { return null } val discoveryJson = intent.getStringExtra(extraAuthServiceDiscovery) try { return AuthorizationServiceDiscovery(JSONObject(discoveryJson)) } catch (ex: JSONException) { throw IllegalStateException("Malformed JSON in discovery doc") } catch (ex: AuthorizationServiceDiscovery.MissingArgumentException) { throw IllegalStateException("Malformed JSON in discovery doc") } } private fun fetchUserInfo(): Boolean { var error = false if (authState!!.authorizationServiceConfiguration == null) { return true } authState!!.performActionWithFreshTokens(authorizationService!!, AuthState.AuthStateAction { accessToken, _, ex -> if (ex != null) { error = true return@AuthStateAction } val discoveryDoc = getDiscoveryDocFromIntent(activity!!.intent) ?: throw IllegalStateException("no available discovery doc") val userInfoEndpoint: URL try { userInfoEndpoint = URL(discoveryDoc.userinfoEndpoint!!.toString()) } catch (urlEx: MalformedURLException) { error = true return@AuthStateAction } var userInfoResponse: InputStream? = null try { val conn = userInfoEndpoint.openConnection() as HttpURLConnection conn.setRequestProperty("Authorization", "Bearer " + accessToken!!) conn.instanceFollowRedirects = false userInfoResponse = conn.inputStream val response = readStream(userInfoResponse) updateUserInfo(JSONObject(response)) } catch (ioEx: IOException) { error = true } catch (jsonEx: JSONException) { error = true } finally { if (userInfoResponse != null) { try { userInfoResponse.close() } catch (ioEx: IOException) { error = true } } } }) return error } @Throws(IOException::class) private fun readStream(stream: InputStream?): String { val br = BufferedReader(InputStreamReader(stream!!)) val buffer = CharArray(bufferSize) val sb = StringBuilder() var readCount = br.read(buffer) while (readCount != -1) { sb.append(buffer, 0, readCount) readCount = br.read(buffer) } return sb.toString() } private fun updateUserInfo(jsonObject: JSONObject) { Handler(Looper.getMainLooper()).post { userInfoJson = jsonObject onAccountInfoGotten() } } private fun onAccountInfoGotten() { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } if (userInfoJson != null) { try { var emailAddress = "" if (userInfoJson!!.has("email")) { emailAddress = userInfoJson!!.getString("email") } validateLoginData(emailAddress, authState!!)?.let { info -> DetectConfigurationFragment.newInstance(info).show(fragmentManager, null) } } catch (ex: JSONException) { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } } else { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } } private fun validateLoginData(emailAddress: String, authState: AuthState): LoginInfo? { val baseUrl = Uri.parse("https://apidata.googleusercontent.com/caldav/v2/$emailAddress/events") val uri = validateBaseUrl(baseUrl, false, { message -> view!!.urlpwd_base_url.error = message }) return if (uri != null) LoginInfo(uri, emailAddress, null, authState, null) else null } private fun validateBaseUrl(baseUrl: Uri, httpsRequired: Boolean, reportError: (String) -> Unit): URI? { var uri: URI? = null val scheme = baseUrl.scheme if ((!httpsRequired && scheme.equals("http", true)) || scheme.equals("https", true)) { var host = baseUrl.host if (host.isNullOrBlank()) reportError(getString(R.string.login_url_host_name_required)) else try { host = IDN.toASCII(host) } catch (e: IllegalArgumentException) { Constants.log.log(Level.WARNING, "Host name not conforming to RFC 3490", e) } val path = baseUrl.encodedPath val port = baseUrl.port try { uri = URI(baseUrl.scheme, null, host, port, path, null, null) } catch (e: URISyntaxException) { reportError(e.localizedMessage) } } else reportError(getString(if (httpsRequired) R.string.login_url_must_be_https else R.string.login_url_must_be_http_or_https)) return uri } override fun onDestroy() { super.onDestroy() authorizationService?.dispose() } } app/src/main/java/at/bitfire/davdroid/ui/setup/LoginActivity.kt +2 −3 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ class LoginActivity : AppCompatActivity() { const val ACCOUNT_PROVIDER_EELO = "eelo" const val ACCOUNT_PROVIDER_GOOGLE = "google" const val ACCOUNT_PROVIDER_GOOGLE_AUTH_COMPLETE = "google_auth_complete" const val ACCOUNT_PROVIDER_EELO_AUTH_COMPLETE = "eelo_auth_complete" } Loading @@ -54,10 +55,8 @@ class LoginActivity : AppCompatActivity() { if (savedInstanceState == null) { when (intent.getStringExtra(SETUP_ACCOUNT_PROVIDER_TYPE)) { ACCOUNT_PROVIDER_EELO -> { // Set the eelo Contacts and Calendar service URL intent.putExtra(EXTRA_URL, "https://drive.eelo.io") supportFragmentManager.beginTransaction() .replace(android.R.id.content, DefaultLoginCredentialsFragment()) .replace(android.R.id.content, EeloAuthenticatorFragment()) .commit() } ACCOUNT_PROVIDER_GOOGLE -> { Loading Loading
app/build.gradle +1 −1 Original line number Diff line number Diff line Loading @@ -66,7 +66,7 @@ android { defaultConfig { manifestPlaceholders = [ 'appAuthRedirectScheme': 'com.googleusercontent.apps.628867657910-7ade6gut5rhabdgjq6k4rln9i1u9ppca' 'appAuthRedirectScheme': 'net.openid.appauthdemo' ] testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } Loading
app/src/main/AndroidManifest.xml +1 −20 Original line number Diff line number Diff line Loading @@ -254,29 +254,10 @@ <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="net.openid.appauth.demo" /> <data android:scheme="net.openid.appauthdemo" /> <data android:scheme="com.googleusercontent.apps.628867657910-7ade6gut5rhabdgjq6k4rln9i1u9ppca" /> </intent-filter> <!-- for up-to-date Chrome browsers we can intercept the OAuth2 callback directly, if a secure assertion is found on the site matching this app: https://appauth.demo-app.io/.well-known/assetlinks.json The source for this file can also be found in web/.well-known/assetlinks.json --> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="appauth.demo-app.io" android:path="/oauth2redirect" android:scheme="https" /> </intent-filter> </activity> </application> Loading
app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java +13 −1 Original line number Diff line number Diff line Loading @@ -52,8 +52,20 @@ public class IdentityProvider R.string.google_scope_string, R.string.google_name); public static final IdentityProvider EELO = new IdentityProvider( "eelo", R.string.eelo_discovery_uri, NOT_SPECIFIED, // auth endpoint is discovered NOT_SPECIFIED, // token endpoint is discovered R.string.eelo_client_id, NOT_SPECIFIED, // client secret is not required for Google R.string.eelo_auth_redirect_uri, R.string.eelo_scope_string, R.string.eelo_name); public static final List<IdentityProvider> PROVIDERS = Arrays.asList( GOOGLE); GOOGLE, EELO); public static List<IdentityProvider> getEnabledProviders(Context context) { Loading
app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt 0 → 100644 +392 −0 Original line number Diff line number Diff line package at.bitfire.davdroid.ui.setup import android.app.Activity import android.app.PendingIntent import android.content.Context import android.content.Intent import android.net.Uri import android.os.* import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import at.bitfire.dav4android.Constants import at.bitfire.davdroid.authorization.IdentityProvider import at.bitfire.davdroid.R import kotlinx.android.synthetic.main.login_credentials_fragment.view.* import net.openid.appauth.* import org.json.JSONException import org.json.JSONObject import java.io.BufferedReader import java.io.IOException import java.io.InputStream import java.io.InputStreamReader import java.net.* import java.util.HashMap import java.util.logging.Level import android.net.ConnectivityManager import android.widget.Toast class EeloAuthenticatorFragment : Fragment(), AuthorizationService.TokenResponseCallback { private val extraAuthServiceDiscovery = "authServiceDiscovery" private val extraClientSecret = "clientSecret" private var authState: AuthState? = null private var authorizationService: AuthorizationService? = null private val bufferSize = 1024 private var userInfoJson: JSONObject? = null private fun isNetworkAvailable(): Boolean { val connectivityManager = activity!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetworkInfo = connectivityManager.activeNetworkInfo return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_eelo_authenticator, container, false) if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } // Initialise the authorization service authorizationService = AuthorizationService(context!!) activity?.intent?.let { if (!it.getBooleanExtra(LoginActivity.ACCOUNT_PROVIDER_EELO_AUTH_COMPLETE, false)) { // Get all the account providers val providers = IdentityProvider.getEnabledProviders(context) // Iterate over the account providers for (idp in providers) { val retrieveCallback = AuthorizationServiceConfiguration.RetrieveConfigurationCallback { serviceConfiguration, ex -> if (ex == null && serviceConfiguration != null) { makeAuthRequest(serviceConfiguration, idp) } else { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } } if (idp.name == getString(R.string.eelo_name)) { // Get configurations for the eelo account provider idp.retrieveConfig(context, retrieveCallback) } } } else { val response = AuthorizationResponse.fromIntent(activity!!.intent) val ex = AuthorizationException.fromIntent(activity!!.intent) authState = AuthState(response, ex) if (response != null) { exchangeAuthorizationCode(response) } else { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } } } return view } private fun makeAuthRequest( serviceConfig: AuthorizationServiceConfiguration, idp: IdentityProvider) { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } val authRequest = AuthorizationRequest.Builder( serviceConfig, idp.clientId, ResponseTypeValues.CODE, idp.redirectUri) .setScope(idp.scope) .build() authorizationService?.performAuthorizationRequest( authRequest, createPostAuthorizationIntent( context!!, authRequest, serviceConfig.discoveryDoc, idp.clientSecret), authorizationService?.createCustomTabsIntentBuilder()!! .build()) requireActivity().setResult(Activity.RESULT_OK) requireActivity().finish() } private fun createPostAuthorizationIntent( context: Context, request: AuthorizationRequest, discoveryDoc: AuthorizationServiceDiscovery?, clientSecret: String?): PendingIntent { val intent = Intent(context, LoginActivity::class.java) if (discoveryDoc != null) { intent.putExtra(extraAuthServiceDiscovery, discoveryDoc.docJson.toString()) } if (clientSecret != null) { intent.putExtra(extraClientSecret, clientSecret) } intent.putExtra(LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE, LoginActivity.ACCOUNT_PROVIDER_EELO) intent.putExtra(LoginActivity.ACCOUNT_PROVIDER_EELO_AUTH_COMPLETE, true) return PendingIntent.getActivity(context, request.hashCode(), intent, 0) } private fun exchangeAuthorizationCode(authorizationResponse: AuthorizationResponse) { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } val additionalParams = HashMap<String, String?>() if (getClientSecretFromIntent(activity!!.intent) != null) { additionalParams["client_secret"] = getClientSecretFromIntent(activity!!.intent) } performTokenRequest(authorizationResponse.createTokenExchangeRequest(additionalParams)) } private fun getClientSecretFromIntent(intent: Intent): String? { return if (!intent.hasExtra(extraClientSecret)) { null } else intent.getStringExtra(extraClientSecret) } private fun performTokenRequest(request: TokenRequest) { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } authorizationService?.performTokenRequest( request, this) } override fun onTokenRequestCompleted(response: TokenResponse?, ex: AuthorizationException?) { authState?.update(response, ex) // TODO Get the userId for future requests //getAccountInfo() } private fun getAccountInfo() { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } val discoveryDoc = getDiscoveryDocFromIntent(activity!!.intent) if (!authState!!.isAuthorized || discoveryDoc == null || discoveryDoc.userinfoEndpoint == null) { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } else { object : AsyncTask<Void, Void, Void>() { override fun doInBackground(vararg params: Void): Void? { if (fetchUserInfo()) { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } return null } }.execute() } } private fun getDiscoveryDocFromIntent(intent: Intent): AuthorizationServiceDiscovery? { if (!intent.hasExtra(extraAuthServiceDiscovery)) { return null } val discoveryJson = intent.getStringExtra(extraAuthServiceDiscovery) try { return AuthorizationServiceDiscovery(JSONObject(discoveryJson)) } catch (ex: JSONException) { throw IllegalStateException("Malformed JSON in discovery doc") } catch (ex: AuthorizationServiceDiscovery.MissingArgumentException) { throw IllegalStateException("Malformed JSON in discovery doc") } } private fun fetchUserInfo(): Boolean { var error = false if (authState!!.authorizationServiceConfiguration == null) { return true } authState!!.performActionWithFreshTokens(authorizationService!!, AuthState.AuthStateAction { accessToken, _, ex -> if (ex != null) { error = true return@AuthStateAction } val discoveryDoc = getDiscoveryDocFromIntent(activity!!.intent) ?: throw IllegalStateException("no available discovery doc") val userInfoEndpoint: URL try { userInfoEndpoint = URL(discoveryDoc.userinfoEndpoint!!.toString()) } catch (urlEx: MalformedURLException) { error = true return@AuthStateAction } var userInfoResponse: InputStream? = null try { val conn = userInfoEndpoint.openConnection() as HttpURLConnection conn.setRequestProperty("Authorization", "Bearer " + accessToken!!) conn.instanceFollowRedirects = false userInfoResponse = conn.inputStream val response = readStream(userInfoResponse) updateUserInfo(JSONObject(response)) } catch (ioEx: IOException) { error = true } catch (jsonEx: JSONException) { error = true } finally { if (userInfoResponse != null) { try { userInfoResponse.close() } catch (ioEx: IOException) { error = true } } } }) return error } @Throws(IOException::class) private fun readStream(stream: InputStream?): String { val br = BufferedReader(InputStreamReader(stream!!)) val buffer = CharArray(bufferSize) val sb = StringBuilder() var readCount = br.read(buffer) while (readCount != -1) { sb.append(buffer, 0, readCount) readCount = br.read(buffer) } return sb.toString() } private fun updateUserInfo(jsonObject: JSONObject) { Handler(Looper.getMainLooper()).post { userInfoJson = jsonObject onAccountInfoGotten() } } private fun onAccountInfoGotten() { if (!isNetworkAvailable()) { Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() activity!!.finish() } if (userInfoJson != null) { try { var emailAddress = "" if (userInfoJson!!.has("email")) { emailAddress = userInfoJson!!.getString("email") } validateLoginData(emailAddress, authState!!)?.let { info -> DetectConfigurationFragment.newInstance(info).show(fragmentManager, null) } } catch (ex: JSONException) { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } } else { Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show() activity!!.finish() } } private fun validateLoginData(emailAddress: String, authState: AuthState): LoginInfo? { val baseUrl = Uri.parse("https://apidata.googleusercontent.com/caldav/v2/$emailAddress/events") val uri = validateBaseUrl(baseUrl, false, { message -> view!!.urlpwd_base_url.error = message }) return if (uri != null) LoginInfo(uri, emailAddress, null, authState, null) else null } private fun validateBaseUrl(baseUrl: Uri, httpsRequired: Boolean, reportError: (String) -> Unit): URI? { var uri: URI? = null val scheme = baseUrl.scheme if ((!httpsRequired && scheme.equals("http", true)) || scheme.equals("https", true)) { var host = baseUrl.host if (host.isNullOrBlank()) reportError(getString(R.string.login_url_host_name_required)) else try { host = IDN.toASCII(host) } catch (e: IllegalArgumentException) { Constants.log.log(Level.WARNING, "Host name not conforming to RFC 3490", e) } val path = baseUrl.encodedPath val port = baseUrl.port try { uri = URI(baseUrl.scheme, null, host, port, path, null, null) } catch (e: URISyntaxException) { reportError(e.localizedMessage) } } else reportError(getString(if (httpsRequired) R.string.login_url_must_be_https else R.string.login_url_must_be_http_or_https)) return uri } override fun onDestroy() { super.onDestroy() authorizationService?.dispose() } }
app/src/main/java/at/bitfire/davdroid/ui/setup/LoginActivity.kt +2 −3 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ class LoginActivity : AppCompatActivity() { const val ACCOUNT_PROVIDER_EELO = "eelo" const val ACCOUNT_PROVIDER_GOOGLE = "google" const val ACCOUNT_PROVIDER_GOOGLE_AUTH_COMPLETE = "google_auth_complete" const val ACCOUNT_PROVIDER_EELO_AUTH_COMPLETE = "eelo_auth_complete" } Loading @@ -54,10 +55,8 @@ class LoginActivity : AppCompatActivity() { if (savedInstanceState == null) { when (intent.getStringExtra(SETUP_ACCOUNT_PROVIDER_TYPE)) { ACCOUNT_PROVIDER_EELO -> { // Set the eelo Contacts and Calendar service URL intent.putExtra(EXTRA_URL, "https://drive.eelo.io") supportFragmentManager.beginTransaction() .replace(android.R.id.content, DefaultLoginCredentialsFragment()) .replace(android.R.id.content, EeloAuthenticatorFragment()) .commit() } ACCOUNT_PROVIDER_GOOGLE -> { Loading