mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 02:29:55 +02:00
fix(receive): harden invitation open path and cover receive loop
Tighten cold-open and in-app invitation handling so ticket acquisition is stricter and less racey across hosts, and expand automated coverage for the receive history and acquisition flow before merge.
This commit is contained in:
@@ -24,11 +24,26 @@
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<!-- Preferred: exact VniDrop invitation MIME type. -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:mimeType="application/vnd.vnidrop.transfer"/>
|
||||
</intent-filter>
|
||||
<!-- Fallback: .vnd files often arrive as octet-stream / unknown MIME. -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="content"/>
|
||||
<data android:scheme="file"/>
|
||||
<data android:mimeType="*/*"/>
|
||||
<data android:pathPattern=".*\\.vnd"/>
|
||||
<data android:pathPattern=".*\\..*\\.vnd"/>
|
||||
<data android:pathPattern=".*\\..*\\..*\\.vnd"/>
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.vnd"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
||||
@@ -11,8 +11,7 @@ import com.vnidrop.app.feature.receive.ExternalInvitationController
|
||||
import com.vnidrop.app.feature.receive.MaxVniDropInvitationBytes
|
||||
import com.vnidrop.app.feature.receive.VniDropInvitationExtension
|
||||
import com.vnidrop.app.feature.receive.VniDropInvitationMimeType
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.charset.CodingErrorAction
|
||||
import com.vnidrop.app.feature.receive.decodeInvitationBytes
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -53,15 +52,13 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
private fun readInvitation(uri: Uri, declaredType: String?): Result<String> = runCatching {
|
||||
val resolvedType = declaredType ?: contentResolver.getType(uri)
|
||||
val hasExpectedName = uri.lastPathSegment?.endsWith(".$VniDropInvitationExtension", ignoreCase = true) == true
|
||||
val path = uri.path.orEmpty()
|
||||
val lastSegment = uri.lastPathSegment.orEmpty()
|
||||
val hasExpectedName = lastSegment.endsWith(".$VniDropInvitationExtension", ignoreCase = true) ||
|
||||
path.endsWith(".$VniDropInvitationExtension", ignoreCase = true)
|
||||
require(resolvedType == VniDropInvitationMimeType || hasExpectedName) { "This is not a VniDrop invitation" }
|
||||
val bytes = contentResolver.openInputStream(uri)?.use { it.readNBytes(MaxVniDropInvitationBytes + 1) }
|
||||
?: error("The invitation could not be opened")
|
||||
require(bytes.size <= MaxVniDropInvitationBytes) { "The invitation is too large" }
|
||||
Charsets.UTF_8.newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT)
|
||||
.decode(ByteBuffer.wrap(bytes))
|
||||
.toString()
|
||||
decodeInvitationBytes(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user