アカウント追加時のサーバ名入力補完リストの更新。apiHostではなくapDomainが入力された場合にWebFingerを使ってホストを推測する。
This commit is contained in:
parent
c9fcd8d5c1
commit
12f129a878
|
@ -0,0 +1,44 @@
|
|||
package jp.juggler.subwaytooter.api
|
||||
|
||||
import jp.juggler.subwaytooter.api.entity.Host
|
||||
import jp.juggler.util.data.mayUri
|
||||
import jp.juggler.util.data.notEmpty
|
||||
import jp.juggler.util.log.LogCategory
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import org.w3c.dom.NodeList
|
||||
import java.io.ByteArrayInputStream
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
private val log = LogCategory("WebFinger")
|
||||
|
||||
private fun NodeList.items() =
|
||||
(0 until length).mapNotNull { item(it) }
|
||||
|
||||
suspend fun TootApiClient.getApiHostFromWebFinger(apDomain: Host): Host? {
|
||||
val (result, bytes) = this.getHttpBytes("https://${apDomain.ascii}/.well-known/host-meta")
|
||||
result ?: throw CancellationException()
|
||||
result.error?.notEmpty()?.let { error(it) }
|
||||
bytes ?: error("getApiHostFromWebFinger: missing response body.")
|
||||
|
||||
val document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
.parse(ByteArrayInputStream(bytes))
|
||||
|
||||
val hostSet = document.getElementsByTagName("Link")
|
||||
.items()
|
||||
.filter { "lrdd" == it.attributes?.getNamedItem("rel")?.nodeValue }
|
||||
.mapNotNull { it.attributes?.getNamedItem("template")?.nodeValue?.mayUri()?.authority?.notEmpty() }
|
||||
.map { Host.parse(it) }
|
||||
.toSet()
|
||||
|
||||
return when (hostSet.size) {
|
||||
1 -> hostSet.first()
|
||||
0 -> {
|
||||
log.e("can't find api host for domain ${apDomain.pretty} .")
|
||||
null
|
||||
}
|
||||
else -> {
|
||||
log.e("multiple hosts found for domain ${apDomain.pretty} . ${hostSet.joinToString(", ") { it.pretty }}")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,11 +45,7 @@ class Host private constructor(
|
|||
val cached = hostSet[srcArg]
|
||||
if (cached != null) return cached
|
||||
val src = srcArg.removeUrlSchema()
|
||||
val ascii = if( """[^A-Za-z0-9._-]""".toRegex().find(src)!=null){
|
||||
IDN.toASCII(src, IDN.ALLOW_UNASSIGNED).lowercase()
|
||||
}else{
|
||||
IDN.toASCII(src, IDN.ALLOW_UNASSIGNED).lowercase()
|
||||
}
|
||||
val ascii = IDN.toASCII(src, IDN.ALLOW_UNASSIGNED).lowercase()
|
||||
val pretty = IDN.toUnicode(src, IDN.ALLOW_UNASSIGNED)
|
||||
val host = if (ascii == pretty) Host(ascii) else Host(ascii, pretty)
|
||||
hostSet[src] = host
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.core.widget.addTextChangedListener
|
|||
import jp.juggler.subwaytooter.R
|
||||
import jp.juggler.subwaytooter.api.entity.Host
|
||||
import jp.juggler.subwaytooter.api.entity.TootInstance
|
||||
import jp.juggler.subwaytooter.api.getApiHostFromWebFinger
|
||||
import jp.juggler.subwaytooter.api.runApiTask2
|
||||
import jp.juggler.subwaytooter.databinding.DlgAccountAddBinding
|
||||
import jp.juggler.subwaytooter.databinding.LvAuthTypeBinding
|
||||
|
@ -219,16 +220,25 @@ class LoginForm(
|
|||
private fun nextPage() {
|
||||
activity.run {
|
||||
launchAndShowError {
|
||||
val hostname = validateAndShow() ?: return@launchAndShowError
|
||||
val host = Host.parse(hostname)
|
||||
var host = Host.parse(validateAndShow() ?: return@launchAndShowError)
|
||||
var error: String? = null
|
||||
val tootInstance = try {
|
||||
runApiTask2(host) {
|
||||
TootInstance.getExOrThrow(it, forceUpdate =true)
|
||||
val tootInstance = runApiTask2(host) { client ->
|
||||
try {
|
||||
// ユーザの入力がホスト名かドメイン名かは分からない。
|
||||
// WebFingerでホストを調べる
|
||||
client.getApiHostFromWebFinger(host)?.let {
|
||||
if (it != host) {
|
||||
host = it
|
||||
client.apiHost = it
|
||||
}
|
||||
}
|
||||
|
||||
// サーバ情報を読む
|
||||
TootInstance.getExOrThrow(client, forceUpdate = true)
|
||||
} catch (ex: Throwable) {
|
||||
error = ex.message
|
||||
null
|
||||
}
|
||||
} catch (ex: Throwable) {
|
||||
error = ex.message
|
||||
null
|
||||
}
|
||||
if (isDestroyed || isFinishing) return@launchAndShowError
|
||||
targetServer = host
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue