Support for login by m.login.token during QR code sign in

This commit is contained in:
Hugh Nimmo-Smith 2022-10-13 15:11:15 +01:00
parent 9429a4f22a
commit 88238c0f04
7 changed files with 125 additions and 5 deletions

View file

@ -130,4 +130,17 @@ interface AuthenticationService {
* Return true if qr code login is supported by the server, false otherwise.
*/
suspend fun isQrLoginSupported(homeServerConnectionConfig: HomeServerConnectionConfig): Boolean
* Authenticate using m.login.token method during sign in with QR code.
* @param homeServerConnectionConfig the information about the homeserver and other configuration
* @param loginToken the m.login.token
* @param initialDeviceName the initial device name
* @param deviceId the device id, optional. If not provided or null, the server will generate one.
*/
suspend fun loginUsingQrLoginToken(
homeServerConnectionConfig: HomeServerConnectionConfig,
loginToken: String,
initialDeviceName: String,
deviceId: String? = null
): Session
}

View file

@ -22,7 +22,8 @@ enum class LoginType {
UNSUPPORTED,
CUSTOM,
DIRECT,
UNKNOWN;
UNKNOWN,
QR;
companion object {
@ -32,6 +33,7 @@ enum class LoginType {
UNSUPPORTED.name -> UNSUPPORTED
CUSTOM.name -> CUSTOM
DIRECT.name -> DIRECT
QR.name -> QR
else -> UNKNOWN
}
}

View file

@ -40,6 +40,7 @@ import org.matrix.android.sdk.internal.auth.data.WebClientConfig
import org.matrix.android.sdk.internal.auth.db.PendingSessionData
import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
import org.matrix.android.sdk.internal.auth.login.QrLoginTokenTask
import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard
import org.matrix.android.sdk.internal.auth.version.Versions
import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
@ -64,7 +65,8 @@ internal class DefaultAuthenticationService @Inject constructor(
private val sessionCreator: SessionCreator,
private val pendingSessionStore: PendingSessionStore,
private val getWellknownTask: GetWellknownTask,
private val directLoginTask: DirectLoginTask
private val directLoginTask: DirectLoginTask,
private val loginTokenAuthTask: QrLoginTokenTask
) : AuthenticationService {
private var pendingSessionData: PendingSessionData? = pendingSessionStore.getPendingSessionData()
@ -420,6 +422,17 @@ internal class DefaultAuthenticationService @Inject constructor(
}
}
override suspend fun loginUsingQrLoginToken(homeServerConnectionConfig: HomeServerConnectionConfig, loginToken: String, initialDeviceName: String, deviceId: String?): Session {
return loginTokenAuthTask.execute(
QrLoginTokenTask.Params(
homeServerConnectionConfig = homeServerConnectionConfig,
loginToken = loginToken,
deviceName = initialDeviceName,
deviceId = deviceId
)
)
}
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUriBase.toString())
return retrofit.create(AuthAPI::class.java)

View file

@ -18,4 +18,6 @@ package org.matrix.android.sdk.internal.auth.data
internal interface LoginParams {
val type: String
val deviceDisplayName: String?
val deviceId: String?
}

View file

@ -30,8 +30,8 @@ internal data class PasswordLoginParams(
@Json(name = "identifier") val identifier: Map<String, String>,
@Json(name = "password") val password: String,
@Json(name = "type") override val type: String,
@Json(name = "initial_device_display_name") val deviceDisplayName: String?,
@Json(name = "device_id") val deviceId: String?
@Json(name = "initial_device_display_name") override val deviceDisplayName: String?,
@Json(name = "device_id") override val deviceId: String?
) : LoginParams {
companion object {

View file

@ -23,5 +23,7 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
@JsonClass(generateAdapter = true)
internal data class TokenLoginParams(
@Json(name = "type") override val type: String = LoginFlowTypes.TOKEN,
@Json(name = "token") val token: String
@Json(name = "token") val token: String,
@Json(name = "initial_device_display_name") override val deviceDisplayName: String?,
@Json(name = "device_id") override val deviceId: String?
) : LoginParams

View file

@ -0,0 +1,88 @@
/*
* Copyright 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.auth.login
import dagger.Lazy
import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.auth.LoginType
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.internal.auth.AuthAPI
import org.matrix.android.sdk.internal.auth.SessionCreator
import org.matrix.android.sdk.internal.auth.data.TokenLoginParams
import org.matrix.android.sdk.internal.di.Unauthenticated
import org.matrix.android.sdk.internal.network.RetrofitFactory
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.network.httpclient.addSocketFactory
import org.matrix.android.sdk.internal.network.ssl.UnrecognizedCertificateException
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject
internal interface QrLoginTokenTask : Task<QrLoginTokenTask.Params, Session> {
data class Params(
val homeServerConnectionConfig: HomeServerConnectionConfig,
val loginToken: String,
val deviceName: String?,
val deviceId: String?
)
}
internal class DefaultQrLoginTokenTask @Inject constructor(
@Unauthenticated
private val okHttpClient: Lazy<OkHttpClient>,
private val retrofitFactory: RetrofitFactory,
private val sessionCreator: SessionCreator,
) : QrLoginTokenTask {
override suspend fun execute(params: QrLoginTokenTask.Params): Session {
val client = buildClient(params.homeServerConnectionConfig)
val homeServerUrl = params.homeServerConnectionConfig.homeServerUriBase.toString()
val authAPI = retrofitFactory.create(client, homeServerUrl)
.create(AuthAPI::class.java)
val loginParams = TokenLoginParams(
token = params.loginToken,
deviceDisplayName = params.deviceName,
deviceId = params.deviceId
)
val credentials = try {
executeRequest(null) {
authAPI.login(loginParams)
}
} catch (throwable: Throwable) {
throw when (throwable) {
is UnrecognizedCertificateException -> Failure.UnrecognizedCertificateFailure(
homeServerUrl,
throwable.fingerprint
)
else -> throwable
}
}
return sessionCreator.createSession(credentials, params.homeServerConnectionConfig, LoginType.QR)
}
private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient {
return okHttpClient.get()
.newBuilder()
.addSocketFactory(homeServerConnectionConfig)
.build()
}
}