Someting
This commit is contained in:
parent
05cce802f0
commit
e4908dfd1e
@ -20,6 +20,17 @@ dependencies {
|
||||
implementation("org.slf4j:slf4j-api:2.0.10")
|
||||
implementation("net.lamgc:scalabot-extension:0.6.1")
|
||||
|
||||
val exposedVersion = "0.45.0"
|
||||
implementation("org.jetbrains.exposed:exposed-core:$exposedVersion")
|
||||
implementation("org.jetbrains.exposed:exposed-crypt:$exposedVersion")
|
||||
implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion")
|
||||
implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion")
|
||||
implementation("org.jetbrains.exposed:exposed-kotlin-datetime:$exposedVersion")
|
||||
|
||||
implementation("org.xerial:sqlite-jdbc:3.44.1.0")
|
||||
implementation("mysql:mysql-connector-java:8.0.33")
|
||||
implementation("com.zaxxer:HikariCP:5.1.0")
|
||||
|
||||
implementation("com.microsoft.graph:microsoft-graph:5.77.0")
|
||||
implementation("com.azure:azure-identity:1.11.1")
|
||||
|
||||
|
63
src/main/kotlin/Databases.kt
Normal file
63
src/main/kotlin/Databases.kt
Normal file
@ -0,0 +1,63 @@
|
||||
package net.lamgc.scext.onedrive_transfer
|
||||
|
||||
import com.microsoft.aad.msal4j.ITokenCacheAccessAspect
|
||||
import com.microsoft.aad.msal4j.ITokenCacheAccessContext
|
||||
import org.jetbrains.exposed.dao.LongEntity
|
||||
import org.jetbrains.exposed.dao.LongEntityClass
|
||||
import org.jetbrains.exposed.dao.id.EntityID
|
||||
import org.jetbrains.exposed.dao.id.LongIdTable
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
object MicrosoftAccounts : LongIdTable() {
|
||||
val telegramUserId = long("tg_user_id").uniqueIndex()
|
||||
val accountId = varchar("account_id", 128)
|
||||
val userName = varchar("user_name", 96)
|
||||
|
||||
}
|
||||
|
||||
class MicrosoftAccount(id: EntityID<Long>) : LongEntity(id) {
|
||||
var telegramUserId by MicrosoftAccounts.telegramUserId
|
||||
var accountId by MicrosoftAccounts.accountId
|
||||
var userName by MicrosoftAccounts.accountId
|
||||
|
||||
companion object : LongEntityClass<MicrosoftAccount>(MicrosoftAccounts)
|
||||
}
|
||||
|
||||
object TokenCaches : LongIdTable() {
|
||||
val accountId = varchar("access_id", 256).uniqueIndex()
|
||||
val cache = text("cache_data")
|
||||
}
|
||||
|
||||
class TokenCache(id: EntityID<Long>) : LongEntity(id) {
|
||||
var accountId by TokenCaches.accountId
|
||||
var cache by TokenCaches.cache
|
||||
|
||||
companion object : LongEntityClass<TokenCache>(TokenCaches)
|
||||
}
|
||||
|
||||
class DatabaseTokenCache(private val db: Database) : ITokenCacheAccessAspect {
|
||||
|
||||
override fun beforeCacheAccess(context: ITokenCacheAccessContext) {
|
||||
transaction(db) {
|
||||
TokenCache.find { TokenCaches.accountId eq context.account().homeAccountId() }.firstOrNull()?.let {
|
||||
context.tokenCache().deserialize(it.cache)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterCacheAccess(context: ITokenCacheAccessContext) {
|
||||
transaction(db) {
|
||||
val existCache =
|
||||
TokenCache.find { TokenCaches.accountId eq context.account().homeAccountId() }.firstOrNull()
|
||||
if (existCache == null) {
|
||||
TokenCache.new {
|
||||
accountId = context.account().homeAccountId()
|
||||
cache = context.tokenCache().serialize()
|
||||
}
|
||||
} else {
|
||||
existCache.cache = context.tokenCache().serialize()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,5 +3,4 @@ package net.lamgc.scext.onedrive_transfer
|
||||
data class ExtensionConfig(
|
||||
val clientId: String,
|
||||
val clientSecret: String,
|
||||
val authUrl: String?
|
||||
)
|
||||
|
72
src/main/kotlin/MicrosoftAccountManager.kt
Normal file
72
src/main/kotlin/MicrosoftAccountManager.kt
Normal file
@ -0,0 +1,72 @@
|
||||
package net.lamgc.scext.onedrive_transfer
|
||||
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.transactions.TransactionManager
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import com.microsoft.aad.msal4j.*
|
||||
import java.sql.Connection
|
||||
import java.net.URL
|
||||
import java.net.URI
|
||||
|
||||
class MicrosoftAccountManager(private val authClient: ConfidentialClientApplication, private val db: Database) {
|
||||
|
||||
|
||||
init {
|
||||
TransactionManager.manager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE
|
||||
}
|
||||
|
||||
fun getMicrosoftByTelegramUser(userId: Long): MicrosoftAccount? {
|
||||
return transaction(db) {
|
||||
return@transaction MicrosoftAccount.find { MicrosoftAccounts.telegramUserId eq userId }.firstOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun createAuthorizationRequest(userId: Long): URL {
|
||||
val parameters = AuthorizationRequestUrlParameters
|
||||
.builder("http://localhost:45678/", OAUTH2_SCOPE)
|
||||
.responseMode(ResponseMode.QUERY)
|
||||
.prompt(Prompt.SELECT_ACCOUNT)
|
||||
.build()
|
||||
return authClient.getAuthorizationRequestUrl(parameters)
|
||||
}
|
||||
|
||||
fun updateAccount(userId: Long, token: String): MicrosoftAccount {
|
||||
val future = authClient.acquireToken(
|
||||
AuthorizationCodeParameters
|
||||
.builder(token, URI.create("http://localhost:45678/"))
|
||||
.build()
|
||||
)
|
||||
val result = future.get()
|
||||
return transaction(db) {
|
||||
val account = MicrosoftAccount.find { MicrosoftAccounts.telegramUserId eq userId }.firstOrNull()
|
||||
account?.apply {
|
||||
accountId = result.account().homeAccountId()
|
||||
userName = result.account().username()
|
||||
}
|
||||
?: MicrosoftAccount.new {
|
||||
telegramUserId = userId
|
||||
accountId = result.account().homeAccountId()
|
||||
userName = result.account().username()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val AUTHORITY = "https://login.microsoftonline.com/common"
|
||||
val OAUTH2_SCOPE = setOf(
|
||||
"User.Read",
|
||||
"Files.Read",
|
||||
"Files.ReadWrite",
|
||||
"Files.Read.All",
|
||||
"Files.ReadWrite.All",
|
||||
"Sites.ReadWrite.All",
|
||||
"offline_access"
|
||||
)
|
||||
|
||||
fun getTokenFromUrl(url: URL): String {
|
||||
return url.query.split("&").find { it.startsWith("code=") }?.substring(5) ?: throw IllegalArgumentException(
|
||||
"Invalid URL."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,23 @@
|
||||
package net.lamgc.scext.onedrive_transfer
|
||||
|
||||
import com.azure.identity.AuthorizationCodeCredentialBuilder
|
||||
import com.google.gson.Gson
|
||||
import com.microsoft.aad.msal4j.*
|
||||
import com.microsoft.graph.requests.GraphServiceClient
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.telegram.abilitybots.api.bot.BaseAbilityBot
|
||||
import org.telegram.abilitybots.api.objects.Ability
|
||||
import org.telegram.abilitybots.api.objects.Locality
|
||||
import org.telegram.abilitybots.api.objects.Privacy
|
||||
import org.telegram.abilitybots.api.objects.Reply
|
||||
import org.telegram.abilitybots.api.util.AbilityExtension
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
class OneDriveTransferExtension(val bot: BaseAbilityBot, val dataFolder: File) : AbilityExtension {
|
||||
|
||||
private val config: ExtensionConfig
|
||||
private val authClient: ConfidentialClientApplication
|
||||
private val accountManager: MicrosoftAccountManager
|
||||
|
||||
init {
|
||||
val configFile = File(dataFolder, "config.json")
|
||||
@ -20,25 +26,43 @@ class OneDriveTransferExtension(val bot: BaseAbilityBot, val dataFolder: File) :
|
||||
configFile.writeText("{}")
|
||||
}
|
||||
config = Gson().fromJson(configFile.reader(), ExtensionConfig::class.java)
|
||||
|
||||
val credentialBuilder = AuthorizationCodeCredentialBuilder()
|
||||
.clientId(config.clientId)
|
||||
.clientSecret(config.clientSecret)
|
||||
.redirectUrl("http://localhost:8080")
|
||||
val db = Database.connect("jdbc:sqlite:${File(dataFolder, "./data.db").canonicalPath}", "org.sqlite.JDBC")
|
||||
authClient = ConfidentialClientApplication.builder(
|
||||
config.clientId,
|
||||
ClientCredentialFactory.createFromSecret(config.clientSecret),
|
||||
)
|
||||
.authority(MicrosoftAccountManager.AUTHORITY)
|
||||
.setTokenCacheAccessAspect(DatabaseTokenCache(db))
|
||||
.build()
|
||||
accountManager = MicrosoftAccountManager(authClient, db)
|
||||
}
|
||||
|
||||
fun loginOneDrive(): Ability {
|
||||
return Ability
|
||||
.builder()
|
||||
.name("odt_login")
|
||||
.info("登录 OneDrive 账户.")
|
||||
.locality(Locality.USER)
|
||||
.privacy(Privacy.PUBLIC)
|
||||
.action { ctx ->
|
||||
fun loginOneDrive(): Ability = Ability
|
||||
.builder()
|
||||
.name("odt_login")
|
||||
.info("登录 OneDrive 账户.")
|
||||
.locality(Locality.USER)
|
||||
.privacy(Privacy.PUBLIC)
|
||||
.action { ctx ->
|
||||
val url = accountManager.createAuthorizationRequest(ctx.user().id)
|
||||
ctx.bot().silent().send("""
|
||||
请使用以下链接进行登录:
|
||||
$url
|
||||
|
||||
-------------------------------------------
|
||||
登录成功后会显示无法访问,是正常情况,请将地址栏的链接发回给机器人。
|
||||
""".trimIndent(), ctx.chatId())
|
||||
}
|
||||
.reply(Reply.of(
|
||||
{bot, upd ->
|
||||
val token = MicrosoftAccountManager.getTokenFromUrl(URL(upd.message.text.trim()))
|
||||
val account = accountManager.updateAccount(upd.message.chat.id, token)
|
||||
|
||||
},
|
||||
{ upd ->
|
||||
upd.hasMessage()
|
||||
}
|
||||
.build()
|
||||
}
|
||||
))
|
||||
.build()
|
||||
|
||||
}
|
||||
|
7
src/main/kotlin/Services.kt
Normal file
7
src/main/kotlin/Services.kt
Normal file
@ -0,0 +1,7 @@
|
||||
package net.lamgc.scext.onedrive_transfer
|
||||
|
||||
class OneDriveTransferService() {
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user