Balance exchange source points, link account with Solarpass with drasl

This commit is contained in:
2025-10-05 23:46:06 +08:00
parent 3803e27a06
commit a902ecef8d
14 changed files with 576 additions and 118 deletions

View File

@@ -0,0 +1,132 @@
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
}
}
}