mirror of
https://github.com/dalbodeule/chibot-chzzk-bot.git
synced 2025-06-09 07:18:22 +00:00
add discord login
- add discord login logics - add discord api classes, functions. - add current user's discord guilds. (if session has discordGuilds, return it else return null lists)
This commit is contained in:
parent
dd628738f7
commit
9c047d3d87
@ -4,6 +4,7 @@ import applicationHttpClient
|
|||||||
import io.github.cdimascio.dotenv.dotenv
|
import io.github.cdimascio.dotenv.dotenv
|
||||||
import io.ktor.client.call.*
|
import io.ktor.client.call.*
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
|
import io.ktor.client.statement.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.serialization.kotlinx.*
|
import io.ktor.serialization.kotlinx.*
|
||||||
import io.ktor.serialization.kotlinx.json.*
|
import io.ktor.serialization.kotlinx.json.*
|
||||||
@ -20,6 +21,9 @@ import io.ktor.server.sessions.*
|
|||||||
import io.ktor.server.websocket.*
|
import io.ktor.server.websocket.*
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import space.mori.chzzk_bot.common.models.User
|
||||||
|
import space.mori.chzzk_bot.common.services.UserService
|
||||||
|
import space.mori.chzzk_bot.common.utils.getUserInfo
|
||||||
import space.mori.chzzk_bot.webserver.routes.*
|
import space.mori.chzzk_bot.webserver.routes.*
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
|
||||||
@ -70,6 +74,29 @@ val server = embeddedServer(Netty, port = 8080, ) {
|
|||||||
)}
|
)}
|
||||||
client = applicationHttpClient
|
client = applicationHttpClient
|
||||||
}
|
}
|
||||||
|
oauth("auth-oauth-discord") {
|
||||||
|
urlProvider = { "${dotenv["HOST"]}/auth/discord/callback" }
|
||||||
|
providerLookup = { OAuthServerSettings.OAuth2ServerSettings(
|
||||||
|
name = "discord",
|
||||||
|
authorizeUrl = "https://discord.com/oauth2/authorize",
|
||||||
|
accessTokenUrl = "https://discord.com/api/oauth2/token",
|
||||||
|
clientId = dotenv["DISCORD_CLIENT_ID"],
|
||||||
|
clientSecret = dotenv["DISCORD_CLIENT_SECRET"],
|
||||||
|
defaultScopes = listOf(),
|
||||||
|
extraAuthParameters = listOf(
|
||||||
|
Pair("permissions", "826781355072"),
|
||||||
|
Pair("response_type", "code"),
|
||||||
|
Pair("integration_type", "0"),
|
||||||
|
Pair("scope", "guilds+bot")
|
||||||
|
),
|
||||||
|
onStateCreated = { call, state ->
|
||||||
|
call.request.queryParameters["redirectUrl"]?.let {
|
||||||
|
redirects[state] = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
client = applicationHttpClient
|
||||||
|
}
|
||||||
}
|
}
|
||||||
routing {
|
routing {
|
||||||
route("/auth") {
|
route("/auth") {
|
||||||
@ -88,7 +115,7 @@ val server = embeddedServer(Netty, port = 8080, ) {
|
|||||||
}.body()
|
}.body()
|
||||||
|
|
||||||
call.sessions.set(userInfo.response?.let { profile ->
|
call.sessions.set(userInfo.response?.let { profile ->
|
||||||
UserSession(state, profile.id)
|
UserSession(state, profile.id, listOf())
|
||||||
})
|
})
|
||||||
|
|
||||||
redirects[state]?.let { redirect ->
|
redirects[state]?.let { redirect ->
|
||||||
@ -97,7 +124,28 @@ val server = embeddedServer(Netty, port = 8080, ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
call.respondRedirect("${ if(dotenv["FRONTEND_HTTPS"].toBoolean()) "https://" else "http://" }${dotenv["FRONTEND"]}")
|
call.respondRedirect(getFrontendURL(""))
|
||||||
|
}
|
||||||
|
get("/discord/callback") {
|
||||||
|
val principal = call.principal<OAuthAccessTokenResponse.OAuth2>()
|
||||||
|
val session = call.sessions.get<UserSession>()
|
||||||
|
val user = session?.id?.let { UserService.getUserWithNaverId(it)}
|
||||||
|
|
||||||
|
if(principal != null && session != null && user != null) {
|
||||||
|
val accessToken = principal.accessToken
|
||||||
|
val userInfo = getDiscordUser(accessToken)
|
||||||
|
val guilds = getUserGuilds(accessToken)
|
||||||
|
|
||||||
|
userInfo?.user?.id?.toLong()?.let { id -> UserService.updateUser(user, id) }
|
||||||
|
|
||||||
|
call.sessions.set(UserSession(
|
||||||
|
session.state,
|
||||||
|
session.id,
|
||||||
|
guilds.map { it.id }
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
call.respondRedirect(getFrontendURL(""))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get("/logout") {
|
get("/logout") {
|
||||||
@ -145,10 +193,14 @@ fun stop() {
|
|||||||
server.stop()
|
server.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getFrontendURL(path: String)
|
||||||
|
= "${if(dotenv["FRONTEND_HTTPS"].toBoolean()) "https://" else "http://" }${dotenv["FRONTEND"]}${path}";
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class UserSession(
|
data class UserSession(
|
||||||
val state: String,
|
val state: String,
|
||||||
val id: String
|
val id: String,
|
||||||
|
val discordGuildList: List<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -157,4 +209,66 @@ data class NaverMeAPI(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class NaverAPI<T>(val resultcode: String, val message: String, val response: T?)
|
data class NaverAPI<T>(val resultcode: String, val message: String, val response: T?)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DiscordMeAPI(
|
||||||
|
val application: DiscordApplicationAPI,
|
||||||
|
val scopes: List<String>,
|
||||||
|
val user: DiscordUserAPI
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DiscordApplicationAPI(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val icon: String,
|
||||||
|
val description: String,
|
||||||
|
val hook: Boolean,
|
||||||
|
val bot_public: Boolean,
|
||||||
|
val bot_require_code_grant: Boolean,
|
||||||
|
val verify_key: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DiscordUserAPI(
|
||||||
|
val id: String,
|
||||||
|
val username: String,
|
||||||
|
val avatar: String,
|
||||||
|
val discriminator: String,
|
||||||
|
val global_name: String,
|
||||||
|
val public_flags: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DiscordGuildListAPI(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val icon: String,
|
||||||
|
val banner: String,
|
||||||
|
val owner: Boolean,
|
||||||
|
val permissions: Int,
|
||||||
|
val features: List<String>,
|
||||||
|
val approximate_member_count: Int,
|
||||||
|
val approximate_presence_count: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun getDiscordUser(accessToken: String): DiscordMeAPI? {
|
||||||
|
val response: HttpResponse = applicationHttpClient.get("https://discord.com/api/oauth2/@me") {
|
||||||
|
headers {
|
||||||
|
append(HttpHeaders.Authorization, "Bearer $accessToken")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.body<DiscordMeAPI?>()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getUserGuilds(accessToken: String): List<DiscordGuildListAPI> {
|
||||||
|
val response = applicationHttpClient.get("https://discord.com/api/users/@me/") {
|
||||||
|
headers {
|
||||||
|
append(HttpHeaders.Authorization, "Bearer $accessToken")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.body<List<DiscordGuildListAPI>>()
|
||||||
|
}
|
@ -52,6 +52,20 @@ fun Route.apiDiscordRoutes() {
|
|||||||
|
|
||||||
call.respond(HttpStatusCode.OK)
|
call.respond(HttpStatusCode.OK)
|
||||||
}
|
}
|
||||||
|
get {
|
||||||
|
val session = call.sessions.get<UserSession>()
|
||||||
|
if(session == null) {
|
||||||
|
call.respond(HttpStatusCode.BadRequest, "Session is required")
|
||||||
|
return@get
|
||||||
|
}
|
||||||
|
val user = UserService.getUserWithNaverId(session.id)
|
||||||
|
if(user == null) {
|
||||||
|
call.respond(HttpStatusCode.BadRequest, "User does not exist")
|
||||||
|
return@get
|
||||||
|
}
|
||||||
|
call.respond(HttpStatusCode.OK, session.discordGuildList)
|
||||||
|
return@get
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user