Commit 647b7dd3 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Check for server accounts information before showing the login options view.

This also will show the login with username/email + password with there is only this method enabled by the server.
parent e89bc7cc
......@@ -15,11 +15,13 @@ import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.login.presentation.LoginPresenter
import chat.rocket.android.authentication.login.presentation.LoginView
import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.helper.getCredentials
import chat.rocket.android.helper.hasCredentialsSupport
import chat.rocket.android.helper.requestStoredCredentials
import chat.rocket.android.helper.saveCredentials
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.clearLightStatusBar
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
......@@ -27,25 +29,40 @@ import chat.rocket.android.util.extensions.ui
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import javax.inject.Inject
private const val SERVER_NAME = "server_name"
internal const val REQUEST_CODE_FOR_SIGN_IN_REQUIRED = 1
internal const val REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION = 2
internal const val REQUEST_CODE_FOR_SAVE_RESOLUTION = 3
fun newInstance() = LoginFragment()
fun newInstance(serverName: String): Fragment {
return LoginFragment().apply {
arguments = Bundle(1).apply {
putString(SERVER_NAME, serverName)
}
}
}
class LoginFragment : Fragment(), LoginView {
@Inject
lateinit var presenter: LoginPresenter
@Inject
lateinit var analyticsManager: AnalyticsManager
private var serverName: String? = null
private val editTextsDisposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
val bundle = arguments
if (bundle != null) {
serverName = bundle.getString(SERVER_NAME)
}
}
override fun onCreateView(
......@@ -56,11 +73,10 @@ class LoginFragment : Fragment(), LoginView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
presenter.setupView()
subscribeEditTexts()
setupOnClickListener()
analyticsManager.logScreenView(ScreenViewEvent.Login)
}
......@@ -95,6 +111,15 @@ class LoginFragment : Fragment(), LoginView {
unsubscribeEditTexts()
}
private fun setupToolbar() {
with(activity as AuthenticationActivity) {
this.clearLightStatusBar()
toolbar.isVisible = true
toolbar.title = serverName?.replace(getString(R.string.default_protocol), "")
}
}
override fun showLoading() {
ui {
disableUserInput()
......
......@@ -5,7 +5,6 @@ import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.OauthHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetConnectingServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
......@@ -13,28 +12,12 @@ import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SaveAccountInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.casLoginUrl
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.gitlabUrl
import chat.rocket.android.server.domain.isCasAuthenticationEnabled
import chat.rocket.android.server.domain.isFacebookAuthenticationEnabled
import chat.rocket.android.server.domain.isGithubAuthenticationEnabled
import chat.rocket.android.server.domain.isGitlabAuthenticationEnabled
import chat.rocket.android.server.domain.isGoogleAuthenticationEnabled
import chat.rocket.android.server.domain.isLinkedinAuthenticationEnabled
import chat.rocket.android.server.domain.isLoginFormEnabled
import chat.rocket.android.server.domain.isRegistrationEnabledForNewUsers
import chat.rocket.android.server.domain.isWordpressAuthenticationEnabled
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.domain.wordpressUrl
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.casUrl
import chat.rocket.android.util.extensions.generateRandomString
import chat.rocket.android.util.extensions.parseColor
import chat.rocket.android.util.extensions.samlUrl
import chat.rocket.android.util.extensions.serverLogoUrl
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatAuthException
......@@ -48,9 +31,7 @@ import chat.rocket.core.internal.rest.loginWithCas
import chat.rocket.core.internal.rest.loginWithOauth
import chat.rocket.core.internal.rest.loginWithSaml
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.settingsOauth
import kotlinx.coroutines.experimental.delay
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject
......@@ -58,12 +39,6 @@ private const val TYPE_LOGIN_OAUTH = 1
private const val TYPE_LOGIN_CAS = 2
private const val TYPE_LOGIN_SAML = 3
private const val TYPE_LOGIN_DEEP_LINK = 4
private const val SERVICE_NAME_FACEBOOK = "facebook"
private const val SERVICE_NAME_GITHUB = "github"
private const val SERVICE_NAME_GOOGLE = "google"
private const val SERVICE_NAME_LINKEDIN = "linkedin"
private const val SERVICE_NAME_GILAB = "gitlab"
private const val SERVICE_NAME_WORDPRESS = "wordpress"
class LoginOptionsPresenter @Inject constructor(
private val view: LoginOptionsView,
......@@ -88,254 +63,9 @@ class LoginOptionsPresenter @Inject constructor(
private lateinit var deepLinkToken: String
private lateinit var loginMethod: AuthenticationEvent
fun setupView() {
setupConnectionInfo(currentServer)
setupAccountContainerView()
setupLoginWithEmailView()
setupCreateNewAccountView()
}
private fun setupConnectionInfo(serverUrl: String) {
currentServer = serverUrl
client = factory.create(currentServer)
settings = settingsInteractor.get(currentServer)
}
private fun setupAccountContainerView() {
launchUI(strategy) {
try {
val services = retryIO("settingsOauth()") {
client.settingsOauth().services
}
if (services.isNotEmpty()) {
val state = OauthHelper.getState()
var totalSocialAccountsEnabled = 0
// OAuth accounts.
if (settings.isFacebookAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_FACEBOOK)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
view.setupFacebookButtonListener(
OauthHelper.getFacebookOauthUrl(
clientId,
currentServer,
state
), state
)
view.enableLoginByFacebook()
totalSocialAccountsEnabled++
}
}
}
if (settings.isGithubAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GITHUB)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
view.setupGithubButtonListener(
OauthHelper.getGithubOauthUrl(
clientId,
state
), state
)
view.enableLoginByGithub()
totalSocialAccountsEnabled++
}
}
}
if (settings.isGoogleAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GOOGLE)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
view.setupGoogleButtonListener(
OauthHelper.getGoogleOauthUrl(
clientId,
currentServer,
state
), state
)
view.enableLoginByGoogle()
totalSocialAccountsEnabled++
}
}
}
if (settings.isLinkedinAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_LINKEDIN)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
view.setupLinkedinButtonListener(
OauthHelper.getLinkedinOauthUrl(
clientId,
currentServer,
state
), state
)
view.enableLoginByLinkedin()
totalSocialAccountsEnabled++
}
}
}
if (settings.isGitlabAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GILAB)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
val gitlabOauthUrl = if (settings.gitlabUrl() != null) {
OauthHelper.getGitlabOauthUrl(
host = settings.gitlabUrl(),
clientId = clientId,
serverUrl = currentServer,
state = state
)
} else {
OauthHelper.getGitlabOauthUrl(
clientId = clientId,
serverUrl = currentServer,
state = state
)
}
view.setupGitlabButtonListener(gitlabOauthUrl, state)
view.enableLoginByGitlab()
totalSocialAccountsEnabled++
}
}
}
if (settings.isWordpressAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_WORDPRESS)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
val wordpressOauthUrl =
if (settings.wordpressUrl().isNullOrEmpty()) {
OauthHelper.getWordpressComOauthUrl(
clientId,
currentServer,
state
)
} else {
OauthHelper.getWordpressCustomOauthUrl(
getCustomOauthHost(serviceMap)
?: "https://public-api.wordpress.com",
getCustomOauthAuthorizePath(serviceMap)
?: "/oauth/authorize",
clientId,
currentServer,
SERVICE_NAME_WORDPRESS,
state,
getCustomOauthScope(serviceMap) ?: "openid"
)
}
view.setupWordpressButtonListener(wordpressOauthUrl, state)
view.enableLoginByWordpress()
totalSocialAccountsEnabled++
}
}
}
// CAS account.
if (settings.isCasAuthenticationEnabled()) {
val casToken = generateRandomString(17)
view.setupCasButtonListener(
settings.casLoginUrl().casUrl(currentServer, casToken), casToken
)
view.enableLoginByCas()
totalSocialAccountsEnabled++
}
// Custom OAuth account.
getCustomOauthServices(services).let {
for (serviceMap in it) {
val serviceName = getCustomOauthServiceName(serviceMap)
val host = getCustomOauthHost(serviceMap)
val authorizePath = getCustomOauthAuthorizePath(serviceMap)
val clientId = getOauthClientId(serviceMap)
val scope = getCustomOauthScope(serviceMap)
val textColor = getServiceNameColorForCustomOauthOrSaml(serviceMap)
val buttonColor = getServiceButtonColor(serviceMap)
if (serviceName != null &&
host != null &&
authorizePath != null &&
clientId != null &&
scope != null &&
textColor != null &&
buttonColor != null
) {
val customOauthUrl = OauthHelper.getCustomOauthUrl(
host,
authorizePath,
clientId,
currentServer,
serviceName,
state,
scope
)
view.addCustomOauthButton(
customOauthUrl,
state,
serviceName,
textColor,
buttonColor
)
totalSocialAccountsEnabled++
}
}
}
// SAML account.
getSamlServices(services).let {
val samlToken = generateRandomString(17)
for (serviceMap in it) {
val provider = getSamlProvider(serviceMap)
val serviceName = getSamlServiceName(serviceMap)
val textColor = getServiceNameColorForCustomOauthOrSaml(serviceMap)
val buttonColor = getServiceButtonColor(serviceMap)
if (provider != null &&
serviceName != null &&
textColor != null &&
buttonColor != null
) {
view.addSamlButton(
currentServer.samlUrl(provider, samlToken),
samlToken,
serviceName,
textColor,
buttonColor
)
totalSocialAccountsEnabled++
}
}
}
if (totalSocialAccountsEnabled > 0) {
view.showAccountsView()
if (totalSocialAccountsEnabled > 3) {
view.setupExpandAccountsView()
}
}
}
} catch (exception: RocketChatException) {
Timber.e(exception)
}
}
}
private fun setupLoginWithEmailView() {
if (settings.isLoginFormEnabled()) {
view.showLoginWithEmailButton()
}
}
private fun setupCreateNewAccountView() {
if (settings.isRegistrationEnabledForNewUsers() && settings.isLoginFormEnabled()) {
view.showCreateNewAccountButton()
}
}
fun toCreateAccount() = navigator.toCreateAccount()
fun toLoginWithEmail() = navigator.toLogin()
fun toLoginWithEmail() = navigator.toLogin(currentServer)
fun authenticateWithOauth(oauthToken: String, oauthSecret: String) {
credentialToken = oauthToken
......@@ -365,9 +95,6 @@ class LoginOptionsPresenter @Inject constructor(
tokenRepository.save(serverUrl, Token(deepLinkUserId, deepLinkToken))
loginMethod = AuthenticationEvent.AuthenticationWithDeeplink
doAuthentication(TYPE_LOGIN_DEEP_LINK)
} else {
// If we don't have the login credentials, just go through normal setup and user input.
setupView()
}
}
......@@ -438,6 +165,12 @@ class LoginOptionsPresenter @Inject constructor(
}
}
private fun setupConnectionInfo(serverUrl: String) {
currentServer = serverUrl
client = factory.create(currentServer)
settings = settingsInteractor.get(currentServer)
}
private suspend fun saveAccount(username: String) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
......@@ -451,114 +184,4 @@ class LoginOptionsPresenter @Inject constructor(
}
private fun saveToken(token: Token) = tokenRepository.save(currentServer, token)
/** Returns an OAuth service map given a [serviceName].
*
* @param listMap The list of [Map] to get the service from.
* @param serviceName The service name to get in the [listMap]
* @return The OAuth service map or null otherwise.
*/
private fun getServiceMap(
listMap: List<Map<String, Any>>,
serviceName: String
): Map<String, Any>? = listMap.find { map -> map.containsValue(serviceName) }
/**
* Returns the OAuth client ID of a [serviceMap].
* REMARK: This function works for common OAuth providers (Google, Facebook, Github and so on)
* as well as custom OAuth.
*
* @param serviceMap The service map to get the OAuth client ID.
* @return The OAuth client ID or null otherwise.
*/
private fun getOauthClientId(serviceMap: Map<String, Any>): String? =
serviceMap["clientId"] as? String ?: serviceMap["appId"] as? String
/**
* Returns a custom OAuth service list.
*
* @return A custom OAuth service list, otherwise an empty list if there is no custom OAuth service.
*/
private fun getCustomOauthServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> =
listMap.filter { map -> map["custom"] == true }
/** Returns the custom OAuth service host.
*
* @param serviceMap The service map to get the custom OAuth service host.
* @return The custom OAuth service host, otherwise null.
*/
private fun getCustomOauthHost(serviceMap: Map<String, Any>): String? =
serviceMap["serverURL"] as? String
/** Returns the custom OAuth service authorize path.
*
* @param serviceMap The service map to get the custom OAuth service authorize path.
* @return The custom OAuth service authorize path, otherwise null.
*/
private fun getCustomOauthAuthorizePath(serviceMap: Map<String, Any>): String? =
serviceMap["authorizePath"] as? String
/** Returns the custom OAuth service scope.
*
* @param serviceMap The service map to get the custom OAuth service scope.
* @return The custom OAuth service scope, otherwise null.
*/
private fun getCustomOauthScope(serviceMap: Map<String, Any>): String? =
serviceMap["scope"] as? String
/** Returns the text of the custom OAuth service.
*
* @param serviceMap The service map to get the text of the custom OAuth service.
* @return The text of the custom OAuth service, otherwise null.
*/
private fun getCustomOauthServiceName(serviceMap: Map<String, Any>): String? =
serviceMap["service"] as? String
/**
* Returns a SAML OAuth service list.
*
* @return A SAML service list, otherwise an empty list if there is no SAML OAuth service.
*/
private fun getSamlServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> =
listMap.filter { map -> map["service"] == "saml" }
/**
* Returns the SAML provider.
*
* @param serviceMap The service map to provider from.
* @return The SAML provider, otherwise null.
*/
private fun getSamlProvider(serviceMap: Map<String, Any>): String? =
(serviceMap["clientConfig"] as Map<*, *>)["provider"] as? String
/**
* Returns the text of the SAML service.
*
* @param serviceMap The service map to get the text of the SAML service.
* @return The text of the SAML service, otherwise null.
*/
private fun getSamlServiceName(serviceMap: Map<String, Any>): String? =
serviceMap["buttonLabelText"] as? String
/**
* Returns the text color of the service name.
* REMARK: This can be used for custom OAuth or SAML.
*
* @param serviceMap The service map to get the text color from.
* @return The text color of the service (custom OAuth or SAML), otherwise null.
*/
private fun getServiceNameColorForCustomOauthOrSaml(serviceMap: Map<String, Any>): Int? =
(serviceMap["buttonLabelColor"] as? String)?.parseColor()
/**
* Returns the button color of the service name.
* REMARK: This can be used for custom OAuth or SAML.
*
* @param serviceMap The service map to get the button color from.
* @return The button color of the service (custom OAuth or SAML), otherwise null.
*/
private fun getServiceButtonColor(serviceMap: Map<String, Any>): Int? =
(serviceMap["buttonColor"] as? String)?.parseColor()
}
\ No newline at end of file
......@@ -28,14 +28,34 @@ import chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_TOKEN
import chat.rocket.android.webview.oauth.ui.oauthWebViewIntent
import chat.rocket.android.webview.sso.ui.INTENT_SSO_TOKEN
import chat.rocket.android.webview.sso.ui.ssoWebViewIntent
import chat.rocket.common.util.ifNull
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_authentication_login_options.*
import javax.inject.Inject
private const val BUNDLE_SERVER_NAME = "BUNDLE_SERVER_NAME"
private const val DEEP_LINK_INFO = "DeepLinkInfo"
private const val SERVER_NAME = "server_name"
private const val STATE = "state"
private const val FACEBOOK_OAUTH_URL = "facebook_oauth_url"
private const val GITHUB_OAUTH_URL = "github_oauth_url"
private const val GOOGLE_OAUTH_URL = "google_oauth_url"
private const val LINKEDIN_OAUTH_URL = "linkedin_oauth_url"
private const val GITLAB_OAUTH_URL = "gitlab_oauth_url"
private const val WORDPRESS_OAUTH_URL = "wordpress_oauth_url"
private const val CAS_LOGIN_URL = "cas_login_url"
private const val CAS_TOKEN = "cas_token"
private const val CUSTOM_OAUTH_URL = "custom_oauth_url"
private const val CUSTOM_OAUTH_SERVICE_NAME = "custom_oauth_service_name"
private const val CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR = "custom_oauth_service_name_text_color"
private const val CUSTOM_OAUTH_SERVICE_BUTTON_COLOR = "custom_oauth_service_button_color"
private const val SAML_URL = "saml_url"
private const val SAML_TOKEN = "saml_token"
private const val SAML_SERVICE_NAME = "saml_service_name"
private const val SAML_SERVICE_NAME_TEXT_COLOR = "saml_service_name_text_color"
private const val SAML_SERVICE_BUTTON_COLOR = "saml_service_button_color"
private const val TOTAL_SOCIAL_ACCOUNTS = "total_social_accounts"
private const val IS_LOGIN_FORM_ENABLED = "is_login_form_enabled"
private const val IS_NEW_ACCOUNT_CREATION_ENABLED = "is_new_account_creation_enabled"
private const val DEEP_LINK_INFO = "deep-link-info"
internal const val REQUEST_CODE_FOR_OAUTH = 1
internal const val REQUEST_CODE_FOR_CAS = 2
......@@ -43,11 +63,53 @@ internal const val REQUEST_CODE_FOR_SAML = 3
fun newInstance(
serverName: String,
state: String? = null,
facebookOauthUrl: String? = null,
githubOauthUrl: String? = null,
googleOauthUrl: String? = null,
linkedinOauthUrl: String? = null,
gitlabOauthUrl: String? = null,
wordpressOauthUrl: String? = null,
casLoginUrl: String? = null,
casToken: String? = null,
customOauthUrl: String? = null,
customOauthServiceName: String? = null,
customOauthServiceNameTextColor: Int = 0,
customOauthServiceButtonColor: Int = 0,
samlUrl: String? = null,
samlToken: String? = null,
samlServiceName: String? = null,
samlServiceNameTextColor: Int = 0,
samlServiceButtonColor: Int = 0,
totalSocialAccountsEnabled: Int = 0,
isLoginFormEnabled: Boolean,
isNewAccountCreationEnabled: Boolean,
deepLinkInfo: LoginDeepLinkInfo? = null
): Fragment {
return LoginOptionsFragment().apply {
arguments = Bundle(2).apply {
putString(BUNDLE_SERVER_NAME, serverName)
arguments = Bundle(19).apply {
putString(SERVER_NAME, serverName)
putString(STATE, state)
putString(FACEBOOK_OAUTH_URL, facebookOauthUrl)
putString(GITHUB_OAUTH_URL, githubOauthUrl)
putString(GOOGLE_OAUTH_URL, googleOauthUrl)
putString(LINKEDIN_OAUTH_URL, linkedinOauthUrl)
putString(GITLAB_OAUTH_URL, gitlabOauthUrl)
putString(WORDPRESS_OAUTH_URL, wordpressOauthUrl)
putString(CAS_LOGIN_URL, casLoginUrl)
putString(CAS_TOKEN, casToken)
putString(CUSTOM_OAUTH_URL, customOauthUrl)
putString(CUSTOM_OAUTH_SERVICE_NAME, customOauthServiceName)
putInt(CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR, customOauthServiceNameTextColor)
putInt(CUSTOM_OAUTH_SERVICE_BUTTON_COLOR, customOauthServiceButtonColor)
putString(SAML_URL, samlUrl)
putString(SAML_TOKEN, samlToken)
putString(SAML_SERVICE_NAME, samlServiceName)
putInt(SAML_SERVICE_NAME_TEXT_COLOR, samlServiceNameTextColor)
putInt(SAML_SERVICE_BUTTON_COLOR, samlServiceButtonColor)
putInt(TOTAL_SOCIAL_ACCOUNTS, totalSocialAccountsEnabled)
putBoolean(IS_LOGIN_FORM_ENABLED, isLoginFormEnabled)
putBoolean(IS_NEW_ACCOUNT_CREATION_ENABLED, isNewAccountCreationEnabled)
putParcelable(DEEP_LINK_INFO, deepLinkInfo)
}
}
......@@ -58,8 +120,29 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
lateinit var presenter: LoginOptionsPresenter
@Inject
lateinit var analyticsManager: AnalyticsManager
private var deepLinkInfo: LoginDeepLinkInfo? = null
private var serverName: String? = null
private var state: String? = null
private var facebookOauthUrl: String? = null
private var githubOauthUrl: String? = null
private var googleOauthUrl: String? = null
private var linkedinOauthUrl: String? = null
private var gitlabOauthUrl: String? = null
private var wordpressOauthUrl: String? = null
private var casLoginUrl: String? = null
private var casToken: String? = null
private var customOauthUrl: String? = null
private var customOauthServiceName: String? = null
private var customOauthServiceTextColor: Int = 0
private var customOauthServiceButtonColor: Int = 0
private var samlUrl: String? = null
private var samlToken: String? = null
private var samlServiceName: String? = null
private var samlServiceTextColor: Int = 0
private var samlServiceButtonColor: Int = 0
private var totalSocialAccountsEnabled = 0
private var isLoginFormEnabled = false
private var isNewAccountCreationEnabled = false
private var deepLinkInfo: LoginDeepLinkInfo? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -67,7 +150,28 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
val bundle = arguments
if (bundle != null) {
serverName = bundle.getString(BUNDLE_SERVER_NAME)
serverName = bundle.getString(SERVER_NAME)
state = bundle.getString(STATE)
facebookOauthUrl = bundle.getString(FACEBOOK_OAUTH_URL)
githubOauthUrl = bundle.getString(GITHUB_OAUTH_URL)
googleOauthUrl = bundle.getString(GOOGLE_OAUTH_URL)
linkedinOauthUrl = bundle.getString(LINKEDIN_OAUTH_URL)
gitlabOauthUrl = bundle.getString(GITLAB_OAUTH_URL)
wordpressOauthUrl = bundle.getString(WORDPRESS_OAUTH_URL)
casLoginUrl = bundle.getString(CAS_LOGIN_URL)
casToken = bundle.getString(CAS_TOKEN)
customOauthUrl = bundle.getString(CUSTOM_OAUTH_URL)
customOauthServiceName = bundle.getString(CUSTOM_OAUTH_SERVICE_NAME)
customOauthServiceTextColor = bundle.getInt(CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR)
customOauthServiceButtonColor = bundle.getInt(CUSTOM_OAUTH_SERVICE_BUTTON_COLOR)
samlUrl = bundle.getString(SAML_URL)
samlToken = bundle.getString(SAML_TOKEN)
samlServiceName = bundle.getString(SAML_SERVICE_NAME)
samlServiceTextColor = bundle.getInt(SAML_SERVICE_NAME_TEXT_COLOR)
samlServiceButtonColor = bundle.getInt(SAML_SERVICE_BUTTON_COLOR)
totalSocialAccountsEnabled = bundle.getInt(TOTAL_SOCIAL_ACCOUNTS)
isLoginFormEnabled = bundle.getBoolean(IS_LOGIN_FORM_ENABLED)
isNewAccountCreationEnabled = bundle.getBoolean(IS_NEW_ACCOUNT_CREATION_ENABLED)
deepLinkInfo = bundle.getParcelable(DEEP_LINK_INFO)
}
}
......@@ -81,14 +185,9 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
presenter.setupView()
setupAccounts()
analyticsManager.logScreenView(ScreenViewEvent.LoginOptions)
deepLinkInfo?.let {
presenter.authenticateWithDeepLink(it)
}.ifNull {
presenter.setupView()
}
deepLinkInfo?.let { presenter.authenticateWithDeepLink(it) }
}
private fun setupToolbar() {
......@@ -99,6 +198,99 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
}
}
private fun setupAccounts() {
setupSocialAccounts()
setupCas()
setupCustomOauth()
setupSaml()
setupLoginWithEmailView()
setupCreateNewAccountView()
}
private fun setupSocialAccounts() {
if (facebookOauthUrl != null && state != null) {
setupFacebookButtonListener(facebookOauthUrl.toString(), state.toString())
enableLoginByFacebook()
}
if (githubOauthUrl != null && state != null) {
setupGithubButtonListener(githubOauthUrl.toString(), state.toString())
enableLoginByGithub()
}
if (googleOauthUrl != null && state != null) {
setupGoogleButtonListener(googleOauthUrl.toString(), state.toString())
enableLoginByGoogle()
}
if (linkedinOauthUrl != null && state != null) {
setupLinkedinButtonListener(linkedinOauthUrl.toString(), state.toString())
enableLoginByLinkedin()
}
if (gitlabOauthUrl != null && state != null) {
setupGitlabButtonListener(gitlabOauthUrl.toString(), state.toString())
enableLoginByGitlab()
}
if (wordpressOauthUrl != null && state != null) {
setupWordpressButtonListener(wordpressOauthUrl.toString(), state.toString())
enableLoginByWordpress()
}
if (totalSocialAccountsEnabled > 0) {
showAccountsView()
if (totalSocialAccountsEnabled > 3) {
setupExpandAccountsView()
}
}
}
private fun setupCas() {
if (casLoginUrl != null && casToken != null) {
setupCasButtonListener(casLoginUrl.toString(), casToken.toString())
enableLoginByCas()
}
}
private fun setupCustomOauth() {
if (customOauthUrl != null && state != null && customOauthServiceName != null) {
addCustomOauthButton(
customOauthUrl.toString(),
state.toString(),
customOauthServiceName.toString(),
customOauthServiceTextColor,
customOauthServiceButtonColor
)
}
}
private fun setupSaml() {
if (samlUrl != null && samlToken != null && samlServiceName != null) {
addSamlButton(
samlUrl.toString(),
samlToken.toString(),
samlServiceName.toString(),
samlServiceTextColor,
samlServiceButtonColor
)
}
}
private fun setupLoginWithEmailView() {
if (isLoginFormEnabled) {
showLoginWithEmailButton()
}
}
private fun setupCreateNewAccountView() {
if (isNewAccountCreationEnabled) {
showCreateNewAccountButton()
}
}
// OAuth Accounts.
override fun enableLoginByFacebook() = enableAccountButton(button_facebook)
......@@ -170,18 +362,18 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
}
override fun setupExpandAccountsView() {
ui {
ui { _ ->
expand_more_accounts_container.isVisible = true
var isAccountsCollapsed = true
button_expand_collapse_accounts.setOnClickListener { view ->
if (isAccountsCollapsed) {
button_expand_collapse_accounts.setOnClickListener {
isAccountsCollapsed = if (isAccountsCollapsed) {
button_expand_collapse_accounts.rotateBy(180F, 400)
expandAccountsView()
isAccountsCollapsed = false
false
} else {
button_expand_collapse_accounts.rotateBy(180F, 400)
collapseAccountsView()
isAccountsCollapsed = true
true
}
}
}
......
package chat.rocket.android.authentication.onboarding.presentation
import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.behaviours.showMessage
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveConnectingServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.launchUI
import kotlinx.coroutines.experimental.DefaultDispatcher
import kotlinx.coroutines.experimental.withContext
import javax.inject.Inject
class OnBoardingPresenter @Inject constructor(
......@@ -16,31 +20,71 @@ class OnBoardingPresenter @Inject constructor(
private val navigator: AuthenticationNavigator,
private val serverInteractor: SaveConnectingServerInteractor,
private val refreshSettingsInteractor: RefreshSettingsInteractor,
private val getAccountsInteractor: GetAccountsInteractor
) {
private val getAccountsInteractor: GetAccountsInteractor,
val settingsInteractor: GetSettingsInteractor,
val factory: RocketChatClientFactory
) : CheckServerPresenter(strategy, factory, settingsInteractor) {
fun toConnectWithAServer(deepLinkInfo: LoginDeepLinkInfo?) =
navigator.toConnectWithAServer(deepLinkInfo)
fun toSignInToYourServer() = navigator.toSignInToYourServer()
fun connectToCommunityServer(communityServer: String) =
connectToServer(communityServer) { navigator.toLoginOptions(communityServer) }
fun connectToCommunityServer(communityServerUrl: String) {
connectToServer(communityServerUrl) {
if (totalSocialAccountsEnabled == 0 && !isNewAccountCreationEnabled) {
navigator.toLogin(communityServerUrl)
} else {
navigator.toLoginOptions(
communityServerUrl,
state,
facebookOauthUrl,
githubOauthUrl,
googleOauthUrl,
linkedinOauthUrl,
gitlabOauthUrl,
wordpressOauthUrl,
casLoginUrl,
casToken,
customOauthUrl,
customOauthServiceName,
customOauthServiceNameTextColor,
customOauthServiceButtonColor,
samlUrl,
samlToken,
samlServiceName,
samlServiceNameTextColor,
samlServiceButtonColor,
totalSocialAccountsEnabled,
isLoginFormEnabled,
isNewAccountCreationEnabled
)
}
}
}
fun toCreateANewServer(createServerUrl: String) = navigator.toWebPage(createServerUrl)
private fun connectToServer(server: String, block: () -> Unit) {
private fun connectToServer(serverUrl: String, block: () -> Unit) {
launchUI(strategy) {
// Check if we already have an account for this server...
val account = getAccountsInteractor.get().firstOrNull { it.serverUrl == server }
val account = getAccountsInteractor.get().firstOrNull { it.serverUrl == serverUrl }
if (account != null) {
navigator.toChatList(server)
navigator.toChatList(serverUrl)
return@launchUI
}
view.showLoading()
try {
refreshSettingsInteractor.refresh(server)
serverInteractor.save(server)
block()
withContext(DefaultDispatcher) {
setupConnectionInfo(serverUrl)
// preparing next fragment before showing it
checkEnabledAccounts(serverUrl)
checkIfLoginFormIsEnabled()
checkIfCreateNewAccountIsEnabled()
refreshSettingsInteractor.refresh(serverUrl)
serverInteractor.save(serverUrl)
block()
}
} catch (ex: Exception) {
view.showMessage(ex)
} finally {
......
......@@ -9,7 +9,6 @@ import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.domain.model.getLoginDeepLinkInfo
import chat.rocket.android.authentication.onboarding.presentation.OnBoardingPresenter
import chat.rocket.android.authentication.onboarding.presentation.OnBoardingView
import chat.rocket.android.authentication.ui.AuthenticationActivity
......@@ -42,13 +41,12 @@ class OnBoardingFragment : Fragment(), OnBoardingView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToobar()
setupToolbar()
setupOnClickListener()
analyticsManager.logScreenView(ScreenViewEvent.OnBoarding)
}
private fun setupToobar() {
private fun setupToolbar() {
with(activity as AuthenticationActivity) {
view?.let { this.setLightStatusBar(it) }
toolbar.isVisible = false
......@@ -56,7 +54,7 @@ class OnBoardingFragment : Fragment(), OnBoardingView {
}
private fun setupOnClickListener() {
connect_with_a_server_container.setOnClickListener { connectWithAServer() }
connect_with_a_server_container.setOnClickListener { signInToYourServer() }
join_community_container.setOnClickListener { joinInTheCommunity() }
create_server_container.setOnClickListener { createANewServer() }
}
......@@ -87,21 +85,19 @@ class OnBoardingFragment : Fragment(), OnBoardingView {
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
private fun connectWithAServer() = ui {
presenter.toConnectWithAServer(activity?.intent?.getLoginDeepLinkInfo())
private fun signInToYourServer() = ui {
presenter.toSignInToYourServer()
}
private fun joinInTheCommunity() = ui {
presenter.connectToCommunityServer(
getString(R.string.default_protocol) +
getString(R.string.community_server_url)
getString(R.string.default_protocol) + getString(R.string.community_server_url)
)
}
private fun createANewServer() = ui {
presenter.toCreateANewServer(
getString(R.string.default_protocol) +
getString(R.string.create_server_url)
getString(R.string.default_protocol) + getString(R.string.create_server_url)
)
}
}
......@@ -13,18 +13,66 @@ import chat.rocket.android.webview.ui.webViewIntent
class AuthenticationNavigator(internal val activity: AuthenticationActivity) {
fun toConnectWithAServer(deepLinkInfo: LoginDeepLinkInfo?) {
fun toSignInToYourServer() {
activity.addFragmentBackStack(ScreenViewEvent.Server.screenName, R.id.fragment_container) {
chat.rocket.android.authentication.server.ui.newInstance(deepLinkInfo)
chat.rocket.android.authentication.server.ui.newInstance()
}
}
fun toLoginOptions(server: String, deepLinkInfo: LoginDeepLinkInfo? = null) {
fun toLoginOptions(
serverUrl: String,
state: String? = null,
facebookOauthUrl: String? = null,
githubOauthUrl: String? = null,
googleOauthUrl: String? = null,
linkedinOauthUrl: String? = null,
gitlabOauthUrl: String? = null,
wordpressOauthUrl: String? = null,
casLoginUrl: String? = null,
casToken: String? = null,
customOauthUrl: String? = null,
customOauthServiceName: String? = null,
customOauthServiceNameTextColor: Int = 0,
customOauthServiceButtonColor: Int = 0,
samlUrl: String? = null,
samlToken: String? = null,
samlServiceName: String? = null,
samlServiceNameTextColor: Int = 0,
samlServiceButtonColor: Int = 0,
totalSocialAccountsEnabled: Int = 0,
isLoginFormEnabled: Boolean = true,
isNewAccountCreationEnabled: Boolean = true,
deepLinkInfo: LoginDeepLinkInfo? = null
) {
activity.addFragmentBackStack(
ScreenViewEvent.LoginOptions.screenName,
R.id.fragment_container
) {
chat.rocket.android.authentication.loginoptions.ui.newInstance(server, deepLinkInfo)
chat.rocket.android.authentication.loginoptions.ui.newInstance(
serverUrl,
state,
facebookOauthUrl,
githubOauthUrl,
googleOauthUrl,
linkedinOauthUrl,
gitlabOauthUrl,
wordpressOauthUrl,
casLoginUrl,
casToken,
customOauthUrl,
customOauthServiceName,
customOauthServiceNameTextColor,
customOauthServiceButtonColor,
samlUrl,
samlToken,
samlServiceName,
samlServiceNameTextColor,
samlServiceButtonColor,
totalSocialAccountsEnabled,
isLoginFormEnabled,
isNewAccountCreationEnabled,
deepLinkInfo
)
}
}
......@@ -40,9 +88,9 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) {
}
}
fun toLogin() {
fun toLogin(serverUrl: String) {
activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) {
chat.rocket.android.authentication.login.ui.newInstance()
chat.rocket.android.authentication.login.ui.newInstance(serverUrl)
}
}
......
......@@ -5,6 +5,7 @@ import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.behaviours.showMessage
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveConnectingServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
......@@ -20,20 +21,57 @@ class ServerPresenter @Inject constructor(
private val serverInteractor: SaveConnectingServerInteractor,
private val refreshSettingsInteractor: RefreshSettingsInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
factory: RocketChatClientFactory
) : CheckServerPresenter(strategy, factory, view) {
val settingsInteractor: GetSettingsInteractor,
val factory: RocketChatClientFactory
) : CheckServerPresenter(strategy, factory, settingsInteractor, view) {
fun checkServer(server: String) {
if (!server.isValidUrl()) {
view.showInvalidServerUrlMessage()
} else {
view.showLoading()
setupConnectionInfo(server)
checkServerInfo(server)
}
}
fun connect(server: String) {
connectToServer(server) { navigator.toLoginOptions(server) }
fun connect(serverUrl: String) {
connectToServer(serverUrl) {
if (totalSocialAccountsEnabled == 0 && !isNewAccountCreationEnabled) {
navigator.toLogin(serverUrl)
} else {
navigator.toLoginOptions(
serverUrl,
state,
facebookOauthUrl,
githubOauthUrl,
googleOauthUrl,
linkedinOauthUrl,
gitlabOauthUrl,
wordpressOauthUrl,
casLoginUrl,
casToken,
customOauthUrl,
customOauthServiceName,
customOauthServiceNameTextColor,
customOauthServiceButtonColor,
samlUrl,
samlToken,
samlServiceName,
samlServiceNameTextColor,
samlServiceButtonColor,
totalSocialAccountsEnabled,
isLoginFormEnabled,
isNewAccountCreationEnabled
)
}
}
}
fun deepLink(deepLinkInfo: LoginDeepLinkInfo) {
connectToServer(deepLinkInfo.url) {
navigator.toLoginOptions(deepLinkInfo.url, deepLinkInfo = deepLinkInfo)
}
}
private fun connectToServer(server: String, block: () -> Unit) {
......@@ -47,11 +85,18 @@ class ServerPresenter @Inject constructor(
navigator.toChatList(server)
return@launchUI
}
view.showLoading()
try {
refreshSettingsInteractor.refresh(server)
serverInteractor.save(server)
setupConnectionInfo(server)
// preparing next fragment before showing it
checkEnabledAccounts(server)
checkIfLoginFormIsEnabled()
checkIfCreateNewAccountIsEnabled()
block()
} catch (ex: Exception) {
view.showMessage(ex)
......@@ -62,9 +107,4 @@ class ServerPresenter @Inject constructor(
}
}
fun deepLink(deepLinkInfo: LoginDeepLinkInfo) {
connectToServer(deepLinkInfo.url) {
navigator.toLoginOptions(deepLinkInfo.url, deepLinkInfo)
}
}
}
\ No newline at end of file
......@@ -41,13 +41,7 @@ import okhttp3.HttpUrl
import java.util.concurrent.TimeUnit
import javax.inject.Inject
fun newInstance(deepLinkInfo: LoginDeepLinkInfo?): Fragment {
return ServerFragment().apply {
arguments = Bundle(1).apply {
putParcelable(DEEP_LINK_INFO, deepLinkInfo)
}
}
}
fun newInstance() = ServerFragment()
private const val DEEP_LINK_INFO = "DeepLinkInfo"
......
......@@ -99,7 +99,7 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
R.id.fragment_container,
allowStateLoss = true
) {
chat.rocket.android.authentication.server.ui.newInstance(deepLinkInfo)
chat.rocket.android.authentication.server.ui.newInstance()
}
}
......
......@@ -3,61 +3,413 @@ package chat.rocket.android.server.presentation
import chat.rocket.android.BuildConfig
import chat.rocket.android.authentication.server.presentation.VersionCheckView
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.OauthHelper
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.casLoginUrl
import chat.rocket.android.server.domain.gitlabUrl
import chat.rocket.android.server.domain.isCasAuthenticationEnabled
import chat.rocket.android.server.domain.isFacebookAuthenticationEnabled
import chat.rocket.android.server.domain.isGithubAuthenticationEnabled
import chat.rocket.android.server.domain.isGitlabAuthenticationEnabled
import chat.rocket.android.server.domain.isGoogleAuthenticationEnabled
import chat.rocket.android.server.domain.isLinkedinAuthenticationEnabled
import chat.rocket.android.server.domain.isLoginFormEnabled
import chat.rocket.android.server.domain.isRegistrationEnabledForNewUsers
import chat.rocket.android.server.domain.isWordpressAuthenticationEnabled
import chat.rocket.android.server.domain.wordpressUrl
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.VersionInfo
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.casUrl
import chat.rocket.android.util.extensions.generateRandomString
import chat.rocket.android.util.extensions.parseColor
import chat.rocket.android.util.extensions.samlUrl
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
import chat.rocket.common.RocketChatInvalidProtocolException
import chat.rocket.common.model.ServerInfo
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.serverInfo
import chat.rocket.core.internal.rest.settingsOauth
import kotlinx.coroutines.experimental.Job
import timber.log.Timber
private const val SERVICE_NAME_FACEBOOK = "facebook"
private const val SERVICE_NAME_GITHUB = "github"
private const val SERVICE_NAME_GOOGLE = "google"
private const val SERVICE_NAME_LINKEDIN = "linkedin"
private const val SERVICE_NAME_GILAB = "gitlab"
private const val SERVICE_NAME_WORDPRESS = "wordpress"
abstract class CheckServerPresenter constructor(
private val strategy: CancelStrategy,
private val factory: RocketChatClientFactory,
private val view: VersionCheckView
private val settingsInteractor: GetSettingsInteractor? = null,
private val view: VersionCheckView? = null
) {
private lateinit var currentServer: String
private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings
internal var state: String = ""
internal var facebookOauthUrl: String? = null
internal var githubOauthUrl: String? = null
internal var googleOauthUrl: String? = null
internal var linkedinOauthUrl: String? = null
internal var gitlabOauthUrl: String? = null
internal var wordpressOauthUrl: String? = null
internal var casLoginUrl: String? = null
internal var casToken: String? = null
internal var customOauthUrl: String? = null
internal var customOauthServiceName: String? = null
internal var customOauthServiceNameTextColor: Int = 0
internal var customOauthServiceButtonColor: Int = 0
internal var samlUrl: String? = null
internal var samlToken: String? = null
internal var samlServiceName: String? = null
internal var samlServiceNameTextColor: Int = 0
internal var samlServiceButtonColor: Int = 0
internal var totalSocialAccountsEnabled = 0
internal var isLoginFormEnabled = false
internal var isNewAccountCreationEnabled = false
internal fun setupConnectionInfo(serverUrl: String) {
settingsInteractor?.get(serverUrl)?.let {
settings = it
}
client = factory.create(serverUrl)
}
internal fun checkServerInfo(serverUrl: String): Job {
return launchUI(strategy) {
try {
currentServer = serverUrl
client = factory.create(currentServer)
val serverInfo = retryIO(description = "serverInfo", times = 5) {
client.serverInfo()
}
if (serverInfo.redirected) {
view.updateServerUrl(serverInfo.url)
view?.updateServerUrl(serverInfo.url)
}
val version = checkServerVersion(serverInfo)
when (version) {
is Version.VersionOk -> {
Timber.i("Your version is nice! (Requires: 0.62.0, Yours: ${version.version})")
view.versionOk()
view?.versionOk()
}
is Version.RecommendedVersionWarning -> {
Timber.i("Your server ${version.version} is bellow recommended version ${BuildConfig.RECOMMENDED_SERVER_VERSION}")
view.alertNotRecommendedVersion()
view?.alertNotRecommendedVersion()
}
is Version.OutOfDateError -> {
Timber.i("Oops. Looks like your server ${version.version} is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!")
view.blockAndAlertNotRequiredVersion()
view?.blockAndAlertNotRequiredVersion()
}
}
} catch (ex: Exception) {
Timber.d(ex, "Error getting server info")
when (ex) {
is RocketChatInvalidProtocolException -> view.errorInvalidProtocol()
else -> view.errorCheckingServerVersion()
is RocketChatInvalidProtocolException -> view?.errorInvalidProtocol()
else -> view?.errorCheckingServerVersion()
}
}
}
}
internal suspend fun checkEnabledAccounts(serverUrl: String) {
launchUI(strategy) {
try {
val services = retryIO("settingsOauth()") {
client.settingsOauth().services
}
if (services.isNotEmpty()) {
state = OauthHelper.getState()
// OAuth accounts.
if (settings.isFacebookAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_FACEBOOK)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
facebookOauthUrl =
OauthHelper.getFacebookOauthUrl(clientId, serverUrl, state)
totalSocialAccountsEnabled++
}
}
}
if (settings.isGithubAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GITHUB)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
githubOauthUrl =
OauthHelper.getGithubOauthUrl(clientId, state)
totalSocialAccountsEnabled++
}
}
}
if (settings.isGoogleAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GOOGLE)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
googleOauthUrl =
OauthHelper.getGoogleOauthUrl(clientId, serverUrl, state)
totalSocialAccountsEnabled++
}
}
}
if (settings.isLinkedinAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_LINKEDIN)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
linkedinOauthUrl =
OauthHelper.getLinkedinOauthUrl(clientId, serverUrl, state)
totalSocialAccountsEnabled++
}
}
}
if (settings.isGitlabAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GILAB)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
gitlabOauthUrl = if (settings.gitlabUrl() != null) {
OauthHelper.getGitlabOauthUrl(
host = settings.gitlabUrl(),
clientId = clientId,
serverUrl = serverUrl,
state = state
)
} else {
OauthHelper.getGitlabOauthUrl(
clientId = clientId,
serverUrl = serverUrl,
state = state
)
}
totalSocialAccountsEnabled++
}
}
}
if (settings.isWordpressAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_WORDPRESS)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
wordpressOauthUrl =
if (settings.wordpressUrl().isNullOrEmpty()) {
OauthHelper.getWordpressComOauthUrl(
clientId,
serverUrl,
state
)
} else {
OauthHelper.getWordpressCustomOauthUrl(
getCustomOauthHost(serviceMap)
?: "https://public-api.wordpress.com",
getCustomOauthAuthorizePath(serviceMap)
?: "/oauth/authorize",
clientId,
serverUrl,
SERVICE_NAME_WORDPRESS,
state,
getCustomOauthScope(serviceMap) ?: "openid"
)
}
totalSocialAccountsEnabled++
}
}
}
// CAS account.
if (settings.isCasAuthenticationEnabled()) {
casToken = generateRandomString(17)
casLoginUrl = settings.casLoginUrl().casUrl(serverUrl, casToken.toString())
totalSocialAccountsEnabled++
}
// Custom OAuth account.
getCustomOauthServices(services).let {
for (serviceMap in it) {
customOauthServiceName = getCustomOauthServiceName(serviceMap)
val host = getCustomOauthHost(serviceMap)
val authorizePath = getCustomOauthAuthorizePath(serviceMap)
val clientId = getOauthClientId(serviceMap)
val scope = getCustomOauthScope(serviceMap)
val serviceNameTextColor =
getServiceNameColorForCustomOauthOrSaml(serviceMap)
val serviceButtonColor = getServiceButtonColor(serviceMap)
if (customOauthServiceName != null &&
host != null &&
authorizePath != null &&
clientId != null &&
scope != null &&
serviceNameTextColor != null &&
serviceButtonColor != null
) {
customOauthUrl = OauthHelper.getCustomOauthUrl(
host,
authorizePath,
clientId,
serverUrl,
customOauthServiceName.toString(),
state,
scope
)
customOauthServiceNameTextColor = serviceNameTextColor
customOauthServiceButtonColor = serviceButtonColor
totalSocialAccountsEnabled++
}
}
}
// SAML account.
getSamlServices(services).let {
samlToken = generateRandomString(17)
for (serviceMap in it) {
val provider = getSamlProvider(serviceMap)
samlServiceName = getSamlServiceName(serviceMap)
val serviceNameTextColor =
getServiceNameColorForCustomOauthOrSaml(serviceMap)
val serviceButtonColor = getServiceButtonColor(serviceMap)
if (provider != null &&
samlServiceName != null &&
serviceNameTextColor != null &&
serviceButtonColor != null
) {
samlUrl = serverUrl.samlUrl(provider, samlToken.toString())
samlServiceNameTextColor = serviceNameTextColor
samlServiceButtonColor = serviceButtonColor
totalSocialAccountsEnabled++
}
}
}
}
} catch (exception: RocketChatException) {
Timber.e(exception)
}
}
}
internal fun checkIfLoginFormIsEnabled() {
if (settings.isLoginFormEnabled()) {
isLoginFormEnabled = true
}
}
internal fun checkIfCreateNewAccountIsEnabled() {
if (settings.isRegistrationEnabledForNewUsers() && settings.isLoginFormEnabled()) {
isNewAccountCreationEnabled = true
}
}
/** Returns an OAuth service map given a [serviceName].
*
* @param listMap The list of [Map] to get the service from.
* @param serviceName The service name to get in the [listMap]
* @return The OAuth service map or null otherwise.
*/
private fun getServiceMap(
listMap: List<Map<String, Any>>,
serviceName: String
): Map<String, Any>? = listMap.find { map -> map.containsValue(serviceName) }
/**
* Returns the OAuth client ID of a [serviceMap].
* REMARK: This function works for common OAuth providers (Google, Facebook, Github and so on)
* as well as custom OAuth.
*
* @param serviceMap The service map to get the OAuth client ID.
* @return The OAuth client ID or null otherwise.
*/
private fun getOauthClientId(serviceMap: Map<String, Any>): String? =
serviceMap["clientId"] as? String ?: serviceMap["appId"] as? String
/**
* Returns a custom OAuth service list.
*
* @return A custom OAuth service list, otherwise an empty list if there is no custom OAuth service.
*/
private fun getCustomOauthServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> =
listMap.filter { map -> map["custom"] == true }
/** Returns the custom OAuth service host.
*
* @param serviceMap The service map to get the custom OAuth service host.
* @return The custom OAuth service host, otherwise null.
*/
private fun getCustomOauthHost(serviceMap: Map<String, Any>): String? =
serviceMap["serverURL"] as? String
/** Returns the custom OAuth service authorize path.
*
* @param serviceMap The service map to get the custom OAuth service authorize path.
* @return The custom OAuth service authorize path, otherwise null.
*/
private fun getCustomOauthAuthorizePath(serviceMap: Map<String, Any>): String? =
serviceMap["authorizePath"] as? String
/** Returns the custom OAuth service scope.
*
* @param serviceMap The service map to get the custom OAuth service scope.
* @return The custom OAuth service scope, otherwise null.
*/
private fun getCustomOauthScope(serviceMap: Map<String, Any>): String? =
serviceMap["scope"] as? String
/** Returns the text of the custom OAuth service.
*
* @param serviceMap The service map to get the text of the custom OAuth service.
* @return The text of the custom OAuth service, otherwise null.
*/
private fun getCustomOauthServiceName(serviceMap: Map<String, Any>): String? =
serviceMap["service"] as? String
/**
* Returns a SAML OAuth service list.
*
* @return A SAML service list, otherwise an empty list if there is no SAML OAuth service.
*/
private fun getSamlServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> =
listMap.filter { map -> map["service"] == "saml" }
/**
* Returns the SAML provider.
*
* @param serviceMap The service map to provider from.
* @return The SAML provider, otherwise null.
*/
private fun getSamlProvider(serviceMap: Map<String, Any>): String? =
(serviceMap["clientConfig"] as Map<*, *>)["provider"] as? String
/**
* Returns the text of the SAML service.
*
* @param serviceMap The service map to get the text of the SAML service.
* @return The text of the SAML service, otherwise null.
*/
private fun getSamlServiceName(serviceMap: Map<String, Any>): String? =
serviceMap["buttonLabelText"] as? String
/**
* Returns the text color of the service name.
* REMARK: This can be used for custom OAuth or SAML.
*
* @param serviceMap The service map to get the text color from.
* @return The text color of the service (custom OAuth or SAML), otherwise null.
*/
private fun getServiceNameColorForCustomOauthOrSaml(serviceMap: Map<String, Any>): Int? =
(serviceMap["buttonLabelColor"] as? String)?.parseColor()
/**
* Returns the button color of the service name.
* REMARK: This can be used for custom OAuth or SAML.
*
* @param serviceMap The service map to get the button color from.
* @return The button color of the service (custom OAuth or SAML), otherwise null.
*/
private fun getServiceButtonColor(serviceMap: Map<String, Any>): Int? =
(serviceMap["buttonColor"] as? String)?.parseColor()
private fun checkServerVersion(serverInfo: ServerInfo): Version {
val thisServerVersion = serverInfo.version
val isRequiredVersion = isRequiredServerVersion(thisServerVersion)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment