Skip to content

Commit

Permalink
feat(castor): Resolve LongFormatPrismDIDs in Castor (#23)
Browse files Browse the repository at this point in the history
* Adding LongFormatPrismDID resolution + tests.
Co-authored-by: Ahmed Moussa <[email protected]>
Signed-off-by: Javi <[email protected]>
  • Loading branch information
elribonazo authored and hamada147 committed May 13, 2024
1 parent 0fed9ef commit e07a79f
Show file tree
Hide file tree
Showing 24 changed files with 474 additions and 22 deletions.
1 change: 1 addition & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
DISABLE: COPYPASTE,SPELL
GITHUB_TOKEN: ${{ secrets.ATALA_GITHUB_TOKEN }}
DISABLE_LINTERS: REPOSITORY_GITLEAKS
DISABLE_ERRORS_LINTERS: PROTOBUF_PROTOLINT
steps:
- name: Checkout Code
uses: actions/checkout@v3
Expand Down
4 changes: 2 additions & 2 deletions apollo/src/commonMain/kotlin/ApolloMock.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ class ApolloMock : Apollo {
publicKey = PublicKey(KeyCurve(Curve.ED25519), ByteArray(0))
)
var compressedPublicKeyReturn: CompressedPublicKey = CompressedPublicKey(
PublicKey(KeyCurve(Curve.ED25519), ByteArray(0)),
PublicKey(KeyCurve(Curve.SECP256K1), ByteArray(0)),
ByteArray(0)
)
var publicKeyReturn: PublicKey = PublicKey(KeyCurve(Curve.ED25519), ByteArray(0))
var signMessageReturn: Signature = Signature(ByteArray(0))
var verifySignatureReturn: Boolean = true
var compressedPublicKeyDataReturn: CompressedPublicKey = CompressedPublicKey(
PublicKey(KeyCurve(Curve.ED25519), ByteArray(0)),
PublicKey(KeyCurve(Curve.SECP256K1), ByteArray(0)),
ByteArray(0)
)
var signMessageByteArrayReturn: Signature = Signature(ByteArray(0))
Expand Down
22 changes: 20 additions & 2 deletions castor/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,18 @@ kotlin {
}
val commonMain by getting {
dependsOn(commonAntlr)
kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/main/kotlin")
resources.srcDir("${project(":protosLib").projectDir}/src/main")
dependencies {
implementation(project(":domain"))
implementation(project(":apollo"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
implementation("io.iohk.atala.prism:didpeer:1.0.0-alpha")
implementation(project(":apollo"))
implementation(project(":domain"))
implementation("io.iohk.atala.prism:apollo:1.0.0-alpha")
api("io.iohk:pbandk-runtime:0.20.7") {
exclude("com.google.protobuf")
}
}
}
val commonTest by getting {
Expand Down Expand Up @@ -218,5 +224,17 @@ tasks.matching {
it.name == "compileKotlinJs" ||
it.name == "compileKotlinJvm"
}.all {
this.dependsOn(":protosLib:generateProto")
this.dependsOn(antlrGenerationTask)
}

val buildProtoLibsGen by tasks.creating {
group = "build"
this.dependsOn(":protosLib:generateProto")
}

tasks.getByName("build") {
this.doFirst {
":protosLib:generateProto"
}
}
10 changes: 7 additions & 3 deletions castor/src/commonMain/kotlin/CastorImpl.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.iohk.atala.prism.castor

import io.iohk.atala.prism.apollo.ApolloImpl
import io.iohk.atala.prism.castor.did.DIDParser
import io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.resolvers.LongFormPrismDIDResolver
import io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.resolvers.PeerDIDResolver
import io.iohk.atala.prism.domain.buildingBlocks.Apollo
import io.iohk.atala.prism.domain.buildingBlocks.Castor
Expand All @@ -27,14 +29,16 @@ import kotlinx.serialization.json.Json

open class CastorImpl : Castor {
private val apollo: Apollo
private var resolvers: Array<DIDResolver> = arrayOf(
PeerDIDResolver()
)
private var resolvers: Array<DIDResolver>

constructor(
apollo: Apollo? = null,
) {
this.apollo = apollo ?: ApolloImpl()
this.resolvers = arrayOf(
PeerDIDResolver(),
LongFormPrismDIDResolver(this.apollo)
)
}

override fun parseDID(did: String): DID {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.iohk.atala.prism.castor
package io.iohk.atala.prism.castor.did

import io.iohk.atala.prism.castor.antlrgrammar.DIDAbnfLexer
import io.iohk.atala.prism.castor.antlrgrammar.DIDAbnfParser
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.iohk.atala.prism.castor
package io.iohk.atala.prism.castor.did

import io.iohk.atala.prism.castor.antlrgrammar.DIDAbnfBaseListener
import io.iohk.atala.prism.castor.antlrgrammar.DIDAbnfParser
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.iohk.atala.prism.castor
package io.iohk.atala.prism.castor.did

import io.iohk.atala.prism.castor.antlrgrammar.DIDUrlAbnfLexer
import io.iohk.atala.prism.castor.antlrgrammar.DIDUrlAbnfParser
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.iohk.atala.prism.castor
package io.iohk.atala.prism.castor.did

import io.iohk.atala.prism.castor.antlrgrammar.DIDUrlAbnfBaseListener
import io.iohk.atala.prism.castor.antlrgrammar.DIDUrlAbnfParser
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.iohk.atala.prism.castor
package io.iohk.atala.prism.castor.did

import org.antlr.v4.kotlinruntime.DefaultErrorStrategy
import org.antlr.v4.kotlinruntime.Parser
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.iohk.atala.prism.castor
package io.iohk.atala.prism.castor.did

class InvalidDIDStringError(override val message: String) : Exception(message) {
val code: String = "InvalidDIDStringError"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.did.prismdid

import io.iohk.atala.prism.castor.did.prismdid.PrismDIDMethodId
import io.iohk.atala.prism.domain.models.CastorError
import io.iohk.atala.prism.domain.models.DID

data class
LongFormPrismDID(val did: DID) {
private val prismMethodId: PrismDIDMethodId
val stateHash: String
val encodedState: String

init {
val methodId = PrismDIDMethodId(
did.methodId
)

if (methodId.sections.size !== 2) {
throw CastorError.InvalidLongFormDID()
}

val stateHash = methodId.sections.first()
val encodedState = methodId.sections.last()

this.prismMethodId = methodId
this.stateHash = stateHash
this.encodedState = encodedState
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.iohk.atala.prism.castor.did.prismdid

import io.iohk.atala.prism.domain.models.CastorError

data class PrismDIDMethodId(private val value: String) {
val sections: List<String>
get() = value.split(":").map { it }

override fun toString(): String {
return value
}

constructor(sections: List<String>) : this(sections.joinToString(":")) {
val sectionRegex = Regex("^[A-Za-z0-9_-]+$")
if (!sections.all { sectionRegex.matches(it) }) {
throw CastorError.MethodIdIsDoesNotSatisfyRegex()
}
val methodSpecificIdRegex = Regex("^([A-Za-z0-9_-]*:)*[A-Za-z0-9_-]+$")
if (!methodSpecificIdRegex.matches(value)) {
throw CastorError.MethodIdIsDoesNotSatisfyRegex()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package io.iohk.atala.prism.castor.did.prismdid

import io.iohk.atala.prism.domain.buildingBlocks.Apollo
import io.iohk.atala.prism.domain.models.CastorError
import io.iohk.atala.prism.domain.models.CompressedPublicKey
import io.iohk.atala.prism.domain.models.PublicKey
import io.iohk.atala.prism.protos.CompressedECKeyData
import io.iohk.atala.prism.protos.KeyUsage
import pbandk.ByteArr

class PrismDIDPublicKey {
enum class Usage(val value: String) {
MASTER_KEY("masterKey"),
ISSUING_KEY("issuingKey"),
AUTHENTICATION_KEY("authenticationKey"),
REVOCATION_KEY("revocationKey"),
CAPABILITY_DELEGATION_KEY("capabilityDelegationKey"),
CAPABILITY_INVOCATION_KEY("capabilityInvocationKey"),
KEY_AGREEMENT_KEY("keyAgreementKey"),
UNKNOWN_KEY("unknownKey")
}

private val apollo: Apollo
val id: String
val usage: Usage
val keyData: PublicKey

constructor(apollo: Apollo, id: String, usage: Usage, keyData: PublicKey) {
this.apollo = apollo
this.id = id
this.usage = usage
this.keyData = keyData
}

constructor(apollo: Apollo, proto: io.iohk.atala.prism.protos.PublicKey) {
this.apollo = apollo
this.id = proto.id
this.usage = proto.usage.fromProto()
this.keyData = when (proto.keyData) {
is io.iohk.atala.prism.protos.PublicKey.KeyData.CompressedEcKeyData -> {
apollo.compressedPublicKey(compressedData = proto.keyData.value.data.array).uncompressed
}
else -> {
throw CastorError.InvalidPublicKeyEncoding()
}
}
}

fun toProto(): io.iohk.atala.prism.protos.PublicKey {
val compressed = apollo.compressedPublicKey(keyData)
return io.iohk.atala.prism.protos.PublicKey(
id = id,
usage = usage.toProto(),
keyData = io.iohk.atala.prism.protos.PublicKey.KeyData.CompressedEcKeyData(
compressed.toProto()
)
)
}
}

fun KeyUsage.fromProto(): PrismDIDPublicKey.Usage {
return when (this) {
is KeyUsage.MASTER_KEY -> PrismDIDPublicKey.Usage.MASTER_KEY
is KeyUsage.ISSUING_KEY -> PrismDIDPublicKey.Usage.ISSUING_KEY
is KeyUsage.AUTHENTICATION_KEY -> PrismDIDPublicKey.Usage.AUTHENTICATION_KEY
is KeyUsage.REVOCATION_KEY -> PrismDIDPublicKey.Usage.REVOCATION_KEY
is KeyUsage.CAPABILITY_DELEGATION_KEY -> PrismDIDPublicKey.Usage.CAPABILITY_DELEGATION_KEY
is KeyUsage.CAPABILITY_INVOCATION_KEY -> PrismDIDPublicKey.Usage.CAPABILITY_INVOCATION_KEY
is KeyUsage.KEY_AGREEMENT_KEY -> PrismDIDPublicKey.Usage.KEY_AGREEMENT_KEY
is KeyUsage.UNKNOWN_KEY -> PrismDIDPublicKey.Usage.UNKNOWN_KEY
is KeyUsage.UNRECOGNIZED -> PrismDIDPublicKey.Usage.UNKNOWN_KEY
}
}

fun CompressedPublicKey.toProto(): CompressedECKeyData {
return CompressedECKeyData(
curve = uncompressed.curve.curve.value,
data = ByteArr(value)
)
}

fun PrismDIDPublicKey.Usage.id(index: Int): String {
return when (this) {
PrismDIDPublicKey.Usage.MASTER_KEY -> "master$index"
PrismDIDPublicKey.Usage.ISSUING_KEY -> "issuing$index"
PrismDIDPublicKey.Usage.AUTHENTICATION_KEY -> "authentication$index"
PrismDIDPublicKey.Usage.REVOCATION_KEY -> "revocation$index"
PrismDIDPublicKey.Usage.CAPABILITY_DELEGATION_KEY -> "capabilityDelegation$index"
PrismDIDPublicKey.Usage.CAPABILITY_INVOCATION_KEY -> "capabilityInvocation$index"
PrismDIDPublicKey.Usage.KEY_AGREEMENT_KEY -> "keyAgreement$index"
PrismDIDPublicKey.Usage.UNKNOWN_KEY -> "unknown$index"
}
}

fun PrismDIDPublicKey.Usage.toProto(): KeyUsage {
return when (this) {
PrismDIDPublicKey.Usage.MASTER_KEY -> KeyUsage.MASTER_KEY
PrismDIDPublicKey.Usage.ISSUING_KEY -> KeyUsage.ISSUING_KEY
PrismDIDPublicKey.Usage.AUTHENTICATION_KEY -> KeyUsage.AUTHENTICATION_KEY
PrismDIDPublicKey.Usage.REVOCATION_KEY -> KeyUsage.REVOCATION_KEY
PrismDIDPublicKey.Usage.CAPABILITY_DELEGATION_KEY -> KeyUsage.CAPABILITY_DELEGATION_KEY
PrismDIDPublicKey.Usage.CAPABILITY_INVOCATION_KEY -> KeyUsage.CAPABILITY_INVOCATION_KEY
PrismDIDPublicKey.Usage.KEY_AGREEMENT_KEY -> KeyUsage.KEY_AGREEMENT_KEY
PrismDIDPublicKey.Usage.UNKNOWN_KEY -> KeyUsage.UNKNOWN_KEY
}
}
Loading

0 comments on commit e07a79f

Please sign in to comment.