diff --git a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/data/RepositoryDataType.scala b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/data/RepositoryDataType.scala index ccdd261e..f4eb6355 100644 --- a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/data/RepositoryDataType.scala +++ b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/data/RepositoryDataType.scala @@ -5,13 +5,13 @@ import java.time.Instant import akka.http.scaladsl.model.Uri import com.advancedtelematic.libats.data.DataType.Checksum +import com.advancedtelematic.libtuf.crypt.CanonicalJson._ import com.advancedtelematic.libtuf.data.ClientDataType.{MetaItem, MetaPath, _} -import com.advancedtelematic.libtuf.data.TufDataType.{JsonSignedPayload, RepoId, TargetFilename} -import io.circe.syntax._ import com.advancedtelematic.libtuf.data.TufCodecs._ -import com.advancedtelematic.libtuf.crypt.CanonicalJson._ +import com.advancedtelematic.libtuf.data.TufDataType.{JsonSignedPayload, RepoId, TargetFilename} import com.advancedtelematic.libtuf_server.crypto.Sha256Digest -import io.circe.{Decoder, Json} +import io.circe.Decoder +import io.circe.syntax._ object RepositoryDataType { object StorageMethod extends Enumeration { @@ -25,7 +25,11 @@ object RepositoryDataType { case class SignedRole[T : TufRole](repoId: RepoId, content: JsonSignedPayload, checksum: Checksum, length: Long, version: Int, expiresAt: Instant) { def role(implicit dec: Decoder[T]): T = - RepositoryDataType.role[T](content.signed) + content.signed.as[T] match { + case Left(err) => + throw new IllegalArgumentException(s"Could not decode a role saved in database as ${implicitly[TufRole[T]]} but not parseable as such a type: $err") + case Right(p) => p + } def asMetaRole: (MetaPath, MetaItem) = { val hashes = Map(checksum.method -> checksum.hash) @@ -35,19 +39,6 @@ object RepositoryDataType { def tufRole: TufRole[T] = implicitly[TufRole[T]] } - private def role[T: TufRole](json: Json)(implicit dec: Decoder[T]): T = json.as[T] match { - case Left(err) => - throw new IllegalArgumentException(s"Could not decode a role saved in database as ${implicitly[TufRole[T]]} but not parseable as such a type: $err") - case Right(p) => p - } - - def asMetaItem(content: JsonSignedPayload)(implicit dec: Decoder[TargetsRole]): MetaItem = { - val canonicalJson = content.asJson.canonical - val checksum = Sha256Digest.digest(canonicalJson.getBytes) - val hashes = Map(checksum.method -> checksum.hash) - MetaItem(hashes, canonicalJson.length, role[TargetsRole](content.signed).version) - } - object SignedRole { def withChecksum[T : TufRole](repoId: RepoId, content: JsonSignedPayload, version: Int, expireAt: Instant): SignedRole[T] = { val canonicalJson = content.asJson.canonical diff --git a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/db/Repository.scala b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/db/Repository.scala index 62ed2454..2d0be7c4 100644 --- a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/db/Repository.scala +++ b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/db/Repository.scala @@ -16,7 +16,7 @@ import com.advancedtelematic.libats.slick.db.SlickExtensions._ import com.advancedtelematic.libats.slick.codecs.SlickRefined._ import com.advancedtelematic.libats.slick.db.SlickUUIDKey._ import com.advancedtelematic.libats.slick.db.SlickAnyVal._ -import com.advancedtelematic.libtuf.data.ClientDataType.{DelegatedRoleName, TufRole} +import com.advancedtelematic.libtuf.data.ClientDataType.{DelegatedRoleName, SnapshotRole, TimestampRole, TufRole} import com.advancedtelematic.libtuf_server.data.Requests.TargetComment import com.advancedtelematic.libtuf_server.data.TufSlickMappings._ import com.advancedtelematic.tuf.reposerver.db.DBDataType.{DbDelegation, DbSignedRole} @@ -289,8 +289,8 @@ trait DelegationRepositorySupport extends DatabaseSupport { protected [db] class DelegationRepository()(implicit db: Database, ec: ExecutionContext) { - def find(repoId: RepoId, roleName: DelegatedRoleName): Future[DbDelegation] = db.run { - Schema.delegations.filter(_.repoId === repoId).filter(_.roleName === roleName).result.failIfNotSingle(Errors.DelegationNotFound) + def find(repoId: RepoId, roleNames: DelegatedRoleName*): Future[DbDelegation] = db.run { + Schema.delegations.filter(_.repoId === repoId).filter(_.roleName.inSet(roleNames)).result.failIfNotSingle(Errors.DelegationNotFound) } def persist(repoId: RepoId, roleName: DelegatedRoleName, content: JsonSignedPayload): Future[Unit] = db.run { diff --git a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/delegations/DelegationsManagement.scala b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/delegations/DelegationsManagement.scala index b2bcf6df..764e67a5 100644 --- a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/delegations/DelegationsManagement.scala +++ b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/delegations/DelegationsManagement.scala @@ -1,34 +1,66 @@ package com.advancedtelematic.tuf.reposerver.delegations -import java.time.Instant - import cats.data.Validated.{Invalid, Valid} import cats.data.ValidatedNel +import com.advancedtelematic.libats.data.RefinedUtils._ import com.advancedtelematic.libtuf.crypt.TufCrypto import com.advancedtelematic.libtuf.data.ClientCodecs._ import com.advancedtelematic.libtuf.data.ClientDataType.{DelegatedRoleName, Delegation, MetaItem, MetaPath, TargetsRole, ValidMetaPath} import com.advancedtelematic.libtuf.data.TufDataType.{JsonSignedPayload, RepoId, SignedPayload} -import com.advancedtelematic.libtuf_server.keyserver.KeyserverClient -import com.advancedtelematic.tuf.reposerver.data.RepositoryDataType.{SignedRole, asMetaItem} +import com.advancedtelematic.libtuf_server.crypto.Sha256Digest +import com.advancedtelematic.tuf.reposerver.data.RepositoryDataType.SignedRole import com.advancedtelematic.tuf.reposerver.db.{DelegationRepositorySupport, SignedRoleRepositorySupport} -import com.advancedtelematic.tuf.reposerver.http.{Errors, RepoRoleRefresh, RoleSigner} -import eu.timepit.refined.api.Refined -import com.advancedtelematic.libats.data.RefinedUtils._ +import com.advancedtelematic.tuf.reposerver.http._ import slick.jdbc.MySQLProfile.api._ import scala.async.Async._ import scala.concurrent.{ExecutionContext, Future} +import scala.util.Try + +class SignedRoleDelegationsFind()(implicit val db: Database, val ec: ExecutionContext) extends DelegationRepositorySupport { + import cats.implicits._ + import com.advancedtelematic.libtuf.crypt.CanonicalJson._ + import com.advancedtelematic.libtuf.data.TufCodecs._ + import io.circe.syntax._ + + def findSignedTargetRoleDelegations(targetRole: SignedRole[TargetsRole]): Future[Map[MetaPath, MetaItem]] = { + val delegatedRoleNames = targetRole.role.delegations.map(_.roles.map(_.name)).getOrElse(List.empty) + val delegationsF = + delegatedRoleNames + .map { name => delegationsRepo.find(targetRole.repoId, name).map((name, _)) } + .sequence + .recover { case Errors.DelegationNotFound => List.empty } + + for { + delegations <- delegationsF + delegationsAsMetaItems <- delegations.map { case (name, d) => + Future.fromTry { (name.value + ".json").refineTry[ValidMetaPath].product(asMetaItem(d.content)) } + }.sequence + } yield delegationsAsMetaItems.toMap + } + + private def asMetaItem(content: JsonSignedPayload): Try[MetaItem] = { + val canonicalJson = content.asJson.canonical + val checksum = Sha256Digest.digest(canonicalJson.getBytes) + val hashes = Map(checksum.method -> checksum.hash) + val versionT = content.signed.hcursor.downField("version").as[Int].toTry + + versionT.map { version => MetaItem(hashes, canonicalJson.length, version) } + } +} + class DelegationsManagement()(implicit val db: Database, val ec: ExecutionContext) extends DelegationRepositorySupport with SignedRoleRepositorySupport { - - def create(repoId: RepoId, roleName: DelegatedRoleName, delegationMetadata: SignedPayload[TargetsRole]): Future[Unit] = async { + def create(repoId: RepoId, roleName: DelegatedRoleName, delegationMetadata: SignedPayload[TargetsRole]) + (implicit signedRoleGeneration: SignedRoleGeneration): Future[Unit] = async { val targetsRole = await(signedRoleRepository.find[TargetsRole](repoId)).role val delegation = findDelegationMetadataByName(targetsRole, roleName) validateDelegationMetadataSignatures(targetsRole, delegation, delegationMetadata) match { case Valid(_) => await(delegationsRepo.persist(repoId, roleName, delegationMetadata.asJsonSignedPayload)) + await(signedRoleGeneration.regenerateSnapshots(repoId)) case Invalid(err) => throw Errors.PayloadSignatureInvalid(err) } @@ -40,17 +72,6 @@ class DelegationsManagement()(implicit val db: Database, val ec: ExecutionContex private def findDelegationMetadataByName(targetsRole: TargetsRole, delegatedRoleName: DelegatedRoleName): Delegation = { targetsRole.delegations.flatMap(_.roles.find(_.name == delegatedRoleName)).getOrElse(throw Errors.DelegationNotDefined) } - - def findDelegations(targets: SignedRole[TargetsRole]): Future[Map[MetaPath, MetaItem]] = { - val delegatedRoleNames = targets.role.delegations.map(_.roles.map(_.name)).getOrElse(Nil) - val delegations = Future.sequence(delegatedRoleNames.map { name => find(targets.repoId, name).map((name, _)) }) - .recover { case Errors.DelegationNotFound => Nil } - - delegations.map(_.map { case (name: DelegatedRoleName, d: JsonSignedPayload) => - (name.value + ".json").refineTry[ValidMetaPath].get -> asMetaItem(d) - }.toMap) - } - private def validateDelegationMetadataSignatures(targetsRole: TargetsRole, delegation: Delegation, delegationMetadata: SignedPayload[TargetsRole]): ValidatedNel[String, SignedPayload[TargetsRole]] = { diff --git a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/OfflineSignedRoleStorage.scala b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/OfflineSignedRoleStorage.scala index 47efa20b..070be65d 100644 --- a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/OfflineSignedRoleStorage.scala +++ b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/OfflineSignedRoleStorage.scala @@ -20,7 +20,7 @@ import com.advancedtelematic.libtuf.data.ClientDataType.TufRole._ import scala.async.Async.{async, await} import scala.concurrent.{ExecutionContext, Future} import com.advancedtelematic.libtuf_server.keyserver.KeyserverClient -import com.advancedtelematic.tuf.reposerver.delegations.DelegationsManagement +import com.advancedtelematic.tuf.reposerver.delegations.{SignedRoleDelegationsFind} import com.advancedtelematic.tuf.reposerver.http.RoleChecksumHeader.RoleChecksum import com.advancedtelematic.tuf.reposerver.target_store.TargetStore import org.slf4j.LoggerFactory @@ -33,8 +33,6 @@ class OfflineSignedRoleStorage(keyserverClient: KeyserverClient) private val signedRoleGeneration = new SignedRoleGeneration(keyserverClient) - private val delegationsManagement = new DelegationsManagement() - def store(repoId: RepoId, signedPayload: SignedPayload[TargetsRole]): Future[ValidatedNel[String, (Seq[TargetItem], SignedRole[TargetsRole])]] = for { validatedPayloadSig <- payloadSignatureIsValid(repoId, signedPayload) @@ -44,8 +42,8 @@ class OfflineSignedRoleStorage(keyserverClient: KeyserverClient) case Valid(items) => val signedTargetRole = SignedRole.withChecksum[TargetsRole](repoId, signedPayload.asJsonSignedPayload, signedPayload.signed.version, signedPayload.signed.expires) for { - (targets, timestamps) <- signedRoleGeneration.regenerateSignedDependent(repoId, signedTargetRole, signedPayload.signed.expires) - _ <- signedRoleRepository.storeAll(targetItemRepo)(repoId: RepoId, List(signedTargetRole, targets, timestamps), items) + (targets, timestamps) <- signedRoleGeneration.freshSignedDependent(repoId, signedTargetRole, signedPayload.signed.expires) + _ <- signedRoleRepository.storeAll(targetItemRepo)(repoId: RepoId, List(signedTargetRole, targets, timestamps), items) } yield (existingTargets, signedTargetRole).validNel case i @ Invalid(_) => FastFuture.successful(i) diff --git a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/RepoResource.scala b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/RepoResource.scala index 2612eae7..41a057cf 100644 --- a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/RepoResource.scala +++ b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/RepoResource.scala @@ -48,7 +48,7 @@ class RepoResource(keyserverClient: KeyserverClient, namespaceValidation: Namesp with SignedRoleRepositorySupport with Settings { - private val signedRoleGeneration = new SignedRoleGeneration(keyserverClient) + private implicit val signedRoleGeneration = new SignedRoleGeneration(keyserverClient) private val offlineSignedRoleStorage = new OfflineSignedRoleStorage(keyserverClient) private val delegations = new DelegationsManagement() @@ -213,7 +213,7 @@ class RepoResource(keyserverClient: KeyserverClient, namespaceValidation: Namesp } ~ path("delegations" / DelegatedRoleUriPath) { delegatedRoleName => (put & entity(as[SignedPayload[TargetsRole]])) { payload => - complete(signedRoleGeneration.createDelegatedRole(repoId, delegatedRoleName, payload).map(_ => StatusCodes.NoContent)) + complete(delegations.create(repoId, delegatedRoleName, payload).map(_ => StatusCodes.NoContent)) } ~ get { complete(delegations.find(repoId, delegatedRoleName)) diff --git a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/RoleRefresh.scala b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/RoleRefresh.scala index 0d33b093..7dcf4a3e 100644 --- a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/RoleRefresh.scala +++ b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/RoleRefresh.scala @@ -3,22 +3,21 @@ package com.advancedtelematic.tuf.reposerver.http import java.time.Instant import java.time.temporal.ChronoUnit +import com.advancedtelematic.libtuf.data.ClientCodecs._ import com.advancedtelematic.libtuf.data.ClientDataType.{MetaItem, MetaPath, SnapshotRole, TargetsRole, TimestampRole, TufRole, _} -import com.advancedtelematic.libtuf.data.TufDataType.{JsonSignedPayload, RepoId} +import com.advancedtelematic.libtuf.data.TufDataType.RepoId import com.advancedtelematic.libtuf_server.keyserver.KeyserverClient import com.advancedtelematic.tuf.reposerver.data.RepositoryDataType.SignedRole import com.advancedtelematic.tuf.reposerver.db.SignedRoleRepositorySupport +import com.advancedtelematic.tuf.reposerver.delegations.{SignedRoleDelegationsFind, DelegationsManagement} import io.circe.syntax._ import io.circe.{Decoder, Encoder} import slick.jdbc.MySQLProfile.api._ -import com.advancedtelematic.libtuf.data.ClientCodecs._ -import com.advancedtelematic.tuf.reposerver.delegations.DelegationsManagement import scala.async.Async.{async, await} import scala.concurrent.{ExecutionContext, Future} - -class RoleSigner(repoId: RepoId, keyserverClient: KeyserverClient)(implicit ec: ExecutionContext) { +protected class RepoRoleSigner(repoId: RepoId, keyserverClient: KeyserverClient)(implicit ec: ExecutionContext) { def apply[T : Encoder](role: T)(implicit tufRole: TufRole[T]): Future[SignedRole[T]] = { keyserverClient.sign(repoId, tufRole.roleType, role.asJson).map { signedRole => SignedRole.withChecksum[T](repoId, signedRole, role.version, role.expires) @@ -26,9 +25,10 @@ class RoleSigner(repoId: RepoId, keyserverClient: KeyserverClient)(implicit ec: } } -class RepoRoleRefresh(signFn: RoleSigner)(implicit val db: Database, val ec: ExecutionContext) extends SignedRoleRepositorySupport { - val roleRefresh = new RoleRefresh(signFn) +class RepoRoleRefresh(keyserverClient: KeyserverClient)(implicit val db: Database, val ec: ExecutionContext) extends SignedRoleRepositorySupport { + val roleRefresh: RepoId => RoleRefresh = repoId => new RoleRefresh(new RepoRoleSigner(repoId, keyserverClient)) val delegationsManagement = new DelegationsManagement() + val targetRoleDelegationFind = new SignedRoleDelegationsFind() private def findExisting[T](repoId: RepoId)(implicit tufRole: TufRole[T]): Future[SignedRole[T]] = { signedRoleRepository.find[T](repoId) @@ -43,8 +43,8 @@ class RepoRoleRefresh(signFn: RoleSigner)(implicit val db: Database, val ec: Exe val existingTargets = await(findExisting[TargetsRole](repoId)) val existingSnapshots = await(findExisting[SnapshotRole](repoId)) val existingTimestamps = await(findExisting[TimestampRole](repoId)) - val delegations = await(delegationsManagement.findDelegations(existingTargets)) - val (newTargets, dependencies) = await(roleRefresh.refreshTargets(existingTargets, existingTimestamps, existingSnapshots, delegations)) + val existingDelegations = await(targetRoleDelegationFind.findSignedTargetRoleDelegations(existingTargets)) + val (newTargets, dependencies) = await(roleRefresh(repoId).refreshTargets(existingTargets, existingTimestamps, existingSnapshots, existingDelegations)) await(commitRefresh(newTargets, dependencies)) } @@ -52,29 +52,29 @@ class RepoRoleRefresh(signFn: RoleSigner)(implicit val db: Database, val ec: Exe val existingTargets = await(findExisting[TargetsRole](repoId)) val existingSnapshots = await(findExisting[SnapshotRole](repoId)) val existingTimestamps = await(findExisting[TimestampRole](repoId)) - val delegations = await(delegationsManagement.findDelegations(existingTargets)) + val delegations = await(targetRoleDelegationFind.findSignedTargetRoleDelegations(existingTargets)) - val (newSnapshots, dependencies) = await(roleRefresh.refreshSnapshots(existingSnapshots, existingTimestamps, existingTargets, delegations)) + val (newSnapshots, dependencies) = await(roleRefresh(repoId).refreshSnapshots(existingSnapshots, existingTimestamps, existingTargets, delegations)) await(commitRefresh(newSnapshots, dependencies)) } def refreshTimestamp(repoId: RepoId): Future[SignedRole[TimestampRole]] = async { val existingTimestamp = await(findExisting[TimestampRole](repoId)) val existingSnapshots = await(findExisting[SnapshotRole](repoId)) - val newTimestamp = await(roleRefresh.refreshTimestamps(existingTimestamp, existingSnapshots)) + val newTimestamp = await(roleRefresh(repoId).refreshTimestamps(existingTimestamp, existingSnapshots)) await(commitRefresh(newTimestamp, List.empty)) } } -class RoleRefresh(signFn: RoleSigner)(implicit ec: ExecutionContext) { +protected class RoleRefresh(signFn: RepoRoleSigner)(implicit ec: ExecutionContext) { def refreshTargets(existingTargets: SignedRole[TargetsRole], existingTimestamps: SignedRole[TimestampRole], existingSnapshots: SignedRole[SnapshotRole], - delegations: Map[MetaPath, MetaItem]): Future[(SignedRole[TargetsRole], List[SignedRole[_]])] = async { + existingDelegations: Map[MetaPath, MetaItem]): Future[(SignedRole[TargetsRole], List[SignedRole[_]])] = async { val newTargetsRole = refreshRole[TargetsRole](existingTargets) val signedTargets = await(signFn(newTargetsRole)) - val (newSnapshots, dependencies) = await(refreshSnapshots(existingSnapshots, existingTimestamps, signedTargets, delegations)) + val (newSnapshots, dependencies) = await(refreshSnapshots(existingSnapshots, existingTimestamps, signedTargets, existingDelegations)) (signedTargets, newSnapshots :: dependencies) } @@ -85,11 +85,10 @@ class RoleRefresh(signFn: RoleSigner)(implicit ec: ExecutionContext) { delegations: Map[MetaPath, MetaItem]): Future[(SignedRole[SnapshotRole], List[SignedRole[_]])] = async { val refreshed = refreshRole[SnapshotRole](existingSnapshots) - val newMeta: Map[MetaPath, MetaItem] = existingSnapshots.role.meta + newTargets.asMetaRole ++ delegations + val newMeta = existingSnapshots.role.meta + newTargets.asMetaRole ++ delegations val newSnapshot = SnapshotRole(newMeta, refreshed.expires, refreshed.version) val signedSnapshot = await(signFn(newSnapshot)) - val timestampRole = await(refreshTimestamps(existingTimestamps, signedSnapshot)) (signedSnapshot, List(timestampRole)) diff --git a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/SignedRoleGeneration.scala b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/SignedRoleGeneration.scala index c742d723..57d5318b 100644 --- a/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/SignedRoleGeneration.scala +++ b/reposerver/src/main/scala/com/advancedtelematic/tuf/reposerver/http/SignedRoleGeneration.scala @@ -7,27 +7,28 @@ import akka.http.scaladsl.util.FastFuture import com.advancedtelematic.libtuf.data.ClientCodecs._ import com.advancedtelematic.libtuf.data.ClientDataType._ import com.advancedtelematic.libtuf.data.TufDataType.RoleType.RoleType -import com.advancedtelematic.libtuf.data.TufDataType.{JsonSignedPayload, RepoId, RoleType, SignedPayload, TargetFilename} +import com.advancedtelematic.libtuf.data.TufDataType.{JsonSignedPayload, RepoId, RoleType, TargetFilename} +import com.advancedtelematic.libtuf_server.keyserver.KeyserverClient import com.advancedtelematic.tuf.reposerver.data.RepositoryDataType.{SignedRole, TargetItem} -import com.advancedtelematic.tuf.reposerver.db._ import com.advancedtelematic.tuf.reposerver.db.DbSignedRoleRepository.SignedRoleNotFound -import io.circe.syntax._ +import com.advancedtelematic.tuf.reposerver.db._ +import com.advancedtelematic.tuf.reposerver.delegations.SignedRoleDelegationsFind import io.circe.Encoder +import io.circe.syntax._ +import org.slf4j.LoggerFactory import slick.jdbc.MySQLProfile.api._ import scala.async.Async._ import scala.concurrent.{ExecutionContext, Future} -import com.advancedtelematic.libtuf_server.keyserver.KeyserverClient -import com.advancedtelematic.tuf.reposerver.delegations.DelegationsManagement -import org.slf4j.LoggerFactory class SignedRoleGeneration(keyserverClient: KeyserverClient) - (implicit val db: Database, val ec: ExecutionContext) extends SignedRoleRepositorySupport { + (implicit val db: Database, val ec: ExecutionContext) + extends SignedRoleRepositorySupport with DelegationRepositorySupport { private val log = LoggerFactory.getLogger(this.getClass) val targetRoleGeneration = new TargetRoleGeneration(keyserverClient) - val delegationsManagement = new DelegationsManagement() + val signedRoleDelegationsFind = new SignedRoleDelegationsFind() def regenerateAllSignedRoles(repoId: RepoId): Future[JsonSignedPayload] = async { @@ -39,21 +40,27 @@ class SignedRoleGeneration(keyserverClient: KeyserverClient) val targetRole = await(targetRoleGeneration.generate(repoId, expireAt, targetVersion)) val signedTarget = await(signRole(repoId, targetRole)) - val (newSnapshots, newTimestamps) = await(regenerateSignedDependent(repoId, signedTarget, expireAt)) + val (newSnapshots, newTimestamps) = await(freshSignedDependent(repoId, signedTarget, expireAt)) await(signedRoleRepository.persistAll(List(signedTarget, newSnapshots, newTimestamps))) signedTarget.content } - def regenerateSignedDependent(repoId: RepoId, - targetRole: SignedRole[TargetsRole], - expireAt: Instant): Future[(SignedRole[SnapshotRole], SignedRole[TimestampRole])] = async { + def regenerateSnapshots(repoId: RepoId): Future[(SignedRole[SnapshotRole], SignedRole[TimestampRole])] = async { + val existingTargets = await(signedRoleRepository.find[TargetsRole](repoId)) + val (snapshots, timestamps) = await(freshSignedDependent(repoId, existingTargets, defaultExpire)) + await(signedRoleRepository.persistAll(List(snapshots, timestamps))) + (snapshots, timestamps) + } + + def freshSignedDependent(repoId: RepoId, + targetRole: SignedRole[TargetsRole], + expireAt: Instant): Future[(SignedRole[SnapshotRole], SignedRole[TimestampRole])] = async { val signedRoot = await(fetchRootRole(repoId)) val snapshotVersion = await(nextVersion[SnapshotRole](repoId)) - val delegations = await(delegationsManagement.findDelegations(targetRole)) - + val delegations = await(signedRoleDelegationsFind.findSignedTargetRoleDelegations(targetRole)) val snapshotRole = genSnapshotRole(signedRoot, targetRole, delegations, expireAt, snapshotVersion) val signedSnapshot = await(signRole(repoId, snapshotRole)) @@ -73,10 +80,8 @@ class SignedRoleGeneration(keyserverClient: KeyserverClient) _ <- regenerateAllSignedRoles(repoId) } yield () - - private def signRole[T : Encoder : TufRole](repoId: RepoId, role: T): Future[SignedRole[T]] = { - new RoleSigner(repoId, keyserverClient).apply(role) - } + private def signRole[T : Encoder : TufRole](repoId: RepoId, role: T): Future[SignedRole[T]] = + new RepoRoleSigner(repoId, keyserverClient).apply(role) private def ensureTargetsCanBeSigned(repoId: RepoId): Future[SignedRole[TargetsRole]] = async { val targetsRole = await(signedRoleRepository.find[TargetsRole](repoId)).role @@ -116,7 +121,7 @@ class SignedRoleGeneration(keyserverClient: KeyserverClient) } def findRole(repoId: RepoId, roleType: RoleType): Future[SignedRole[_]] = { - lazy val refresher = new RepoRoleRefresh(new RoleSigner(repoId, keyserverClient)) + lazy val refresher = new RepoRoleRefresh(keyserverClient) roleType match { case RoleType.ROOT => @@ -151,13 +156,6 @@ class SignedRoleGeneration(keyserverClient: KeyserverClient) TimestampRole(meta, expireAt, version) } - def createDelegatedRole(repoId: RepoId, delegatedRoleName: DelegatedRoleName, payload: SignedPayload[TargetsRole]): Future[Unit] = - delegationsManagement.create(repoId, delegatedRoleName, payload).flatMap { _ => - val refresher = new RepoRoleRefresh(new RoleSigner(repoId, keyserverClient)) - - refresher.refreshSnapshots(repoId).map(_ => ()) - } - private def defaultExpire: Instant = Instant.now().plus(31, ChronoUnit.DAYS) } @@ -172,6 +170,8 @@ protected class TargetRoleGeneration(roleSigningClient: KeyserverClient) def deleteTargetItem(repoId: RepoId, filename: TargetFilename): Future[Unit] = targetItemRepo.deleteItemAndComments(filenameCommentRepo)(repoId, filename) + // TODO: Fix for https://saeljira.it.here.com/browse/OTA-2366 is related to this code + // We should rely on the existing TargetsRole and just add a target item, rather than regenerate a new TargetsRole def generate(repoId: RepoId, expireAt: Instant, version: Int): Future[TargetsRole] = { targetItemRepo.findFor(repoId).map { targetItems => val targets = targetItems.map { item => diff --git a/reposerver/src/test/scala/com/advancedtelematic/tuf/reposerver/http/RepoResourceDelegationsSpec.scala b/reposerver/src/test/scala/com/advancedtelematic/tuf/reposerver/http/RepoResourceDelegationsSpec.scala index 275745c1..371ebb54 100644 --- a/reposerver/src/test/scala/com/advancedtelematic/tuf/reposerver/http/RepoResourceDelegationsSpec.scala +++ b/reposerver/src/test/scala/com/advancedtelematic/tuf/reposerver/http/RepoResourceDelegationsSpec.scala @@ -201,7 +201,6 @@ class RepoResourceDelegationsSpec extends TufReposerverSpec Get(apiUri(s"repo/${repoId.show}/snapshot.json")) ~> routes ~> check { status shouldBe StatusCodes.OK val signed = responseAs[SignedPayload[SnapshotRole]].signed - signed.meta(Refined.unsafeApply(s"${delegatedRoleName.value}.json")).length shouldBe delegationLength } }