Files
ConnectMinecraft/src/main/kotlin/dev/solsynth/snConnect/services/AuthUserService.kt

133 lines
3.6 KiB
Kotlin

package dev.solsynth.snConnect.services
import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import okhttp3.Request
import java.io.IOException
@Serializable
data class DraslPlayer(
@SerialName("userUuid")
val userUuid: String,
val name: String,
val uuid: String,
@SerialName("offlineUuid")
val offlineUuid: String,
@SerialName("fallbackPlayer")
val fallbackPlayer: String,
@SerialName("skinModel")
val skinModel: String,
@SerialName("skinUrl")
val skinUrl: String?,
@SerialName("capeUrl")
val capeUrl: String?,
@SerialName("createdAt")
val createdAt: String, // ISO string
@SerialName("nameLastChangedAt")
val nameLastChangedAt: String
)
@Serializable
data class DraslOIDCIdentity(
@SerialName("userUuid")
val userUuid: String,
@SerialName("oidcProviderName")
val oidcProviderName: String,
val issuer: String,
val subject: String
)
@Serializable
data class DraslUser(
@SerialName("isAdmin")
val isAdmin: Boolean,
@SerialName("isLocked")
val isLocked: Boolean,
val uuid: String,
val username: String,
@SerialName("preferredLanguage")
val preferredLanguage: String,
@SerialName("maxPlayerCount")
val maxPlayerCount: Int,
val players: List<DraslPlayer>,
@SerialName("oidcIdentities")
val oidcIdentities: List<DraslOIDCIdentity>
)
@Serializable
data class APILoginRequest(
val username: String,
val password: String
)
@Serializable
data class APILoginResponse(
val user: DraslUser,
val token: String,
@SerialName("expires_at")
val expiresAt: Instant
)
@Serializable
data class APIOIDCTokenRequest(
@SerialName("provider")
val provider: String,
val code: String,
val state: String
)
@Serializable
data class APIOIDCTokenResponse(
val user: DraslUser,
val token: String,
@SerialName("expires_at")
val expiresAt: Instant
)
class AuthUserService(private val sn: AuthService) {
private val json = Json {
ignoreUnknownKeys = true
}
private fun addAuthHeader(builder: Request.Builder): Request.Builder {
sn.siteSecret?.let { builder.header("Authorization", "Bearer $it") }
return builder
}
fun getUser(id: String): DraslUser {
val requestBuilder = Request.Builder()
.url(sn.getUrl("/drasl/api/v2/users/$id"))
.get()
sn.client.newCall(addAuthHeader(requestBuilder).build()).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
val responseBody = response.body!!.string()
return json.decodeFromString<DraslUser>(responseBody)
}
}
fun getPlayerByUuid(uuid: String): DraslPlayer {
val requestBuilder = Request.Builder()
.url(sn.getUrl("/drasl/api/v2/players/$uuid"))
.get()
sn.client.newCall(addAuthHeader(requestBuilder).build()).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
val responseBody = response.body!!.string()
return json.decodeFromString<DraslPlayer>(responseBody)
}
}
fun getSnByPlayer(playerUuid: String): String? {
return try {
val player = getPlayerByUuid(playerUuid)
val user = getUser(player.userUuid)
user.oidcIdentities.find { it.oidcProviderName == "Solarpass" }?.subject
} catch (e: IOException) {
null
}
}
}