fix: harden captcha and long poll parsing

This commit is contained in:
Codex
2026-05-18 20:45:41 +03:00
parent 255a194c25
commit c18a7963bf
5 changed files with 124 additions and 167 deletions
@@ -21,8 +21,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
internal class LongPollEventParser(
private val coroutineScope: CoroutineScope,
@@ -35,7 +35,7 @@ internal class LongPollEventParser(
val eventId = event.first().asInt()
when (val eventType = ApiEvent.parseOrNull(eventId)) {
null -> Log.d("LongPollEventParser", "parseNextUpdate: unknownEvent: $event")
null -> Unit
ApiEvent.MESSAGE_SET_FLAGS -> parseMessageSetFlags(eventType, event)
ApiEvent.MESSAGE_CLEAR_FLAGS -> parseMessageClearFlags(eventType, event)
@@ -62,8 +62,6 @@ internal class LongPollEventParser(
}
private fun parseMessageSetFlags(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val cmId = event[1].asLong()
val flags = event[2].asInt()
val peerId = event[3].asLong()
@@ -128,8 +126,6 @@ internal class LongPollEventParser(
}
private fun parseMessageClearFlags(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val cmId = event[1].asLong()
val flags = event[2].asInt()
val peerId = event[3].asLong()
@@ -192,8 +188,6 @@ internal class LongPollEventParser(
}
private fun parseMessageNew(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val cmId = event[1].asLong()
val peerId = event[4].asLong()
@@ -223,8 +217,6 @@ internal class LongPollEventParser(
}
private fun parseMessageEdit(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val cmId = event[1].asLong()
val peerId = event[3].asLong()
@@ -239,40 +231,28 @@ internal class LongPollEventParser(
}
private fun parseMessageReadIncoming(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val peerId = event[1].asLong()
val cmId = event[2].asLong()
val unreadCount = event[3].asInt()
dispatch(
LongPollEvent.INCOMING_MESSAGE_READ,
LongPollParsedEvent.IncomingMessageRead(
peerId = peerId,
cmId = cmId,
unreadCount = unreadCount
dispatchMessageRead(
longPollEvent = LongPollEvent.INCOMING_MESSAGE_READ,
parsedEvent = LongPollParsedEvent.IncomingMessageRead(
peerId = event[1].asLong(),
cmId = event[2].asLong(),
unreadCount = event[3].asInt()
)
)
}
private fun parseMessageReadOutgoing(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val peerId = event[1].asLong()
val cmId = event[2].asLong()
val unreadCount = event[3].asInt()
dispatch(
LongPollEvent.OUTGOING_MESSAGE_READ,
LongPollParsedEvent.OutgoingMessageRead(
peerId = peerId,
cmId = cmId,
unreadCount = unreadCount
dispatchMessageRead(
longPollEvent = LongPollEvent.OUTGOING_MESSAGE_READ,
parsedEvent = LongPollParsedEvent.OutgoingMessageRead(
peerId = event[1].asLong(),
cmId = event[2].asLong(),
unreadCount = event[3].asInt()
)
)
}
private fun parseChatClearFlags(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val peerId = event[1].asLong()
val flags = event[2].asInt()
@@ -284,23 +264,11 @@ internal class LongPollEventParser(
parsedFlags.forEach { flag ->
when (flag) {
ConvoFlags.ARCHIVED -> {
val convo = loadConvo(
handleArchivedChat(
peerId = peerId,
extended = true,
fields = VkConstants.ALL_FIELDS
) ?: return@forEach
val message = loadMessage(
peerId = peerId,
cmId = convo.lastCmId
archived = false,
eventsToSend = eventsToSend
)
val eventToSend = LongPollParsedEvent.ChatArchived(
convo = convo.copy(lastMessage = message),
archived = false
)
eventsToSend += eventToSend
dispatch(LongPollEvent.CHAT_ARCHIVED, eventToSend)
}
else -> Unit
@@ -312,8 +280,6 @@ internal class LongPollEventParser(
}
private fun parseChatSetFlags(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val peerId = event[1].asLong()
val flags = event[2].asInt()
@@ -325,23 +291,11 @@ internal class LongPollEventParser(
parsedFlags.forEach { flag ->
when (flag) {
ConvoFlags.ARCHIVED -> {
val convo = loadConvo(
handleArchivedChat(
peerId = peerId,
extended = true,
fields = VkConstants.ALL_FIELDS
) ?: return@forEach
val message = loadMessage(
peerId = peerId,
cmId = convo.lastCmId
archived = true,
eventsToSend = eventsToSend
)
val eventToSend = LongPollParsedEvent.ChatArchived(
convo = convo.copy(lastMessage = message),
archived = true
)
eventsToSend += eventToSend
dispatch(LongPollEvent.CHAT_ARCHIVED, eventToSend)
}
else -> Unit
@@ -353,8 +307,6 @@ internal class LongPollEventParser(
}
private fun parseMessagesDeleted(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val peerId = event[1].asLong()
val cmId = event[2].asLong()
@@ -368,8 +320,6 @@ internal class LongPollEventParser(
}
private fun parseChatMajorChanged(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val peerId = event[1].asLong()
val majorId = event[2].asInt()
@@ -383,8 +333,6 @@ internal class LongPollEventParser(
}
private fun parseChatMinorChanged(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val peerId = event[1].asLong()
val minorId = event[2].asInt()
@@ -398,8 +346,6 @@ internal class LongPollEventParser(
}
private fun parseInteraction(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType: $event")
val interactionType = when (eventType) {
ApiEvent.TYPING -> InteractionType.Typing
ApiEvent.AUDIO_MESSAGE_RECORDING -> InteractionType.VoiceMessage
@@ -438,8 +384,6 @@ internal class LongPollEventParser(
}
private fun parseUnreadCounterUpdate(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType $event")
val unreadCount = event[1].asInt()
val unreadUnmutedCount = event[2].asInt()
val showOnlyMuted = event[3].asInt() == 1
@@ -463,8 +407,6 @@ internal class LongPollEventParser(
}
private fun parseMessageUpdated(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType $event")
val cmId = event[1].asLong()
val peerId = event[4].asLong()
@@ -479,8 +421,6 @@ internal class LongPollEventParser(
}
private fun parseMessageCacheClear(eventType: ApiEvent, event: List<Any>) {
Log.d("LongPollEventParser", "$eventType $event")
val messageId = event[1].asLong()
coroutineScope.launch(Dispatchers.IO) {
@@ -497,10 +437,10 @@ internal class LongPollEventParser(
peerId: Long? = null,
cmId: Long? = null,
messageId: Long? = null
): VkMessage? = suspendCoroutine { continuation ->
): VkMessage? = suspendCancellableCoroutine { continuation ->
require((peerId != null && cmId != null) || messageId != null)
coroutineScope.launch(Dispatchers.IO) {
val job = coroutineScope.launch(Dispatchers.IO) {
messagesUseCase.getById(
peerCmIds = null,
peerId = peerId,
@@ -525,14 +465,18 @@ internal class LongPollEventParser(
)
}
}
continuation.invokeOnCancellation {
job.cancel()
}
}
private suspend fun loadConvo(
peerId: Long,
extended: Boolean = false,
fields: String? = null
): VkConvo? = suspendCoroutine { continuation ->
coroutineScope.launch(Dispatchers.IO) {
): VkConvo? = suspendCancellableCoroutine { continuation ->
val job = coroutineScope.launch(Dispatchers.IO) {
convoUseCase.getById(
peerIds = listOf(peerId),
extended = extended,
@@ -554,5 +498,40 @@ internal class LongPollEventParser(
)
}
}
continuation.invokeOnCancellation {
job.cancel()
}
}
private suspend fun handleArchivedChat(
peerId: Long,
archived: Boolean,
eventsToSend: MutableList<LongPollParsedEvent>
) {
val convo = loadConvo(
peerId = peerId,
extended = true,
fields = VkConstants.ALL_FIELDS
) ?: return
val message = loadMessage(
peerId = peerId,
cmId = convo.lastCmId
)
val eventToSend = LongPollParsedEvent.ChatArchived(
convo = convo.copy(lastMessage = message),
archived = archived
)
eventsToSend += eventToSend
dispatch(LongPollEvent.CHAT_ARCHIVED, eventToSend)
}
private fun dispatchMessageRead(
longPollEvent: LongPollEvent,
parsedEvent: LongPollParsedEvent
) {
dispatch(longPollEvent, parsedEvent)
}
}
@@ -22,22 +22,35 @@ class OAuthUseCaseImpl(
): Flow<State<AuthInfo>> = flow {
emit(State.Loading)
val newState = oAuthRepository.auth(
val newState = when (val authResult = oAuthRepository.auth(
login = login,
password = password,
forceSms = forceSms,
validationCode = validationCode,
captchaSid = captchaSid,
captchaKey = captchaKey
).asState(
successMapper = {
AuthInfo(
userId = it.userId!!,
accessToken = it.accessToken!!,
validationHash = it.validationHash!!
)
)) {
is com.slack.eithernet.ApiResult.Success -> {
val value = authResult.value
val userId = value.userId
val accessToken = value.accessToken
val validationHash = value.validationHash
if (userId == null || accessToken == null || validationHash == null) {
State.Error.InternalError
} else {
State.Success(
AuthInfo(
userId = userId,
accessToken = accessToken,
validationHash = validationHash
)
)
}
}
)
else -> authResult.asState()
}
emit(newState)
}