• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

input-output-hk / atala-prism-building-blocks / 8699251619

16 Apr 2024 02:54AM UTC coverage: 31.165% (+0.4%) from 30.781%
8699251619

Pull #969

CryptoKnightIOG
ATL-6782: Aud check

Signed-off-by: Bassam Riman <bassam.riman@iohk.io>
Pull Request #969: feat: VC Verification Audiance check

0 of 46 new or added lines in 4 files covered. (0.0%)

486 existing lines in 113 files now uncovered.

4512 of 14478 relevant lines covered (31.16%)

0.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.82
/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/sql/package.scala
1
package io.iohk.atala.agent.walletapi
2

3
import com.nimbusds.jose.jwk.OctetKeyPair
4
import doobie.*
5
import doobie.postgres.implicits.*
6
import doobie.util.invariant.InvalidEnum
7
import io.circe.*
8
import io.circe.parser.*
9
import io.circe.syntax.*
10
import io.iohk.atala.agent.walletapi.model.Wallet
11
import io.iohk.atala.agent.walletapi.model.{ManagedDIDState, PublicationState, KeyManagementMode}
12
import io.iohk.atala.castor.core.model.ProtoModelHelper.*
13
import io.iohk.atala.castor.core.model.did.InternalKeyPurpose
14
import io.iohk.atala.castor.core.model.did.VerificationRelationship
15
import io.iohk.atala.castor.core.model.did.{PrismDID, PrismDIDOperation, ScheduledDIDOperationStatus}
16
import io.iohk.atala.event.notification.EventNotificationConfig
17
import io.iohk.atala.prism.protos.node_models
18
import io.iohk.atala.shared.models.WalletId
19
import zio.json.*
20
import zio.json.ast.Json
21
import zio.json.ast.Json.*
22

23
import java.net.URL
24
import java.time.Instant
25
import java.util.UUID
26
import scala.collection.immutable.ArraySeq
27
import scala.util.Try
28

