1package com.peachpasswords.passkeys23import java.io.File4import org.junit.Assert.assertEquals5import org.junit.Assert.assertFalse6import org.junit.Assert.assertTrue7import org.junit.Test89class CredentialProviderContractTest {10 @Test11 fun authenticationActionPendingIntentIsMutableForFrameworkRequestAttachment() {12 val source = source("passkeys/PasskeyUnlockIntent.kt")1314 assertTrue(source.contains("PendingIntent.FLAG_MUTABLE"))15 assertFalse(source.contains("PendingIntent.FLAG_IMMUTABLE"))16 }1718 @Test19 fun selectedRowUsesOnlyTheFinalProviderRequest() {20 val selection = source("passkeys/PasskeyCredentialSelectionActivity.kt")2122 assertTrue(selection.contains("retrieveProviderGetCredentialRequest(intent)"))23 assertFalse(selection.contains("selectionOrigin("))24 assertFalse(selection.contains("selectionClientDataHash("))25 assertFalse(selection.contains("selectionRequestJson("))26 assertFalse(selection.contains("selectionRequiresUserVerification("))27 assertFalse(selection.contains("EXTRA_AUTHENTICATED_CLIENT_DATA_HASH"))28 }2930 @Test31 fun providerOffersAnExplicitManualPasskeyChooser() {32 val service = source("passkeys/PeachCredentialProviderService.kt")33 val unlock = source("credentials/CredentialProviderUnlockActivity.kt")34 val selection = source("passkeys/PasskeyCredentialSelectionActivity.kt")3536 assertTrue(service.contains("Choose another Peach passkey"))37 assertTrue(unlock.contains("Choose another Peach passkey"))38 assertTrue(selection.contains("retrieveBeginGetCredentialRequest(intent)"))39 assertTrue(selection.contains("PasskeyCredentialPlanner.candidates"))40 }4142 @Test43 fun api35PasskeyRowsDelegateVerificationToCredentialManager() {44 val service = source("passkeys/PeachCredentialProviderService.kt")45 val unlock = source("credentials/CredentialProviderUnlockActivity.kt")46 val factory = source("passkeys/PasskeyCredentialEntryFactory.kt")4748 assertTrue(service.contains("PasskeyCredentialEntryFactory.create"))49 assertTrue(unlock.contains("PasskeyCredentialEntryFactory.create"))50 assertTrue(factory.contains("Build.VERSION_CODES.VANILLA_ICE_CREAM"))51 assertTrue(factory.contains("setBiometricPromptData"))52 assertTrue(factory.contains("BIOMETRIC_STRONG or DEVICE_CREDENTIAL"))53 }5455 @Test56 fun credentialManagerVerificationResultHasOneOwner() {57 assertEquals(58 PasskeyVerificationRoute.ACCEPT,59 passkeyVerificationRoute(60 verifiedByUnlock = false,61 hasEmbeddedResult = true,62 embeddedSucceeded = true,63 ),64 )65 assertEquals(66 PasskeyVerificationRoute.REJECT,67 passkeyVerificationRoute(68 verifiedByUnlock = false,69 hasEmbeddedResult = true,70 embeddedSucceeded = false,71 ),72 )73 assertEquals(74 PasskeyVerificationRoute.PROMPT_IN_PEACH,75 passkeyVerificationRoute(76 verifiedByUnlock = false,77 hasEmbeddedResult = false,78 embeddedSucceeded = false,79 ),80 )81 assertEquals(82 PasskeyVerificationRoute.ACCEPT,83 passkeyVerificationRoute(84 verifiedByUnlock = true,85 hasEmbeddedResult = false,86 embeddedSucceeded = false,87 ),88 )89 }9091 @Test92 fun authenticatedUnlockPreservesVaultForExactlyTheCredentialManagerHandoff() {93 val unlock = source("credentials/CredentialProviderUnlockActivity.kt")9495 assertTrue(unlock.contains("vault.expectTransientBackground()"))96 assertTrue(unlock.contains("verifiedByUnlock = true"))97 assertTrue(source("passkeys/PasskeyCredentialSelectionActivity.kt").contains("PendingIntent.FLAG_ONE_SHOT"))98 }99100 @Test101 fun pendingIntentRequestCodesAreNeverReusedWithinAProcess() {102 val codes = (1..1_000).map { PasskeyPendingIntentIds.next() }103104 assertEquals(codes.size, codes.toSet().size)105 }106107 private fun source(relativePath: String): String =108 File("src/main/java/com/peachpasswords/$relativePath").readText()109}