Skip to content

Commit

Permalink
Mastodonのクライアント情報再利用チェックでAPIがエラーを返した際のフォールバックが不足していた
Browse files Browse the repository at this point in the history
  • Loading branch information
tateisu committed Mar 3, 2023
1 parent 953cdea commit c4150b1
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 47 deletions.
88 changes: 45 additions & 43 deletions app/src/main/java/jp/juggler/subwaytooter/api/auth/AuthMastodon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -104,59 +104,61 @@ class AuthMastodon(override val client: TootApiClient) : AuthBase() {
// スコープ一覧を取得する
val scopeString = mastodonScope(tootInstance)

when {
// 古いクライアント情報は使わない。削除もしない。
AUTH_VERSION != clientInfo?.int(KEY_AUTH_VERSION) -> Unit

// Misskeyにはclient情報をまだ利用できるかどうか調べる手段がないので、再利用しない
clientInfo.boolean(KEY_IS_MISSKEY) == true -> Unit

else -> {
val clientCredential = prepareClientCredential(apiHost, clientInfo, clientName)
// client_credential があるならcredentialがまだ使えるか確認する
if (!clientCredential.isNullOrEmpty()) {

// 存在確認するだけで、結果は使ってない
api.verifyClientCredential(apiHost, clientCredential)

// 過去にはスコープを+で連結したものを保存していた
val oldScope = clientInfo.string(KEY_CLIENT_SCOPE)
?.replace("+", " ")

when {
// クライアント情報を再利用する
!forceUpdateClient && oldScope == scopeString -> return clientInfo

else -> try {
// マストドン2.4でスコープが追加された
// 取得時のスコープ指定がマッチしない(もしくは記録されていない)ならクライアント情報を再利用してはいけない
daoClientInfo.delete(apiHost, clientName)

// クライアントアプリ情報そのものはまだサーバに残っているが、明示的に消す方法は現状存在しない
// client credential だけは消せる
api.revokeClientCredential(
apiHost = apiHost,
clientId = clientInfo.string("client_id")
?: error("revokeClientCredential: missing client_id"),
clientSecret = clientInfo.string("client_secret")
?: error("revokeClientCredential: missing client_secret"),
clientCredential = clientCredential,
)
} catch (ex: Throwable) {
// クライアント情報の削除処理はエラーが起きても無視する
log.w(ex, "can't delete client information.")
try {
when {
// 古いクライアント情報は使わない。削除もしない。
AUTH_VERSION != clientInfo?.int(KEY_AUTH_VERSION) -> Unit

// Misskeyにはclient情報をまだ利用できるかどうか調べる手段がないので、再利用しない
clientInfo.boolean(KEY_IS_MISSKEY) == true -> Unit

else -> {
val clientCredential = prepareClientCredential(apiHost, clientInfo, clientName)
// client_credential があるならcredentialがまだ使えるか確認する
if (!clientCredential.isNullOrEmpty()) {

// 存在確認するだけで、結果は使ってない
api.verifyClientCredential(apiHost, clientCredential)

// 過去にはスコープを+で連結したものを保存していた
val oldScope = clientInfo.string(KEY_CLIENT_SCOPE)
?.replace("+", " ")

when {
// クライアント情報を再利用する
!forceUpdateClient && oldScope == scopeString -> return clientInfo

else -> {
// マストドン2.4でスコープが追加された
// 取得時のスコープ指定がマッチしない(もしくは記録されていない)ならクライアント情報を再利用してはいけない
daoClientInfo.delete(apiHost, clientName)

// クライアントアプリ情報そのものはまだサーバに残っているが、明示的に消す方法は現状存在しない
// client credential だけは消せる
api.revokeClientCredential(
apiHost = apiHost,
clientId = clientInfo.string("client_id")
?: error("revokeClientCredential: missing client_id"),
clientSecret = clientInfo.string("client_secret")
?: error("revokeClientCredential: missing client_secret"),
clientCredential = clientCredential,
)
}
}
}
}
}
} catch (ex: Throwable) {
// クライアント再利用チェックやクライアント情報の削除処理はエラーが起きても無視する
log.w(ex, "can't verify/delete client information.")
}

clientInfo = api.registerClient(apiHost, scopeString, clientName, callbackUrl).apply {
// {"id":999,"redirect_uri":"urn:ietf:wg:oauth:2.0:oob","client_id":"******","client_secret":"******"}
put(KEY_AUTH_VERSION, AUTH_VERSION)
put(KEY_CLIENT_SCOPE, scopeString)
}
if(DEBUG_AUTH) log.i("DEBUG_AUTH client_id=${clientInfo.string("client_id")}")
if (DEBUG_AUTH) log.i("DEBUG_AUTH client_id=${clientInfo.string("client_id")}")
// client credentialを取得して保存する
// この時点ではまだ client credential がないので、必ず更新と保存が行われる
prepareClientCredential(apiHost, clientInfo, clientName)
Expand Down Expand Up @@ -295,7 +297,7 @@ class AuthMastodon(override val client: TootApiClient) : AuthBase() {

val accessToken = tokenInfo.string("access_token")
?.notEmpty() ?: error("can't parse access token.")
if(DEBUG_AUTH) log.i("DEBUG_AUTH accessToken=${accessToken}")
if (DEBUG_AUTH) log.i("DEBUG_AUTH accessToken=${accessToken}")

val accountJson = verifyAccount(
accessToken = accessToken,
Expand Down
10 changes: 6 additions & 4 deletions app/src/main/java/jp/juggler/subwaytooter/dialog/EmojiPicker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -204,20 +204,22 @@ private class EmojiPicker(
}

private inner class VhCategory(
parent: ViewGroup,
view: FrameLayout = FrameLayout(activity),
) : ViewHolderBase(view) {
var lastItem: PickerItemCategory? = null

val tv = AppCompatTextView(activity).apply {
layoutParams = FrameLayout.LayoutParams(matchParent, wrapContent)
minHeightCompat = (density * 48f + 0.5f).toInt()
gravity = Gravity.START or Gravity.CENTER_VERTICAL
includeFontPadding = false
background = ContextCompat.getDrawable(
this@EmojiPicker.activity,
R.drawable.btn_bg_transparent_round6dp
)
gravity = Gravity.START or Gravity.CENTER_VERTICAL
includeFontPadding = false
val paddingH = (density * 4f + 0.5f).toInt()
val paddingV = (density * 2f + 0.5f).toInt()
setPadding(paddingH,paddingV,paddingH,paddingV)
compoundDrawablePadding = (density * 4f + 0.5f).toInt()

setOnClickListener {
Expand Down Expand Up @@ -401,7 +403,7 @@ private class EmojiPicker(

override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int) =
when (viewType) {
VT_CATEGORY -> VhCategory(viewGroup)
VT_CATEGORY -> VhCategory()
VT_CUSTOM_EMOJI -> VhCustomEmoji()
VT_TWEMOJI -> VhTwemoji()
VT_COMPAT_EMOJI -> VhAppCompatEmoji()
Expand Down

0 comments on commit c4150b1

Please sign in to comment.