實作更新DDNS功能

This commit is contained in:
Raymond Yang 2023-08-12 13:30:21 +08:00
parent 935af29314
commit cac3e9487b
5 changed files with 155 additions and 5 deletions

View File

@ -13,6 +13,12 @@ repositories {
dependencies {
testImplementation(kotlin("test"))
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.google.code.gson:gson:2.10.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jsoup:jsoup:1.14.3")
}
tasks.test {

4
config.json Normal file
View File

@ -0,0 +1,4 @@
{
"token": "n_9L9-W70oYWtMV16GgYTs0yWZ72Vjs17QD4dUZl",
"domain": "ray650128.com"
}

View File

@ -1,7 +1,138 @@
fun main(args: Array<String>) {
import api.CloudflareApiService
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import model.Configure
import model.zones.UpdateDnsBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.io.IOException
private lateinit var config: Configure
private lateinit var token: String
private lateinit var domain: String
fun main() {
println("Cloudflare DDNS 更新程式已啟動")
// Try adding program arguments via Run/Debug configuration.
// Learn more about running applications: https://www.jetbrains.com/help/idea/running-applications.html.
println("Program arguments: ${args.joinToString()}")
val confFile = File("config.json")
if (!confFile.exists()) {
confFile.createNewFile()
println("請先設定 config.json 檔案")
return
}
val configRawText = confFile.readText(Charsets.UTF_8)
if (configRawText.isEmpty()) {
println("請先設定 config.json 檔案")
return
}
config = loadConfigFile(configRawText)
val retrofit = Retrofit.Builder()
.baseUrl("https://api.cloudflare.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService = retrofit.create(CloudflareApiService::class.java)
runBlocking {
println("-------- [ 開始更新 DNS ] --------")
val client = OkHttpClient()
val request: Request = Request.Builder()
.url("https://ifconfig.me")
.addHeader("User-Agent", "")
.method("GET", null)
.build()
val ipAddress = try {
val response = withContext(Dispatchers.IO) {
client.newCall(request).execute()
}
if (response.isSuccessful) {
response.body()?.string() ?: run {
println("無法取得 WAN IP 位址")
return@runBlocking
}
} else {
null
}
} catch (e: IOException) {
null
} finally {
client.dispatcher().executorService().shutdown()
}
if (ipAddress != null) {
println("您目前的 WAN IP 位址為: $ipAddress")
try {
println("驗證 CF 權杖是否有效...")
val verifyTokenResult = apiService.getVerifyToken("Bearer $token")
if (verifyTokenResult.success) {
println("CF 權杖有效,載入 Zone 資料中...")
val zonesResult = apiService.getZones("Bearer $token")
if (zonesResult.success) {
println("Zone 資料載入成功,取得域名資料中...")
val zoneData = zonesResult.result.firstOrNull { it.name == domain } ?: run {
println("無法找到指定的域名 [ $domain ]...")
return@runBlocking
}
val zoneId = zoneData.id
val zoneDnsRecords = apiService.getZoneDnsRecords("Bearer $token", zoneId)
if (zoneDnsRecords.success) {
println("域名資料載入成功,處理中...")
val record = zoneDnsRecords.result.firstOrNull { it.name == domain } ?: run {
println("無法找到指定的域名 [ $domain ]...")
return@runBlocking
}
val recordId = record.id
val updateDnsBody = UpdateDnsBody(
type = "A",
name = record.name,
content = ipAddress,
ttl = 120,
proxied = false
)
val updateDnsResult = apiService.updateZoneDnsRecords("Bearer $token", zoneId, recordId, updateDnsBody)
if (updateDnsResult.success) {
println("更新 DDNS 成功")
} else {
println("更新 DDNS 失敗")
}
} else {
println("無法取得域名資料資料")
}
} else {
println("無法取得 Zone 資料")
}
} else {
println("CF 權杖無效")
}
} catch (e: Exception) {
e.printStackTrace()
println("Error: ${e.message}")
}
} else {
println("Error retrieving IP address")
}
}
}
private fun loadConfigFile(configRawText: String): Configure {
val config = Gson().fromJson(configRawText, Configure::class.java)
token = config.token
domain = config.domain
println("-------- [ 設定檔已載入 ] --------")
println("CF 權杖: $token")
println("欲更新的域名: $domain")
return config
}

View File

@ -17,7 +17,7 @@ interface CloudflareApiService {
@GET("/client/v4/zones")
suspend fun getZones(
@Header("Authorization") token: String
): CloudflareResult<ZonesResult>
): CloudflareResult<List<ZonesResult>>
@GET("/client/v4/zones/{ZONE_ID}/dns_records")
suspend fun getZoneDnsRecords(

View File

@ -0,0 +1,9 @@
package model
import com.google.gson.annotations.SerializedName
data class Configure(
val token: String,
val domain: String
)