mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-09-19 04:59:59 +00:00
Match the persisted peer state on its fingerprint field
findAuthenticatedFingerprintByPeerID took the first stored record that began with the peer ID. If that record's first field was not a fingerprint, the search stopped there with nothing found. The lookup now reads the fingerprint field of each record and takes the one that is 64 hex characters starting with the peer ID, skipping any record whose field is not a fingerprint. Records this app writes behave the same as before. One test puts a record whose first field is not a fingerprint ahead of the real one and checks that the real one is still found.
This commit is contained in:
parent
e1da7f8960
commit
605958b405
@ -393,16 +393,27 @@ class SecureIdentityStateManager {
|
||||
|
||||
/**
|
||||
* Fingerprint of the persisted authenticated peer state for a peer ID. A peer ID is the
|
||||
* first sixteen hex characters of the fingerprint of its Noise static key, so a record
|
||||
* whose fingerprint starts with the peer ID is that peer's; the record must still parse.
|
||||
* first sixteen hex characters of the fingerprint of its Noise static key. Each record is
|
||||
* matched on its fingerprint field, 64 hex characters starting with the peer ID; a record
|
||||
* whose field does not parse is skipped, and the matched record must still load.
|
||||
*/
|
||||
fun findAuthenticatedFingerprintByPeerID(peerID: String): String? {
|
||||
val prefix = peerID.lowercase()
|
||||
if (prefix.length != 16 || !prefix.all { it in '0'..'9' || it in 'a'..'f' }) return null
|
||||
val records = prefs.getStringSet(KEY_AUTHENTICATED_PEER_STATES, emptySet()) ?: return null
|
||||
val fingerprint = records.firstOrNull { it.startsWith(prefix) }?.substringBefore(':') ?: return null
|
||||
return fingerprint.takeIf { isValidFingerprint(it) && getAuthenticatedPeerState(it) != null }
|
||||
val fingerprint = fingerprintFieldFor(prefix, records) ?: return null
|
||||
return fingerprint.takeIf { getAuthenticatedPeerState(it) != null }
|
||||
}
|
||||
|
||||
/**
|
||||
* The fingerprint field of the first record, in the order given, that parses to 64 hex
|
||||
* characters starting with [prefix]. A record whose field does not parse is skipped, not
|
||||
* taken for a match on the raw string.
|
||||
*/
|
||||
internal fun fingerprintFieldFor(prefix: String, records: Iterable<String>): String? =
|
||||
records.asSequence()
|
||||
.map { it.substringBefore(':').lowercase() }
|
||||
.firstOrNull { isValidFingerprint(it) && it.startsWith(prefix) }
|
||||
|
||||
// MARK: - Peer ID Rotation Management (removed)
|
||||
// Android now derives peer ID from the persisted Noise identity fingerprint.
|
||||
|
||||
@ -52,4 +52,15 @@ class SecureAuthenticatedPeerStateStoreTest {
|
||||
assertNull("a cached nickname is not a persisted identity", store.persistedFingerprintFor(peerID))
|
||||
assertNull(store.load(fingerprint))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a record whose fingerprint field is not 64 hex is ignored`() {
|
||||
val (_, identity) = freshStore()
|
||||
// The raw string starts with the peer ID but the fingerprint field is only 16 characters.
|
||||
// Examined first, it must be skipped and the real record still found.
|
||||
val malformed = "$peerID:0:${"00".repeat(32)}"
|
||||
val real = "$fingerprint:0:${"5a".repeat(32)}"
|
||||
|
||||
assertEquals(fingerprint, identity.fingerprintFieldFor(peerID, listOf(malformed, real)))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user