diff --git a/app/uk/gov/hmrc/agentservicesaccount/models/AgencyDetails.scala b/app/uk/gov/hmrc/agentservicesaccount/models/AgencyDetails.scala index 3d67a2c4..2d501420 100644 --- a/app/uk/gov/hmrc/agentservicesaccount/models/AgencyDetails.scala +++ b/app/uk/gov/hmrc/agentservicesaccount/models/AgencyDetails.scala @@ -16,18 +16,31 @@ package uk.gov.hmrc.agentservicesaccount.models -import play.api.libs.json.{Json, OFormat} +import play.api.libs.functional.syntax.{toFunctionalBuilderOps, unlift} +import play.api.libs.json.{Format, Json, OFormat, __} +import uk.gov.hmrc.agentservicesaccount.utils.EncryptedStringUtil.fallbackStringFormat +import uk.gov.hmrc.crypto.{Decrypter, Encrypter} case class BusinessAddress( addressLine1: String, addressLine2: Option[String], addressLine3: Option[String] = None, - addressLine4: Option[String]= None, + addressLine4: Option[String] = None, postalCode: Option[String], countryCode: String) object BusinessAddress { implicit val format: OFormat[BusinessAddress] = Json.format + + def databaseFormat(implicit crypto: Encrypter with Decrypter): Format[BusinessAddress] = + ( + (__ \ "addressLine1").format[String](fallbackStringFormat) and + (__ \ "addressLine2").formatNullable[String](fallbackStringFormat) and + (__ \ "addressLine3").formatNullable[String](fallbackStringFormat) and + (__ \ "addressLine4").formatNullable[String](fallbackStringFormat) and + (__ \ "postalCode").formatNullable[String](fallbackStringFormat) and + (__ \ "countryCode").format[String](fallbackStringFormat) + )(BusinessAddress.apply, unlift(BusinessAddress.unapply)) } case class AgencyDetails( @@ -39,5 +52,13 @@ case class AgencyDetails( object AgencyDetails { implicit val format: OFormat[AgencyDetails] = Json.format + + def databaseFormat(implicit crypto: Encrypter with Decrypter): Format[AgencyDetails] = + ( + (__ \ "agencyName").formatNullable[String](fallbackStringFormat) and + (__ \ "agencyEmail").formatNullable[String](fallbackStringFormat) and + (__ \ "agencyTelephone").formatNullable[String](fallbackStringFormat) and + (__ \ "agencyAddress").formatNullable[BusinessAddress](BusinessAddress.databaseFormat) + )(AgencyDetails.apply, unlift(AgencyDetails.unapply)) } diff --git a/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/DesignatoryDetails.scala b/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/DesignatoryDetails.scala index c4d4f672..1d4e9c6a 100644 --- a/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/DesignatoryDetails.scala +++ b/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/DesignatoryDetails.scala @@ -16,14 +16,22 @@ package uk.gov.hmrc.agentservicesaccount.models.desiDetails -import play.api.libs.json.{Json, OFormat} +import play.api.libs.functional.syntax.{toFunctionalBuilderOps, unlift} +import play.api.libs.json.{Format, Json, OFormat, __} import uk.gov.hmrc.agentservicesaccount.models.AgencyDetails +import uk.gov.hmrc.crypto.{Decrypter, Encrypter} case class DesignatoryDetails( - agencyDetails: AgencyDetails, - otherServices: OtherServices - ) + agencyDetails: AgencyDetails, + otherServices: OtherServices + ) object DesignatoryDetails { implicit val desiDetailsFormat: OFormat[DesignatoryDetails] = Json.format[DesignatoryDetails] + + def databaseFormat(implicit crypto: Encrypter with Decrypter): Format[DesignatoryDetails] = + ( + (__ \ "agencyDetails").format[AgencyDetails](AgencyDetails.databaseFormat) and + (__ \ "otherServices").format[OtherServices](OtherServices.databaseFormat) + )(DesignatoryDetails.apply, unlift(DesignatoryDetails.unapply)) } diff --git a/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/OtherServices.scala b/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/OtherServices.scala index dfc1d1bc..d6da4d9e 100644 --- a/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/OtherServices.scala +++ b/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/OtherServices.scala @@ -16,32 +16,63 @@ package uk.gov.hmrc.agentservicesaccount.models.desiDetails -import play.api.libs.json.{Json, OFormat} +import play.api.libs.functional.syntax.{toFunctionalBuilderOps, unlift} +import play.api.libs.json.{Format, Json, OFormat, __} +import uk.gov.hmrc.agentservicesaccount.utils.EncryptedStringUtil.fallbackStringFormat +import uk.gov.hmrc.crypto.{Decrypter, Encrypter} import uk.gov.hmrc.domain.{CtUtr, SaUtr} case class CtChanges( applyChanges: Boolean, - ctAgentReference:Option[CtUtr] + ctAgentReference: Option[CtUtr] ) + object CtChanges { implicit val ctChangesFormat: OFormat[CtChanges] = Json.format[CtChanges] + + def databaseFormat(implicit crypto: Encrypter with Decrypter): Format[CtChanges] = + ( + (__ \ "applyChanges").format[Boolean] and + (__ \ "ctAgentReference").formatNullable[String](fallbackStringFormat) + .bimap[Option[CtUtr]]( + _.map(CtUtr(_)), + _.map(_.utr) + ) + )(CtChanges.apply, unlift(CtChanges.unapply)) } case class SaChanges( applyChanges: Boolean, - saAgentReference:Option[SaUtr] + saAgentReference: Option[SaUtr] ) + object SaChanges { implicit val saCodeChangesFormat: OFormat[SaChanges] = Json.format[SaChanges] + + def databaseFormat(implicit crypto: Encrypter with Decrypter): Format[SaChanges] = + ( + (__ \ "applyChanges").format[Boolean] and + (__ \ "saAgentReference").formatNullable[String](fallbackStringFormat) + .bimap[Option[SaUtr]]( + _.map(SaUtr(_)), + _.map(_.utr) + ) + )(SaChanges.apply, unlift(SaChanges.unapply)) } -case class OtherServices ( - saChanges: SaChanges, - ctChanges: CtChanges - ) +case class OtherServices( + saChanges: SaChanges, + ctChanges: CtChanges + ) object OtherServices { implicit val otherServicesFormat: OFormat[OtherServices] = Json.format[OtherServices] + + def databaseFormat(implicit crypto: Encrypter with Decrypter): Format[OtherServices] = + ( + (__ \ "saChanges").format[SaChanges](SaChanges.databaseFormat) and + (__ \ "ctChanges").format[CtChanges](CtChanges.databaseFormat) + )(OtherServices.apply, unlift(OtherServices.unapply)) } diff --git a/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/YourDetails.scala b/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/YourDetails.scala index 994bc7e2..25b07212 100644 --- a/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/YourDetails.scala +++ b/app/uk/gov/hmrc/agentservicesaccount/models/desiDetails/YourDetails.scala @@ -16,9 +16,20 @@ package uk.gov.hmrc.agentservicesaccount.models.desiDetails -import play.api.libs.json.{Format, Json} +import play.api.libs.functional.syntax.{toFunctionalBuilderOps, unlift} +import play.api.libs.json.{Format, Json, __} +import uk.gov.hmrc.agentservicesaccount.utils.EncryptedStringUtil.fallbackStringFormat +import uk.gov.hmrc.crypto.{Decrypter, Encrypter} + case class YourDetails(fullName: String, telephone: String) + object YourDetails { implicit val format: Format[YourDetails] = Json.format[YourDetails] + + def databaseFormat(implicit crypto: Encrypter with Decrypter): Format[YourDetails] = + ( + (__ \ "fullName").format[String](fallbackStringFormat) and + (__ \ "telephone").format[String](fallbackStringFormat) + )(YourDetails.apply, unlift(YourDetails.unapply)) } diff --git a/app/uk/gov/hmrc/agentservicesaccount/modules/CryptoProviderModule.scala b/app/uk/gov/hmrc/agentservicesaccount/modules/CryptoProviderModule.scala new file mode 100644 index 00000000..2eabb6fe --- /dev/null +++ b/app/uk/gov/hmrc/agentservicesaccount/modules/CryptoProviderModule.scala @@ -0,0 +1,52 @@ +/* + * Copyright 2024 HM Revenue & Customs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.hmrc.agentservicesaccount.modules + +import play.api.inject.{Binding, Module} +import play.api.{Configuration, Environment} +import uk.gov.hmrc.crypto.{Crypted, Decrypter, Encrypter, PlainBytes, PlainContent, PlainText, SymmetricCryptoFactory} + +import java.nio.charset.StandardCharsets +import java.util.Base64 + +class CryptoProviderModule extends Module { + + def aesCryptoInstance(configuration: Configuration): Encrypter with Decrypter = if ( + configuration.underlying.getBoolean("fieldLevelEncryption.enable") + ) + SymmetricCryptoFactory.aesCryptoFromConfig("fieldLevelEncryption", configuration.underlying) + else + NoCrypto + + override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = + Seq( + bind[Encrypter with Decrypter].qualifiedWith("aes").toInstance(aesCryptoInstance(configuration)) + ) +} + +/** Encrypter/decrypter that does nothing (i.e. leaves content in plaintext). Only to be used for debugging. + */ +trait NoCrypto extends Encrypter with Decrypter { + def encrypt(plain: PlainContent): Crypted = plain match { + case PlainText(text) => Crypted(text) + case PlainBytes(bytes) => Crypted(new String(Base64.getEncoder.encode(bytes), StandardCharsets.UTF_8)) + } + def decrypt(notEncrypted: Crypted): PlainText = PlainText(notEncrypted.value) + def decryptAsBytes(nullEncrypted: Crypted): PlainBytes = PlainBytes(Base64.getDecoder.decode(nullEncrypted.value)) +} + +object NoCrypto extends NoCrypto diff --git a/app/uk/gov/hmrc/agentservicesaccount/services/SessionCacheService.scala b/app/uk/gov/hmrc/agentservicesaccount/services/SessionCacheService.scala index e8e6f1e6..51d7207c 100644 --- a/app/uk/gov/hmrc/agentservicesaccount/services/SessionCacheService.scala +++ b/app/uk/gov/hmrc/agentservicesaccount/services/SessionCacheService.scala @@ -18,15 +18,19 @@ package uk.gov.hmrc.agentservicesaccount.services import play.api.libs.json.{Reads, Writes} import play.api.mvc.{Request, Result} -import uk.gov.hmrc.agentservicesaccount.controllers.sessionKeys +import uk.gov.hmrc.agentservicesaccount.controllers.{ARN, DESCRIPTION, DRAFT_NEW_CONTACT_DETAILS, DRAFT_SUBMITTED_BY, EMAIL, EMAIL_PENDING_VERIFICATION, NAME, PHONE, sessionKeys} +import uk.gov.hmrc.agentservicesaccount.models.desiDetails.{DesignatoryDetails, YourDetails} import uk.gov.hmrc.agentservicesaccount.repository.SessionCacheRepository +import uk.gov.hmrc.agentservicesaccount.utils.EncryptedStringUtil +import uk.gov.hmrc.crypto.{Decrypter, Encrypter} import uk.gov.hmrc.mongo.cache.DataKey -import javax.inject.{Inject, Singleton} +import javax.inject.{Inject, Named, Singleton} import scala.concurrent.{ExecutionContext, Future} @Singleton -class SessionCacheService @Inject()(sessionCacheRepository: SessionCacheRepository) { +class SessionCacheService @Inject()(sessionCacheRepository: SessionCacheRepository) + (implicit @Named("aes") crypto: Encrypter with Decrypter) { def withSessionItem[T](dataKey: DataKey[T]) @@ -37,16 +41,34 @@ class SessionCacheService @Inject()(sessionCacheRepository: SessionCacheReposito def get[T](dataKey: DataKey[T]) (implicit reads: Reads[T], request: Request[_]): Future[Option[T]] = { - sessionCacheRepository.getFromSession[T](dataKey) + dataKey match { + case key: DataKey[String @unchecked] if Seq(NAME, EMAIL, PHONE, ARN, DESCRIPTION, EMAIL_PENDING_VERIFICATION).contains(key) => + sessionCacheRepository.getFromSession(key)(EncryptedStringUtil.fallbackStringFormat, request) + case key: DataKey[DesignatoryDetails @unchecked] if key == DRAFT_NEW_CONTACT_DETAILS => + sessionCacheRepository.getFromSession(key)(DesignatoryDetails.databaseFormat, request) + case key: DataKey[YourDetails @unchecked] if key == DRAFT_SUBMITTED_BY => + sessionCacheRepository.getFromSession(key)(YourDetails.databaseFormat, request) + case _ => + sessionCacheRepository.getFromSession[T](dataKey) + } } def put[T](dataKey: DataKey[T], value: T) (implicit writes: Writes[T], request: Request[_]): Future[(String, String)] = { - sessionCacheRepository.putSession(dataKey, value) + dataKey match { + case key: DataKey[String @unchecked] if Seq(NAME, EMAIL, PHONE, ARN, DESCRIPTION, EMAIL_PENDING_VERIFICATION).contains(key) => + sessionCacheRepository.putSession(key, value)(EncryptedStringUtil.fallbackStringFormat, request) + case key: DataKey[DesignatoryDetails @unchecked] if key == DRAFT_NEW_CONTACT_DETAILS => + sessionCacheRepository.putSession(key, value)(DesignatoryDetails.databaseFormat, request) + case key: DataKey[YourDetails @unchecked] if key == DRAFT_SUBMITTED_BY => + sessionCacheRepository.putSession(key, value)(YourDetails.databaseFormat, request) + case _ => + sessionCacheRepository.putSession(dataKey, value) + } } def delete[T](dataKey: DataKey[T]) - (implicit request: Request[_]): Future[Unit] = { + (implicit request: Request[_]): Future[Unit] = { sessionCacheRepository.deleteFromSession(dataKey) } diff --git a/app/uk/gov/hmrc/agentservicesaccount/utils/EncryptedStringUtil.scala b/app/uk/gov/hmrc/agentservicesaccount/utils/EncryptedStringUtil.scala new file mode 100644 index 00000000..cd80811c --- /dev/null +++ b/app/uk/gov/hmrc/agentservicesaccount/utils/EncryptedStringUtil.scala @@ -0,0 +1,37 @@ +/* + * Copyright 2024 HM Revenue & Customs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.hmrc.agentservicesaccount.utils + +import play.api.Logging +import play.api.libs.json.{Format, Json} +import uk.gov.hmrc.crypto.json.JsonEncryption.{stringDecrypter, stringEncrypter} +import uk.gov.hmrc.crypto.{Decrypter, Encrypter} + +object EncryptedStringUtil extends Logging { + //TODO: replace all usages of this with stringDecrypterEncrypter once all old sessions have timed out + def fallbackStringFormat(implicit crypto: Encrypter with Decrypter): Format[String] = + Format( + json => try { + stringDecrypter.reads(json) + } catch { + case _: Throwable => + logger.warn("[EncryptedStringUtil] found unencrypted string") + Json.fromJson[String](json) + }, + stringEncrypter + ) +} diff --git a/conf/application.conf b/conf/application.conf index 53b7d20c..6a7738d0 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -18,6 +18,7 @@ play.modules.enabled += "uk.gov.hmrc.play.bootstrap.AuthModule" play.modules.enabled += "uk.gov.hmrc.play.bootstrap.HttpClientModule" play.modules.enabled += "uk.gov.hmrc.play.bootstrap.HttpClientV2Module" +play.modules.enabled += "uk.gov.hmrc.agentservicesaccount.modules.CryptoProviderModule" play.modules.enabled += "uk.gov.hmrc.mongo.play.PlayMongoModule" @@ -227,3 +228,10 @@ suspendedContactDetails { } pillar2-submission-frontend.external-url = "http://localhost:10053" + + +fieldLevelEncryption { + enable = true + key = "edkOOwt7uvzw1TXnFIN6aRVHkfWcgiOrbBvkEQvO65g=" + previousKeys = [] +} diff --git a/project/AppDependencies.scala b/project/AppDependencies.scala index fa749c1e..88af9421 100644 --- a/project/AppDependencies.scala +++ b/project/AppDependencies.scala @@ -14,6 +14,7 @@ object AppDependencies { "com.beachape" %% "enumeratum-play" % enumeratumVersion, "org.julienrf" %% "play-json-derived-codecs" % "11.0.0", "org.apache.commons" % "commons-text" % "1.12.0", + "uk.gov.hmrc" %% "crypto-json-play-30" % "8.0.0" ) val test: Seq[ModuleID] = Seq( diff --git a/test/uk/gov/hmrc/agentservicesaccount/model/DesignatoryDetailsSpec.scala b/test/uk/gov/hmrc/agentservicesaccount/model/DesignatoryDetailsSpec.scala new file mode 100644 index 00000000..e0c62175 --- /dev/null +++ b/test/uk/gov/hmrc/agentservicesaccount/model/DesignatoryDetailsSpec.scala @@ -0,0 +1,126 @@ +/* + * Copyright 2024 HM Revenue & Customs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.hmrc.agentservicesaccount.model + +import play.api.libs.json.{JsObject, Json} +import uk.gov.hmrc.agentservicesaccount.models.desiDetails.{CtChanges, DesignatoryDetails, OtherServices, SaChanges} +import uk.gov.hmrc.agentservicesaccount.models.{AgencyDetails, BusinessAddress} +import uk.gov.hmrc.agentservicesaccount.support.UnitSpec +import uk.gov.hmrc.crypto.{Decrypter, Encrypter, SymmetricCryptoFactory} +import uk.gov.hmrc.domain.{CtUtr, SaUtr} + +class DesignatoryDetailsSpec extends UnitSpec { + + implicit val crypto: Encrypter with Decrypter = SymmetricCryptoFactory.aesCrypto("edkOOwt7uvzw1TXnFIN6aRVHkfWcgiOrbBvkEQvO65g=") + + val testDesignatoryDetails: DesignatoryDetails = DesignatoryDetails( + AgencyDetails( + Some("testName"), + Some("testEmail"), + Some("testPhone"), + Some(BusinessAddress( + "line1", + Some("line2"), + Some("line3"), + Some("line4"), + Some("postCode"), + "countryCode" + )) + ), + OtherServices( + SaChanges( + applyChanges = true, + Some(SaUtr("sautr")) + ), + CtChanges( + applyChanges = true, + Some(CtUtr("ctutr")) + ) + ) + ) + val testJson: JsObject = Json.obj( + "agencyDetails" -> Json.obj( + "agencyName" -> "testName", + "agencyEmail" -> "testEmail", + "agencyTelephone" -> "testPhone", + "agencyAddress" -> Json.obj( + "addressLine1" -> "line1", + "addressLine2" -> "line2", + "addressLine3" -> "line3", + "addressLine4" -> "line4", + "postalCode" -> "postCode", + "countryCode" -> "countryCode" + ) + ), + "otherServices" -> Json.obj( + "saChanges" -> Json.obj( + "applyChanges" -> true, + "saAgentReference" -> "sautr" + ), + "ctChanges" -> Json.obj( + "applyChanges" -> true, + "ctAgentReference" -> "ctutr" + ) + ) + ) + val testEncryptedJson: JsObject = Json.obj( + "agencyDetails" -> Json.obj( + "agencyName" -> "7g352kI4Rfh0Af6Jm7Bl1g==", + "agencyEmail" -> "BVfLzY//sJgIMS+Frv7dHQ==", + "agencyTelephone" -> "2NFf8EgEOaFuVowl+Zotcw==", + "agencyAddress" -> Json.obj( + "addressLine1" -> "u3kG4I/2HMwvbg6DgKW2NA==", + "addressLine2" -> "wv13MNc1x64H4C2I7pK/9g==", + "addressLine3" -> "6hEc2+5vL10UZ5wxTijhdA==", + "addressLine4" -> "vIlbrtn9c/iM4Xg6+QxdXw==", + "postalCode" -> "14YJ/1yyIF7SptIAKKJJ6Q==", + "countryCode" -> "Q80Jvd8jhZzman3gH6Gh0A==" + ) + ), + "otherServices" -> Json.obj( + "saChanges" -> Json.obj( + "applyChanges" -> true, + "saAgentReference" -> "r6af9+6cwYaHzCIsbO1VDw==" + ), + "ctChanges" -> Json.obj( + "applyChanges" -> true, + "ctAgentReference" -> "jHBh7aHi6yaOzzXrUP0+6g==" + ) + ) + ) + "DesignatoryDetails" when { + "using default format" should { + "serialise to Json correctly" in { + Json.toJson(testDesignatoryDetails) shouldBe testJson + } + "deserialise from Json correctly" in { + testJson.as[DesignatoryDetails] shouldBe testDesignatoryDetails + } + } + "using crypto format" should { + "serialise to Json correctly" in { + Json.toJson(testDesignatoryDetails)(DesignatoryDetails.databaseFormat) shouldBe testEncryptedJson + } + "deserialise from unencrypted Json correctly" in { + testJson.as[DesignatoryDetails](DesignatoryDetails.databaseFormat) shouldBe testDesignatoryDetails + } + "deserialise from encrypted Json correctly" in { + testEncryptedJson.as[DesignatoryDetails](DesignatoryDetails.databaseFormat) shouldBe testDesignatoryDetails + } + } + } +} diff --git a/test/uk/gov/hmrc/agentservicesaccount/model/YourDetailsSpec.scala b/test/uk/gov/hmrc/agentservicesaccount/model/YourDetailsSpec.scala new file mode 100644 index 00000000..05cc06f7 --- /dev/null +++ b/test/uk/gov/hmrc/agentservicesaccount/model/YourDetailsSpec.scala @@ -0,0 +1,61 @@ +/* + * Copyright 2024 HM Revenue & Customs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.hmrc.agentservicesaccount.model + +import play.api.libs.json.{JsObject, Json} +import uk.gov.hmrc.agentservicesaccount.models.desiDetails.YourDetails +import uk.gov.hmrc.agentservicesaccount.support.UnitSpec +import uk.gov.hmrc.crypto.{Decrypter, Encrypter, SymmetricCryptoFactory} + +class YourDetailsSpec extends UnitSpec { + + implicit val crypto: Encrypter with Decrypter = SymmetricCryptoFactory.aesCrypto("edkOOwt7uvzw1TXnFIN6aRVHkfWcgiOrbBvkEQvO65g=") + + val testYourDetails: YourDetails = YourDetails( + "testName", + "testPhone" + ) + val testJson: JsObject = Json.obj( + "fullName" -> "testName", + "telephone" -> "testPhone" + ) + val testEncryptedJson: JsObject = Json.obj( + "fullName" -> "7g352kI4Rfh0Af6Jm7Bl1g==", + "telephone" -> "2NFf8EgEOaFuVowl+Zotcw==" + ) + "YourDetails" when { + "using default format" should { + "serialise to Json correctly" in { + Json.toJson(testYourDetails) shouldBe testJson + } + "deserialise from Json correctly" in { + testJson.as[YourDetails] shouldBe testYourDetails + } + } + "using crypto format" should { + "serialise to Json correctly" in { + Json.toJson(testYourDetails)(YourDetails.databaseFormat) shouldBe testEncryptedJson + } + "deserialise from unencrypted Json correctly" in { + testJson.as[YourDetails](YourDetails.databaseFormat) shouldBe testYourDetails + } + "deserialise from encrypted Json correctly" in { + testEncryptedJson.as[YourDetails](YourDetails.databaseFormat) shouldBe testYourDetails + } + } + } +}