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

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

24 Apr 2024 03:32PM UTC coverage: 50.082% (+18.2%) from 31.912%
8819221863

Pull #973

mineme0110
minor cleanup

Signed-off-by: mineme0110 <shailesh.patil@iohk.io>
Pull Request #973: feat: Align the repo with new name identus-cloud-agent

1 of 6 new or added lines in 4 files covered. (16.67%)

2998 existing lines in 264 files now uncovered.

7340 of 14656 relevant lines covered (50.08%)

0.5 hits per line

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

71.43
/castor/lib/core/src/main/scala/io/iohk/atala/castor/core/model/did/w3c/W3CModelHelper.scala
1
package io.iohk.atala.castor.core.model.did.w3c
2

3
import io.iohk.atala.castor.core.model.did.{
4
  DIDData,
5
  DIDMetadata,
6
  PrismDID,
7
  PublicKey,
8
  PublicKeyData,
9
  Service,
10
  VerificationRelationship
11
}
12
import io.iohk.atala.shared.models.HexString
13
import io.iohk.atala.castor.core.model.did.ServiceType
14
import io.circe.Json
15
import io.iohk.atala.castor.core.model.did.ServiceEndpoint
16
import io.iohk.atala.castor.core.model.did.ServiceEndpoint.UriOrJsonEndpoint
17
import io.iohk.atala.castor.core.model.did.EllipticCurve
18
import java.time.format.DateTimeFormatter
19
import java.time.ZoneOffset
20
import java.time.Instant
21

22
object W3CModelHelper extends W3CModelHelper
23

