Someting
This commit is contained in:
parent
05cce802f0
commit
e4908dfd1e
@ -20,6 +20,17 @@ dependencies {
|
|||||||
implementation("org.slf4j:slf4j-api:2.0.10")
|
implementation("org.slf4j:slf4j-api:2.0.10")
|
||||||
implementation("net.lamgc:scalabot-extension:0.6.1")
|
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.microsoft.graph:microsoft-graph:5.77.0")
|
||||||
implementation("com.azure:azure-identity:1.11.1")
|
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(
|
data class ExtensionConfig(
|
||||||
val clientId: String,
|
val clientId: String,
|
||||||
val clientSecret: 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
|
package net.lamgc.scext.onedrive_transfer
|
||||||
|
|
||||||
import com.azure.identity.AuthorizationCodeCredentialBuilder
|
|
||||||
import com.google.gson.Gson
|
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.bot.BaseAbilityBot
|
||||||
import org.telegram.abilitybots.api.objects.Ability
|
import org.telegram.abilitybots.api.objects.Ability
|
||||||
import org.telegram.abilitybots.api.objects.Locality
|
import org.telegram.abilitybots.api.objects.Locality
|
||||||
import org.telegram.abilitybots.api.objects.Privacy
|
import org.telegram.abilitybots.api.objects.Privacy
|
||||||
|
import org.telegram.abilitybots.api.objects.Reply
|
||||||
import org.telegram.abilitybots.api.util.AbilityExtension
|
import org.telegram.abilitybots.api.util.AbilityExtension
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
class OneDriveTransferExtension(val bot: BaseAbilityBot, val dataFolder: File) : AbilityExtension {
|
class OneDriveTransferExtension(val bot: BaseAbilityBot, val dataFolder: File) : AbilityExtension {
|
||||||
|
|
||||||
private val config: ExtensionConfig
|
private val config: ExtensionConfig
|
||||||
|
private val authClient: ConfidentialClientApplication
|
||||||
|
private val accountManager: MicrosoftAccountManager
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val configFile = File(dataFolder, "config.json")
|
val configFile = File(dataFolder, "config.json")
|
||||||
@ -20,25 +26,43 @@ class OneDriveTransferExtension(val bot: BaseAbilityBot, val dataFolder: File) :
|
|||||||
configFile.writeText("{}")
|
configFile.writeText("{}")
|
||||||
}
|
}
|
||||||
config = Gson().fromJson(configFile.reader(), ExtensionConfig::class.java)
|
config = Gson().fromJson(configFile.reader(), ExtensionConfig::class.java)
|
||||||
|
val db = Database.connect("jdbc:sqlite:${File(dataFolder, "./data.db").canonicalPath}", "org.sqlite.JDBC")
|
||||||
val credentialBuilder = AuthorizationCodeCredentialBuilder()
|
authClient = ConfidentialClientApplication.builder(
|
||||||
.clientId(config.clientId)
|
config.clientId,
|
||||||
.clientSecret(config.clientSecret)
|
ClientCredentialFactory.createFromSecret(config.clientSecret),
|
||||||
.redirectUrl("http://localhost:8080")
|
)
|
||||||
|
.authority(MicrosoftAccountManager.AUTHORITY)
|
||||||
|
.setTokenCacheAccessAspect(DatabaseTokenCache(db))
|
||||||
.build()
|
.build()
|
||||||
|
accountManager = MicrosoftAccountManager(authClient, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loginOneDrive(): Ability {
|
fun loginOneDrive(): Ability = Ability
|
||||||
return Ability
|
.builder()
|
||||||
.builder()
|
.name("odt_login")
|
||||||
.name("odt_login")
|
.info("登录 OneDrive 账户.")
|
||||||
.info("登录 OneDrive 账户.")
|
.locality(Locality.USER)
|
||||||
.locality(Locality.USER)
|
.privacy(Privacy.PUBLIC)
|
||||||
.privacy(Privacy.PUBLIC)
|
.action { ctx ->
|
||||||
.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