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

hyperledger / identus-cloud-agent / 10793991050

10 Sep 2024 01:56PM CUT coverage: 48.504% (-4.5%) from 52.962%
10793991050

push

web-flow
build: sbt and plugins dependency update (#1337)

Signed-off-by: Hyperledger Bot <hyperledger-bot@hyperledger.org>
Signed-off-by: Yurii Shynbuiev <yurii.shynbuiev@iohk.io>
Co-authored-by: Hyperledger Bot <hyperledger-bot@hyperledger.org>
Co-authored-by: Yurii Shynbuiev <yurii.shynbuiev@iohk.io>

7406 of 15269 relevant lines covered (48.5%)

0.49 hits per line

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

79.17
/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/schema/CredentialSchema.scala
1
package org.hyperledger.identus.pollux.core.model.schema
2

3
import org.hyperledger.identus.pollux.core.model.error.CredentialSchemaError
4
import org.hyperledger.identus.pollux.core.model.error.CredentialSchemaError.*
5
import org.hyperledger.identus.pollux.core.model.schema.`type`.{
6
  AnoncredSchemaType,
7
  CredentialJsonSchemaType,
8
  CredentialSchemaType
9
}
10
import org.hyperledger.identus.pollux.core.model.schema.`type`.anoncred.AnoncredSchemaSerDesV1
11
import org.hyperledger.identus.pollux.core.service.URIDereferencer
12
import org.hyperledger.identus.shared.json.{JsonSchemaValidator, JsonSchemaValidatorImpl}
13
import zio.*
14
import zio.json.*
15
import zio.json.ast.Json
16

17
import java.net.URI
18
import java.time.{OffsetDateTime, ZoneOffset}
19
import java.util.UUID
20

21
type Schema = zio.json.ast.Json
22

23
/** @param guid
24
  *   Globally unique identifier of the CredentialSchema object It's calculated as a UUID from string that contains the
25
  *   following fields: author, id and version
26
  * @param id
27
  *   Locally unique identifier of the CredentialSchema. It is UUID When the version of the credential schema changes
28
  *   this `id` keeps the same value
29
  * @param name
30
  *   Human readable name of the CredentialSchema
31
  * @param version
32
  *   Version of the CredentialSchema
33
  * @param author
34
  *   DID of the CredentialSchema's author
35
  * @param authored
36
  *   Datetime stamp of the schema creation
37
  * @param tags
38
  *   Tags of the CredentialSchema used for convenient lookup
39
  * @param description
40
  *   Human readable description of the schema
41
  * @param schema
42
  *   Internal schema object that depends on concrete implementation For W3C JsonSchema it is a JsonSchema object For
43
  *   AnonCreds schema is a AnonCreds schema
44
  */
45
case class CredentialSchema(
46
    guid: UUID,
47
    id: UUID,
48
    name: String,
49
    version: String,
50
    author: String,
51
    authored: OffsetDateTime,
52
    tags: Seq[String],
53
    description: String,
54
    `type`: String,
55
    schema: Schema
56
) {
57
  def longId = CredentialSchema.makeLongId(author, id, version)
1✔
58
}
59

60
object CredentialSchema {
61

62
  def makeLongId(author: String, id: UUID, version: String) =
1✔
63
    s"$author/${id.toString}?version=${version}"
1✔
64

65
  def makeGUID(author: String, id: UUID, version: String) =
1✔
66
    UUID.nameUUIDFromBytes(makeLongId(author, id, version).getBytes)
1✔
67

68
  def make(in: Input): UIO[CredentialSchema] = {
1✔
69
    for {
1✔
70
      id <- zio.Random.nextUUID
1✔
71
      cs <- make(id, in)
1✔
72
    } yield cs
73
  }
74
  def make(id: UUID, in: Input): UIO[CredentialSchema] = {
1✔
75
    for {
1✔
76
      ts <- zio.Clock.currentDateTime.map(
1✔
77
        _.atZoneSameInstant(ZoneOffset.UTC).toOffsetDateTime
1✔
78
      )
79
      guid = makeGUID(in.author, id, in.version)
1✔
80
    } yield CredentialSchema(
1✔
81
      guid = guid,
82
      id = id,
83
      name = in.name,
84
      version = in.version,
85
      author = in.author,
86
      authored = ts,
87
      tags = in.tags,
88
      description = in.description,
89
      `type` = in.`type`,
90
      schema = in.schema
91
    )
92
  }
93

94
  val defaultAgentDid = "did:prism:agent"
95

96
  case class Input(
97
      name: String,
98
      version: String,
99
      description: String,
100
      authored: Option[OffsetDateTime],
×
101
      tags: Seq[String],
102
      author: String = defaultAgentDid,
103
      `type`: String,
104
      schema: Schema
105
  )
106

107
  case class Filter(
108
      author: Option[String] = None,
1✔
109
      name: Option[String] = None,
1✔
110
      version: Option[String] = None,
1✔
111
      tags: Option[String] = None
1✔
112
  )
113

114
  case class FilteredEntries(entries: Seq[CredentialSchema], count: Long, totalCount: Long)
115

116
  given JsonEncoder[CredentialSchema] = DeriveJsonEncoder.gen[CredentialSchema]
×
117
  given JsonDecoder[CredentialSchema] = DeriveJsonDecoder.gen[CredentialSchema]
×
118

119
  def resolveJWTSchema(uri: URI, uriDereferencer: URIDereferencer): IO[CredentialSchemaParsingError, Json] = {
1✔
120
    for {
1✔
121
      content <- uriDereferencer.dereference(uri).orDieAsUnmanagedFailure
1✔
122
      json <- ZIO
1✔
123
        .fromEither(content.fromJson[Json])
1✔
124
        .mapError(error => CredentialSchemaParsingError(error))
125
    } yield json
126
  }
127

128
  def validSchemaValidator(
1✔
129
      schemaId: String,
130
      uriDereferencer: URIDereferencer
131
  ): IO[InvalidURI | CredentialSchemaParsingError, JsonSchemaValidator] = {
132
    for {
1✔
133
      uri <- ZIO.attempt(new URI(schemaId)).mapError(_ => InvalidURI(schemaId))
1✔
134
      json <- resolveJWTSchema(uri, uriDereferencer)
1✔
135
      schemaValidator <- JsonSchemaValidatorImpl
1✔
136
        .from(json)
1✔
137
        .orElse(
138
          ZIO
×
139
            .fromEither(json.as[CredentialSchema])
×
140
            .mapError(error => CredentialSchemaParsingError(error))
141
            .flatMap(cs =>
142
              JsonSchemaValidatorImpl.from(cs.schema).mapError(error => CredentialSchemaParsingError(error.error))
×
143
            )
×
144
        )
×
145
    } yield schemaValidator
×
146
  }
×
147

148
  def validateJWTCredentialSubject(
1✔
149
      schemaId: String,
150
      credentialSubject: String,
151
      uriDereferencer: URIDereferencer
152
  ): IO[InvalidURI | CredentialSchemaParsingError | CredentialSchemaValidationError, Unit] = {
153
    for {
1✔
154
      schemaValidator <- validSchemaValidator(schemaId, uriDereferencer)
1✔
155
      _ <- schemaValidator.validate(credentialSubject).mapError(CredentialSchemaValidationError.apply)
1✔
156
    } yield ()
1✔
157
  }
158

159
  def validateAnonCredsClaims(
1✔
160
      schemaId: String,
161
      claims: String,
162
      uriDereferencer: URIDereferencer
163
  ): IO[InvalidURI | CredentialSchemaParsingError | VCClaimsParsingError | VCClaimValidationError, Unit] = {
164
    for {
1✔
165
      uri <- ZIO.attempt(new URI(schemaId)).mapError(_ => InvalidURI(schemaId))
1✔
166
      content <- uriDereferencer.dereference(uri).orDieAsUnmanagedFailure
1✔
167
      validAttrNames <-
1✔
168
        AnoncredSchemaSerDesV1.schemaSerDes
1✔
169
          .deserialize(content)
170
          .mapError(error => CredentialSchemaParsingError(error.error))
×
171
          .map(_.attrNames)
172
      jsonClaims <- ZIO.fromEither(claims.fromJson[Json]).mapError(error => VCClaimsParsingError(error))
1✔
173
      _ <- jsonClaims match
1✔
174
        case Json.Obj(fields) =>
1✔
175
          ZIO.foreach(fields) {
1✔
176
            case (k, _) if !validAttrNames.contains(k) =>
×
177
              ZIO.fail(VCClaimValidationError(k, "Name undefined in schema"))
×
178
            case (k, Json.Str(v)) => ZIO.succeed(k -> v)
1✔
179
            case (k, _)           => ZIO.fail(VCClaimValidationError(k, "Value should be a string"))
×
180
          }
181
        case _ => ZIO.fail(VCClaimsParsingError("The JSON claims is not a JSON 'object'"))
×
182
    } yield ()
1✔
183
  }
184

185
  private val supportedCredentialSchemaTypes: Map[String, CredentialSchemaType] =
186
    IndexedSeq(CredentialJsonSchemaType, AnoncredSchemaType)
1✔
187
      .map(credentialSchemaType => (credentialSchemaType.`type`, credentialSchemaType))
1✔
188
      .toMap
189

190
  def resolveCredentialSchemaType(`type`: String): IO[UnsupportedCredentialSchemaType, CredentialSchemaType] = {
1✔
191
    ZIO
1✔
192
      .fromOption(supportedCredentialSchemaTypes.get(`type`))
1✔
193
      .mapError(_ => UnsupportedCredentialSchemaType(`type`))
194
  }
195

196
  def validateCredentialSchema(
1✔
197
      vcSchema: CredentialSchema
198
  ): IO[UnsupportedCredentialSchemaType | CredentialSchemaValidationError, Unit] = {
199
    for {
1✔
200
      resolvedSchemaType <- resolveCredentialSchemaType(vcSchema.`type`)
1✔
201
      _ <- resolvedSchemaType.validate(vcSchema.schema).mapError(CredentialSchemaValidationError.apply)
1✔
202
    } yield ()
1✔
203
  }
204

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