mirror of
https://github.com/corda/corda.git
synced 2025-01-18 18:56:28 +00:00
CORDA-2112 Update the uploader
field for Attachments loaded upon Node CorDapp startup (#4127)
* CORDA-2112 Update the `uploader` field upon Node startup for CorDapps where an Attachment is already in a nodes attachment store (from an untrusted source). * Removed incorrect assertion. * Fix broken unit test. * Reverted back throw FileAlreadyExistsException API semantics on public API. * De-duplicate DuplicateAttachmentException * Revert original Exception handling logic.
This commit is contained in:
parent
13815d252e
commit
e064800173
@ -2,6 +2,7 @@ package net.corda.node.services.persistence
|
||||
|
||||
import net.corda.core.node.services.AttachmentId
|
||||
import net.corda.core.node.services.AttachmentStorage
|
||||
import net.corda.nodeapi.exceptions.DuplicateAttachmentException
|
||||
import java.io.InputStream
|
||||
|
||||
interface AttachmentStorageInternal : AttachmentStorage {
|
||||
@ -10,4 +11,9 @@ interface AttachmentStorageInternal : AttachmentStorage {
|
||||
* and is only for the node.
|
||||
*/
|
||||
fun privilegedImportAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId
|
||||
|
||||
/**
|
||||
* Similar to above but returns existing [AttachmentId] instead of throwing [DuplicateAttachmentException]
|
||||
*/
|
||||
fun privilegedImportOrGetAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId
|
||||
}
|
||||
|
@ -6,13 +6,11 @@ import com.google.common.hash.HashCode
|
||||
import com.google.common.hash.Hashing
|
||||
import com.google.common.hash.HashingInputStream
|
||||
import com.google.common.io.CountingInputStream
|
||||
import net.corda.core.ClientRelevantError
|
||||
import net.corda.core.CordaRuntimeException
|
||||
import net.corda.core.contracts.Attachment
|
||||
import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.node.ServicesForResolution
|
||||
@ -286,6 +284,14 @@ class NodeAttachmentService(
|
||||
return import(jar, uploader, filename)
|
||||
}
|
||||
|
||||
override fun privilegedImportOrGetAttachment(jar: InputStream, uploader: String, filename: String?): AttachmentId {
|
||||
return try {
|
||||
import(jar, uploader, filename)
|
||||
} catch (faee: java.nio.file.FileAlreadyExistsException) {
|
||||
AttachmentId.parse(faee.message!!)
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasAttachment(attachmentId: AttachmentId): Boolean = database.transaction {
|
||||
currentDBSession().find(NodeAttachmentService.DBAttachment::class.java, attachmentId.toString()) != null
|
||||
}
|
||||
@ -306,9 +312,7 @@ class NodeAttachmentService(
|
||||
val id = bytes.sha256()
|
||||
if (!hasAttachment(id)) {
|
||||
checkIsAValidJAR(bytes.inputStream())
|
||||
|
||||
val jarSigners = getSigners(bytes)
|
||||
|
||||
val session = currentDBSession()
|
||||
val attachment = NodeAttachmentService.DBAttachment(
|
||||
attId = id.toString(),
|
||||
@ -318,14 +322,24 @@ class NodeAttachmentService(
|
||||
contractClassNames = contractClassNames,
|
||||
signers = jarSigners
|
||||
)
|
||||
|
||||
session.save(attachment)
|
||||
attachmentCount.inc()
|
||||
log.info("Stored new attachment $id")
|
||||
id
|
||||
} else {
|
||||
throw DuplicateAttachmentException(id.toString())
|
||||
return@withContractsInJar id
|
||||
}
|
||||
if (isUploaderTrusted(uploader)) {
|
||||
val session = currentDBSession()
|
||||
val attachment = session.get(NodeAttachmentService.DBAttachment::class.java, id.toString())
|
||||
// update the `upLoader` field (as the existing attachment may have been resolved from a peer)
|
||||
if (attachment.uploader != uploader) {
|
||||
attachment.uploader = uploader
|
||||
session.saveOrUpdate(attachment)
|
||||
log.info("Updated attachment $id with uploader $uploader")
|
||||
attachmentCache.invalidate(id)
|
||||
attachmentContentCache.invalidate(id)
|
||||
}
|
||||
}
|
||||
throw DuplicateAttachmentException(id.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import com.nhaarman.mockito_kotlin.whenever
|
||||
import net.corda.core.JarSignatureTestUtils.createJar
|
||||
import net.corda.core.JarSignatureTestUtils.generateKey
|
||||
import net.corda.core.JarSignatureTestUtils.signJar
|
||||
import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.flows.FlowLogic
|
||||
@ -47,6 +48,7 @@ import javax.tools.StandardLocation
|
||||
import javax.tools.ToolProvider
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
|
||||
@ -123,6 +125,30 @@ class NodeAttachmentServiceTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `insert contract attachment as an untrusted uploader and then as trusted CorDapp uploader`() {
|
||||
val contractJarName = makeTestContractJar("com.example.MyContract")
|
||||
val testJar = dir.resolve(contractJarName)
|
||||
val expectedHash = testJar.readAll().sha256()
|
||||
|
||||
// PRIVILEGED_UPLOADERS = listOf(DEPLOYED_CORDAPP_UPLOADER, RPC_UPLOADER, P2P_UPLOADER, UNKNOWN_UPLOADER)
|
||||
// TRUSTED_UPLOADERS = listOf(DEPLOYED_CORDAPP_UPLOADER, RPC_UPLOADER)
|
||||
|
||||
database.transaction {
|
||||
val id = testJar.read { storage.privilegedImportOrGetAttachment(it, P2P_UPLOADER, null) }
|
||||
assertEquals(expectedHash, id)
|
||||
val attachment1 = storage.openAttachment(expectedHash)
|
||||
|
||||
val id2 = testJar.read { storage.privilegedImportOrGetAttachment(it, DEPLOYED_CORDAPP_UPLOADER, null) }
|
||||
assertEquals(expectedHash, id2)
|
||||
val attachment2 = storage.openAttachment(expectedHash)
|
||||
|
||||
assertNotEquals(attachment1, attachment2)
|
||||
assertEquals(P2P_UPLOADER, (attachment1 as ContractAttachment).uploader)
|
||||
assertEquals(DEPLOYED_CORDAPP_UPLOADER, (attachment2 as ContractAttachment).uploader)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `missing is not cached`() {
|
||||
val (testJar, expectedHash) = makeTestJar()
|
||||
|
Loading…
Reference in New Issue
Block a user