29
package object sql {
30

31
  sealed trait PublicationStatusType
32
  object PublicationStatusType {
33
    case object CREATED extends PublicationStatusType
34
    case object PUBLICATION_PENDING extends PublicationStatusType
35
    case object PUBLISHED extends PublicationStatusType
36

1✔
37
    def from(status: PublicationState): PublicationStatusType = status match {
1✔
38
      case PublicationState.Created()             => CREATED
1✔
39
      case PublicationState.PublicationPending(_) => PUBLICATION_PENDING
1✔
40
      case PublicationState.Published(_)          => PUBLISHED
41
    }
42
  }
43

1✔
44
  given Meta[VerificationRelationship | InternalKeyPurpose] = pgEnumString(
45
    "PRISM_DID_KEY_USAGE",
46
    {
1✔
47
      case "MASTER"                => InternalKeyPurpose.Master
×
48
      case "ISSUING"               => VerificationRelationship.AssertionMethod
1✔
49
      case "KEY_AGREEMENT"         => VerificationRelationship.KeyAgreement
1✔
50
      case "AUTHENTICATION"        => VerificationRelationship.Authentication
×
51
      case "REVOCATION"            => InternalKeyPurpose.Revocation
×
52
      case "CAPABILITY_INVOCATION" => VerificationRelationship.CapabilityInvocation
×
53
      case "CAPABILITY_DELEGATION" => VerificationRelationship.CapabilityDelegation
×
54
      case s                       => throw InvalidEnum[VerificationRelationship | InternalKeyPurpose](s)
55
    },
56
    {
1✔
57
      case InternalKeyPurpose.Master                     => "MASTER"
1✔
58
      case VerificationRelationship.AssertionMethod      => "ISSUING"
1✔
59
      case VerificationRelationship.KeyAgreement         => "KEY_AGREEMENT"
1✔
60
      case VerificationRelationship.Authentication       => "AUTHENTICATION"
×
61
      case InternalKeyPurpose.Revocation                 => "REVOCATION"
×
62
      case VerificationRelationship.CapabilityInvocation => "CAPABILITY_INVOCATION"
×
63
      case VerificationRelationship.CapabilityDelegation => "CAPABILITY_DELEGATION"
64
    }
65
  )
66

1✔
67
  given Meta[KeyManagementMode] = pgEnumString(
68
    "PRISM_DID_KEY_MODE",
69
    {
1✔
70
      case "HD" => KeyManagementMode.HD
×
71
      case s    => throw InvalidEnum[KeyManagementMode](s)
72
    },
1✔
73
    { case KeyManagementMode.HD => "HD" }
74
  )
75

1✔
76
  given Meta[PublicationStatusType] = pgEnumString(
77
    "PRISM_DID_WALLET_STATUS",
78
    {
1✔
79
      case "CREATED"             => PublicationStatusType.CREATED
1✔
80
      case "PUBLICATION_PENDING" => PublicationStatusType.PUBLICATION_PENDING
1✔
81
      case "PUBLISHED"           => PublicationStatusType.PUBLISHED
×
82
      case s                     => throw InvalidEnum[PublicationStatusType](s)
83
    },
84
    {
1✔
85
      case PublicationStatusType.CREATED             => "CREATED"
1✔
86
      case PublicationStatusType.PUBLICATION_PENDING => "PUBLICATION_PENDING"
1✔
87
      case PublicationStatusType.PUBLISHED           => "PUBLISHED"
88
    }
89
  )
90

1✔
91
  given Meta[ScheduledDIDOperationStatus] = pgEnumString(
92
    "PRISM_DID_OPERATION_STATUS",
93
    {
1✔
94
      case "PENDING_SUBMISSION"     => ScheduledDIDOperationStatus.Pending
×
95
      case "AWAIT_CONFIRMATION"     => ScheduledDIDOperationStatus.AwaitingConfirmation
1✔
96
      case "CONFIRMED_AND_APPLIED"  => ScheduledDIDOperationStatus.Confirmed
×
97
      case "CONFIRMED_AND_REJECTED" => ScheduledDIDOperationStatus.Rejected
×
98
      case s                        => throw InvalidEnum[ScheduledDIDOperationStatus](s)
99
    },
100
    {
1✔
101
      case ScheduledDIDOperationStatus.Pending              => "PENDING_SUBMISSION"
1✔
102
      case ScheduledDIDOperationStatus.AwaitingConfirmation => "AWAIT_CONFIRMATION"
1✔
103
      case ScheduledDIDOperationStatus.Confirmed            => "CONFIRMED_AND_APPLIED"
×
104
      case ScheduledDIDOperationStatus.Rejected             => "CONFIRMED_AND_REJECTED"
105
    }
106
  )
107

×
108
  given prismDIDGet: Get[PrismDID] = Get[String].map(PrismDID.fromString(_).left.map(Exception(_)).toTry.get)
1✔
109
  given prismDIDPut: Put[PrismDID] = Put[String].contramap(_.asCanonical.toString)
UNCOV
110

×
111
  given arraySeqByteGet: Get[ArraySeq[Byte]] = Get[Array[Byte]].map(ArraySeq.from)
1✔
112
  given arraySeqBytePut: Put[ArraySeq[Byte]] = Put[Array[Byte]].contramap(_.toArray)
113

×
114
  given urlGet: Get[URL] = Get[String].map(URL(_))
1✔
115
  given urlPut: Put[URL] = Put[String].contramap(_.toString())
116

1✔
117
  given octetKeyPairGet: Get[OctetKeyPair] = Get[String].map(OctetKeyPair.parse)
1✔
118
  given octetKeyPairPut: Put[OctetKeyPair] = Put[String].contramap(_.toJSONString)
119

×
120
  given jsonGet: Get[Json] = Get[String].map(_.fromJson[Json] match {
1✔
121
    case Right(value) => value
×
122
    case Left(error)  => throw new RuntimeException(error)
123
  })
1✔
124
  given jsonPut: Put[Json] = Put[String].contramap(_.toString())
125

126
  final case class DIDStateRow(
127
      did: PrismDID,
128
      publicationStatus: PublicationStatusType,
129
      atalaOperationContent: Array[Byte],
130
      publishOperationId: Option[Array[Byte]],
131
      createdAt: Instant,
132
      updatedAt: Instant,
133
      keyMode: KeyManagementMode,
134
      didIndex: Int,
135
      walletId: WalletId
136
  ) {
1✔
137
    def toDomain: Try[ManagedDIDState] = {
138
      publicationStatus match {
1✔
139
        case PublicationStatusType.CREATED =>
1✔
140
          createDIDOperation.map(op => ManagedDIDState(op, didIndex, PublicationState.Created()))
1✔
141
        case PublicationStatusType.PUBLICATION_PENDING =>
1✔
142
          for {
×
143
            createDIDOperation <- createDIDOperation
1✔
144
            operationId <- publishOperationId
×
145
              .toRight(RuntimeException(s"DID publication operation id does not exists for PUBLICATION_PENDING status"))
146
              .toTry
147
          } yield ManagedDIDState(
148
            createDIDOperation,
149
            didIndex,
1✔
150
            PublicationState.PublicationPending(ArraySeq.from(operationId))
151
          )
1✔
152
        case PublicationStatusType.PUBLISHED =>
1✔
153
          for {
×
154
            createDIDOperation <- createDIDOperation
1✔
155
            operationId <- publishOperationId
×
156
              .toRight(RuntimeException(s"DID publication operation id does not exists for PUBLISHED status"))
157
              .toTry
1✔
158
          } yield ManagedDIDState(createDIDOperation, didIndex, PublicationState.Published(ArraySeq.from(operationId)))
159
      }
160
    }
161

1✔
162
    private def createDIDOperation: Try[PrismDIDOperation.Create] = {
×
163
      Try(node_models.AtalaOperation.parseFrom(atalaOperationContent))
1✔
164
        .flatMap { atalaOperation =>
1✔
165
          atalaOperation.operation.createDid
×
166
            .toRight(
×
167
              s"cannot extract CreateDIDOperation from AtalaOperation (${atalaOperation.operation.getClass.getSimpleName} found)"
168
            )
×
169
            .flatMap(_.toDomain)
×
170
            .left
1✔
171
            .map(RuntimeException(_))
172
            .toTry
173
        }
174
    }
175
  }
176

177
  object DIDStateRow {
1✔
178
    def from(did: PrismDID, state: ManagedDIDState, now: Instant, walletId: WalletId): DIDStateRow = {
179
      val createOperation = state.createOperation
1✔
180
      val status = PublicationStatusType.from(state.publicationState)
181
      val publishedOperationId = state.publicationState match {
1✔
182
        case PublicationState.Created()                       => None
1✔
183
        case PublicationState.PublicationPending(operationId) => Some(operationId.toArray)
1✔
184
        case PublicationState.Published(operationId)          => Some(operationId.toArray)
185
      }
186
      DIDStateRow(
187
        did = did,
188
        publicationStatus = status,
1✔
189
        atalaOperationContent = createOperation.toAtalaOperation.toByteArray,
1✔
190
        publishOperationId = publishedOperationId.map(_.toArray),
191
        createdAt = now,
192
        updatedAt = now,
1✔
193
        keyMode = state.keyMode,
194
        didIndex = state.didIndex,
195
        walletId = walletId
196
      )
197
    }
198
  }
199

200
  final case class WalletRow(
201
      id: WalletId,
202
      name: String,
203
      createdAt: Instant,
204
      updatedAt: Instant
205
  ) {
1✔
206
    def toDomain: Wallet = {
207
      Wallet(
208
        id: WalletId,
209
        name: String,
210
        createdAt: Instant,
211
        updatedAt: Instant
212
      )
213
    }
214
  }
215

216
  object WalletRow {
1✔
217
    def from(wallet: Wallet): WalletRow = {
218
      WalletRow(
219
        id = wallet.id,
220
        name = wallet.name,
221
        createdAt = wallet.createdAt,
222
        updatedAt = wallet.updatedAt
223
      )
224
    }
225
  }
226

227
  final case class WalletNofiticationRow(
228
      id: UUID,
229
      walletId: WalletId,
230
      url: URL,
231
      customHeaders: String,
232
      createdAt: Instant,
233
  ) {
1✔
234
    def toDomain: Try[EventNotificationConfig] = {
×
235
      decode[Map[String, String]](customHeaders).toTry
1✔
236
        .map { headers =>
237
          EventNotificationConfig(
238
            id = id,
239
            walletId = walletId,
240
            url = url,
241
            customHeaders = headers,
242
            createdAt = createdAt,
243
          )
244
        }
245
    }
246
  }
247

248
  object WalletNofiticationRow {
1✔
249
    def from(config: EventNotificationConfig): WalletNofiticationRow = {
250
      WalletNofiticationRow(
251
        id = config.id,
252
        walletId = config.walletId,
253
        url = config.url,
1✔
254
        customHeaders = config.customHeaders.asJson.noSpacesSortKeys,
255
        createdAt = config.createdAt,
256
      )
257
    }
258
  }
259

260
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc