Skip to content

Commit

Permalink
fix(FilePublicSessionKeyStore): Include nodeId in scope (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
gnarea authored Dec 17, 2023
1 parent 794e198 commit 5cd0863
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 33 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies {
// Align versions of all Kotlin components
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))

api("tech.relaycorp:awala:[1.66.4,2.0.0)")
api("tech.relaycorp:awala:[1.68.2,2.0.0)")
testImplementation("tech.relaycorp:awala-testing:1.5.26")

implementation("org.mongodb:bson:4.11.1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ public class FileSessionPublicKeystore(
@Suppress("MemberVisibilityCanBePrivate")
public val rootDirectory: File = keystoreRoot.directory.resolve("public")

override suspend fun saveKeyData(keyData: SessionPublicKeyData, peerId: String) {
override suspend fun saveKeyData(
keyData: SessionPublicKeyData,
nodeId: String,
peerId: String
) {
val wasDirectoryCreated = rootDirectory.mkdirs()
if (!wasDirectoryCreated && !rootDirectory.exists()) {
throw FileKeystoreException("Failed to create root directory for public keys")
}

val keyDataFile = getKeyDataFile(peerId)
val keyDataFile = getKeyDataFile(nodeId, peerId)
val bsonSerialization = BasicOutputBuffer().use { buffer ->
BsonBinaryWriter(buffer).use {
it.writeStartDocument()
Expand All @@ -41,8 +45,8 @@ public class FileSessionPublicKeystore(
}
}

override suspend fun retrieveKeyData(peerId: String): SessionPublicKeyData? {
val keyDataFile = getKeyDataFile(peerId)
override suspend fun retrieveKeyData(nodeId: String, peerId: String): SessionPublicKeyData? {
val keyDataFile = getKeyDataFile(nodeId, peerId)
val serialization = try {
keyDataFile.readBytes()
} catch (exc: IOException) {
Expand All @@ -66,11 +70,11 @@ public class FileSessionPublicKeystore(
return data
}

override suspend fun delete(peerId: String) {
val keyDataFile = getKeyDataFile(peerId)
override suspend fun delete(nodeId: String, peerId: String) {
val keyDataFile = getKeyDataFile(nodeId, peerId)
keyDataFile.delete()
}

private fun getKeyDataFile(peerId: String) =
rootDirectory.resolve(peerId)
private fun getKeyDataFile(nodeId: String, peerId: String) =
rootDirectory.resolve("$nodeId-$peerId")
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,22 @@ import tech.relaycorp.relaynet.testing.pki.PDACertPath
@ExperimentalCoroutinesApi
@Suppress("BlockingMethodInNonBlockingContext")
class FileSessionPublicKeystoreTest : KeystoreTestCase() {
private val nodeId = PDACertPath.PDA.issuerCommonName
private val peerId = PDACertPath.PDA.subjectId

private val sessionKeyPair = SessionKeyPair.generate()

private val publicKeystoreRootPath = keystoreRoot.directory.resolve("public").toPath()
private val keyDataFilePath = publicKeystoreRootPath.resolve(peerId)
private val keyDataFilePath = publicKeystoreRootPath.resolve("$nodeId-$peerId")

@Nested
inner class Save {
@Test
fun `Keystore directory should be reused if it already exists`() = runTest {
@Suppress("BlockingMethodInNonBlockingContext")
publicKeystoreRootPath.createDirectory()
val keystore = FileSessionPublicKeystore(keystoreRoot)

keystore.save(sessionKeyPair.sessionKey, peerId)
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId)

readKeyData()
}
Expand All @@ -55,7 +55,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
assertFalse(publicKeystoreRootPath.exists())
val keystore = FileSessionPublicKeystore(keystoreRoot)

keystore.save(sessionKeyPair.sessionKey, peerId)
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId)

readKeyData()
}
Expand All @@ -65,7 +65,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
keystoreRoot.directory.delete()
val keystore = FileSessionPublicKeystore(keystoreRoot)

keystore.save(sessionKeyPair.sessionKey, peerId)
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId)

readKeyData()
}
Expand All @@ -78,7 +78,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
val keystore = FileSessionPublicKeystore(keystoreRoot)

val exception = assertThrows<FileKeystoreException> {
keystore.save(sessionKeyPair.sessionKey, peerId)
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId)
}

assertEquals(
Expand All @@ -93,7 +93,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
val creationTime = ZonedDateTime.now()
val keystore = FileSessionPublicKeystore(keystoreRoot)

keystore.save(sessionKeyPair.sessionKey, peerId, creationTime)
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId, creationTime)

val savedKeyData = readKeyData()
assertEquals(
Expand All @@ -114,10 +114,10 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
fun `Existing file should be updated if there is a prior key for peer`() = runTest {
val now = ZonedDateTime.now()
val keystore = FileSessionPublicKeystore(keystoreRoot)
keystore.save(sessionKeyPair.sessionKey, peerId, now.minusSeconds(1))
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId, now.minusSeconds(1))
val (newSessionKey) = SessionKeyPair.generate()

keystore.save(newSessionKey, peerId, now)
keystore.save(newSessionKey, nodeId, peerId, now)

val savedKeyData = readKeyData()
assertEquals(
Expand All @@ -140,13 +140,14 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
// Make the read operation work but the subsequent write operation fail
keystore.save(
sessionKeyPair.sessionKey,
nodeId,
peerId,
ZonedDateTime.now().minusDays(1)
)
keyDataFilePath.toFile().setWritable(false)

val exception = assertThrows<FileKeystoreException> {
keystore.save(sessionKeyPair.sessionKey, peerId)
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId)
}

assertEquals(
Expand Down Expand Up @@ -177,14 +178,14 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
publicKeystoreRootPath.deleteExisting()
val keystore = FileSessionPublicKeystore(keystoreRoot)

assertThrows<MissingKeyException> { keystore.retrieve(peerId) }
assertThrows<MissingKeyException> { keystore.retrieve(nodeId, peerId) }
}

@Test
fun `Key should be reported as missing if the file doesn't exist`() = runTest {
val keystore = FileSessionPublicKeystore(keystoreRoot)

assertThrows<MissingKeyException> { keystore.retrieve(peerId) }
assertThrows<MissingKeyException> { keystore.retrieve(nodeId, peerId) }
}

@Test
Expand All @@ -195,7 +196,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
val keystore = FileSessionPublicKeystore(keystoreRoot)

val exception = assertThrows<FileKeystoreException> {
keystore.retrieve(peerId)
keystore.retrieve(nodeId, peerId)
}

assertEquals("Failed to read key file", exception.message)
Expand All @@ -208,7 +209,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
val keystore = FileSessionPublicKeystore(keystoreRoot)

val exception = assertThrows<FileKeystoreException> {
keystore.retrieve(peerId)
keystore.retrieve(nodeId, peerId)
}

assertEquals("Key file is malformed", exception.message)
Expand All @@ -224,7 +225,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
val keystore = FileSessionPublicKeystore(keystoreRoot)

val exception = assertThrows<FileKeystoreException> {
keystore.retrieve(peerId)
keystore.retrieve(nodeId, peerId)
}

assertEquals("Key file is malformed", exception.message)
Expand All @@ -240,7 +241,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
val keystore = FileSessionPublicKeystore(keystoreRoot)

val exception = assertThrows<FileKeystoreException> {
keystore.retrieve(peerId)
keystore.retrieve(nodeId, peerId)
}

assertEquals("Key file is malformed", exception.message)
Expand All @@ -256,7 +257,7 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
val keystore = FileSessionPublicKeystore(keystoreRoot)

val exception = assertThrows<FileKeystoreException> {
keystore.retrieve(peerId)
keystore.retrieve(nodeId, peerId)
}

assertEquals("Key file is malformed", exception.message)
Expand All @@ -266,9 +267,9 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
@Test
fun `Data should be returned if file exists and is valid`() = runTest {
val keystore = FileSessionPublicKeystore(keystoreRoot)
keystore.save(sessionKeyPair.sessionKey, peerId)
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId)

val key = keystore.retrieve(peerId)
val key = keystore.retrieve(nodeId, peerId)

assertEquals(sessionKeyPair.sessionKey, key)
}
Expand Down Expand Up @@ -300,24 +301,24 @@ class FileSessionPublicKeystoreTest : KeystoreTestCase() {
publicKeystoreRootPath.deleteExisting()
val keystore = FileSessionPublicKeystore(keystoreRoot)

keystore.delete(peerId)
keystore.delete(nodeId, peerId)
}

@Test
fun `Deletion should be skipped if the file doesn't exist`() = runTest {
val keystore = FileSessionPublicKeystore(keystoreRoot)

keystore.delete(peerId)
keystore.delete(nodeId, peerId)
}

@Test
fun `File should be deleted if it exists`() = runTest {
val keystore = FileSessionPublicKeystore(keystoreRoot)
keystore.save(sessionKeyPair.sessionKey, peerId)
keystore.save(sessionKeyPair.sessionKey, nodeId, peerId)

keystore.delete(peerId)
keystore.delete(nodeId, peerId)

assertThrows<MissingKeyException> { keystore.retrieve(peerId) }
assertThrows<MissingKeyException> { keystore.retrieve(nodeId, peerId) }
}
}
}

0 comments on commit 5cd0863

Please sign in to comment.