24
private[castor] trait W3CModelHelper {
25

26
  private val XML_DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")
1✔
27

28
  private def toXmlDateTime(time: Instant): String = {
×
29
    val zonedDateTime = time.atZone(ZoneOffset.UTC)
×
UNCOV
30
    XML_DATETIME_FORMATTER.format(zonedDateTime)
×
31
  }
32

33
  extension (didMetadata: DIDMetadata) {
34
    def toW3C: DIDDocumentMetadataRepr = DIDDocumentMetadataRepr(
1✔
35
      deactivated = didMetadata.deactivated,
UNCOV
36
      canonicalId = didMetadata.canonicalId.map(_.toString),
×
37
      versionId = HexString.fromByteArray(didMetadata.lastOperationHash.toArray).toString,
1✔
UNCOV
38
      created = didMetadata.created.map(toXmlDateTime),
×
UNCOV
39
      updated = didMetadata.updated.map(toXmlDateTime)
×
40
    )
41
  }
42

43
  extension (didData: DIDData) {
44
    def toW3C(did: PrismDID): DIDDocumentRepr = {
1✔
45
      import VerificationRelationship.*
46
      val embeddedKeys = didData.publicKeys.map(k => k.toW3C(did, did))
1✔
47
      val keyRefWithPurpose = didData.publicKeys.map(k => k.purpose -> s"${did.toString}#${k.id}")
1✔
48
      val services = didData.services.map(_.toW3C(did))
1✔
49
      DIDDocumentRepr(
50
        id = did.toString,
1✔
51
        controller = did.toString,
1✔
52
        verificationMethod = embeddedKeys,
53
        authentication = keyRefWithPurpose.collect { case (Authentication, k) => k },
1✔
54
        assertionMethod = keyRefWithPurpose.collect { case (AssertionMethod, k) => k },
1✔
55
        keyAgreement = keyRefWithPurpose.collect { case (KeyAgreement, k) => k },
1✔
56
        capabilityInvocation = keyRefWithPurpose.collect { case (CapabilityInvocation, k) => k },
1✔
57
        capabilityDelegation = keyRefWithPurpose.collect { case (CapabilityDelegation, k) => k },
1✔
58
        service = services,
59
        context = deriveContext(embeddedKeys, services)
1✔
60
      )
61
    }
62

63
    // Reference: https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#constructing-a-json-ld-did-document
64
    private def deriveContext(keys: Seq[PublicKeyRepr], services: Seq[ServiceRepr]): Seq[String] = {
1✔
65
      val mandatoryContext = Seq("https://www.w3.org/ns/did/v1")
1✔
66
      val additionalContext = {
67
        val keyTypes = keys.map(_.`type`).toSet
1✔
68
        val serviceTypes = services
69
          .map(_.`type`)
1✔
70
          .flatMap {
1✔
UNCOV
71
            case s: String      => Seq(s)
×
72
            case s: Seq[String] => s
1✔
73
          }
74
          .toSet
1✔
75
        Seq(
1✔
76
          Option.when(keyTypes.contains("JsonWebKey2020"))("https://w3id.org/security/suites/jws-2020/v1"),
1✔
77
          Option.when(serviceTypes.contains("DIDCommMessaging"))("https://didcomm.org/messaging/contexts/v2"),
1✔
78
          Option.when(serviceTypes.contains("LinkedDomains"))(
1✔
79
            "https://identity.foundation/.well-known/did-configuration/v1"
80
          )
81
        ).flatten
82
      }
83
      val userDefinedContext = didData.context
84
      mandatoryContext ++ additionalContext ++ userDefinedContext
1✔
85
    }
86
  }
87

88
  extension (service: Service) {
89
    def toW3C(did: PrismDID): ServiceRepr =
1✔
90
      ServiceRepr(
91
        id = s"${did.toString}#${service.id}",
1✔
92
        `type` = serviceTypeToW3C(service.`type`),
1✔
93
        serviceEndpoint = serviceEndpointToW3C(service.serviceEndpoint)
1✔
94
      )
95

96
    private def serviceTypeToW3C(serviceType: ServiceType): String | Seq[String] = {
1✔
97
      import ServiceType.*
98
      serviceType match {
UNCOV
99
        case ServiceType.Single(name)    => name.value
×
100
        case names: ServiceType.Multiple => names.values.map(_.value)
1✔
101
      }
102
    }
103

104
    private def serviceEndpointToW3C(serviceEndpoint: ServiceEndpoint): Json = {
1✔
105
      serviceEndpoint match {
106
        case ServiceEndpoint.Single(uri) =>
1✔
107
          uri match {
108
            case UriOrJsonEndpoint.Uri(uri)   => Json.fromString(uri.value)
1✔
109
            case UriOrJsonEndpoint.Json(json) => Json.fromJsonObject(json)
1✔
110
          }
111
        case ep: ServiceEndpoint.Multiple =>
112
          val uris = ep.values.map {
×
113
            case UriOrJsonEndpoint.Uri(uri)   => Json.fromString(uri.value)
×
UNCOV
114
            case UriOrJsonEndpoint.Json(json) => Json.fromJsonObject(json)
×
115
          }
UNCOV
116
          Json.arr(uris: _*)
×
117
      }
118
    }
119
  }
120

121
  // FIXME: do we need to support uncompress for OKP key types?
122
  extension (publicKey: PublicKey) {
123
    def toW3C(did: PrismDID, controller: PrismDID): PublicKeyRepr = {
1✔
124
      val curve = publicKey.publicKeyData match {
125
        case PublicKeyData.ECCompressedKeyData(crv, _) => crv
1✔
126
        case PublicKeyData.ECKeyData(crv, _, _)        => crv
1✔
127
      }
128
      val publicKeyJwk = curve match {
129
        case EllipticCurve.SECP256K1 => secp256k1Repr(publicKey.publicKeyData)
1✔
130
        case EllipticCurve.ED25519   => okpPublicKeyRepr(publicKey.publicKeyData)
×
UNCOV
131
        case EllipticCurve.X25519    => okpPublicKeyRepr(publicKey.publicKeyData)
×
132
      }
133
      PublicKeyRepr(
134
        id = s"${did.toString}#${publicKey.id}",
1✔
135
        `type` = "JsonWebKey2020",
136
        controller = controller.toString,
1✔
137
        publicKeyJwk = publicKeyJwk
138
      )
139
    }
140

UNCOV
141
    private def okpPublicKeyRepr(pk: PublicKeyData): PublicKeyJwk = {
×
142
      pk match {
UNCOV
143
        case PublicKeyData.ECCompressedKeyData(crv, data) =>
×
144
          PublicKeyJwk(
145
            kty = "OKP",
146
            crv = crv.name,
UNCOV
147
            x = Some(data.toStringNoPadding),
×
148
            y = None
149
          )
150
        case PublicKeyData.ECKeyData(crv, _, _) =>
×
UNCOV
151
          throw Exception(s"Uncompressed key for curve ${crv.name} is not supported")
×
152
      }
153
    }
154

155
    private def secp256k1Repr(pk: PublicKeyData): PublicKeyJwk = {
1✔
156
      pk match {
157
        case pk: PublicKeyData.ECCompressedKeyData =>
158
          val uncomporessed = pk.toUncompressedKeyData.getOrElse(
1✔
UNCOV
159
            throw Exception(s"Conversion to uncompress key is not supported for curve ${pk.crv.name}")
×
160
          )
161
          PublicKeyJwk(
162
            kty = "EC",
163
            crv = uncomporessed.crv.name,
164
            x = Some(uncomporessed.x.toStringNoPadding),
1✔
165
            y = Some(uncomporessed.y.toStringNoPadding)
1✔
166
          )
167
        case PublicKeyData.ECKeyData(crv, x, y) =>
1✔
168
          PublicKeyJwk(
169
            kty = "EC",
170
            crv = crv.name,
171
            x = Some(x.toStringNoPadding),
1✔
172
            y = Some(y.toStringNoPadding)
1✔
173
          )
174

175
      }
176
    }
177
  }
178

179
}
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