Skip to content
This repository has been archived by the owner on Jan 9, 2024. It is now read-only.

Commit

Permalink
chore: added web and cheqd did methods (#29)
Browse files Browse the repository at this point in the history
* refactor: key database related
* chore: replaced ssikit2 dependency with waltid-did
  • Loading branch information
mikeplotean authored Oct 11, 2023
1 parent ef396b8 commit 20f4260
Show file tree
Hide file tree
Showing 12 changed files with 144 additions and 129 deletions.
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ dependencies {


// SSI Kit 2
implementation("id.walt:waltid-ssikit2:1.0.4-SNAPSHOT")
implementation("id.walt.did:waltid-did:1.0.0")
// implementation("id.walt:waltid-ssikit2:1.0.4-SNAPSHOT")
// implementation id.walt:core-crypto -> provided by id.walt:waltid-ssikit2

// OIDC
Expand Down
9 changes: 4 additions & 5 deletions src/main/kotlin/id/walt/db/Db.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import id.walt.config.ConfigManager
import id.walt.config.DatabaseConfiguration
import id.walt.config.DatasourceConfiguration
import id.walt.db.models.*
import id.walt.service.WalletServiceManager
import id.walt.service.account.AccountsService
import id.walt.ssikit.did.DidService
import id.walt.web.model.EmailLoginRequest
import id.walt.web.model.LoginRequest
import io.github.oshai.kotlinlogging.KotlinLogging
import org.flywaydb.core.Flyway
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.bridge.SLF4JBridgeHandler
Expand Down
3 changes: 0 additions & 3 deletions src/main/kotlin/id/walt/db/models/WalletKeys.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package id.walt.db.models

import id.walt.core.crypto.keys.Key
import kotlinx.serialization.json.Json
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.json.json

object WalletKeys : Table() {
val account = reference("account", Accounts.id)
Expand Down
109 changes: 49 additions & 60 deletions src/main/kotlin/id/walt/service/SSIKit2WalletService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import id.walt.core.crypto.keys.KeySerialization
import id.walt.core.crypto.keys.KeyType
import id.walt.core.crypto.keys.LocalKey
import id.walt.db.models.*
import id.walt.did.dids.DidService
import id.walt.did.dids.registrar.dids.DidCheqdCreateOptions
import id.walt.did.dids.registrar.dids.DidJwkCreateOptions
import id.walt.did.dids.registrar.dids.DidKeyCreateOptions
import id.walt.did.dids.registrar.dids.DidWebCreateOptions
import id.walt.did.helpers.WaltidServices
import id.walt.did.utils.EnumUtils.enumValueIgnoreCase
import id.walt.oid4vc.data.GrantType
import id.walt.oid4vc.data.OpenIDProviderMetadata
import id.walt.oid4vc.providers.OpenIDClientConfig
Expand All @@ -18,12 +25,8 @@ import id.walt.oid4vc.responses.TokenResponse
import id.walt.oid4vc.util.randomUUID
import id.walt.service.dto.LinkedWalletDataTransferObject
import id.walt.service.dto.WalletDataTransferObject
import id.walt.service.keys.KeysService
import id.walt.service.oidc4vc.TestCredentialWallet
import id.walt.ssikit.did.DidService
import id.walt.ssikit.did.registrar.dids.DidJwkCreateOptions
import id.walt.ssikit.did.registrar.dids.DidKeyCreateOptions
import id.walt.ssikit.helpers.WaltidServices
import id.walt.ssikit.utils.EnumUtils.enumValueIgnoreCase
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
Expand All @@ -45,7 +48,6 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction
import java.net.URLDecoder
import java.util.*
import kotlin.collections.HashMap
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.time.Duration.Companion.seconds
Expand Down Expand Up @@ -305,27 +307,22 @@ class SSIKit2WalletService(accountId: UUID) : WalletService(accountId) {

/* DIDs */

override suspend fun createDid(method: String, args: Map<String, JsonPrimitive>, al:String): String {
// TODO: other DIDs, Keys
val newKey = LocalKey.generate(KeyType.Ed25519)
val newKeyId = newKey.getKeyId()
override suspend fun createDid(method: String, args: Map<String, JsonPrimitive>): String {
// TODO: other DIDs
val key = args["keyId"]?.content?.let { getKey(it) }?.getOrNull() ?: LocalKey.generate(KeyType.Ed25519)
val keyId = key.getKeyId()
val options = getDidOptions(method, args)

val result = DidService.registerByKey(method, newKey, options)
val result = DidService.registerByKey(method, key, options)
KeysService.insert(accountId, keyId, KeySerialization.serializeKey(key))

transaction {
WalletKeys.insert {
it[account] = accountId
it[keyId] = newKeyId
it[document] = KeySerialization.serializeKey(newKey)

}

WalletDids.insert {
it[account] = accountId
it[did] = result.did
it[alias] = al
it[keyId] = newKeyId
it[alias] = args["alias"]?.content ?: ""
it[WalletDids.keyId] = keyId
it[document] = Json.encodeToString(result.didDocument)
}
}
Expand Down Expand Up @@ -365,40 +362,36 @@ class SSIKit2WalletService(accountId: UUID) : WalletService(accountId) {

/* Keys */

fun getKey(keyId: String) = KeySerialization.deserializeKey(transaction {
WalletKeys.select { (WalletKeys.account eq accountId) and (WalletKeys.keyId eq keyId) }
.single()[WalletKeys.document]
}).getOrElse { throw IllegalArgumentException("Could not deserialize resolved key: ${it.message}", it) }

suspend fun getKeyByDid(did: String): Key {
val publicKey = DidService.resolveToKey(did).getOrThrow()
val keyId = publicKey.getKeyId()

return getKey(keyId)
private fun getKey(keyId: String) = runCatching {
KeysService.getById(accountId, keyId)?.let {
KeySerialization.deserializeKey(it).getOrThrow()
} ?: throw IllegalArgumentException("Key not found: $keyId")
}

override suspend fun exportKey(alias: String, format: String, private: Boolean): String {
val key = getKey(alias)

return when (format.lowercase()) {
"jwk" -> key.exportJWK()
"pem" -> key.exportPEM()
else -> throw IllegalArgumentException("Unknown format: $format")
suspend fun getKeyByDid(did: String): Key = DidService.resolveToKey(did).fold(
onSuccess = {
getKey(it.getKeyId()).getOrElse { throw IllegalArgumentException("Could not deserialize resolved key: ${it.message}", it) }
},
onFailure = {
throw it
}
}

override suspend fun loadKey(alias: String): JsonObject = Json.parseToJsonElement( transaction {
WalletKeys.select{(WalletKeys.account eq accountId) and (WalletKeys.keyId eq alias)}.single()[WalletKeys.document]
}).jsonObject
)

override suspend fun listKeys(): List<SingleKeyResponse> {
val keyList = transaction {
WalletKeys.select { WalletKeys.account eq accountId }.map {
Pair(it[WalletKeys.keyId], it[WalletKeys.document])
override suspend fun exportKey(alias: String, format: String, private: Boolean): String =
getKey(alias).fold(onSuccess = {
when (format.lowercase()) {
"jwk" -> it.exportJWK()
"pem" -> it.exportPEM()
else -> throw IllegalArgumentException("Unknown format: $format")
}
}
}, onFailure = {
throw it
})

override suspend fun loadKey(alias: String): JsonObject = getKey(alias).getOrThrow().exportJWKObject()

return keyList.map { (id, keyJson) ->
override suspend fun listKeys(): List<SingleKeyResponse> =
KeysService.getAllForAccount(accountId).map { (id, keyJson) ->
val key = KeySerialization.deserializeKey(keyJson).getOrThrow()

SingleKeyResponse(
Expand All @@ -409,20 +402,10 @@ class SSIKit2WalletService(accountId: UUID) : WalletService(accountId) {
keysetHandle = JsonNull
)
}
}

override suspend fun generateKey(type: String): String {

val newKey = LocalKey.generate(KeyType.valueOf(type))
val newKeyId = newKey.getKeyId()
transaction {
WalletKeys.insert {
it[account] = accountId
it[keyId] = newKeyId
it[document] = KeySerialization.serializeKey(newKey)
}
}
return newKeyId
override suspend fun generateKey(type: String): String = LocalKey.generate(KeyType.valueOf(type)).let {
KeysService.insert(accountId, it.getKeyId(), KeySerialization.serializeKey(it))
it.getKeyId()
}

override suspend fun importKey(jwkOrPem: String): String {
Expand Down Expand Up @@ -511,6 +494,12 @@ class SSIKit2WalletService(accountId: UUID) : WalletService(accountId) {
args["key"]?.let { enumValueIgnoreCase<KeyType>(it.content) } ?: KeyType.Ed25519,
args["useJwkJcsPub"]?.let { it.content.toBoolean() } ?: false
)
"jwk" -> DidJwkCreateOptions()
"web" -> DidWebCreateOptions(domain = args["domain"]?.content ?: "", path = args["path"]?.content ?: "")
"cheqd" -> DidCheqdCreateOptions(
network = args["network"]?.content ?: "test",
document = Json.decodeFromString<JsonObject>(args["document"]?.content ?: "")
)
else -> DidJwkCreateOptions()
}
}
25 changes: 11 additions & 14 deletions src/main/kotlin/id/walt/service/WalletKitWalletService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import id.walt.config.RemoteWalletConfig
import id.walt.db.models.*
import id.walt.service.dto.LinkedWalletDataTransferObject
import id.walt.service.dto.WalletDataTransferObject
import id.walt.ssikit.utils.JsonUtils.toJsonElement
import id.walt.utils.JsonUtils.toJsonPrimitive
import io.ktor.client.*
import io.ktor.client.call.*
Expand All @@ -24,7 +23,6 @@ import kotlinx.datetime.toKotlinInstant
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
Expand Down Expand Up @@ -254,22 +252,21 @@ class WalletKitWalletService(accountId: UUID) : WalletService(accountId) {

/* DIDs */

override suspend fun createDid(method: String, args: Map<String, JsonPrimitive>, alias:String): String {
override suspend fun createDid(method: String, args: Map<String, JsonPrimitive>): String {
val createParams = mutableMapOf("method" to method.toJsonPrimitive())

createParams.putAll(
args.mapKeys {
val k = it.key
when {
method == "ebsi" && k == "bearerToken" -> "didEbsiBearerToken"
method == "ebsi" && k == "version" -> "didEbsiVersion"
createParams.putAll(args.mapKeys {
val k = it.key
when {
method == "ebsi" && k == "bearerToken" -> "didEbsiBearerToken"
method == "ebsi" && k == "version" -> "didEbsiVersion"

method == "web" && k == "domain" -> "didWebDomain"
method == "web" && k == "path" -> "didWebPath"
method == "web" && k == "domain" -> "didWebDomain"
method == "web" && k == "path" -> "didWebPath"

else -> it.key
}
})
else -> it.key
}
})

return authenticatedJsonPost("/api/wallet/did/create", createParams).bodyAsText()
}
Expand Down
5 changes: 1 addition & 4 deletions src/main/kotlin/id/walt/service/WalletService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,8 @@ abstract class WalletService(val accountId: UUID) {
// DIDs
abstract suspend fun listDids(): List<Did>
abstract suspend fun loadDid(did: String): JsonObject
abstract suspend fun createDid(method: String, args: Map<String, JsonPrimitive> = emptyMap(), alias: String): String
abstract suspend fun createDid(method: String, args: Map<String, JsonPrimitive> = emptyMap()): String
abstract suspend fun deleteDid(did: String): Boolean
suspend fun createDidWithParameters(method: String, args: Map<String, Any?>, alias:String): String {
return createDid(method, args.toJsonPrimitives(), alias)
}
abstract suspend fun setDefault(did: String) :Boolean

// Keys
Expand Down
8 changes: 5 additions & 3 deletions src/main/kotlin/id/walt/service/account/AccountsService.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package id.walt.service.account

import id.walt.db.models.Wallets
import id.walt.service.WalletServiceManager
import id.walt.web.generateToken
import id.walt.web.model.AddressLoginRequest
import id.walt.web.model.EmailLoginRequest
import id.walt.web.model.LoginRequest
import kotlinx.coroutines.runBlocking
import org.jetbrains.exposed.sql.transactions.transaction
import kotlinx.serialization.json.JsonPrimitive
import java.util.*

object AccountsService {
Expand All @@ -18,7 +17,10 @@ object AccountsService {
is AddressLoginRequest -> walletStrategy.register(request)
}.also {
it.getOrNull()?.let {
runBlocking { WalletServiceManager.getWalletService(it.id).createDid(method="key", alias = "Onboarding") }
runBlocking {
WalletServiceManager.getWalletService(it.id)
.createDid(method = "key", mapOf("alias" to JsonPrimitive("Onboarding")))
}
}
}

Expand Down
32 changes: 32 additions & 0 deletions src/main/kotlin/id/walt/service/keys/KeysService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package id.walt.service.keys

import id.walt.db.models.WalletKeys
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import java.util.*

//TODO: introduce and implement db-entities
object KeysService {

fun getById(account: UUID, id: String): String? = transaction {
WalletKeys.select { WalletKeys.account eq account and (WalletKeys.keyId eq id) }.firstOrNull()?.let {
it[WalletKeys.document]
}
}

fun getAllForAccount(account: UUID) = transaction {
WalletKeys.select { (WalletKeys.account eq account) }.map {
Pair(it[WalletKeys.keyId], it[WalletKeys.document])
}
}

fun insert(account: UUID, keyId: String, document: String) = transaction {
WalletKeys.insert {
it[WalletKeys.account] = account
it[WalletKeys.keyId] = keyId
it[WalletKeys.document] = document
}.insertedCount == 1
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package id.walt.service.oidc4vc
import id.walt.core.crypto.keys.Key
import id.walt.core.crypto.utils.JsonUtils.toJsonElement
import id.walt.core.crypto.utils.JwsUtils.decodeJws
import id.walt.did.dids.DidService
import id.walt.oid4vc.data.OpenIDProviderMetadata
import id.walt.oid4vc.data.dif.DescriptorMapping
import id.walt.oid4vc.data.dif.PresentationDefinition
Expand All @@ -12,13 +13,11 @@ import id.walt.oid4vc.errors.PresentationError
import id.walt.oid4vc.interfaces.PresentationResult
import id.walt.oid4vc.providers.SIOPCredentialProvider
import id.walt.oid4vc.providers.SIOPProviderConfig
import id.walt.oid4vc.providers.SIOPSession
import id.walt.oid4vc.providers.TokenTarget
import id.walt.oid4vc.requests.AuthorizationRequest
import id.walt.oid4vc.requests.TokenRequest
import id.walt.oid4vc.responses.TokenErrorCode
import id.walt.service.SSIKit2WalletService
import id.walt.ssikit.did.DidService
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
Expand Down
Loading

0 comments on commit 20f4260

Please sign in to comment.