From 1caa995a961872cbd0fb575698a26eca59fb3ba1 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Tue, 23 Jul 2024 01:05:25 +0200 Subject: [PATCH 01/17] fix: update Android dependencies, update Android key, cleanup Android, cleanup crypto --- .../waltid-crypto-android/build.gradle.kts | 5 +- .../id/walt/crypto/keys/AndroidKeyTest.kt | 12 ++ .../kotlin/id/walt/crypto/keys/AndroidKey.kt | 106 ++++++++---------- .../id/walt/crypto/utils/Base64Utils.kt | 11 +- .../kotlin/id/walt/crypto/utils/JwsUtils.kt | 36 ++++-- .../id/walt/crypto/utils/TseUtilsTesting.kt | 38 ------- 6 files changed, 98 insertions(+), 110 deletions(-) delete mode 100644 waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/TseUtilsTesting.kt diff --git a/waltid-libraries/waltid-crypto-android/build.gradle.kts b/waltid-libraries/waltid-crypto-android/build.gradle.kts index 4ba3efb3a..78210fb31 100644 --- a/waltid-libraries/waltid-crypto-android/build.gradle.kts +++ b/waltid-libraries/waltid-crypto-android/build.gradle.kts @@ -81,10 +81,9 @@ kotlin { val androidMain by getting { dependencies { api(project(":waltid-libraries:waltid-crypto")) - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + implementation("io.github.oshai:kotlin-logging:7.0.0") } - - } val androidInstrumentedTest by getting { dependencies { diff --git a/waltid-libraries/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt b/waltid-libraries/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt index 46d0f5915..7804202da 100644 --- a/waltid-libraries/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt +++ b/waltid-libraries/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt @@ -66,4 +66,16 @@ class AndroidKeyTest { assertTrue { identicalEccPublicKey == eccPublicKey } assertFalse { identicalEccPublicKey.hasPrivateKey } } + + //@Test + fun use_ECC_key() = runTest { + val keyPair = AndroidKeyGenerator.generate(KeyType.secp256r1) + val plaintext = "1234abcd".encodeToByteArray() + val signed = keyPair.signRaw(plaintext) + val result = keyPair.verifyRaw(signed, plaintext) + + assertTrue { result.isSuccess } + } + + } diff --git a/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt b/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt index 2f19add16..bbd18a91c 100644 --- a/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt +++ b/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt @@ -1,8 +1,11 @@ package id.walt.crypto.keys -import android.util.Base64 import id.walt.crypto.keys.AndroidKeyGenerator.PUBLIC_KEY_ALIAS_PREFIX +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url +import id.walt.crypto.utils.Base64Utils.encodeToBase64Url import id.walt.crypto.utils.JsonUtils.toJsonElement +import id.walt.crypto.utils.JwsUtils.decodeJwsStrings +import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject @@ -16,6 +19,8 @@ import java.security.spec.ECPublicKeySpec import java.security.spec.RSAPublicKeySpec import java.util.UUID +private val log = KotlinLogging.logger { } + class AndroidKey() : Key() { override val keyType: KeyType @@ -24,9 +29,7 @@ class AndroidKey() : Key() { private lateinit var internalKeyType: KeyType override val hasPrivateKey: Boolean - get() { - return (keyStore.getKey(internalKeyId, null) as PrivateKey?) != null - } + get() = keyStore.getKey(internalKeyId, null) as? PrivateKey? != null private val keyStore = KeyStore.getInstance(AndroidKeyGenerator.ANDROID_KEYSTORE).apply { load(null) @@ -37,7 +40,7 @@ class AndroidKey() : Key() { constructor(keyAlias: KeyAlias, keyType: KeyType) : this() { internalKeyId = keyAlias.alias internalKeyType = keyType - println("Initialised instance of AndroidKey {keyId: '$internalKeyId'}") + log.trace { "Initialised instance of AndroidKey {keyId: '$internalKeyId'}" } } override suspend fun getKeyId(): String = internalKeyId @@ -56,8 +59,8 @@ class AndroidKey() : Key() { val keySpec = keyFactory.getKeySpec(publicKey, RSAPublicKeySpec::class.java) JSONObject().run { put("kty", internalKeyType.name) - put("n", Base64.encodeToString(keySpec.modulus.toByteArray(), Base64.NO_WRAP)) - put("e", Base64.encodeToString(keySpec.publicExponent.toByteArray(), Base64.NO_WRAP)) + put("n", keySpec.modulus.toByteArray().encodeToBase64Url()) + put("e", keySpec.publicExponent.toByteArray().encodeToBase64Url()) toString() } } @@ -68,8 +71,8 @@ class AndroidKey() : Key() { JSONObject().run { put("kty", "EC") put("crv", "P-256") - put("x", Base64.encodeToString(keySpec.w.affineX.toByteArray(), Base64.NO_WRAP)) - put("y", Base64.encodeToString(keySpec.w.affineY.toByteArray(), Base64.NO_WRAP)) + put("x", keySpec.w.affineX.toByteArray().encodeToBase64Url()) + put("y", keySpec.w.affineY.toByteArray().encodeToBase64Url()) toString() } } @@ -88,90 +91,79 @@ class AndroidKey() : Key() { TODO("Not yet implemented") } - override suspend fun signRaw(plaintext: ByteArray): ByteArray { + private fun signWithKeystore(plaintext: ByteArray): ByteArray { check(hasPrivateKey) { "No private key is attached to this key!" } val privateKey: PrivateKey = keyStore.getKey(internalKeyId, null) as PrivateKey - val signature: ByteArray? = getSignature().run { + val signature: ByteArray = getSignature().run { initSign(privateKey) update(plaintext) sign() } - println("Raw message signed with signature {signature: '${Base64.encodeToString(signature, Base64.DEFAULT)}'}") - println("Raw message signed - {raw: '${plaintext.decodeToString()}'}") - - return Base64.encodeToString(signature, Base64.DEFAULT).toByteArray() + return signature } - override suspend fun signJws(plaintext: ByteArray, headers: Map): String { - check(hasPrivateKey) { "No private key is attached to this key!" } + override suspend fun signRaw(plaintext: ByteArray): ByteArray { + val signature: ByteArray = signWithKeystore(plaintext) - val privateKey: PrivateKey = keyStore.getKey(internalKeyId, null) as PrivateKey + log.trace { "Raw message signed - {raw: '${plaintext.decodeToString()}'}" } - val signature: ByteArray = getSignature().run { - initSign(privateKey) - update(plaintext) - sign() - } + return signature + } - val encodedSignature = Base64.encodeToString(signature, Base64.NO_WRAP) + override suspend fun signJws(plaintext: ByteArray, headers: Map): String { + val signature: ByteArray = signWithKeystore(plaintext) + + val encodedSignature = signature.encodeToBase64Url() // Construct the JWS in the format: base64UrlEncode(headers) + '.' + base64UrlEncode(payload) + '.' + base64UrlEncode(signature) - val encodedHeaders = Base64.encodeToString(headers.toString().toByteArray(), Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING) - val encodedPayload = Base64.encodeToString(plaintext, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING) + val encodedHeaders = headers.toString().toByteArray().encodeToBase64Url() + val encodedPayload = plaintext.encodeToBase64Url() return "$encodedHeaders.$encodedPayload.$encodedSignature" } override suspend fun verifyRaw(signed: ByteArray, detachedPlaintext: ByteArray?): Result { - val certificate: Certificate? = keyStore.getCertificate(internalKeyId) + check(detachedPlaintext != null) { "An detached plaintext is needed." } - return if (certificate != null) { - val signature: ByteArray = Base64.decode(signed.decodeToString(), Base64.DEFAULT) + val certificate: Certificate = keyStore.getCertificate(internalKeyId) + ?: return Result.failure(Exception("Certificate not found in KeyStore")) - println("signature to verify- ${signed.decodeToString()}") - println("plaintext - ${detachedPlaintext!!.decodeToString()}") + log.trace { "signature to verify- ${signed.decodeToString()}" } + log.trace { "plaintext - ${detachedPlaintext.decodeToString()}" } - val isValid: Boolean = getSignature().run { - initVerify(certificate) - update(detachedPlaintext) - verify(signature) - } - - return if (isValid) { - Result.success(detachedPlaintext) - } else { - Result.failure(Exception("Signature is not valid")) - } + val isValid: Boolean = getSignature().run { + initVerify(certificate) + update(detachedPlaintext) + verify(signed) + } - } else { - Result.failure(Exception("Certificate not found in KeyStore")) + return when { + isValid -> Result.success(detachedPlaintext) + else -> Result.failure(Exception("Signature is not valid")) } } override suspend fun verifyJws(signedJws: String): Result { return runCatching { - val splitJws = signedJws.split(".") - if (splitJws.size != 3) throw IllegalArgumentException("Invalid JWS format") - - val header = String(android.util.Base64.decode(splitJws[0], android.util.Base64.URL_SAFE)) - val payload = String(android.util.Base64.decode(splitJws[1], android.util.Base64.URL_SAFE)) - val signature = android.util.Base64.decode(splitJws[2], android.util.Base64.NO_WRAP) + val parts = signedJws.decodeJwsStrings() + val (_, payload, signature) = parts + val signable = parts.getSignable() // Get the public key from the Android KeyStore val publicKey = keyStore.getCertificate(internalKeyId).publicKey // Create a Signature instance and initialize it with the public key - val sig = getSignature() - sig.initVerify(publicKey) + val androidSignature = getSignature() + androidSignature.initVerify(publicKey) // Supply the Signature object the data to be signed - sig.update(payload.toByteArray()) + androidSignature.update(signable.toByteArray()) // Verify the signature - val isVerified = sig.verify(signature) + val isVerified = androidSignature.verify(signature.decodeFromBase64Url()) if (!isVerified) throw Exception("Signature verification failed") @@ -212,14 +204,14 @@ class AndroidKey() : Key() { KeyType.Ed25519 -> Signature.getInstance("Ed25519") KeyType.RSA -> Signature.getInstance("SHA256withRSA") } - println("Signature instance created {algorithm: '${sig.algorithm}'}") + log.trace { "Signature instance created {algorithm: '${sig.algorithm}'}" } return sig } companion object : AndroidKeyCreator { override suspend fun generate( type: KeyType, - metadata: JwkKeyMeta? + metadata: JwkKeyMeta?, ): AndroidKey = AndroidKeyGenerator.generate(type, metadata) } -} \ No newline at end of file +} diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt index f7271dd83..949d7cb9e 100644 --- a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt +++ b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt @@ -9,12 +9,15 @@ import kotlin.js.JsExport @JsExport object Base64Utils { + private val base64Url = Base64.UrlSafe.withPadding(Base64.PaddingOption.ABSENT_OPTIONAL) + private val base64 = Base64 + fun String.base64toBase64Url() = this.replace("+", "-").replace("/", "_").trimEnd('=') fun String.base64UrlToBase64() = this.replace("-", "+").replace("_", "/") - fun ByteArray.encodeToBase64Url() = Base64.UrlSafe.encode(this).trimEnd('=') - - fun String.base64UrlDecode() = Base64.UrlSafe.decode(this) + fun ByteArray.encodeToBase64() = base64.encode(this) + fun String.decodeFromBase64() = base64.decode(this) - fun String.base64Decode() = Base64.decode(this) + fun ByteArray.encodeToBase64Url() = base64Url.encode(this) + fun String.decodeFromBase64Url() = base64Url.decode(this) } diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt index 003925390..9b10f6025 100644 --- a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt +++ b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt @@ -34,18 +34,38 @@ object JwsUtils { }.$signature" } - fun String.decodeJws(withSignature: Boolean = false, allowMissingSignature: Boolean = false): JwsParts { - check(startsWith("ey")) { "String does not look like JWS: $this" } - check(count { it == '.' } == 2 || (allowMissingSignature && count { it == '.' } == 1)) { "String does not have JWS part amount of 3 (= 2 dots): $this" } + data class JwsStringParts(val header: String, val payload: String, val signature: String) { + fun getSignable() = "$header.$payload" + } + private fun checkJwsPreconditions(jws: String, allowMissingSignature: Boolean) { + check(jws.startsWith("ey")) { "String does not look like JWS: $this" } + val dots = jws.count { it == '.' } + check( + dots == 2 + || (allowMissingSignature && dots == 1) + ) { "String does not have correct JWS part amount (dots=$dots, allowMissingSignature=$allowMissingSignature): $this" } + } + + fun String.decodeJwsStrings(): JwsStringParts { + checkJwsPreconditions(this, false) val splitted = split(".") - val header = runCatching { splitted[0].decodeJwsPart() }.getOrElse { ex -> - throw IllegalArgumentException("Could not parse JWT header (base64/json issue): ${splitted[0]}", ex) + val (header, payload, signature) = splitted + return JwsStringParts(header, payload, signature) + } + + fun String.decodeJws(withSignature: Boolean = false, allowMissingSignature: Boolean = false): JwsParts { + checkJwsPreconditions(this, allowMissingSignature) + + val parts = this.decodeJwsStrings() + + val header = runCatching { parts.header.decodeJwsPart() }.getOrElse { ex -> + throw IllegalArgumentException("Could not parse JWT header (base64/json issue): ${parts.header}", ex) } - val payload = runCatching { splitted[1].decodeJwsPart() }.getOrElse { ex -> - throw IllegalArgumentException("Could not parse JWT payload (base64/json issue): ${splitted[1]}", ex) + val payload = runCatching { parts.payload.decodeJwsPart() }.getOrElse { ex -> + throw IllegalArgumentException("Could not parse JWT payload (base64/json issue): ${parts.payload}", ex) } - val signature = if (withSignature) splitted[2] else "" + val signature = if (withSignature) parts.signature else "" return JwsParts(header, payload, signature) } diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/TseUtilsTesting.kt b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/TseUtilsTesting.kt deleted file mode 100644 index f21d4ca66..000000000 --- a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/TseUtilsTesting.kt +++ /dev/null @@ -1,38 +0,0 @@ -package id.walt.crypto.utils - -/*import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.jsonObject -import kotlinx.serialization.json.jsonPrimitive -import kotlin.io.encoding.Base64 -import kotlin.io.encoding.ExperimentalEncodingApi*/ - -/* -@OptIn(ExperimentalEncodingApi::class) -fun main() { - val tseKeyExportJson = """ - { - "keys": { - "1": "BGPcgdbwZsNT6jsWnFFT9CXR3OQAc0J9XTrSu0j48uym+IQRL7xSPK95RcJNf8H1Gl+qmLvDcd/hMra7Q40fPA==" - }, - "type": "ed25519", - "name": "k1" -} - """ - - val exportKeyPairBase64 = Json.decodeFromString(tseKeyExportJson)["keys"]!!.jsonObject["1"]!!.jsonPrimitive.content - val decodedKeyPair = Base64.decode(exportKeyPairBase64) - check(decodedKeyPair.size == 64) - - val privateKey = decodedKeyPair.take(32).toByteArray() - val publicKey = decodedKeyPair.drop(32).toByteArray() - - val privateKeyBase64Url = Base64.UrlSafe.encode(privateKey).trimEnd('=') - val publicKeyBase64Url = Base64.UrlSafe.encode(publicKey).trimEnd('=') - - val jwk = - """{"kty":"OKP","d":"$privateKeyBase64Url","use":"sig","crv":"Ed25519","kid":"k1","x":"$publicKeyBase64Url","alg":"EdDSA"}""".trimIndent() - - println(jwk) -} -*/ From 719566e37876b92229337e46b97a727765f69436 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Tue, 23 Jul 2024 23:00:31 +0200 Subject: [PATCH 02/17] fix: update to 2.0.20 (beta 2), update some Base64 usages, however some remain --- build.gradle.kts | 2 +- settings.gradle.kts | 3 ++ .../id/walt/crypto/keys/oci/OCIKey.jvm.kt | 10 ++--- .../id/walt/crypto/keys/oci/OCIKeyRestApi.kt | 10 ++--- .../kotlin/id/walt/crypto/keys/tse/TSEKey.kt | 8 ++-- .../id/walt/crypto/keys/jwk/JWKKey.jvm.kt | 4 +- .../src/jvmTest/kotlin/KeySignTests.kt | 12 +++--- .../did/dids/resolver/local/DidJwkResolver.kt | 4 +- .../walt/mdoc/dataretrieval/DeviceResponse.kt | 9 ++++- .../walt/oid4vc/interfaces/ITokenProvider.kt | 5 ++- .../kotlin/id/walt/oid4vc/util/JwtUtils.kt | 23 +++++------ .../kotlin/id/walt/sdjwt/SDPayload.kt | 3 +- .../kotlin/id/walt/sdjwt/SDisclosure.kt | 3 +- .../kotlin/id/walt/sdjwt/SdjwtStringUtils.kt | 12 ++++++ .../kotlin/id/walt/target/ios/keys/Ed25519.kt | 4 +- .../waltid-issuer-api/build.gradle.kts | 39 ------------------- .../waltid-verifier-api/build.gradle.kts | 39 ------------------- .../webwallet/service/push/Subscription.kt | 6 +-- .../id/walt/webwallet/utils/RandomUtils.kt | 5 +-- 19 files changed, 72 insertions(+), 129 deletions(-) create mode 100644 waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt diff --git a/build.gradle.kts b/build.gradle.kts index 9b1be8053..966565315 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ allprojects { plugins { // val kotlinVersion = "2.0.0" - val kotlinVersion = "2.0.20-Beta1" + val kotlinVersion = "2.0.20-Beta2" kotlin("multiplatform") version kotlinVersion apply false kotlin("jvm") version kotlinVersion diff --git a/settings.gradle.kts b/settings.gradle.kts index 7b5721c2e..f062e43d5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,6 +24,9 @@ val baseModules = listOf( // Service commons "$services:waltid-service-commons", + // Auth Kit for services + "$libraries:waltid-authkit", + // Services based on libs "$services:waltid-issuer-api", "$services:waltid-verifier-api", diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt b/waltid-libraries/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt index de7569f19..6e6c60205 100644 --- a/waltid-libraries/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt +++ b/waltid-libraries/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt @@ -15,8 +15,8 @@ import id.walt.crypto.keys.Key import id.walt.crypto.keys.KeyType import id.walt.crypto.keys.OciKeyMeta import id.walt.crypto.keys.jwk.JWKKey -import id.walt.crypto.utils.Base64Utils.base64Decode -import id.walt.crypto.utils.Base64Utils.base64UrlDecode +import id.walt.crypto.utils.Base64Utils.decodeFromBase64 +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.crypto.utils.Base64Utils.encodeToBase64Url import id.walt.crypto.utils.JvmEccUtils import id.walt.crypto.utils.JwsUtils.jwsAlg @@ -117,7 +117,7 @@ actual class OCIKey actual constructor( val signRequest = SignRequest.builder().signDataDetails(signDataDetails).build() val response = kmsCryptoClient.sign(signRequest) - return response.signedData.signature.base64Decode() + return response.signedData.signature.decodeFromBase64() } private val _internalJwsAlgorithm by lazy { @@ -179,7 +179,7 @@ actual class OCIKey actual constructor( check(parts.size == 3) { "Invalid JWT part count: ${parts.size} instead of 3" } val header = parts[0] - val headers: Map = Json.decodeFromString(header.base64UrlDecode().decodeToString()) + val headers: Map = Json.decodeFromString(header.decodeFromBase64Url().decodeToString()) headers["alg"]?.let { val algValue = it.jsonPrimitive.content check(algValue == keyType.jwsAlg()) { "Invalid key algorithm for JWS: JWS has $algValue, key is ${keyType.jwsAlg()}!" } @@ -187,7 +187,7 @@ actual class OCIKey actual constructor( val payload = parts[1] - val signature = parts[2].base64UrlDecode() + val signature = parts[2].decodeFromBase64Url() val signable = "$header.$payload".encodeToByteArray() diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt index ad42d28fa..51ab6b7d5 100644 --- a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt +++ b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt @@ -5,8 +5,8 @@ import id.walt.crypto.keys.Key import id.walt.crypto.keys.KeyType import id.walt.crypto.keys.OciKeyMeta import id.walt.crypto.keys.jwk.JWKKey -import id.walt.crypto.utils.Base64Utils.base64Decode -import id.walt.crypto.utils.Base64Utils.base64UrlDecode +import id.walt.crypto.utils.Base64Utils.decodeFromBase64 +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.crypto.utils.Base64Utils.encodeToBase64Url import id.walt.crypto.utils.JwsUtils.decodeJws import id.walt.crypto.utils.JwsUtils.jwsAlg @@ -152,7 +152,7 @@ class OCIKeyRestApi( header("Host", host) header("x-content-sha256", calculateSHA256(requestBody)) setBody(requestBody) - }.ociJsonDataBody().jsonObject["signature"]?.jsonPrimitive?.content?.base64Decode() + }.ociJsonDataBody().jsonObject["signature"]?.jsonPrimitive?.content?.decodeFromBase64() response ?: error("No signature returned from OCI.") } } @@ -234,8 +234,8 @@ class OCIKeyRestApi( } val signable = "$header.$payload".encodeToByteArray() - return verifyRaw(signature.base64UrlDecode(), signable).map { - val verifiedPayload = it.decodeToString().substringAfter(".").base64UrlDecode().decodeToString() + return verifyRaw(signature.decodeFromBase64Url(), signable).map { + val verifiedPayload = it.decodeToString().substringAfter(".").decodeFromBase64Url().decodeToString() Json.parseToJsonElement(verifiedPayload) } } diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt index b1a5993f2..13226af73 100644 --- a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt +++ b/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt @@ -4,7 +4,7 @@ import id.walt.crypto.keys.Key import id.walt.crypto.keys.KeyType import id.walt.crypto.keys.TseKeyMeta import id.walt.crypto.keys.jwk.JWKKey -import id.walt.crypto.utils.Base64Utils.base64UrlDecode +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.crypto.utils.Base64Utils.base64toBase64Url import id.walt.crypto.utils.Base64Utils.encodeToBase64Url import id.walt.crypto.utils.JwsUtils.jwsAlg @@ -232,19 +232,19 @@ class TSEKey( check(parts.size == 3) { "Invalid JWT part count: ${parts.size} instead of 3" } val header = parts[0] - val headers: Map = Json.decodeFromString(header.base64UrlDecode().decodeToString()) + val headers: Map = Json.decodeFromString(header.decodeFromBase64Url().decodeToString()) headers["alg"]?.let { val algValue = it.jsonPrimitive.content check(algValue == keyType.jwsAlg()) { "Invalid key algorithm for JWS: JWS has $algValue, key is ${keyType.jwsAlg()}!" } } val payload = parts[1] - val signature = parts[2].base64UrlDecode() + val signature = parts[2].decodeFromBase64Url() val signable = "$header.$payload".encodeToByteArray() return verifyRaw(signature, signable).map { - val verifiedPayload = it.decodeToString().substringAfter(".").base64UrlDecode().decodeToString() + val verifiedPayload = it.decodeToString().substringAfter(".").decodeFromBase64Url().decodeToString() Json.parseToJsonElement(verifiedPayload).jsonObject } } diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt b/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt index 838acf157..e01361395 100644 --- a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt +++ b/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt @@ -9,7 +9,7 @@ import com.nimbusds.jose.util.Base64URL import id.walt.crypto.keys.* import id.walt.crypto.keys.Key import id.walt.crypto.keys.KeyType -import id.walt.crypto.utils.Base64Utils.base64UrlDecode +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.crypto.utils.Base64Utils.encodeToBase64Url import id.walt.crypto.utils.JsonUtils.toJsonElement import id.walt.crypto.utils.JwsUtils.decodeJws @@ -290,7 +290,7 @@ actual class JWKKey actual constructor( val (header, payload, signature) = signedJws.split(".") log.debug { "> Signature verification: Fallback verification checking... (NIMBUS VERIFICATION FAILED) for: $signedJws" } - val res = verifyRaw(signature.base64UrlDecode(), "$header.$payload".encodeToByteArray()).map { + val res = verifyRaw(signature.decodeFromBase64Url(), "$header.$payload".encodeToByteArray()).map { it.decodeToString().decodeJws(allowMissingSignature = true).payload } res.getOrThrow() diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt b/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt index 8ee146fb0..16ed94f23 100644 --- a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt +++ b/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt @@ -36,15 +36,17 @@ class KeySignTests { @ParameterizedTest @ValueSource(strings = ["ed25519.private.json", "secp256k1.private.json", "secp256r1.private.json", "rsa.private.json"]) - @Disabled // not implemented +// @Disabled // not implemented fun `given key and payload, when signing raw then the result is a valid signature`(keyFile: String) = runTest { // given val key = KeyManager.resolveSerializedKey(loadSerializedLocal(keyFile)) // when - val signature = key.signRaw(payload.toString().encodeToByteArray()) - val verificationResult = key.getPublicKey().verifyRaw(signature as ByteArray) + val plaintext = payload.toString().encodeToByteArray() + val signature = key.signRaw(plaintext) + + val verificationResult = key.getPublicKey().verifyRaw(signature as ByteArray, plaintext) // then assertTrue(verificationResult.isSuccess) - assertEquals(payload.toString().encodeToByteArray(), verificationResult.getOrThrow()) + assertEquals(plaintext.toList(), verificationResult.getOrThrow().toList()) } -} \ No newline at end of file +} diff --git a/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/local/DidJwkResolver.kt b/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/local/DidJwkResolver.kt index 52030a255..0c9653052 100644 --- a/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/local/DidJwkResolver.kt +++ b/waltid-libraries/waltid-did/src/commonMain/kotlin/id/walt/did/dids/resolver/local/DidJwkResolver.kt @@ -2,7 +2,7 @@ package id.walt.did.dids.resolver.local import id.walt.crypto.keys.Key import id.walt.crypto.keys.jwk.JWKKey -import id.walt.crypto.utils.Base64Utils.base64UrlDecode +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.did.dids.DidUtils import id.walt.did.dids.document.DidDocument import id.walt.did.dids.document.DidJwkDocument @@ -35,5 +35,5 @@ class DidJwkResolver : LocalResolverMethod("jwk") { @JsPromise @JsExport.Ignore override suspend fun resolveToKey(did: String): Result = - JWKKey.importJWK(DidUtils.pathFromDid(did)!!.base64UrlDecode().decodeToString()) + JWKKey.importJWK(DidUtils.pathFromDid(did)!!.decodeFromBase64Url().decodeToString()) } diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt b/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt index 45961148f..29e22b979 100644 --- a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt +++ b/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt @@ -43,13 +43,18 @@ class DeviceResponse( */ fun toCBORHex() = toMapElement().toCBORHex() + /** * Serialize to CBOR base64 url-encoded string */ @OptIn(ExperimentalEncodingApi::class) - fun toCBORBase64URL() = Base64.UrlSafe.encode(toCBOR()) + fun toCBORBase64URL() = base64Url.encode(toCBOR()) companion object { + + @OptIn(ExperimentalEncodingApi::class) + private val base64Url = Base64.UrlSafe.withPadding(Base64.PaddingOption.ABSENT) + /** * Deserialize from CBOR data */ @@ -62,6 +67,6 @@ class DeviceResponse( fun fromCBORHex(cbor: String) = Cbor.decodeFromHexString(cbor) @OptIn(ExperimentalEncodingApi::class) - fun fromCBORBase64URL(cbor: String) = fromCBOR(Base64.UrlSafe.decode(cbor)) + fun fromCBORBase64URL(cbor: String) = fromCBOR(base64Url.decode(cbor)) } } diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt b/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt index 545800eb2..c206f5236 100644 --- a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt +++ b/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt @@ -1,6 +1,7 @@ package id.walt.oid4vc.interfaces import id.walt.crypto.keys.Key +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.oid4vc.providers.TokenTarget import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject @@ -23,14 +24,14 @@ interface ITokenProvider { @OptIn(ExperimentalEncodingApi::class) fun parseTokenPayload(token: String): JsonObject { return token.substringAfter(".").substringBefore(".").let { - Json.decodeFromString(Base64.UrlSafe.decode(it).decodeToString()) + Json.decodeFromString(it.decodeFromBase64Url().decodeToString()) } } @OptIn(ExperimentalEncodingApi::class) fun parseTokenHeader(token: String): JsonObject { return token.substringBefore(".").let { - Json.decodeFromString(Base64.UrlSafe.decode(it).decodeToString()) + Json.decodeFromString(it.decodeFromBase64Url().decodeToString()) } } } diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt b/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt index 8613cd269..79b520de4 100644 --- a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt +++ b/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt @@ -1,22 +1,19 @@ package id.walt.oid4vc.util +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject -import kotlin.io.encoding.Base64 -import kotlin.io.encoding.ExperimentalEncodingApi object JwtUtils { - @OptIn(ExperimentalEncodingApi::class) - fun parseJWTPayload(token: String): JsonObject { - return token.substringAfter(".").substringBefore(".").let { - Json.decodeFromString(Base64.UrlSafe.decode(it).decodeToString()) + fun parseJWTPayload(token: String): JsonObject { + return token.substringAfter(".").substringBefore(".").let { + Json.decodeFromString(it.decodeFromBase64Url().decodeToString()) + } } - } - @OptIn(ExperimentalEncodingApi::class) - fun parseJWTHeader(token: String): JsonObject { - return token.substringBefore(".").let { - Json.decodeFromString(Base64.UrlSafe.decode(it).decodeToString()) + fun parseJWTHeader(token: String): JsonObject { + return token.substringBefore(".").let { + Json.decodeFromString(it.decodeFromBase64Url().decodeToString()) + } } - } -} \ No newline at end of file +} diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt b/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt index 26c6118d7..c908b608a 100644 --- a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt +++ b/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt @@ -1,6 +1,7 @@ package id.walt.sdjwt import dev.whyoleg.cryptography.random.CryptographyRandom +import id.walt.sdjwt.SdjwtStringUtils.decodeFromBase64Url import korlibs.crypto.SecureRandom import korlibs.crypto.sha256 import kotlinx.serialization.json.* @@ -276,7 +277,7 @@ data class SDPayload internal constructor( */ fun parse(jwtBody: String, disclosures: Set): SDPayload { return SDPayload( - Json.parseToJsonElement(Base64.UrlSafe.decode(jwtBody).decodeToString()).jsonObject, + Json.parseToJsonElement(jwtBody.decodeFromBase64Url().decodeToString()).jsonObject, disclosures.associate { Pair(digest(it), SDisclosure.parse(it)) }) } } diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt b/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt index 3cafed1f7..2690dfc6b 100644 --- a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt +++ b/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt @@ -1,5 +1,6 @@ package id.walt.sdjwt +import id.walt.sdjwt.SdjwtStringUtils.decodeFromBase64Url import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.jsonArray @@ -29,7 +30,7 @@ data class SDisclosure internal constructor( * Parse an encoded disclosure string */ @OptIn(ExperimentalEncodingApi::class) - fun parse(disclosure: String) = Json.parseToJsonElement(Base64.UrlSafe.decode(disclosure).decodeToString()).jsonArray.let { + fun parse(disclosure: String) = Json.parseToJsonElement(disclosure.decodeFromBase64Url().decodeToString()).jsonArray.let { if (it.size != 3) { throw Exception("Invalid selective disclosure") } diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt b/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt new file mode 100644 index 000000000..051631471 --- /dev/null +++ b/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt @@ -0,0 +1,12 @@ +package id.walt.sdjwt + +import kotlin.io.encoding.Base64 +import kotlin.io.encoding.ExperimentalEncodingApi + +@OptIn(ExperimentalEncodingApi::class) +object SdjwtStringUtils { + + private val base64Url = Base64.UrlSafe.withPadding(Base64.PaddingOption.ABSENT_OPTIONAL) + + internal fun String.decodeFromBase64Url() = base64Url.decode(this) +} diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt b/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt index 56e800f2f..6cc03f84c 100644 --- a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt +++ b/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt @@ -67,7 +67,7 @@ sealed class Ed25519 { val signingInput = "$header.$payload" val verifyResult = - verifyRaw(Base64.UrlSafe.decode(signature), signingInput.encodeToByteArray()) + verifyRaw(signature.decodeFromBase64Url(), signingInput.encodeToByteArray()) return when { verifyResult.isSuccess -> Result.success( Json.parseToJsonElement( @@ -268,4 +268,4 @@ internal class Ed25519PublicKeyJwk(private val jwk: String) : Ed25519.PublicKey( override fun externalRepresentation(): ByteArray { return externalRepresentation } -} \ No newline at end of file +} diff --git a/waltid-services/waltid-issuer-api/build.gradle.kts b/waltid-services/waltid-issuer-api/build.gradle.kts index f17779451..3e0858f2e 100644 --- a/waltid-services/waltid-issuer-api/build.gradle.kts +++ b/waltid-services/waltid-issuer-api/build.gradle.kts @@ -18,7 +18,6 @@ plugins { id("org.owasp.dependencycheck") version "9.2.0" id("com.github.jk1.dependency-license-report") version "2.8" application - `maven-publish` id("com.github.ben-manes.versions") } @@ -157,44 +156,6 @@ application { applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") } -publishing { - publications { - create("mavenJava") { - pom { - name.set("walt.id issuer") - description.set( - """ - Kotlin/Java library for walt.id issuer - """.trimIndent() - ) - url.set("https://walt.id") - } - from(components["java"]) - } - } - - repositories { - maven { - val releasesRepoUrl = uri("https://maven.waltid.dev/releases") - val snapshotsRepoUrl = uri("https://maven.waltid.dev/snapshots") - url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl) - val envUsername = System.getenv("MAVEN_USERNAME") - val envPassword = System.getenv("MAVEN_PASSWORD") - - val usernameFile = File("secret_maven_username.txt") - val passwordFile = File("secret_maven_password.txt") - - val secretMavenUsername = envUsername ?: usernameFile.let { if (it.isFile) it.readLines().first() else "" } - val secretMavenPassword = envPassword ?: passwordFile.let { if (it.isFile) it.readLines().first() else "" } - - credentials { - username = secretMavenUsername - password = secretMavenPassword - } - } - } -} - /*licenseReport { renderers = arrayOf(InventoryHtmlReportRenderer("xyzkit-licenses-report.html", "XYZ Kit")) filters = arrayOf(LicenseBundleNormalizer()) diff --git a/waltid-services/waltid-verifier-api/build.gradle.kts b/waltid-services/waltid-verifier-api/build.gradle.kts index 0a8b27245..d101ee705 100644 --- a/waltid-services/waltid-verifier-api/build.gradle.kts +++ b/waltid-services/waltid-verifier-api/build.gradle.kts @@ -18,7 +18,6 @@ plugins { id("org.owasp.dependencycheck") version "9.2.0" id("com.github.jk1.dependency-license-report") version "2.8" application - `maven-publish` id("com.github.ben-manes.versions") } @@ -163,44 +162,6 @@ application { applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") } -publishing { - publications { - create("mavenJava") { - pom { - name.set("walt.id verifier") - description.set( - """ - Kotlin/Java library for the walt.id verifier - """.trimIndent() - ) - url.set("https://walt.id") - } - from(components["java"]) - } - } - - repositories { - maven { - val releasesRepoUrl = uri("https://maven.waltid.dev/releases") - val snapshotsRepoUrl = uri("https://maven.waltid.dev/snapshots") - url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl) - val envUsername = System.getenv("MAVEN_USERNAME") - val envPassword = System.getenv("MAVEN_PASSWORD") - - val usernameFile = File("secret_maven_username.txt") - val passwordFile = File("secret_maven_password.txt") - - val secretMavenUsername = envUsername ?: usernameFile.let { if (it.isFile) it.readLines().first() else "" } - val secretMavenPassword = envPassword ?: passwordFile.let { if (it.isFile) it.readLines().first() else "" } - - credentials { - username = secretMavenUsername - password = secretMavenPassword - } - } - } -} - //licenseReport { // renderers = arrayOf(InventoryHtmlReportRenderer("waltid-verifier-licenses-report.html", "walt.id verifier")) // filters = arrayOf(LicenseBundleNormalizer()) diff --git a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/push/Subscription.kt b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/push/Subscription.kt index 8be24be97..caf9da2ff 100644 --- a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/push/Subscription.kt +++ b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/push/Subscription.kt @@ -1,6 +1,6 @@ package id.walt.webwallet.service.push -import id.walt.crypto.utils.Base64Utils.base64Decode +import id.walt.crypto.utils.Base64Utils.decodeFromBase64 import kotlinx.serialization.Serializable import org.bouncycastle.jce.ECNamedCurveTable import org.bouncycastle.jce.provider.BouncyCastleProvider @@ -17,12 +17,12 @@ data class Subscription( /** * Returns the base64 encoded auth string as a byte[] */ - fun authAsBytes(): ByteArray = auth.base64Decode() + fun authAsBytes(): ByteArray = auth.decodeFromBase64() /** * Returns the base64 encoded public key string as a byte[] */ - fun keyAsBytes(): ByteArray = key.base64Decode() + fun keyAsBytes(): ByteArray = key.decodeFromBase64() /** * Returns the base64 encoded public key as a PublicKey object diff --git a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/utils/RandomUtils.kt b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/utils/RandomUtils.kt index 4f533b89f..2eb3079ff 100644 --- a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/utils/RandomUtils.kt +++ b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/utils/RandomUtils.kt @@ -1,10 +1,9 @@ package id.walt.webwallet.utils +import id.walt.crypto.utils.Base64Utils.encodeToBase64Url import java.security.SecureRandom -import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi -@OptIn(ExperimentalEncodingApi::class) object RandomUtils { val random = SecureRandom() @@ -19,6 +18,6 @@ object RandomUtils { * Make sure bits % 8 == 0 */ fun randomBase64UrlString(bits: Int) = - Base64.UrlSafe.encode(randomBytes(bits / 8)).replace("=", "") + randomBytes(bits / 8).encodeToBase64Url() } From 524a745ee20fbe26c756356d137f346d816d03f4 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Tue, 23 Jul 2024 23:00:49 +0200 Subject: [PATCH 03/17] feat: init auth kit --- waltid-libraries/waltid-authkit/.gitignore | 36 +++ .../waltid-authkit/build.gradle.kts | 53 ++++ .../waltid-authkit/gradle.properties | 4 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + waltid-libraries/waltid-authkit/gradlew | 234 ++++++++++++++++++ waltid-libraries/waltid-authkit/gradlew.bat | 89 +++++++ .../waltid-authkit/settings.gradle.kts | 1 + .../src/main/kotlin/id/walt/Application.kt | 19 ++ .../src/main/kotlin/id/walt/plugins/HTTP.kt | 25 ++ .../main/kotlin/id/walt/plugins/Monitoring.kt | 15 ++ .../main/kotlin/id/walt/plugins/Routing.kt | 55 ++++ .../main/kotlin/id/walt/plugins/Security.kt | 122 +++++++++ .../kotlin/id/walt/plugins/Serialization.kt | 18 ++ .../src/main/resources/logback.xml | 12 + .../test/kotlin/id/walt/ApplicationTest.kt | 21 ++ 16 files changed, 709 insertions(+) create mode 100644 waltid-libraries/waltid-authkit/.gitignore create mode 100644 waltid-libraries/waltid-authkit/build.gradle.kts create mode 100644 waltid-libraries/waltid-authkit/gradle.properties create mode 100644 waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.jar create mode 100644 waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.properties create mode 100755 waltid-libraries/waltid-authkit/gradlew create mode 100644 waltid-libraries/waltid-authkit/gradlew.bat create mode 100644 waltid-libraries/waltid-authkit/settings.gradle.kts create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/resources/logback.xml create mode 100644 waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt diff --git a/waltid-libraries/waltid-authkit/.gitignore b/waltid-libraries/waltid-authkit/.gitignore new file mode 100644 index 000000000..c426c32f8 --- /dev/null +++ b/waltid-libraries/waltid-authkit/.gitignore @@ -0,0 +1,36 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ \ No newline at end of file diff --git a/waltid-libraries/waltid-authkit/build.gradle.kts b/waltid-libraries/waltid-authkit/build.gradle.kts new file mode 100644 index 000000000..e2d69c918 --- /dev/null +++ b/waltid-libraries/waltid-authkit/build.gradle.kts @@ -0,0 +1,53 @@ + +val kotlin_version: String by project +val logback_version: String by project + +plugins { + kotlin("jvm") + kotlin("plugin.serialization") + id("io.ktor.plugin") version "2.3.12" + + application + + id("com.github.ben-manes.versions") +} + +group = "id.walt" +version = "0.0.1" + +application { + mainClass.set("id.walt.ApplicationKt") + + val isDevelopment: Boolean = project.ext.has("development") + applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") +} + +repositories { + mavenCentral() +} + +dependencies { + implementation("io.ktor:ktor-server-core-jvm") + implementation("io.ktor:ktor-server-auth-jvm") + implementation("io.ktor:ktor-server-auth-jwt-jvm") + implementation("io.ktor:ktor-server-auth-ldap-jvm") + implementation("io.ktor:ktor-client-core-jvm") + implementation("io.ktor:ktor-client-apache-jvm") + implementation("io.ktor:ktor-server-sessions-jvm") + implementation("io.ktor:ktor-server-auto-head-response-jvm") + implementation("io.ktor:ktor-server-double-receive-jvm") + implementation("io.ktor:ktor-server-webjars-jvm") + implementation("io.github.smiley4:ktor-swagger-ui:3.2.0") + implementation("io.ktor:ktor-server-host-common-jvm") + implementation("io.ktor:ktor-server-status-pages-jvm") + implementation("io.ktor:ktor-server-cors-jvm") + implementation("io.ktor:ktor-server-default-headers-jvm") + implementation("io.ktor:ktor-server-forwarded-header-jvm") + implementation("io.ktor:ktor-server-call-logging-jvm") + implementation("io.ktor:ktor-server-content-negotiation-jvm") + implementation("io.ktor:ktor-serialization-kotlinx-json-jvm") + implementation("io.ktor:ktor-server-cio-jvm") + implementation("ch.qos.logback:logback-classic:$logback_version") + testImplementation("io.ktor:ktor-server-tests-jvm") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") +} diff --git a/waltid-libraries/waltid-authkit/gradle.properties b/waltid-libraries/waltid-authkit/gradle.properties new file mode 100644 index 000000000..1ab15d0c1 --- /dev/null +++ b/waltid-libraries/waltid-authkit/gradle.properties @@ -0,0 +1,4 @@ +kotlin.code.style=official +ktor_version=2.3.12 +kotlin_version=2.0.0 +logback_version=1.4.14 diff --git a/waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.jar b/waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.properties b/waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e411586a5 --- /dev/null +++ b/waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/waltid-libraries/waltid-authkit/gradlew b/waltid-libraries/waltid-authkit/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/waltid-libraries/waltid-authkit/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/waltid-libraries/waltid-authkit/gradlew.bat b/waltid-libraries/waltid-authkit/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/waltid-libraries/waltid-authkit/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/waltid-libraries/waltid-authkit/settings.gradle.kts b/waltid-libraries/waltid-authkit/settings.gradle.kts new file mode 100644 index 000000000..920e4dbe9 --- /dev/null +++ b/waltid-libraries/waltid-authkit/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "waltid-authkit" diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt new file mode 100644 index 000000000..33bd5c47a --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt @@ -0,0 +1,19 @@ +package id.walt + +import id.walt.plugins.* +import io.ktor.server.application.* +import io.ktor.server.cio.* +import io.ktor.server.engine.* + +fun main() { + embeddedServer(CIO, port = 8080, host = "0.0.0.0", module = Application::module) + .start(wait = true) +} + +fun Application.module() { + configureSecurity() + configureHTTP() + configureMonitoring() + configureSerialization() + configureRouting() +} diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt new file mode 100644 index 000000000..84b2d0813 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt @@ -0,0 +1,25 @@ +package id.walt.plugins + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.plugins.cors.routing.* +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.plugins.forwardedheaders.* +import io.ktor.server.response.* + +fun Application.configureHTTP() { + install(CORS) { + allowMethod(HttpMethod.Options) + allowMethod(HttpMethod.Put) + allowMethod(HttpMethod.Delete) + allowMethod(HttpMethod.Patch) + allowHeader(HttpHeaders.Authorization) + allowHeader("MyCustomHeader") + anyHost() // @TODO: Don't do this in production if possible. Try to limit it. + } + install(DefaultHeaders) { + header("X-Engine", "Ktor") // will send this header with each response + } + install(ForwardedHeaders) // WARNING: for security, do not include this if not behind a reverse proxy + install(XForwardedHeaders) // WARNING: for security, do not include this if not behind a reverse proxy +} diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt new file mode 100644 index 000000000..77cdb7bca --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt @@ -0,0 +1,15 @@ +package id.walt.plugins + +import io.ktor.server.application.* +import io.ktor.server.plugins.callloging.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import org.slf4j.event.* + +fun Application.configureMonitoring() { + install(CallLogging) { + level = Level.INFO + filter { call -> call.request.path().startsWith("/") } + } +} diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt new file mode 100644 index 000000000..c6f5e9b82 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt @@ -0,0 +1,55 @@ +package id.walt.plugins + +import io.github.smiley4.ktorswaggerui.SwaggerUI +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.application.Application +import io.ktor.server.application.install +import io.ktor.server.plugins.autohead.* +import io.ktor.server.plugins.doublereceive.* +import io.ktor.server.plugins.statuspages.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.ktor.server.webjars.* + +fun Application.configureRouting() { + install(AutoHeadResponse) + install(DoubleReceive) + install(Webjars) { + path = "/webjars" //defaults to /webjars + } + install(SwaggerUI) { + swagger { +// swaggerUrl = "swagger-ui" +// forwardRoot = true + } + info { + title = "Example API" + version = "latest" + description = "Example API for testing and demonstration purposes." + } + server { + url = "http://localhost:8080" + description = "Development Server" + } + } + install(StatusPages) { + exception { call, cause -> + call.respondText(text = "500: $cause" , status = HttpStatusCode.InternalServerError) + } + } + routing { + get("/") { + call.respondText("Hello World!") + } + post("/double-receive") { + val first = call.receiveText() + val theSame = call.receiveText() + call.respondText(first + " " + theSame) + } + get("/webjars") { + call.respondText("", ContentType.Text.Html) + } + } +} diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt new file mode 100644 index 000000000..b44778062 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt @@ -0,0 +1,122 @@ +package id.walt.plugins + +import com.auth0.jwt.JWT +import com.auth0.jwt.algorithms.Algorithm +import io.ktor.client.* +import io.ktor.client.engine.apache.* +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.auth.jwt.* +import io.ktor.server.auth.ldap.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.ktor.server.sessions.* + +fun Application.configureSecurity() { + authentication { + basic(name = "myauth1") { + realm = "Ktor Server" + validate { credentials -> + if (credentials.name == credentials.password) { + UserIdPrincipal(credentials.name) + } else { + null + } + } + } + + form(name = "myauth2") { + userParamName = "user" + passwordParamName = "password" + challenge { + /**/ + } + } + } + // Please read the jwt property from the config file if you are using EngineMain + val jwtAudience = "jwt-audience" + val jwtDomain = "https://jwt-provider-domain/" + val jwtRealm = "ktor sample app" + val jwtSecret = "secret" + authentication { + jwt { + realm = jwtRealm + verifier( + JWT + .require(Algorithm.HMAC256(jwtSecret)) + .withAudience(jwtAudience) + .withIssuer(jwtDomain) + .build() + ) + validate { credential -> + if (credential.payload.audience.contains(jwtAudience)) JWTPrincipal(credential.payload) else null + } + } + } + val localhost = "http://0.0.0.0" + val ldapServerPort = 6998 // TODO: change to real value! + authentication { + basic("authName") { + realm = "realm" + validate { credential -> + ldapAuthenticate(credential, "ldap://$localhost:${ldapServerPort}", "uid=%s,ou=system") + } + } + } + authentication { + oauth("auth-oauth-google") { + urlProvider = { "http://localhost:8080/callback" } + providerLookup = { + OAuthServerSettings.OAuth2ServerSettings( + name = "google", + authorizeUrl = "https://accounts.google.com/o/oauth2/auth", + accessTokenUrl = "https://accounts.google.com/o/oauth2/token", + requestMethod = HttpMethod.Post, + clientId = System.getenv("GOOGLE_CLIENT_ID"), + clientSecret = System.getenv("GOOGLE_CLIENT_SECRET"), + defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile") + ) + } + client = HttpClient(Apache) + } + } + data class MySession(val count: Int = 0) + install(Sessions) { + cookie("MY_SESSION") { + cookie.extensions["SameSite"] = "lax" + } + } + routing { + authenticate("myauth1") { + get("/protected/route/basic") { + val principal = call.principal()!! + call.respondText("Hello ${principal.name}") + } + } + authenticate("myauth2") { + get("/protected/route/form") { + val principal = call.principal()!! + call.respondText("Hello ${principal.name}") + } + } + authenticate("auth-oauth-google") { + get("login") { + call.respondRedirect("/callback") + } + + get("/callback") { + val principal: OAuthAccessTokenResponse.OAuth2? = call.authentication.principal() + call.sessions.set(UserSession(principal?.accessToken.toString())) + call.respondRedirect("/hello") + } + } + get("/session/increment") { + val session = call.sessions.get() ?: MySession() + call.sessions.set(session.copy(count = session.count + 1)) + call.respondText("Counter is ${session.count}. Refresh to increment.") + } + } +} + +class UserSession(accessToken: String) diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt new file mode 100644 index 000000000..62a9e6812 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt @@ -0,0 +1,18 @@ +package id.walt.plugins + +import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.application.* +import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.response.* +import io.ktor.server.routing.* + +fun Application.configureSerialization() { + install(ContentNegotiation) { + json() + } + routing { + get("/json/kotlinx-serialization") { + call.respond(mapOf("hello" to "world")) + } + } +} diff --git a/waltid-libraries/waltid-authkit/src/main/resources/logback.xml b/waltid-libraries/waltid-authkit/src/main/resources/logback.xml new file mode 100644 index 000000000..3e11d7811 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/resources/logback.xml @@ -0,0 +1,12 @@ + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt b/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt new file mode 100644 index 000000000..05031b1f6 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt @@ -0,0 +1,21 @@ +package id.walt + +import id.walt.plugins.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.server.testing.* +import kotlin.test.* + +class ApplicationTest { + @Test + fun testRoot() = testApplication { + application { + configureRouting() + } + client.get("/").apply { + assertEquals(HttpStatusCode.OK, status) + assertEquals("Hello World!", bodyAsText()) + } + } +} From 0f96bb8d73c1049893e4a8e8ab139cfb47bcc9e2 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Thu, 25 Jul 2024 00:30:02 +0200 Subject: [PATCH 04/17] feat: Auth Kit, docs --- .../waltid-authkit/build.gradle.kts | 23 ++++++--- waltid-libraries/waltid-authkit/docs/base.md | 49 +++++++++++++++++++ .../src/main/kotlin/id/walt/Application.kt | 33 +++++++++++++ .../id/walt/methods/AuthenticationMethod.kt | 7 +++ .../main/kotlin/id/walt/methods/UserPass.kt | 7 +++ .../main/kotlin/id/walt/plugins/Security.kt | 41 ++++++++-------- .../kotlin/id/walt/sessions/AuthSession.kt | 11 +++++ .../id/walt/sessions/AuthSessionResponse.kt | 14 ++++++ .../test/kotlin/id/walt/ApplicationTest.kt | 24 +++++++++ 9 files changed, 181 insertions(+), 28 deletions(-) create mode 100644 waltid-libraries/waltid-authkit/docs/base.md create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt create mode 100644 waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt diff --git a/waltid-libraries/waltid-authkit/build.gradle.kts b/waltid-libraries/waltid-authkit/build.gradle.kts index e2d69c918..c1a9efbbd 100644 --- a/waltid-libraries/waltid-authkit/build.gradle.kts +++ b/waltid-libraries/waltid-authkit/build.gradle.kts @@ -1,7 +1,3 @@ - -val kotlin_version: String by project -val logback_version: String by project - plugins { kotlin("jvm") kotlin("plugin.serialization") @@ -27,6 +23,7 @@ repositories { } dependencies { + // Ktor server implementation("io.ktor:ktor-server-core-jvm") implementation("io.ktor:ktor-server-auth-jvm") implementation("io.ktor:ktor-server-auth-jwt-jvm") @@ -37,7 +34,6 @@ dependencies { implementation("io.ktor:ktor-server-auto-head-response-jvm") implementation("io.ktor:ktor-server-double-receive-jvm") implementation("io.ktor:ktor-server-webjars-jvm") - implementation("io.github.smiley4:ktor-swagger-ui:3.2.0") implementation("io.ktor:ktor-server-host-common-jvm") implementation("io.ktor:ktor-server-status-pages-jvm") implementation("io.ktor:ktor-server-cors-jvm") @@ -47,7 +43,20 @@ dependencies { implementation("io.ktor:ktor-server-content-negotiation-jvm") implementation("io.ktor:ktor-serialization-kotlinx-json-jvm") implementation("io.ktor:ktor-server-cio-jvm") - implementation("ch.qos.logback:logback-classic:$logback_version") + + // Ktor server external + implementation("io.github.smiley4:ktor-swagger-ui:3.2.0") + + // Logging + implementation("io.klogging:klogging-jvm:0.6.1") + implementation("io.klogging:slf4j-klogging:0.6.0") + + /* --- Testing --- */ + + // Ktor + testImplementation("io.ktor:ktor-server-cio-jvm") testImplementation("io.ktor:ktor-server-tests-jvm") - testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") + + // Kotlin + testImplementation("org.jetbrains.kotlin:kotlin-test-junit") } diff --git a/waltid-libraries/waltid-authkit/docs/base.md b/waltid-libraries/waltid-authkit/docs/base.md new file mode 100644 index 000000000..43e6a2b82 --- /dev/null +++ b/waltid-libraries/waltid-authkit/docs/base.md @@ -0,0 +1,49 @@ +## Most simple auth + +### 1. Request (Client -> AuthKit): UserPass + +Choose from: + +### 1.1 Plain +```http request +POST /auth/userpass +``` +```json +{ + "username": "abc", + "password": "xyz" +} +``` + +### 1.2 Basic +```http request +POST /auth/userpass/basic +Authorization: Basic YWJjOnh5eg== +``` + +### 1.3 Form +```http request +POST /auth/userpass/form +Content-Type: application/x-www-form-urlencoded + +username=abc&password=xyz +``` + +### 2. Response (AuthKit -> Client): AuthSession +```json5 +{ + "session": "a662b620-7d89-41bf-a823-63d0179d82f1", // Session ID + "status": "ok", // ok, continue_next_step, fail + + // Due to success, the following is available: + "user": "dcedede5-b4e1-49e4-b62b-4801b8343311", + "auth_token": "einahf0Gohng4phoob9aeso3ilethaef5eec", // Token generated, used for subsequent authentication + //"valid_until": "2024-07-25T21:53:47Z" +} +``` + +### 3. Use authentication (Client -> Server): SomeRequest +```http request +GET /my-secure-service/xyz +Authorization: Bearer einahf0Gohng4phoob9aeso3ilethaef5eec +``` diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt index 33bd5c47a..d93ee3489 100644 --- a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt @@ -1,11 +1,44 @@ package id.walt import id.walt.plugins.* +import io.klogging.Level +import io.klogging.config.loggingConfiguration +import io.klogging.rendering.RENDER_ANSI +import io.klogging.sending.STDERR +import io.klogging.sending.STDOUT import io.ktor.server.application.* import io.ktor.server.cio.* import io.ktor.server.engine.* fun main() { + + loggingConfiguration(true) { + sink("stdout", RENDER_ANSI, STDOUT) + sink("stderr", RENDER_ANSI, STDERR) + + logging { + fromLoggerBase("io.ktor.routing.Routing", stopOnMatch = true) + fromMinLevel(Level.DEBUG) { + toSink("stdout") + } + } + logging { + fromLoggerBase("org.sqlite.core.NativeDB", stopOnMatch = true) + fromMinLevel(Level.DEBUG) { + toSink("stdout") + } + } + logging { + fromMinLevel(Level.ERROR) { + toSink("stderr") + } + inLevelRange(Level.TRACE, Level.WARN) { + toSink("stdout") + } + } + minDirectLogLevel(Level.TRACE) + } + embeddedServer(CIO, port = 8080, host = "0.0.0.0", module = Application::module) .start(wait = true) } diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt new file mode 100644 index 000000000..91c012ee8 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt @@ -0,0 +1,7 @@ +package id.walt.methods + +abstract class AuthenticationMethod { + + + +} diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt new file mode 100644 index 000000000..d0e5d5dd1 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt @@ -0,0 +1,7 @@ +package id.walt.methods + +class UserPass : AuthenticationMethod() { + + + +} diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt index b44778062..6adcd9592 100644 --- a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt @@ -1,20 +1,13 @@ package id.walt.plugins -import com.auth0.jwt.JWT -import com.auth0.jwt.algorithms.Algorithm -import io.ktor.client.* -import io.ktor.client.engine.apache.* -import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.auth.* -import io.ktor.server.auth.jwt.* import io.ktor.server.auth.ldap.* import io.ktor.server.response.* import io.ktor.server.routing.* -import io.ktor.server.sessions.* fun Application.configureSecurity() { - authentication { + /*authentication { basic(name = "myauth1") { realm = "Ktor Server" validate { credentials -> @@ -25,12 +18,12 @@ fun Application.configureSecurity() { } } } - + form(name = "myauth2") { userParamName = "user" passwordParamName = "password" challenge { - /**/ + *//**//* } } } @@ -53,18 +46,19 @@ fun Application.configureSecurity() { if (credential.payload.audience.contains(jwtAudience)) JWTPrincipal(credential.payload) else null } } - } - val localhost = "http://0.0.0.0" - val ldapServerPort = 6998 // TODO: change to real value! - authentication { - basic("authName") { + }*/ + val localhost = "localhost" + val ldapServerPort = 3893 // TODO: change to real value! + authentication { + basic("auth-ldap") { realm = "realm" validate { credential -> - ldapAuthenticate(credential, "ldap://$localhost:${ldapServerPort}", "uid=%s,ou=system") + println("Validating LDAP credential: $credential") + ldapAuthenticate(credential, "ldap://$localhost:${ldapServerPort}", "cn=%s,ou=superheros,dc=glauth,dc=com") } } } - authentication { + /*authentication { oauth("auth-oauth-google") { urlProvider = { "http://localhost:8080/callback" } providerLookup = { @@ -86,9 +80,14 @@ fun Application.configureSecurity() { cookie("MY_SESSION") { cookie.extensions["SameSite"] = "lax" } - } + }*/ routing { - authenticate("myauth1") { + authenticate("auth-ldap") { + get("/") { + call.respondText("Hello, ${call.principal()?.name}!") + } + } + /*authenticate("myauth1") { get("/protected/route/basic") { val principal = call.principal()!! call.respondText("Hello ${principal.name}") @@ -104,7 +103,7 @@ fun Application.configureSecurity() { get("login") { call.respondRedirect("/callback") } - + get("/callback") { val principal: OAuthAccessTokenResponse.OAuth2? = call.authentication.principal() call.sessions.set(UserSession(principal?.accessToken.toString())) @@ -115,7 +114,7 @@ fun Application.configureSecurity() { val session = call.sessions.get() ?: MySession() call.sessions.set(session.copy(count = session.count + 1)) call.respondText("Counter is ${session.count}. Refresh to increment.") - } + }*/ } } diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt new file mode 100644 index 000000000..02bb44730 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt @@ -0,0 +1,11 @@ +package id.walt.sessions + +enum class AuthSessionStatus(val value: String) { + OK("ok"), + CONTINUE_NEXT_STEP("continue_next_step"), + FAIL("fail"), +} + +data class AuthSession( + val id: String +) diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt new file mode 100644 index 000000000..a206d1467 --- /dev/null +++ b/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt @@ -0,0 +1,14 @@ +package id.walt.sessions + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class AuthSessionResponse( + val session: String, // Session ID + val status: AuthSessionStatus, + + val user: String, + @SerialName("auth_token") + val authToken: String +) diff --git a/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt b/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt index 05031b1f6..650b22474 100644 --- a/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt +++ b/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt @@ -4,15 +4,39 @@ import id.walt.plugins.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.request.* import io.ktor.server.testing.* +import kotlinx.serialization.json.JsonObject import kotlin.test.* class ApplicationTest { @Test fun testRoot() = testApplication { application { + + install(Authentication) { + this.provider("x") { + this.authenticate { + val x = it.call.receive() + + } + } + } + configureRouting() } + + + client.post("/auth/userpass") { + basicAuth("user1", "pass1") + } + + + + + client.get("/").apply { assertEquals(HttpStatusCode.OK, status) assertEquals("Hello World!", bodyAsText()) From 0ee1696c134a9d29a22dd01cf16925e48ff81b4e Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Mon, 29 Jul 2024 23:12:03 +0200 Subject: [PATCH 05/17] feat: add log format compatible with e.g. Datadog, New Relic --- waltid-services/waltid-issuer-api/build.gradle.kts | 4 ++-- waltid-services/waltid-service-commons/README.md | 11 ++++++----- .../waltid-service-commons/build.gradle.kts | 4 ++-- .../main/kotlin/id/walt/commons/logging/LogStrings.kt | 6 +++--- waltid-services/waltid-verifier-api/build.gradle.kts | 4 ++-- waltid-services/waltid-wallet-api/build.gradle.kts | 4 ++-- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/waltid-services/waltid-issuer-api/build.gradle.kts b/waltid-services/waltid-issuer-api/build.gradle.kts index 3e0858f2e..45aee2cfd 100644 --- a/waltid-services/waltid-issuer-api/build.gradle.kts +++ b/waltid-services/waltid-issuer-api/build.gradle.kts @@ -84,8 +84,8 @@ dependencies { // Logging implementation("io.github.oshai:kotlin-logging-jvm:7.0.0") implementation("org.slf4j:jul-to-slf4j:2.0.13") - implementation("io.klogging:klogging-jvm:0.6.1") - implementation("io.klogging:slf4j-klogging:0.6.0") + implementation("io.klogging:klogging-jvm:0.7.0") + implementation("io.klogging:slf4j-klogging:0.7.0") // Test diff --git a/waltid-services/waltid-service-commons/README.md b/waltid-services/waltid-service-commons/README.md index ed18266d2..aee05592a 100644 --- a/waltid-services/waltid-service-commons/README.md +++ b/waltid-services/waltid-service-commons/README.md @@ -110,12 +110,13 @@ The services now benefit from a more advanced logging system based on the servic - Splunk 3. [**Multiple Log Output Formats**](https://github.com/walt-id/waltid-identity/blob/main/waltid-services/waltid-service-commons/src/main/kotlin/id/walt/commons/logging/LogStrings.kt): Supports various formats for log output, including: - - CLEF compact JSON format - - Elastic Common Schema (ECS) - - ECS for .NET - - GELF JSON format + - CLEF compact JSON format (e.g. Serilog) (https://clef-json.org/) + - Elastic Common Schema (ECS) (can be sent directly to ELK stack) (https://www.elastic.co/guide/en/ecs/current/index.html) + - ECS for .NET (https://github.com/elastic/ecs-dotnet/blob/main/examples/aspnetcore-with-serilog/) + - GELF JSON format (for e.g. Graylog) - JSON format for Splunk HTTP Event Collector - - Simple & ISO 8601 rendering + - Simple & ISO 8601 & ANSI rendering + - "Standard" JSON format (e.g. Datadog, New Relic, etc.) 4. **Custom Logging Configurations**: Users can provide custom logging configurations without needing to recompile the module. 5. **Structured and Context Logging**: diff --git a/waltid-services/waltid-service-commons/build.gradle.kts b/waltid-services/waltid-service-commons/build.gradle.kts index 41aa912cc..bd7d79284 100644 --- a/waltid-services/waltid-service-commons/build.gradle.kts +++ b/waltid-services/waltid-service-commons/build.gradle.kts @@ -23,8 +23,8 @@ dependencies { api("io.ktor:ktor-serialization-kotlinx-json-jvm:${Versions.KTOR_VERSION}") // Logging - api("io.klogging:klogging-jvm:0.6.1") // JVM + ~JS - implementation("io.klogging:slf4j-klogging:0.6.0") + api("io.klogging:klogging-jvm:0.7.0") // JVM + ~JS + implementation("io.klogging:slf4j-klogging:0.7.0") implementation("org.slf4j:jul-to-slf4j:2.0.13") // CLI diff --git a/waltid-services/waltid-service-commons/src/main/kotlin/id/walt/commons/logging/LogStrings.kt b/waltid-services/waltid-service-commons/src/main/kotlin/id/walt/commons/logging/LogStrings.kt index d7031d691..e1bf1fdb7 100644 --- a/waltid-services/waltid-service-commons/src/main/kotlin/id/walt/commons/logging/LogStrings.kt +++ b/waltid-services/waltid-service-commons/src/main/kotlin/id/walt/commons/logging/LogStrings.kt @@ -8,10 +8,10 @@ enum class RenderStrings(val renderString: RenderString) { ISO8601(RENDER_ISO8601), ANSI(RENDER_ANSI), CLEF(RENDER_CLEF), - GELD(RENDER_GELF), + GELF(RENDER_GELF), ECS(RENDER_ECS), - ECS_DOTNET(RENDER_ECS_DOTNET) - + ECS_DOTNET(RENDER_ECS_DOTNET), + STANDARD(RENDER_STANDARD) } diff --git a/waltid-services/waltid-verifier-api/build.gradle.kts b/waltid-services/waltid-verifier-api/build.gradle.kts index d101ee705..94ce12319 100644 --- a/waltid-services/waltid-verifier-api/build.gradle.kts +++ b/waltid-services/waltid-verifier-api/build.gradle.kts @@ -89,8 +89,8 @@ dependencies { // Logging implementation("io.github.oshai:kotlin-logging-jvm:7.0.0") implementation("org.slf4j:jul-to-slf4j:2.0.13") - implementation("io.klogging:klogging-jvm:0.6.1") - implementation("io.klogging:slf4j-klogging:0.6.0") + implementation("io.klogging:klogging-jvm:0.7.0") + implementation("io.klogging:slf4j-klogging:0.7.0") implementation("io.ktor:ktor-client-okhttp-jvm:${Versions.KTOR_VERSION}") diff --git a/waltid-services/waltid-wallet-api/build.gradle.kts b/waltid-services/waltid-wallet-api/build.gradle.kts index c0b9c4d40..c9be6df44 100644 --- a/waltid-services/waltid-wallet-api/build.gradle.kts +++ b/waltid-services/waltid-wallet-api/build.gradle.kts @@ -165,8 +165,8 @@ dependencies { // Logging implementation("io.github.oshai:kotlin-logging-jvm:7.0.0") implementation("org.slf4j:jul-to-slf4j:2.0.13") - implementation("io.klogging:klogging-jvm:0.6.1") - implementation("io.klogging:slf4j-klogging:0.6.0") + implementation("io.klogging:klogging-jvm:0.7.0") + implementation("io.klogging:slf4j-klogging:0.7.0") // Test testImplementation("org.jetbrains.kotlin:kotlin-test-junit:2.0.0") From 5bf97b2eec18057a98acee47bce77c840be0b668 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:57:47 +0200 Subject: [PATCH 06/17] feat: more error handling --- .../src/main/kotlin/id/walt/verifier/VerifierApi.kt | 6 +++++- .../id/walt/webwallet/service/exchange/IssuanceService.kt | 2 +- .../id/walt/webwallet/web/controllers/ExchangeController.kt | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/waltid-services/waltid-verifier-api/src/main/kotlin/id/walt/verifier/VerifierApi.kt b/waltid-services/waltid-verifier-api/src/main/kotlin/id/walt/verifier/VerifierApi.kt index 7109945e5..58eadcc06 100644 --- a/waltid-services/waltid-verifier-api/src/main/kotlin/id/walt/verifier/VerifierApi.kt +++ b/waltid-services/waltid-verifier-api/src/main/kotlin/id/walt/verifier/VerifierApi.kt @@ -30,6 +30,7 @@ import id.walt.verifier.oidc.VerificationUseCase import io.github.smiley4.ktorswaggerui.dsl.routing.get import io.github.smiley4.ktorswaggerui.dsl.routing.post import io.github.smiley4.ktorswaggerui.dsl.routing.route +import io.klogging.logger import io.ktor.client.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.logging.* @@ -128,7 +129,7 @@ private const val fixedPresentationDefinitionForEbsiConformanceTest = "{\"id\":\"any\",\"format\":{\"jwt_vp\":{\"alg\":[\"ES256\"]}},\"input_descriptors\":[{\"id\":\"any\",\"format\":{\"jwt_vc\":{\"alg\":[\"ES256\"]}},\"constraints\":{\"fields\":[{\"path\":[\"$.vc.type\"],\"filter\":{\"type\":\"array\",\"contains\":{\"const\":\"VerifiableAttestation\"}}}]}},{\"id\":\"any\",\"format\":{\"jwt_vc\":{\"alg\":[\"ES256\"]}},\"constraints\":{\"fields\":[{\"path\":[\"$.vc.type\"],\"filter\":{\"type\":\"array\",\"contains\":{\"const\":\"VerifiableAttestation\"}}}]}},{\"id\":\"any\",\"format\":{\"jwt_vc\":{\"alg\":[\"ES256\"]}},\"constraints\":{\"fields\":[{\"path\":[\"$.vc.type\"],\"filter\":{\"type\":\"array\",\"contains\":{\"const\":\"VerifiableAttestation\"}}}]}}]}" private val verificationUseCase = VerificationUseCase(httpClient, SimpleJWTCryptoProvider(JWSAlgorithm.EdDSA, null, null)) - +private val logger = logger("Verifier") @OptIn(ExperimentalSerializationApi::class) fun Application.verfierApi() { @@ -304,6 +305,7 @@ fun Application.verfierApi() { context.respondRedirect("openid://?state=$state&error=invalid_request&error_description=$errorDescription") } } else { + logger.error(it) { "/verify error: $errorDescription" } call.respond(HttpStatusCode.BadRequest, errorDescription) } }.also { @@ -333,6 +335,7 @@ fun Application.verfierApi() { verificationUseCase.getResult(id).onSuccess { call.respond(HttpStatusCode.OK, it) }.onFailure { + it.printStackTrace() call.respond(HttpStatusCode.BadRequest, it.localizedMessage) } } @@ -378,6 +381,7 @@ fun Application.verfierApi() { verificationUseCase.getSignedAuthorizationRequestObject(id).onSuccess { call.respondText(it, ContentType.parse("application/oauth-authz-req+jwt"), HttpStatusCode.OK) }.onFailure { + it.printStackTrace() call.respond(HttpStatusCode.BadRequest, it.localizedMessage) } } diff --git a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/exchange/IssuanceService.kt b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/exchange/IssuanceService.kt index cb2e4d1c5..7f5dfeb9b 100644 --- a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/exchange/IssuanceService.kt +++ b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/service/exchange/IssuanceService.kt @@ -138,7 +138,7 @@ object IssuanceService { val credentialResponse = http.post(providerMetadata.credentialEndpoint!!) { contentType(ContentType.Application.Json) - bearerAuth(tokenResp.accessToken!!) + bearerAuth(tokenResp.accessToken ?: error("No access token in token response")) setBody(credReq.toJSON()) }.body().let { CredentialResponse.fromJSON(it) } logger.debug { "credentialResponse: $credentialResponse" } diff --git a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/web/controllers/ExchangeController.kt b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/web/controllers/ExchangeController.kt index 480fcf2f2..25f16b5e5 100644 --- a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/web/controllers/ExchangeController.kt +++ b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/web/controllers/ExchangeController.kt @@ -70,7 +70,7 @@ fun Application.exchange() = walletRoute { context.respond(HttpStatusCode.OK, it) }.onFailure { error -> error.printStackTrace() - context.respond(HttpStatusCode.BadRequest, error.localizedMessage) + context.respond(HttpStatusCode.BadRequest, error.message ?: "Unknown error") } } post("matchCredentialsForPresentationDefinition", { From 9831340970dfd6f3377f830c7e87032b3d9b749e Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:58:12 +0200 Subject: [PATCH 07/17] fix: update base64 API --- .../kotlin/id/walt/issuer/issuance/CIProvider.kt | 6 +++--- .../main/kotlin/id/walt/issuer/issuance/OidcApi.kt | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/waltid-services/waltid-issuer-api/src/main/kotlin/id/walt/issuer/issuance/CIProvider.kt b/waltid-services/waltid-issuer-api/src/main/kotlin/id/walt/issuer/issuance/CIProvider.kt index 720545901..f1e791024 100644 --- a/waltid-services/waltid-issuer-api/src/main/kotlin/id/walt/issuer/issuance/CIProvider.kt +++ b/waltid-services/waltid-issuer-api/src/main/kotlin/id/walt/issuer/issuance/CIProvider.kt @@ -10,6 +10,7 @@ import id.walt.crypto.keys.Key import id.walt.crypto.keys.KeySerialization import id.walt.crypto.keys.KeyType import id.walt.crypto.keys.jwk.JWKKey +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.did.dids.DidService import id.walt.did.dids.DidUtils import id.walt.issuer.config.CredentialTypeConfig @@ -35,7 +36,6 @@ import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.* -import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi import kotlin.time.Duration.Companion.minutes @@ -137,7 +137,7 @@ open class CIProvider : OpenIDCredentialIssuer( log.debug { "Verifying JWS: $token" } log.debug { "JWS Verification: target: $target" } - val tokenHeader = Json.parseToJsonElement(Base64.decode(token.split(".")[0]).decodeToString()).jsonObject + val tokenHeader = Json.parseToJsonElement(token.split(".")[0].decodeFromBase64Url().decodeToString()).jsonObject if (tokenHeader["kid"] != null) { val did = tokenHeader["kid"]!!.jsonPrimitive.content.split("#")[0] log.debug { "Resolving DID: $did" } @@ -279,7 +279,7 @@ open class CIProvider : OpenIDCredentialIssuer( val jwtParts = jwt.split(".") fun decodeJwtPart(idx: Int) = - Json.parseToJsonElement(Base64.decode(jwtParts[idx]).decodeToString()).jsonObject + Json.parseToJsonElement(jwtParts[idx].decodeFromBase64Url().decodeToString()).jsonObject val header = decodeJwtPart(0) val payload = decodeJwtPart(1) diff --git a/waltid-services/waltid-issuer-api/src/main/kotlin/id/walt/issuer/issuance/OidcApi.kt b/waltid-services/waltid-issuer-api/src/main/kotlin/id/walt/issuer/issuance/OidcApi.kt index 00b85fde2..d4ce86d4a 100644 --- a/waltid-services/waltid-issuer-api/src/main/kotlin/id/walt/issuer/issuance/OidcApi.kt +++ b/waltid-services/waltid-issuer-api/src/main/kotlin/id/walt/issuer/issuance/OidcApi.kt @@ -1,6 +1,7 @@ package id.walt.issuer.issuance +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.oid4vc.data.ResponseMode import id.walt.oid4vc.data.ResponseType import id.walt.oid4vc.errors.* @@ -22,7 +23,6 @@ import io.ktor.util.* import kotlinx.coroutines.runBlocking import kotlinx.serialization.Serializable import kotlinx.serialization.json.* -import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi import kotlin.time.Duration.Companion.minutes @@ -213,12 +213,11 @@ object OidcApi : CIProvider() { logger.info { "/token tokenResp: $tokenResp" } val sessionId = Json.parseToJsonElement( - Base64.decode( - (tokenResp.accessToken - ?: throw IllegalArgumentException("No access token was responded with tokenResp?")).split( - "." - )[1] - ).decodeToString() + (tokenResp.accessToken + ?: throw IllegalArgumentException("No access token was responded with tokenResp?")).split( + "." + )[1].decodeFromBase64Url() + .decodeToString() ).jsonObject["sub"]?.jsonPrimitive?.contentOrNull ?: throw IllegalArgumentException("Could not get session ID from token response!") val nonceToken = tokenResp.cNonce From e5b6a58918b9600249519d731d43c1feb7f0e37c Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:59:29 +0200 Subject: [PATCH 08/17] feat: better module organization --- settings.gradle.kts | 79 +++-- .../waltid-android/build.gradle.kts | 4 +- .../waltid-cli/build.gradle.kts | 8 +- .../shared/build.gradle.kts | 8 +- .../{ => auth}/waltid-authkit/.gitignore | 0 .../waltid-authkit/build.gradle.kts | 17 +- .../auth/waltid-authkit/docs/base.md | 17 + .../docs/methods/1_userpass.md} | 0 .../waltid-authkit/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../{ => auth}/waltid-authkit/gradlew | 0 .../{ => auth}/waltid-authkit/gradlew.bat | 0 .../waltid-authkit/settings.gradle.kts | 0 .../src/main/kotlin/id/walt/Application.kt | 0 .../main/kotlin/id/walt/accounts/Account.kt | 6 + .../id/walt/methods/AuthenticationMethod.kt | 0 .../main/kotlin/id/walt/methods/EmailPass.kt | 4 + .../main/kotlin/id/walt/methods/Kerberos.kt | 56 ++++ .../src/main/kotlin/id/walt/methods/LDAP.kt | 124 +++++++ .../src/main/kotlin/id/walt/methods/LDAP2.kt | 30 ++ .../src/main/kotlin/id/walt/methods/RADIUS.kt | 49 +++ .../main/kotlin/id/walt/methods/UserPass.kt | 0 .../src/main/kotlin/id/walt/plugins/HTTP.kt | 0 .../main/kotlin/id/walt/plugins/Monitoring.kt | 0 .../main/kotlin/id/walt/plugins/Routing.kt | 0 .../main/kotlin/id/walt/plugins/Security.kt | 17 +- .../kotlin/id/walt/plugins/Serialization.kt | 0 .../kotlin/id/walt/sessions/AuthSession.kt | 5 +- .../id/walt/sessions/AuthSessionResponse.kt | 0 .../src/main/resources/logback.xml | 0 .../test/kotlin/id/walt/ApplicationTest.kt | 9 +- .../src/main/kotlin/id/walt/App2.kt | 314 ++++++++++++++++++ .../src/main/kotlin/id/walt/Verifier.kt | 97 ++++++ .../waltid-mdoc-credentials/.gitignore | 0 .../CODE_OF_CONDUCT.md | 0 .../waltid-mdoc-credentials/CONTRIBUTING.md | 0 .../waltid-mdoc-credentials/LICENSE | 0 .../waltid-mdoc-credentials/README.md | 0 .../waltid-mdoc-credentials/build.gradle.kts | 0 .../waltid-mdoc-credentials/cert.der | Bin .../examples/js/SimpleCOSECryptoProvider.js | 0 .../examples/js/index.js | 0 .../examples/js/package-lock.json | 0 .../examples/js/package.json | 0 .../waltid-mdoc-credentials/gradlew | 0 .../waltid-mdoc-credentials/gradlew.bat | 0 .../src/commonMain/kotlin/cbor/ByteString.kt | 0 .../src/commonMain/kotlin/cbor/Cbor.kt | 0 .../kotlin/cbor/internal/ByteArrayInput.kt | 0 .../cbor/internal/CborDecodingException.kt | 0 .../kotlin/cbor/internal/SharedHelpers.kt | 0 .../commonMain/kotlin/cbor/internal/Values.kt | 0 .../cbor/internal/decoding/CborDecoder.kt | 0 .../cbor/internal/encoding/CborEncoder.kt | 0 .../src/commonMain/kotlin/id/walt/Values.kt | 0 .../walt/mdoc/cose/AsyncCOSECryptoProvider.kt | 0 .../id/walt/mdoc/cose/COSECryptoProvider.kt | 0 .../kotlin/id/walt/mdoc/cose/COSEMac0.kt | 0 .../kotlin/id/walt/mdoc/cose/COSESign1.kt | 0 .../id/walt/mdoc/cose/COSESimpleBase.kt | 0 .../kotlin/id/walt/mdoc/cose/COSEValues.kt | 0 .../id/walt/mdoc/dataelement/DataElement.kt | 0 .../mdoc/dataelement/DataElementConversion.kt | 0 .../mdoc/dataelement/DataElementSerializer.kt | 0 .../kotlin/id/walt/mdoc/dataelement/MapKey.kt | 0 .../walt/mdoc/dataretrieval/DeviceRequest.kt | 0 .../walt/mdoc/dataretrieval/DeviceResponse.kt | 0 .../dataretrieval/DeviceResponseStatus.kt | 0 .../id/walt/mdoc/devicesigned/DeviceAuth.kt | 0 .../id/walt/mdoc/devicesigned/DeviceSigned.kt | 0 .../kotlin/id/walt/mdoc/doc/MDoc.kt | 0 .../kotlin/id/walt/mdoc/doc/MDocBuilder.kt | 0 .../walt/mdoc/doc/MDocVerificationParams.kt | 0 .../id/walt/mdoc/doc/VerificationType.kt | 0 .../id/walt/mdoc/docrequest/ItemsRequest.kt | 0 .../id/walt/mdoc/docrequest/MDocRequest.kt | 0 .../mdoc/docrequest/MDocRequestBuilder.kt | 0 .../MDocRequestVerificationParams.kt | 0 .../id/walt/mdoc/issuersigned/IssuerSigned.kt | 0 .../mdoc/issuersigned/IssuerSignedItem.kt | 0 .../mdoc/mdocauth/DeviceAuthentication.kt | 0 .../kotlin/id/walt/mdoc/mso/DeviceKeyInfo.kt | 0 .../id/walt/mdoc/mso/DigestAlgorithm.kt | 0 .../commonMain/kotlin/id/walt/mdoc/mso/MSO.kt | 0 .../kotlin/id/walt/mdoc/mso/ValidityInfo.kt | 0 .../mdoc/readerauth/ReaderAuthentication.kt | 0 .../kotlin/id/walt/mdoc/MDocTest.kt | 0 .../id/walt/mdoc/JSAsyncCOSECryptoProvider.kt | 0 .../mdoc/SimpleAsyncCOSECryptoProvider.kt | 0 .../src/jsTest/kotlin/id/walt/mdoc/JSTest.kt | 0 .../id/walt/mdoc/COSECryptoProviderKeyInfo.kt | 0 .../id/walt/mdoc/SimpleCOSECryptoProvider.kt | 0 .../kotlin/id/walt/mdoc/JVMMdocTest.kt | 0 .../waltid-verifiable-credentials/README.md | 0 .../build.gradle.kts | 4 +- .../kotlin/id/walt/credentials/Claims.kt | 0 .../id/walt/credentials/CredentialBuilder.kt | 0 .../walt/credentials/PresentationBuilder.kt | 0 .../credentials/issuance/DataFunctions.kt | 0 .../id/walt/credentials/issuance/Issuer.kt | 0 .../credentials/schemes/JwsSignatureScheme.kt | 0 .../credentials/schemes/SignatureScheme.kt | 0 .../id/walt/credentials/utils/EnumUtils.kt | 0 .../credentials/utils/ExtensionMethods.kt | 0 .../credentials/utils/JsonCanonicalization.kt | 0 .../credentials/utils/W3CDataMergeUtils.kt | 0 .../id/walt/credentials/utils/W3CVcUtils.kt | 0 .../id/walt/credentials/utils/randomUUID.kt | 0 .../id/walt/credentials/vc/vcs/Credential.kt | 0 .../credentials/vc/vcs/CredentialDataModel.kt | 0 .../id/walt/credentials/vc/vcs/MdocsVC.kt | 0 .../credentials/vc/vcs/W3CBaseDataModels.kt | 0 .../id/walt/credentials/vc/vcs/W3CMetadata.kt | 0 .../credentials/vc/vcs/W3CV11DataModel.kt | 0 .../walt/credentials/vc/vcs/W3CV2DataModel.kt | 0 .../id/walt/credentials/vc/vcs/W3CVC.kt | 0 .../CredentialDataValidatorPolicy.kt | 0 .../CredentialWrapperValidatorPolicy.kt | 0 .../credentials/verification/Exceptions.kt | 0 .../verification/JwtVerificationPolicy.kt | 0 .../credentials/verification/PolicyManager.kt | 0 .../verification/VerificationPolicy.kt | 0 .../walt/credentials/verification/Verifier.kt | 0 .../verification/models/PolicyRequest.kt | 0 .../verification/models/PolicyResult.kt | 0 .../models/PresentationResultEntry.kt | 0 .../PresentationVerificationResponse.kt | 0 .../policies/AllowedIssuerPolicy.kt | 0 .../policies/ExpirationDatePolicy.kt | 0 .../verification/policies/JsonSchemaPolicy.kt | 0 .../policies/JwtSignaturePolicy.kt | 0 .../policies/NotBeforeDatePolicy.kt | 0 .../verification/policies/RevocationPolicy.kt | 0 .../verification/policies/WebhookPolicy.kt | 0 .../policies/vp/HolderBindingPolicy.kt | 0 .../policies/vp/MaximumCredentialsPolicy.kt | 0 .../policies/vp/MinimumCredentialsPolicy.kt | 0 .../src/commonTest/kotlin/DataBuilderTest.kt | 0 .../src/commonTest/kotlin/LocalVcAPITest.kt | 0 .../kotlin/PresentationBuilderTest.kt | 0 .../kotlin/PresentationVerificationTest.kt | 0 .../src/commonTest/kotlin/VcApiTest.kt | 0 .../walt/credentials/utils/randomUUID.ios.kt | 0 .../policies/RevocationPolicy.ios.kt | 0 .../utils/CredentialBuilderUtils.kt | 0 .../utils/PresentationVerificationUtils.kt | 0 .../id/walt/credentials/utils/UUID.jvm.kt | 0 .../policies/RevocationPolicy.js.kt | 0 .../src/jsMain/kotlin/uuid/uuid.kt | 0 .../src/jsTest/kotlin/LocalDidMethodTestJs.kt | 0 .../id/walt/credentials/utils/UUID.jvm.kt | 0 .../policies/RevocationPolicy.jvm.kt | 0 .../src/jvmTest/kotlin/LocalDidMethodTest.kt | 0 .../waltid-crypto-android/README.md | 0 .../waltid-crypto-android/build.gradle.kts | 2 +- .../id/walt/crypto/keys/AndroidKeyTest.kt | 0 .../kotlin/id/walt/crypto/keys/AndroidKey.kt | 0 .../id/walt/crypto/keys/AndroidKeyCreator.kt | 0 .../walt/crypto/keys/AndroidKeyGenerator.kt | 0 .../kotlin/id/walt/crypto/keys/KeyAlias.kt | 0 .../id/walt/crypto/keys/jwk/AndroidJWKKey.kt | 0 .../{ => crypto}/waltid-crypto-ios/README.md | 0 .../waltid-crypto-ios/build.gradle.kts | 6 +- .../iosMain/kotlin/id/walt/crypto/IosKey.kt | 0 .../src/iosTest/kotlin/TestClass.kt | 0 .../waltid-crypto-ios.podspec | 0 .../waltid_crypto_ios.podspec | 0 .../{ => crypto}/waltid-crypto-oci/README.md | 0 .../waltid-crypto-oci/build.gradle.kts | 4 +- .../kotlin/id/walt/crypto/keys/oci/OCIKey.kt | 0 .../id/walt/crypto/keys/oci/OCIKeyMetadata.kt | 0 .../id/walt/crypto/keys/oci/OCIsdkMetadata.kt | 0 .../id/walt/crypto/keys/oci/WaltCryptoOci.kt | 0 .../id/walt/crypto/keys/oci/OCIKey.jvm.kt | 0 .../id/walt/crypto/keys/oci/OCIsdkMetadata.kt | 0 .../src/jvmTest/kotlin/OCIKeyTest.kt | 0 .../src/jvmTest/kotlin/OCISdkKeyTest.kt | 0 .../resources/jwk/ed25519.private.json | 0 .../jvmTest/resources/jwk/ed25519.public.json | 0 .../jvmTest/resources/jwk/rsa.private.json | 0 .../src/jvmTest/resources/jwk/rsa.public.json | 0 .../resources/jwk/secp256k1.private.json | 0 .../resources/jwk/secp256k1.public.json | 0 .../resources/jwk/secp256r1.private.json | 0 .../resources/jwk/secp256r1.public.json | 0 .../public-bytes/ed25519-vault.base64 | 0 .../resources/public-bytes/ed25519.bin | 0 .../jvmTest/resources/public-bytes/rsa.bin | Bin .../resources/public-bytes/secp256k1.bin | Bin .../resources/public-bytes/secp256r1.bin | Bin .../serialized/local/ed25519.private.json | 0 .../serialized/local/ed25519.public.json | 0 .../serialized/local/rsa.private.json | 0 .../serialized/local/rsa.public.json | 0 .../serialized/local/secp256k1.private.json | 0 .../serialized/local/secp256k1.public.json | 0 .../serialized/local/secp256r1.private.json | 0 .../serialized/local/secp256r1.public.json | 0 .../serialized/tse/ed25519.private.json | 0 .../serialized/tse/ed25519.public.json | 0 .../jvmTest/resources/signatures/ed25519.txt | 0 .../src/jvmTest/resources/signatures/rsa.txt | 0 .../resources/signatures/secp256k1.txt | 0 .../resources/signatures/secp256r1.txt | 0 .../{ => crypto}/waltid-crypto/README.md | 0 .../waltid-crypto/build.gradle.kts | 0 .../kotlin/id/walt/crypto/keys/EccUtils.kt | 0 .../kotlin/id/walt/crypto/keys/Key.kt | 0 .../kotlin/id/walt/crypto/keys/KeyCreator.kt | 0 .../walt/crypto/keys/KeyGenerationRequest.kt | 0 .../kotlin/id/walt/crypto/keys/KeyManager.kt | 0 .../kotlin/id/walt/crypto/keys/KeyMeta.kt | 0 .../id/walt/crypto/keys/KeySerialization.kt | 0 .../kotlin/id/walt/crypto/keys/KeyType.kt | 0 .../kotlin/id/walt/crypto/keys/jwk/JWKKey.kt | 0 .../id/walt/crypto/keys/jwk/JWKKeyCreator.kt | 0 .../id/walt/crypto/keys/oci/OCIKeyMetadata.kt | 0 .../id/walt/crypto/keys/oci/OCIKeyRestApi.kt | 0 .../kotlin/id/walt/crypto/keys/tse/TSEAuth.kt | 0 .../kotlin/id/walt/crypto/keys/tse/TSEKey.kt | 0 .../id/walt/crypto/keys/tse/TSEKeyCreator.kt | 0 .../id/walt/crypto/keys/tse/TSEKeyMetadata.kt | 0 .../id/walt/crypto/utils/Base58Utils.kt | 0 .../id/walt/crypto/utils/Base64Utils.kt | 0 .../kotlin/id/walt/crypto/utils/CryptoUtil.kt | 0 .../crypto/utils/JsonCanonicalizationUtils.kt | 0 .../kotlin/id/walt/crypto/utils/JsonUtils.kt | 0 .../kotlin/id/walt/crypto/utils/JweUtils.kt | 0 .../kotlin/id/walt/crypto/utils/JwsUtils.kt | 4 +- .../id/walt/crypto/utils/MultiBaseUtils.kt | 0 .../id/walt/crypto/utils/MultiCodecUtils.kt | 0 .../resources/simplelogger.properties | 0 .../src/commonTest/kotlin/TSEKeyTest.kt | 0 .../src/commonTest/kotlin/TseAuthTest.kt | 0 .../id/walt/crypto/keys/jwk/JWKKey.ios.kt | 0 .../id/walt/crypto/utils/CryptoUtil.ios.kt | 0 .../id/walt/crypto/utils/JweUtils.ios.kt | 0 .../src/jsMain/kotlin/crypto/crypto.kt | 0 .../id/walt/crypto/keys/JWKKeyGenerator.js.kt | 0 .../id/walt/crypto/keys/jwk/JWKKey.js.kt | 0 .../kotlin/id/walt/crypto/utils/ArrayUtils.kt | 0 .../id/walt/crypto/utils/CryptoUtil.js.kt | 0 .../id/walt/crypto/utils/JweUtils.js.kt | 0 .../id/walt/crypto/utils/PromiseUtils.kt | 0 .../kotlin/jose/decode_jwt.module_jose.kt | 0 .../decode_protected_header.module_jose.kt | 0 .../jsMain/kotlin/jose/decrypt.module_jose.kt | 0 .../kotlin/jose/embedded.module_jose.kt | 0 .../jsMain/kotlin/jose/encrypt.module_jose.kt | 0 .../jose/generate_secret.module_jose.kt | 0 .../src/jsMain/kotlin/jose/jose.kt | 0 .../jsMain/kotlin/jose/lib.es2015.iterable.kt | 0 .../kotlin/jose/lib.es5.Intl.module_dukat.kt | 0 .../src/jsMain/kotlin/jose/lib.es5.kt | 0 .../src/jsMain/kotlin/jose/lib.scripthost.kt | 0 .../jsMain/kotlin/jose/local.module_jose.kt | 0 .../jsMain/kotlin/jose/produce.module_jose.kt | 0 .../jsMain/kotlin/jose/remote.module_jose.kt | 0 .../jsMain/kotlin/jose/sign.module_jose.kt | 0 .../jsMain/kotlin/jose/types.module_jose.kt | 0 .../src/jsMain/kotlin/multibase/multibase.kt | 0 .../src/jsTest/kotlin/ImportTestsJs.kt | 0 .../kotlin/JWKKeyAndDidManagementTest.kt | 0 .../src/jsTest/kotlin/KeySignTests.kt | 0 .../waltid-crypto/src/jsTest/kotlin/TestJs.kt | 0 .../id/walt/crypto/keys/EccUtils.jvm.kt | 0 .../walt/crypto/keys/JWKKeyGenerator.jvm.kt | 0 .../kotlin/id/walt/crypto/keys/JavaKey.kt | 0 .../id/walt/crypto/keys/jwk/JWKKey.jvm.kt | 0 .../id/walt/crypto/utils/CryptoUtil.jvm.kt | 0 .../id/walt/crypto/utils/JvmEccUtils.kt | 0 .../id/walt/crypto/utils/JweUtils.jvm.kt | 0 .../id/walt/crypto/utils/MultiBaseUtils.kt | 0 .../jvmMain/resources/simplelogger.properties | 0 .../ExportJWKKeyTestsAndDidManagement.kt | 0 .../ImportJWKKeyTestsAndDidManagement.kt | 0 .../kotlin/JWKKeyAndDidManagementTest.kt | 0 .../jvmTest/kotlin/KeySerializationTests.kt | 0 .../src/jvmTest/kotlin/KeySignTests.kt | 0 .../kotlin/LocalJWKKeyAndDidManagementTest.kt | 0 .../src/jvmTest/kotlin/OCIKeyTest.kt | 0 .../src/jvmTest/kotlin/OCISdkKeyTest.kt | 0 .../src/jvmTest/kotlin/TestJvm.kt | 0 .../src/jvmTest/kotlin/TestUtils.kt | 0 .../resources/jwk/ed25519.private.json | 0 .../jvmTest/resources/jwk/ed25519.public.json | 0 .../jvmTest/resources/jwk/rsa.private.json | 0 .../src/jvmTest/resources/jwk/rsa.public.json | 0 .../resources/jwk/secp256k1.private.json | 0 .../resources/jwk/secp256k1.public.json | 0 .../resources/jwk/secp256r1.private.json | 0 .../resources/jwk/secp256r1.public.json | 0 .../public-bytes/ed25519-vault.base64 | 0 .../resources/public-bytes/ed25519.bin | 0 .../jvmTest/resources/public-bytes/rsa.bin | Bin .../resources/public-bytes/secp256k1.bin | Bin .../resources/public-bytes/secp256r1.bin | Bin .../serialized/local/ed25519.private.json | 0 .../serialized/local/ed25519.public.json | 0 .../serialized/local/rsa.private.json | 0 .../serialized/local/rsa.public.json | 0 .../serialized/local/secp256k1.private.json | 0 .../serialized/local/secp256k1.public.json | 0 .../serialized/local/secp256r1.private.json | 0 .../serialized/local/secp256r1.public.json | 0 .../serialized/tse/ed25519.private.json | 0 .../serialized/tse/ed25519.public.json | 0 .../jvmTest/resources/signatures/ed25519.txt | 0 .../src/jvmTest/resources/signatures/rsa.txt | 0 .../resources/signatures/secp256k1.txt | 0 .../resources/signatures/secp256r1.txt | 0 .../{ => crypto}/waltid-target-ios/README.md | 0 .../waltid-target-ios/build.gradle.kts | 0 .../waltid-target-ios/implementation/Podfile | 0 .../implementation/Podfile.lock | 0 .../implementation/build.gradle.kts | 0 .../project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../waltid.crypto.ios.utils/CryptoUtils.swift | 0 .../waltid.crypto.ios.utils-Bridging-Header.h | 0 .../waltid_crypto_ios_utils.h | 0 .../waltid_crypto_ios_utils.m | 0 .../id/walt/target/ios/keys/CFKeychain.kt | 0 .../id/walt/target/ios/keys/CFRetain.kt | 0 .../kotlin/id/walt/target/ios/keys/Ed25519.kt | 0 .../id/walt/target/ios/keys/Foundation.kt | 0 .../walt/target/ios/keys/KeyCapabilities.kt | 0 .../target/ios/keys/KeychainOperations.kt | 0 .../kotlin/id/walt/target/ios/keys/P256.kt | 0 .../kotlin/id/walt/target/ios/keys/RSA.kt | 0 .../nativeInterop/cinterop/implementation.def | 0 .../waltid-target-ios.podspec | 0 .../waltid-openid4vc/OpenID4VP.seq | 0 .../waltid-openid4vc/README.md | 0 .../waltid-openid4vc/architecture.png | Bin .../waltid-openid4vc/build.gradle.kts | 10 +- .../waltid-openid4vc/oid4vci.seq | 0 .../waltid-openid4vc/oid4vp.seq | 0 .../waltid-openid4vc/openid4vp.png | Bin .../kotlin/id/walt/oid4vc/OpenID4VCI.kt | 0 .../kotlin/id/walt/oid4vc/OpenID4VP.kt | 0 .../kotlin/id/walt/oid4vc/Values.kt | 0 .../id/walt/oid4vc/data/AccessTokenScope.kt | 0 .../walt/oid4vc/data/AuthorizationDetails.kt | 0 .../id/walt/oid4vc/data/ClaimDescriptor.kt | 0 .../id/walt/oid4vc/data/ClientIdScheme.kt | 0 .../oid4vc/data/ClientMetadataParameter.kt | 0 .../id/walt/oid4vc/data/CredentialFormat.kt | 0 .../id/walt/oid4vc/data/CredentialOffer.kt | 0 .../walt/oid4vc/data/CredentialSupported.kt | 0 .../id/walt/oid4vc/data/DisplayProperties.kt | 0 .../data/DurationInSecondsSerializer.kt | 0 .../id/walt/oid4vc/data/GrantDetails.kt | 0 .../kotlin/id/walt/oid4vc/data/GrantType.kt | 0 .../id/walt/oid4vc/data/HTTPDataObject.kt | 0 .../id/walt/oid4vc/data/JsonDataObject.kt | 0 .../oid4vc/data/JsonLDCredentialDefinition.kt | 0 .../id/walt/oid4vc/data/LogoProperties.kt | 0 .../id/walt/oid4vc/data/OfferedCredential.kt | 0 .../walt/oid4vc/data/OpenIDClientMetadata.kt | 0 .../oid4vc/data/OpenIDProviderMetadata.kt | 0 .../id/walt/oid4vc/data/OpenId4VPProfile.kt | 0 .../data/PresentationDefinitionParameter.kt | 0 .../id/walt/oid4vc/data/ProofOfPossession.kt | 0 .../id/walt/oid4vc/data/ResponseMode.kt | 0 .../id/walt/oid4vc/data/ResponseType.kt | 0 .../kotlin/id/walt/oid4vc/data/SubjectType.kt | 0 .../id/walt/oid4vc/data/SupportedVPFormat.kt | 0 .../kotlin/id/walt/oid4vc/data/TxCode.kt | 0 .../id/walt/oid4vc/data/VpTokenParameter.kt | 0 .../walt/oid4vc/data/dif/DescriptorMapping.kt | 0 .../oid4vc/data/dif/DisclosureLimitation.kt | 0 .../walt/oid4vc/data/dif/InputDescriptor.kt | 0 .../data/dif/InputDescriptorConstraints.kt | 0 .../oid4vc/data/dif/InputDescriptorField.kt | 0 .../oid4vc/data/dif/InputDescriptorSchema.kt | 0 .../walt/oid4vc/data/dif/OutputDescriptor.kt | 0 .../oid4vc/data/dif/PresentationDefinition.kt | 0 .../oid4vc/data/dif/PresentationSubmission.kt | 0 .../oid4vc/data/dif/SubmissionRequirement.kt | 0 .../data/dif/SubmissionRequirementRule.kt | 0 .../id/walt/oid4vc/data/dif/VCFormat.kt | 0 .../id/walt/oid4vc/definitions/JWTClaims.kt | 0 .../oid4vc/definitions/OIDCDefinitions.kt | 0 .../walt/oid4vc/errors/AuthorizationError.kt | 0 .../id/walt/oid4vc/errors/CredentialError.kt | 0 .../oid4vc/errors/CredentialOfferError.kt | 0 .../walt/oid4vc/errors/PresentationError.kt | 0 .../id/walt/oid4vc/errors/TokenError.kt | 0 .../oid4vc/interfaces/ICredentialProvider.kt | 0 .../id/walt/oid4vc/interfaces/IHttpClient.kt | 0 .../walt/oid4vc/interfaces/ISessionCache.kt | 0 .../walt/oid4vc/interfaces/ITokenProvider.kt | 0 .../oid4vc/interfaces/IVPTokenProvider.kt | 0 .../oid4vc/providers/AuthorizationSession.kt | 0 .../providers/CredentialIssuerConfig.kt | 0 .../providers/CredentialVerifierConfig.kt | 0 .../providers/CredentialWalletConfig.kt | 0 .../walt/oid4vc/providers/IssuanceSession.kt | 0 .../oid4vc/providers/OpenIDClientConfig.kt | 0 .../providers/OpenIDCredentialIssuer.kt | 0 .../providers/OpenIDCredentialVerifier.kt | 0 .../providers/OpenIDCredentialWallet.kt | 0 .../walt/oid4vc/providers/OpenIDProvider.kt | 0 .../oid4vc/providers/OpenIDProviderConfig.kt | 0 .../oid4vc/providers/PresentationSession.kt | 0 .../id/walt/oid4vc/providers/SIOPSession.kt | 0 .../id/walt/oid4vc/providers/TokenTarget.kt | 0 .../requests/AuthorizationJSONRequest.kt | 0 .../oid4vc/requests/AuthorizationRequest.kt | 0 .../oid4vc/requests/BatchCredentialRequest.kt | 0 .../oid4vc/requests/CredentialOfferRequest.kt | 0 .../walt/oid4vc/requests/CredentialRequest.kt | 0 .../oid4vc/requests/EntraIssuanceRequest.kt | 0 .../id/walt/oid4vc/requests/TokenRequest.kt | 0 ...AuthorizationCodeIDTokenRequestResponse.kt | 0 .../responses/AuthorizationCodeResponse.kt | 0 .../AuthorizationDirectPostResponse.kt | 0 .../responses/BatchCredentialResponse.kt | 0 .../oid4vc/responses/CredentialResponse.kt | 0 .../EntraIssuanceCompletionResponse.kt | 0 .../responses/PushedAuthorizationResponse.kt | 0 .../id/walt/oid4vc/responses/TokenResponse.kt | 0 .../kotlin/id/walt/oid4vc/util/HttpUtils.kt | 0 .../kotlin/id/walt/oid4vc/util/JwtUtils.kt | 0 .../id/walt/oid4vc/util/ShortIdUtils.kt | 0 .../kotlin/id/walt/oid4vc/util/Sqids.kt | 0 .../kotlin/id/walt/oid4vc/util/UuidUtils.kt | 0 .../kotlin/id/walt/oid4vc/CITestProvider.kt | 0 .../kotlin/id/walt/oid4vc/CI_JVM_Test.kt | 0 .../kotlin/id/walt/oid4vc/EBSITestWallet.kt | 0 .../id/walt/oid4vc/EBSI_Conformance_Test.kt | 0 .../id/walt/oid4vc/EBSI_Issue_To_Holder.kt | 0 .../kotlin/id/walt/oid4vc/MDoc_Test.kt | 0 .../id/walt/oid4vc/SessionIdUtilTest.kt | 0 .../id/walt/oid4vc/TestCredentialWallet.kt | 0 .../kotlin/id/walt/oid4vc/VPTestVerifier.kt | 0 .../kotlin/id/walt/oid4vc/VP_JVM_Test.kt | 0 .../kotlin/id/walt/oid4vc/wallettest.kt | 0 .../waltid-openid4vc/waltid_openid4vc.podspec | 0 .../waltid-sdjwt-ios/build.gradle.kts | 4 +- .../DigitalSignaturesJWTCryptoProvider.kt | 0 .../id/walt/sdjwt/HMACJWTCryptoProvider.kt | 0 .../src/iosTest/kotlin/SDJwtTestIOS.kt | 0 .../{ => sdjwt}/waltid-sdjwt/.gitignore | 0 .../{ => sdjwt}/waltid-sdjwt/LICENSE | 0 .../{ => sdjwt}/waltid-sdjwt/README.md | 0 .../{ => sdjwt}/waltid-sdjwt/build.gradle.kts | 0 .../waltid-sdjwt/examples/js/index.js | 0 .../waltid-sdjwt/examples/js/package.json | 0 .../{ => sdjwt}/waltid-sdjwt/gradlew | 0 .../{ => sdjwt}/waltid-sdjwt/gradlew.bat | 0 .../src/commonMain/kotlin/id/walt/Values.kt | 0 .../id/walt/sdjwt/AsyncJWTCryptoProvider.kt | 0 .../kotlin/id/walt/sdjwt/DecoyMode.kt | 0 .../kotlin/id/walt/sdjwt/JWTClaimsSet.kt | 0 .../kotlin/id/walt/sdjwt/JWTCryptoProvider.kt | 0 .../kotlin/id/walt/sdjwt/SDField.kt | 0 .../commonMain/kotlin/id/walt/sdjwt/SDJwt.kt | 0 .../commonMain/kotlin/id/walt/sdjwt/SDMap.kt | 0 .../kotlin/id/walt/sdjwt/SDMapBuilder.kt | 0 .../kotlin/id/walt/sdjwt/SDPayload.kt | 0 .../kotlin/id/walt/sdjwt/SDisclosure.kt | 0 .../kotlin/id/walt/sdjwt/SdjwtStringUtils.kt | 0 .../id/walt/sdjwt/VerificationResult.kt | 0 .../kotlin/id/walt/sdjwt/SDJwtTest.kt | 0 .../kotlin/id/walt/sdjwt/JWTClaimsSet.kt | 0 .../id/walt/sdjwt/JSAsyncJWTCryptoProvider.kt | 0 .../kotlin/id/walt/sdjwt/JWTClaimsSet.kt | 0 .../jsMain/kotlin/id/walt/sdjwt/SDJwtJS.kt | 0 .../kotlin/id/walt/sdjwt/SDMapBuilderJS.kt | 0 .../kotlin/id/walt/sdjwt/SDPayloadBuilder.kt | 0 .../sdjwt/SimpleAsyncJWTCryptoProvider.kt | 0 .../src/jsMain/kotlin/id/walt/sdjwt/jose.kt | 0 .../kotlin/id.walt.sdjwt/SDJwtTestJS.kt | 0 .../kotlin/id/walt/sdjwt/JWTClaimsSet.kt | 0 .../id/walt/sdjwt/SimpleJWTCryptoProvider.kt | 0 .../kotlin/id/walt/sdjwt/SDJwtTestJVM.kt | 0 .../kotlin/id/walt/sdjwt/JWTClaimsSet.kt | 0 .../waltid-sdjwt/waltid_sdjwt.podspec | 0 .../waltid-reporting/build.gradle.kts | 0 .../id/walt/reporting/ReportingClient.kt | 0 .../kotlin/id/walt/reporting/models/Events.kt | 0 .../kotlin/id/walt/reporting/models/Stats.kt | 0 .../resources/pem/ecdsa-vault.public.pem | 3 - .../jvmTest/resources/pem/ed25519.private.pem | 6 - .../jvmTest/resources/pem/ed25519.public.pem | 3 - .../resources/pem/rsa-vault.public.pem | 3 - .../src/jvmTest/resources/pem/rsa.private.pem | 27 -- .../src/jvmTest/resources/pem/rsa.public.pem | 9 - .../resources/pem/secp256k1.private.pem | 8 - .../resources/pem/secp256k1.public.pem | 4 - .../resources/pem/secp256r1.private.pem | 10 - .../resources/pem/secp256r1.public.pem | 4 - .../resources/pem/ecdsa-vault.public.pem | 3 - .../jvmTest/resources/pem/ed25519.private.pem | 6 - .../jvmTest/resources/pem/ed25519.public.pem | 3 - .../resources/pem/rsa-vault.public.pem | 3 - .../src/jvmTest/resources/pem/rsa.private.pem | 27 -- .../src/jvmTest/resources/pem/rsa.public.pem | 9 - .../resources/pem/secp256k1.private.pem | 8 - .../resources/pem/secp256k1.public.pem | 4 - .../resources/pem/secp256r1.private.pem | 10 - .../resources/pem/secp256r1.public.pem | 4 - waltid-libraries/waltid-did/build.gradle.kts | 2 +- .../waltid-issuer-api/build.gradle.kts | 8 +- .../waltid-verifier-api/build.gradle.kts | 8 +- .../waltid-wallet-api/build.gradle.kts | 9 +- 512 files changed, 808 insertions(+), 251 deletions(-) rename waltid-libraries/{ => auth}/waltid-authkit/.gitignore (100%) rename waltid-libraries/{ => auth}/waltid-authkit/build.gradle.kts (81%) create mode 100644 waltid-libraries/auth/waltid-authkit/docs/base.md rename waltid-libraries/{waltid-authkit/docs/base.md => auth/waltid-authkit/docs/methods/1_userpass.md} (100%) rename waltid-libraries/{ => auth}/waltid-authkit/gradle.properties (100%) rename waltid-libraries/{ => auth}/waltid-authkit/gradle/wrapper/gradle-wrapper.jar (100%) rename waltid-libraries/{ => auth}/waltid-authkit/gradle/wrapper/gradle-wrapper.properties (100%) rename waltid-libraries/{ => auth}/waltid-authkit/gradlew (100%) rename waltid-libraries/{ => auth}/waltid-authkit/gradlew.bat (100%) rename waltid-libraries/{ => auth}/waltid-authkit/settings.gradle.kts (100%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/Application.kt (100%) create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/accounts/Account.kt rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt (100%) create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/EmailPass.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/Kerberos.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP2.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/RADIUS.kt rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt (100%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt (100%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt (100%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt (100%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt (95%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt (100%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt (69%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt (100%) rename waltid-libraries/{ => auth}/waltid-authkit/src/main/resources/logback.xml (100%) rename waltid-libraries/{ => auth}/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt (75%) create mode 100644 waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt create mode 100644 waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Verifier.kt rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/.gitignore (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/CODE_OF_CONDUCT.md (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/CONTRIBUTING.md (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/LICENSE (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/README.md (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/build.gradle.kts (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/cert.der (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/examples/js/SimpleCOSECryptoProvider.js (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/examples/js/index.js (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/examples/js/package-lock.json (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/examples/js/package.json (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/gradlew (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/gradlew.bat (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/ByteString.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/Cbor.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/ByteArrayInput.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/CborDecodingException.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/SharedHelpers.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/Values.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/decoding/CborDecoder.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/encoding/CborEncoder.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/Values.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/AsyncCOSECryptoProvider.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSECryptoProvider.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEMac0.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESign1.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESimpleBase.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEValues.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElement.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementConversion.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementSerializer.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/MapKey.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceRequest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponseStatus.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceAuth.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceSigned.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDoc.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocBuilder.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocVerificationParams.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/VerificationType.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/ItemsRequest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestBuilder.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestVerificationParams.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSigned.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSignedItem.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mdocauth/DeviceAuthentication.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DeviceKeyInfo.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DigestAlgorithm.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/MSO.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/ValidityInfo.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/readerauth/ReaderAuthentication.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/commonTest/kotlin/id/walt/mdoc/MDocTest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/JSAsyncCOSECryptoProvider.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/SimpleAsyncCOSECryptoProvider.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/jsTest/kotlin/id/walt/mdoc/JSTest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/COSECryptoProviderKeyInfo.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/SimpleCOSECryptoProvider.kt (100%) rename waltid-libraries/{ => credentials}/waltid-mdoc-credentials/src/jvmTest/kotlin/id/walt/mdoc/JVMMdocTest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/README.md (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/build.gradle.kts (98%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/Claims.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/CredentialBuilder.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/PresentationBuilder.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/DataFunctions.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/Issuer.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/JwsSignatureScheme.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/SignatureScheme.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/EnumUtils.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/ExtensionMethods.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/JsonCanonicalization.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CDataMergeUtils.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CVcUtils.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/randomUUID.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/Credential.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/CredentialDataModel.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/MdocsVC.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CBaseDataModels.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CMetadata.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV11DataModel.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV2DataModel.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CVC.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialDataValidatorPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialWrapperValidatorPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Exceptions.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/JwtVerificationPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/PolicyManager.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/VerificationPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Verifier.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyRequest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyResult.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationResultEntry.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationVerificationResponse.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/AllowedIssuerPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JsonSchemaPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JwtSignaturePolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/WebhookPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/HolderBindingPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MaximumCredentialsPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MinimumCredentialsPolicy.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonTest/kotlin/DataBuilderTest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonTest/kotlin/LocalVcAPITest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationBuilderTest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationVerificationTest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/commonTest/kotlin/VcApiTest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/utils/randomUUID.ios.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.ios.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/CredentialBuilderUtils.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/PresentationVerificationUtils.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.js.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jsMain/kotlin/uuid/uuid.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jsTest/kotlin/LocalDidMethodTestJs.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.jvm.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jvmTest/kotlin/LocalDidMethodTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-android/README.md (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-android/build.gradle.kts (98%) rename waltid-libraries/{ => crypto}/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyCreator.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyGenerator.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/KeyAlias.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/jwk/AndroidJWKKey.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-ios/README.md (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-ios/build.gradle.kts (88%) rename waltid-libraries/{ => crypto}/waltid-crypto-ios/src/iosMain/kotlin/id/walt/crypto/IosKey.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-ios/src/iosTest/kotlin/TestClass.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-ios/waltid-crypto-ios.podspec (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-ios/waltid_crypto_ios.podspec (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/README.md (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/build.gradle.kts (97%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKey.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/WaltCryptoOci.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/kotlin/OCIKeyTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/kotlin/OCISdkKeyTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519-vault.base64 (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519.bin (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/public-bytes/rsa.bin (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256k1.bin (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256r1.bin (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/signatures/ed25519.txt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/signatures/rsa.txt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256k1.txt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256r1.txt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/README.md (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/build.gradle.kts (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/EccUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/Key.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyCreator.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyGenerationRequest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyManager.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyMeta.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeySerialization.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyType.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKeyCreator.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEAuth.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyCreator.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyMetadata.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base58Utils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/CryptoUtil.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonCanonicalizationUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JweUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt (94%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiCodecUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonMain/resources/simplelogger.properties (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonTest/kotlin/TSEKeyTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/commonTest/kotlin/TseAuthTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.ios.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/CryptoUtil.ios.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/JweUtils.ios.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/crypto/crypto.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.js.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.js.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/ArrayUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/CryptoUtil.js.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/JweUtils.js.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/PromiseUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/decode_jwt.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/decode_protected_header.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/decrypt.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/embedded.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/encrypt.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/generate_secret.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/lib.es2015.iterable.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.Intl.module_dukat.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/lib.scripthost.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/local.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/produce.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/remote.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/sign.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/jose/types.module_jose.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsMain/kotlin/multibase/multibase.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsTest/kotlin/ImportTestsJs.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsTest/kotlin/JWKKeyAndDidManagementTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsTest/kotlin/KeySignTests.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jsTest/kotlin/TestJs.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/EccUtils.jvm.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.jvm.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JavaKey.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/CryptoUtil.jvm.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JvmEccUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JweUtils.jvm.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmMain/resources/simplelogger.properties (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/ExportJWKKeyTestsAndDidManagement.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/ImportJWKKeyTestsAndDidManagement.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/JWKKeyAndDidManagementTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/KeySerializationTests.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/LocalJWKKeyAndDidManagementTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/OCIKeyTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/OCISdkKeyTest.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/TestJvm.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/kotlin/TestUtils.kt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/jwk/ed25519.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/jwk/ed25519.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/jwk/rsa.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/jwk/rsa.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519-vault.base64 (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519.bin (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/public-bytes/rsa.bin (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/public-bytes/secp256k1.bin (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/public-bytes/secp256r1.bin (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.private.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.public.json (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/signatures/ed25519.txt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/signatures/rsa.txt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/signatures/secp256k1.txt (100%) rename waltid-libraries/{ => crypto}/waltid-crypto/src/jvmTest/resources/signatures/secp256r1.txt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/README.md (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/build.gradle.kts (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/Podfile (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/Podfile.lock (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/build.gradle.kts (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.pbxproj (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/contents.xcworkspacedata (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils/CryptoUtils.swift (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid.crypto.ios.utils-Bridging-Header.h (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.h (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.m (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFKeychain.kt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFRetain.kt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Foundation.kt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeyCapabilities.kt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeychainOperations.kt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/P256.kt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/RSA.kt (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/src/nativeInterop/cinterop/implementation.def (100%) rename waltid-libraries/{ => crypto}/waltid-target-ios/waltid-target-ios.podspec (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/OpenID4VP.seq (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/README.md (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/architecture.png (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/build.gradle.kts (95%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/oid4vci.seq (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/oid4vp.seq (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/openid4vp.png (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VP.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/Values.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AccessTokenScope.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AuthorizationDetails.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClaimDescriptor.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientIdScheme.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientMetadataParameter.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialFormat.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialOffer.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialSupported.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DisplayProperties.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DurationInSecondsSerializer.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantDetails.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantType.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/HTTPDataObject.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonDataObject.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonLDCredentialDefinition.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/LogoProperties.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OfferedCredential.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDClientMetadata.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDProviderMetadata.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenId4VPProfile.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/PresentationDefinitionParameter.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ProofOfPossession.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseMode.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseType.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SubjectType.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SupportedVPFormat.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/TxCode.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/VpTokenParameter.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DescriptorMapping.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DisclosureLimitation.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptor.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorConstraints.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorField.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorSchema.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/OutputDescriptor.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationDefinition.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationSubmission.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirement.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirementRule.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/VCFormat.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/JWTClaims.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/OIDCDefinitions.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/AuthorizationError.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialError.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialOfferError.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/PresentationError.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/TokenError.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ICredentialProvider.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IHttpClient.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ISessionCache.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IVPTokenProvider.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/AuthorizationSession.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialIssuerConfig.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialVerifierConfig.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialWalletConfig.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/IssuanceSession.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDClientConfig.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialIssuer.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialVerifier.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialWallet.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProvider.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProviderConfig.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/PresentationSession.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/SIOPSession.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/TokenTarget.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationJSONRequest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationRequest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/BatchCredentialRequest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialOfferRequest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialRequest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/EntraIssuanceRequest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/TokenRequest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeIDTokenRequestResponse.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeResponse.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationDirectPostResponse.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/BatchCredentialResponse.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/CredentialResponse.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/EntraIssuanceCompletionResponse.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/PushedAuthorizationResponse.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/TokenResponse.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/HttpUtils.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/ShortIdUtils.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/Sqids.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/UuidUtils.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CITestProvider.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CI_JVM_Test.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSITestWallet.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Conformance_Test.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Issue_To_Holder.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/MDoc_Test.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/SessionIdUtilTest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/TestCredentialWallet.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VPTestVerifier.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VP_JVM_Test.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/wallettest.kt (100%) rename waltid-libraries/{ => protocols}/waltid-openid4vc/waltid_openid4vc.podspec (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt-ios/build.gradle.kts (95%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/DigitalSignaturesJWTCryptoProvider.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/HMACJWTCryptoProvider.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt-ios/src/iosTest/kotlin/SDJwtTestIOS.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/.gitignore (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/LICENSE (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/README.md (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/build.gradle.kts (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/examples/js/index.js (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/examples/js/package.json (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/gradlew (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/gradlew.bat (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/Values.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/AsyncJWTCryptoProvider.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/DecoyMode.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTCryptoProvider.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDField.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMap.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMapBuilder.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/VerificationResult.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/commonTest/kotlin/id/walt/sdjwt/SDJwtTest.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/iosMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JSAsyncJWTCryptoProvider.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDJwtJS.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDMapBuilderJS.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDPayloadBuilder.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SimpleAsyncJWTCryptoProvider.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/jose.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jsTest/kotlin/id.walt.sdjwt/SDJwtTestJS.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/SimpleJWTCryptoProvider.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/jvmTest/kotlin/id/walt/sdjwt/SDJwtTestJVM.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/src/nativeMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt (100%) rename waltid-libraries/{ => sdjwt}/waltid-sdjwt/waltid_sdjwt.podspec (100%) rename waltid-libraries/{ => util}/waltid-reporting/build.gradle.kts (100%) rename waltid-libraries/{ => util}/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/ReportingClient.kt (100%) rename waltid-libraries/{ => util}/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Events.kt (100%) rename waltid-libraries/{ => util}/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Stats.kt (100%) delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ecdsa-vault.public.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ed25519.private.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ed25519.public.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa-vault.public.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa.private.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa.public.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256k1.private.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256k1.public.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256r1.private.pem delete mode 100644 waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256r1.public.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ecdsa-vault.public.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ed25519.private.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ed25519.public.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa-vault.public.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa.private.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa.public.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256k1.private.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256k1.public.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256r1.private.pem delete mode 100644 waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256r1.public.pem diff --git a/settings.gradle.kts b/settings.gradle.kts index c44af08b5..7edb782f6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,6 +4,9 @@ fun getSetting(name: String) = providers.gradleProperty(name).orNull.toBoolean() val enableAndroidBuild = getSetting("enableAndroidBuild") val enableIosBuild = getSetting("enableIosBuild") +infix fun String.whenEnabled(setting: Boolean) = if (setting) this else null +fun String.group(vararg elements: String?) = elements.map { it?.let { "$this:$it" } }.toTypedArray() + // Build setup: // Shorthands @@ -11,22 +14,46 @@ val libraries = ":waltid-libraries" val applications = ":waltid-applications" val services = ":waltid-services" -val baseModules = listOf( - "$libraries:waltid-crypto", - "$libraries:waltid-did", - "$libraries:waltid-verifiable-credentials", - "$libraries:waltid-mdoc-credentials", - "$libraries:waltid-sdjwt", +val modules = listOf( + * "$libraries:crypto".group( + "waltid-crypto", + "waltid-crypto-oci", + "waltid-crypto-android" whenEnabled enableAndroidBuild, + "waltid-crypto-ios" whenEnabled enableIosBuild, + "waltid-target-ios" whenEnabled enableIosBuild, + "waltid-target-ios:implementation" whenEnabled enableIosBuild, + ), + + * "$libraries:credentials".group( + "waltid-verifiable-credentials", + "waltid-mdoc-credentials", + ), + + * "$libraries:auth".group( + "waltid-authkit", + "waltid-idpkit" + ), + + * "$libraries:protocols".group( + "waltid-openid4vc" + ), + + * "$libraries:sdjwt".group( + "waltid-sdjwt", + "waltid-sdjwt-ios" whenEnabled enableIosBuild, + ), + + /* + * "$libraries:util".group( + "waltid-reporting" + ), + */ - // Protocols - "$libraries:waltid-openid4vc", + "$libraries:waltid-did", // Service commons "$services:waltid-service-commons", - // Auth Kit for services - "$libraries:waltid-authkit", - // Services based on libs "$services:waltid-issuer-api", "$services:waltid-verifier-api", @@ -38,33 +65,13 @@ val baseModules = listOf( // CLI "$applications:waltid-cli", - // Reporting - "$libraries:waltid-reporting", - - // OCI extension for waltid-crypto - "$libraries:waltid-crypto-oci", -) - -val androidModules = listOf( - ":waltid-libraries:waltid-crypto-android", - ":waltid-applications:waltid-android" -) - -val iosModules = listOf( - "$libraries:waltid-crypto-ios", - "$libraries:waltid-sdjwt-ios", - "$libraries:waltid-target-ios", - "$libraries:waltid-target-ios:implementation", - "$applications:waltid-openid4vc-ios-testApp", - "$applications:waltid-openid4vc-ios-testApp:shared" -) - -val enabledModules = ArrayList(baseModules) + ":waltid-applications:waltid-android" whenEnabled enableAndroidBuild, -if (enableAndroidBuild) enabledModules.addAll(androidModules) -if (enableIosBuild) enabledModules.addAll(iosModules) + "$applications:waltid-openid4vc-ios-testApp" whenEnabled enableIosBuild, + "$applications:waltid-openid4vc-ios-testApp:shared" whenEnabled enableIosBuild +).filterNotNull() -include(*enabledModules.toTypedArray()) +include(*modules.toTypedArray()) pluginManagement { repositories { diff --git a/waltid-applications/waltid-android/build.gradle.kts b/waltid-applications/waltid-android/build.gradle.kts index 20e653645..915e786fa 100644 --- a/waltid-applications/waltid-android/build.gradle.kts +++ b/waltid-applications/waltid-android/build.gradle.kts @@ -55,8 +55,8 @@ dependencies { api(project(":waltid-libraries:waltid-crypto-android")) api(project(":waltid-libraries:waltid-did")) - api(project(":waltid-libraries:waltid-verifiable-credentials")) - api(project(":waltid-libraries:waltid-sdjwt")) + api(project(":waltid-libraries:credentials:waltid-verifiable-credentials")) + api(project(":waltid-libraries:sdjwt:waltid-sdjwt")) // JSON implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") diff --git a/waltid-applications/waltid-cli/build.gradle.kts b/waltid-applications/waltid-cli/build.gradle.kts index 2fab1bc48..eb211349a 100644 --- a/waltid-applications/waltid-cli/build.gradle.kts +++ b/waltid-applications/waltid-cli/build.gradle.kts @@ -58,11 +58,11 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - api(project(":waltid-libraries:waltid-crypto")) + api(project(":waltid-libraries:crypto:waltid-crypto")) api(project(":waltid-libraries:waltid-did")) - api(project(":waltid-libraries:waltid-verifiable-credentials")) - api(project(":waltid-libraries:waltid-sdjwt")) - api(project(":waltid-libraries:waltid-openid4vc")) + api(project(":waltid-libraries:credentials:waltid-verifiable-credentials")) + api(project(":waltid-libraries:sdjwt:waltid-sdjwt")) + api(project(":waltid-libraries:protocols:waltid-openid4vc")) implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0") diff --git a/waltid-applications/waltid-openid4vc-ios-testApp/shared/build.gradle.kts b/waltid-applications/waltid-openid4vc-ios-testApp/shared/build.gradle.kts index 626557f9c..ddb9ef673 100644 --- a/waltid-applications/waltid-openid4vc-ios-testApp/shared/build.gradle.kts +++ b/waltid-applications/waltid-openid4vc-ios-testApp/shared/build.gradle.kts @@ -24,10 +24,10 @@ kotlin { sourceSets { commonMain.dependencies { - implementation(project(":waltid-libraries:waltid-sdjwt")) + implementation(project(":waltid-libraries:sdjwt:waltid-sdjwt")) implementation(project(":waltid-libraries:waltid-did")) - implementation(project(":waltid-libraries:waltid-openid4vc")) - implementation(project(":waltid-libraries:waltid-verifiable-credentials")) + implementation(project(":waltid-libraries:protocols:waltid-openid4vc")) + implementation(project(":waltid-libraries:credentials:waltid-verifiable-credentials")) } commonTest.dependencies { @@ -46,4 +46,4 @@ kotlin { } } } -} \ No newline at end of file +} diff --git a/waltid-libraries/waltid-authkit/.gitignore b/waltid-libraries/auth/waltid-authkit/.gitignore similarity index 100% rename from waltid-libraries/waltid-authkit/.gitignore rename to waltid-libraries/auth/waltid-authkit/.gitignore diff --git a/waltid-libraries/waltid-authkit/build.gradle.kts b/waltid-libraries/auth/waltid-authkit/build.gradle.kts similarity index 81% rename from waltid-libraries/waltid-authkit/build.gradle.kts rename to waltid-libraries/auth/waltid-authkit/build.gradle.kts index c1a9efbbd..118323adc 100644 --- a/waltid-libraries/waltid-authkit/build.gradle.kts +++ b/waltid-libraries/auth/waltid-authkit/build.gradle.kts @@ -23,11 +23,22 @@ repositories { } dependencies { + // Auth methods + + // RADIUS + implementation("org.aaa4j.radius:aaa4j-radius-client:0.3.0") + + // LDAP + //implementation("org.apache.directory.server:apacheds-server-integ:2.0.0.AM27") + implementation("org.apache.directory.api:api-all:2.1.6") + + + // Ktor server implementation("io.ktor:ktor-server-core-jvm") implementation("io.ktor:ktor-server-auth-jvm") implementation("io.ktor:ktor-server-auth-jwt-jvm") - implementation("io.ktor:ktor-server-auth-ldap-jvm") + //implementation("io.ktor:ktor-server-auth-ldap-jvm") implementation("io.ktor:ktor-client-core-jvm") implementation("io.ktor:ktor-client-apache-jvm") implementation("io.ktor:ktor-server-sessions-jvm") @@ -48,8 +59,8 @@ dependencies { implementation("io.github.smiley4:ktor-swagger-ui:3.2.0") // Logging - implementation("io.klogging:klogging-jvm:0.6.1") - implementation("io.klogging:slf4j-klogging:0.6.0") + implementation("io.klogging:klogging-jvm:0.7.0") + implementation("io.klogging:slf4j-klogging:0.7.0") /* --- Testing --- */ diff --git a/waltid-libraries/auth/waltid-authkit/docs/base.md b/waltid-libraries/auth/waltid-authkit/docs/base.md new file mode 100644 index 000000000..b0dedd7ee --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/docs/base.md @@ -0,0 +1,17 @@ +# walt.id Auth Kit library + +## Model + +The walt.id Auth Kit provides a vast set of authentication mechanisms +that can be reused by a Ktor based service. +It provides all features necessary for authentication and +session management, while retaining flexibility for service implementations. + +In practice, this means that the Auth Kit works + +- as an abstraction layer around various + authentication mechanisms and protocols (e.g. Username/Email + Password, OAuth2/OIDC, SAML, LDAP, RADIUS, WebAuthn, TOTP) +- distributed session management +- MFA (multi-factor authentication, e.g. Email+Password and TOTP) +- distributed authentication storage +- stored authentication mutation (password reset, add WebAuthn device, etc.) diff --git a/waltid-libraries/waltid-authkit/docs/base.md b/waltid-libraries/auth/waltid-authkit/docs/methods/1_userpass.md similarity index 100% rename from waltid-libraries/waltid-authkit/docs/base.md rename to waltid-libraries/auth/waltid-authkit/docs/methods/1_userpass.md diff --git a/waltid-libraries/waltid-authkit/gradle.properties b/waltid-libraries/auth/waltid-authkit/gradle.properties similarity index 100% rename from waltid-libraries/waltid-authkit/gradle.properties rename to waltid-libraries/auth/waltid-authkit/gradle.properties diff --git a/waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.jar b/waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.jar rename to waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.jar diff --git a/waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.properties b/waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from waltid-libraries/waltid-authkit/gradle/wrapper/gradle-wrapper.properties rename to waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.properties diff --git a/waltid-libraries/waltid-authkit/gradlew b/waltid-libraries/auth/waltid-authkit/gradlew similarity index 100% rename from waltid-libraries/waltid-authkit/gradlew rename to waltid-libraries/auth/waltid-authkit/gradlew diff --git a/waltid-libraries/waltid-authkit/gradlew.bat b/waltid-libraries/auth/waltid-authkit/gradlew.bat similarity index 100% rename from waltid-libraries/waltid-authkit/gradlew.bat rename to waltid-libraries/auth/waltid-authkit/gradlew.bat diff --git a/waltid-libraries/waltid-authkit/settings.gradle.kts b/waltid-libraries/auth/waltid-authkit/settings.gradle.kts similarity index 100% rename from waltid-libraries/waltid-authkit/settings.gradle.kts rename to waltid-libraries/auth/waltid-authkit/settings.gradle.kts diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/Application.kt similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/Application.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/Application.kt diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/accounts/Account.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/accounts/Account.kt new file mode 100644 index 000000000..1b56b8b79 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/accounts/Account.kt @@ -0,0 +1,6 @@ +package id.walt.accounts + +import kotlin.uuid.Uuid + +@OptIn(ExperimentalStdlibApi::class) +data class Account(val id: Uuid) diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/EmailPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/EmailPass.kt new file mode 100644 index 000000000..0780c1a1f --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/EmailPass.kt @@ -0,0 +1,4 @@ +package id.walt.methods + +class EmailPass { +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/Kerberos.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/Kerberos.kt new file mode 100644 index 000000000..1b32def00 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/Kerberos.kt @@ -0,0 +1,56 @@ +package id.walt.methods + +/* +import org.ietf.jgss.* + +fun auth(kerberosRealm: String, kerberosKdc: String, servicePrincipal: String, username: String, password: String): Boolean { + System.setProperty("java.security.krb5.realm", kerberosRealm) + System.setProperty("java.security.krb5.kdc", kerberosKdc) + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false") + + val gssManager = GSSManager.getInstance() + val clientPrincipalName = "user@$kerberosRealm" + val clientPrincipal = GSSName.NT_USER_NAME.apply { + gssManager.createName(clientPrincipalName, this) + } + + val credentials = gssManager.createCredential( + clientPrincipal, + GSSCredential.DEFAULT_LIFETIME, + null, + GSSCredential.INITIATE_ONLY + ) + + val serverPrincipal = gssManager.createName(servicePrincipal, GSSName.NT_HOSTBASED_SERVICE) + + val context = gssManager.createContext( + serverPrincipal, + GSSUtil.GSS_KRB5_MECH_OID, + credentials, + GSSContext.DEFAULT_LIFETIME + ) + + return try { + context.requestMutualAuth(true) + context.requestConf(true) + context.requestInteg(true) + + val token = ByteArray(0) + val outToken = context.initSecContext(token, 0, token.size) + + // This is where you would send the outToken to the server and get a response token back + // For the purposes of this example, we'll assume the server accepted the token + context.isEstablished + } catch (e: GSSException) { + e.printStackTrace() + false + } finally { + context.dispose() + } +} + +// Example usage +fun main() { + val result = auth("EXAMPLE.COM", "kerberos.example.com", "HTTP/kerberos.example.com", "user1", "pass1") + println("Authentication result: $result") +}*/ diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP.kt new file mode 100644 index 000000000..3c362a686 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP.kt @@ -0,0 +1,124 @@ +package id.walt.methods + +import io.ktor.server.auth.* +import java.util.* +import javax.naming.* +import javax.naming.directory.* + +/** + * Provides the ability to authenticate an LDAP user. + * This function accepts a credential and validates it against a specified LDAP server. + * + * To learn more about LDAP authentication in Ktor, see [LDAP](https://ktor.io/docs/ldap.html). + */ +public fun ldapAuthenticate( + credential: K, + ldapServerURL: String, + ldapEnvironmentBuilder: (MutableMap) -> Unit = {}, + doVerify: InitialDirContext.(K) -> P? +): P? { + return try { + val root = ldapLogin(ldapServerURL, ldapEnvironmentBuilder) + try { + root.doVerify(credential) + } finally { + root.close() + } + } catch (ne: NamingException) { + null + } +} + +/** + * Provides the ability to authenticates an LDAP user. + * This function accepts [UserPasswordCredential] and validates it against a specified LDAP server. + * + * To learn more about LDAP authentication in Ktor, see [LDAP](https://ktor.io/docs/ldap.html). + */ +public fun

ldapAuthenticate( + credential: UserPasswordCredential, + ldapServerURL: String, + userDNFormat: String, + validate: InitialDirContext.(UserPasswordCredential) -> P? +): P? { + val configurator: (MutableMap) -> Unit = { env -> + env[Context.SECURITY_AUTHENTICATION] = "simple" + env[Context.SECURITY_PRINCIPAL] = userDNFormat.format(ldapEscape(credential.name)) + env[Context.SECURITY_CREDENTIALS] = credential.password + } + + return ldapAuthenticate(credential, ldapServerURL, configurator, validate) +} + +/** + * Provides the ability to authenticates an LDAP user. + * This function accepts [UserPasswordCredential] and validates it against a specified LDAP server. + * + * To learn more about LDAP authentication in Ktor, see [LDAP](https://ktor.io/docs/ldap.html). + */ +public fun ldapAuthenticate( + credential: UserPasswordCredential, + ldapServerURL: String, + userDNFormat: String +): UserIdPrincipal? { + return ldapAuthenticate(credential, ldapServerURL, userDNFormat) { UserIdPrincipal(it.name) } +} + +private fun ldapLogin(ldapURL: String, ldapEnvironmentBuilder: (MutableMap) -> Unit): InitialDirContext { + val env = Hashtable() + env[Context.INITIAL_CONTEXT_FACTORY] = "com.sun.jndi.ldap.LdapCtxFactory" + env[Context.PROVIDER_URL] = ldapURL + + ldapEnvironmentBuilder(env) + + return InitialDirContext(env) +} + +internal fun ldapEscape(string: String): String { + for (index in 0..string.lastIndex) { + val character = string[index] + if (character.shouldEscape()) { + return ldapEscapeImpl(string, index) + } + } + + return string +} + +private fun ldapEscapeImpl(string: String, firstIndex: Int): String = buildString { + var lastIndex = 0 + for (index in firstIndex..string.lastIndex) { + val character = string[index] + if (character.shouldEscape()) { + append(string, lastIndex, index) + if (character in ESCAPE_CHARACTERS) { + append('\\') + append(character) + } else { + character.toString().toByteArray().let { encoded -> + for (byteIndex in 0 until encoded.size) { + val unsignedValue = encoded[byteIndex].toInt() and 0xff + append('\\') + append(unsignedValue.toString(16).padStart(2, '0')) + } + } + } + + lastIndex = index + 1 + } + } + + append(string, lastIndex, string.length) +} + +private val ESCAPE_CHARACTERS = charArrayOf(' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\') + +private fun Char.shouldEscape(): Boolean = this.code.let { codepoint -> + when (codepoint) { + in 0x3f..0x7e -> codepoint == 0x5c // the only forbidden character is backslash + in 0x2d..0x3a -> false // minus, point, slash (allowed), digits + colon : + in 0x24..0x2a -> false // $%&'()* + 0x21 -> false // exclamation + else -> true + } +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP2.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP2.kt new file mode 100644 index 000000000..cda3a44da --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP2.kt @@ -0,0 +1,30 @@ +package id.walt.methods + +import org.apache.directory.api.ldap.model.exception.LdapException +import org.apache.directory.ldap.client.api.LdapConnection +import org.apache.directory.ldap.client.api.LdapNetworkConnection + +fun auth(ldapServerUrl: String, userDNFormat: String, username: String, password: String): Boolean { + val (hostname, port) = ldapServerUrl.removePrefix("ldap://").split(":") + val userDN = userDNFormat.format(username) + + var connection: LdapConnection? = null + + return try { + connection = LdapNetworkConnection(hostname, port.toInt()) + connection.bind(userDN, password) + true + } catch (e: LdapException) { + e.printStackTrace() + false + } finally { + connection?.unBind() + connection?.close() + } +} + +// Example usage +fun main() { + val result = auth("ldap://localhost:3893", "cn=%s,ou=superheros,dc=glauth,dc=com", "hackers", "dogood") + println("Authentication result: $result") +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/RADIUS.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/RADIUS.kt new file mode 100644 index 000000000..d9c8dbc79 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/RADIUS.kt @@ -0,0 +1,49 @@ +package id.walt.methods + +import org.aaa4j.radius.client.RadiusClient +import org.aaa4j.radius.client.RadiusClientException +import org.aaa4j.radius.client.clients.UdpRadiusClient +import org.aaa4j.radius.core.attribute.Attribute +import org.aaa4j.radius.core.attribute.StringData +import org.aaa4j.radius.core.attribute.TextData +import org.aaa4j.radius.core.attribute.attributes.NasIdentifier +import org.aaa4j.radius.core.attribute.attributes.UserName +import org.aaa4j.radius.core.attribute.attributes.UserPassword +import org.aaa4j.radius.core.packet.Packet +import org.aaa4j.radius.core.packet.packets.AccessAccept +import org.aaa4j.radius.core.packet.packets.AccessRequest +import java.net.InetSocketAddress + +class RADIUS { + + val radiusClient: RadiusClient = UdpRadiusClient.newBuilder() + .secret("sharedsecret".toByteArray()) + .address(InetSocketAddress("10.1.1.10", 1812)) + .build() + + fun auth(): Result { + val accessRequest = AccessRequest( + listOf( + UserName(TextData("john.doe")), + UserPassword(StringData("hunter2".toByteArray())), + NasIdentifier(TextData("SSID1")) + ) + ) + + try { + val responsePacket: Packet = radiusClient.send(accessRequest) + + if (responsePacket is AccessAccept) { + println(responsePacket) + return Result.success(true) + } else { + return Result.failure(NotImplementedError("no exception here yet")) + TODO("todo") + } + } catch (e: RadiusClientException) { + e.printStackTrace() + return Result.failure(e) + } + } + +} diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt similarity index 95% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt index 6adcd9592..9018421d2 100644 --- a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt @@ -1,12 +1,11 @@ package id.walt.plugins import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.auth.ldap.* -import io.ktor.server.response.* -import io.ktor.server.routing.* fun Application.configureSecurity() { + + +} /*authentication { basic(name = "myauth1") { realm = "Ktor Server" @@ -47,7 +46,7 @@ fun Application.configureSecurity() { } } }*/ - val localhost = "localhost" + /* val localhost = "localhost" val ldapServerPort = 3893 // TODO: change to real value! authentication { basic("auth-ldap") { @@ -57,7 +56,7 @@ fun Application.configureSecurity() { ldapAuthenticate(credential, "ldap://$localhost:${ldapServerPort}", "cn=%s,ou=superheros,dc=glauth,dc=com") } } - } + }*/ /*authentication { oauth("auth-oauth-google") { urlProvider = { "http://localhost:8080/callback" } @@ -81,12 +80,12 @@ fun Application.configureSecurity() { cookie.extensions["SameSite"] = "lax" } }*/ - routing { + /* routing { authenticate("auth-ldap") { get("/") { call.respondText("Hello, ${call.principal()?.name}!") } - } + }*/ /*authenticate("myauth1") { get("/protected/route/basic") { val principal = call.principal()!! @@ -115,7 +114,9 @@ fun Application.configureSecurity() { call.sessions.set(session.copy(count = session.count + 1)) call.respondText("Counter is ${session.count}. Refresh to increment.") }*/ +/* } } class UserSession(accessToken: String) +*/ diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt similarity index 69% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt index 02bb44730..2f5b088ed 100644 --- a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt @@ -1,11 +1,14 @@ package id.walt.sessions +import kotlin.uuid.Uuid + enum class AuthSessionStatus(val value: String) { OK("ok"), CONTINUE_NEXT_STEP("continue_next_step"), FAIL("fail"), } +@OptIn(ExperimentalStdlibApi::class) data class AuthSession( - val id: String + val id: Uuid ) diff --git a/waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt diff --git a/waltid-libraries/waltid-authkit/src/main/resources/logback.xml b/waltid-libraries/auth/waltid-authkit/src/main/resources/logback.xml similarity index 100% rename from waltid-libraries/waltid-authkit/src/main/resources/logback.xml rename to waltid-libraries/auth/waltid-authkit/src/main/resources/logback.xml diff --git a/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt b/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt similarity index 75% rename from waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt rename to waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt index 650b22474..0e501377b 100644 --- a/waltid-libraries/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt +++ b/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt @@ -16,14 +16,7 @@ class ApplicationTest { fun testRoot() = testApplication { application { - install(Authentication) { - this.provider("x") { - this.authenticate { - val x = it.call.receive() - - } - } - } + configureRouting() } diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt new file mode 100644 index 000000000..e48cd806a --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt @@ -0,0 +1,314 @@ +@file:OptIn(ExperimentalStdlibApi::class) + +package id.walt + +import io.klogging.Level +import io.klogging.config.loggingConfiguration +import io.klogging.rendering.RENDER_ANSI +import io.klogging.sending.STDERR +import io.klogging.sending.STDOUT +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.application.* +import io.ktor.server.cio.* +import io.ktor.server.engine.* +import io.ktor.server.plugins.callloging.* +import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.plugins.doublereceive.* +import io.ktor.server.plugins.statuspages.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.ktor.server.util.* +import io.ktor.util.* +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromJsonElement +import kotlinx.serialization.json.encodeToJsonElement +import kotlin.uuid.Uuid + +fun main() { + loggingConfiguration(true) { + sink("stdout", RENDER_ANSI, STDOUT) + sink("stderr", RENDER_ANSI, STDERR) + + logging { + fromLoggerBase("io.ktor", stopOnMatch = true) + fromMinLevel(Level.INFO) { + toSink("stdout") + } + } + logging { + fromLoggerBase("org.sqlite.core.NativeDB", stopOnMatch = true) + fromMinLevel(Level.DEBUG) { + toSink("stdout") + } + } + logging { + fromMinLevel(Level.ERROR) { + toSink("stderr") + } + inLevelRange(Level.TRACE, Level.WARN) { + toSink("stdout") + } + } + minDirectLogLevel(Level.TRACE) + } + + embeddedServer(CIO, port = 8080) { + install(ContentNegotiation) { + json() + } + + install(DoubleReceive) + + install(CallLogging) { + level = org.slf4j.event.Level.DEBUG + format { call -> + """ + -v-v-v- + > Request: + ${call.request.httpMethod.value} ${call.request.uri} + Headers: ${call.request.headers.toMap().dropCommonHeaders()} + ${if ((call.request.contentLength() ?: 0) > 0) "Body: ${runBlocking { call.receiveText() }}" else "No body"} + + > Response: + ${call.response.status()} (${call.response.responseType?.type?.simpleName}) + -^-^-^- + """.trimIndent() + } + } + + install(StatusPages) { + exception { call, cause -> + cause.printStackTrace() + call.respond(HttpStatusCode.InternalServerError, cause.localizedMessage) + } + } + + test() + }.start(wait = true) +} + +private fun Map>.dropCommonHeaders(): Map> = + this.toMutableMap().apply { + keys.removeIf { it.startsWith("Sec-") || it.startsWith("Upgrade-") || it.startsWith("Accept") } + keys.removeAll( + listOf( + "Connection", + "Cookie", + "DNT", + "User-Agent", "Priority" + ) + ) + } + +@Serializable +data class AuthorizeRequest( + /** CSRF protection */ + val state: String? = null, + /** server-side relay protection */ + val nonce: String? = null, + /** scope */ + //val scope: List, + val scope: String, + /** OIDC Provider will redirect here */ + @SerialName("redirect_uri") + val redirectUri: String, + @SerialName("response_type") + val responseType: String = "code", + /** Relying Party identifier */ + @SerialName("client_id") + val clientId: String, +) + +@Serializable +data class TokenResponse( + @SerialName("id_token") + val idToken: String, + @SerialName("access_token") + val accessToken: String, + @SerialName("token_type") + val tokenType: String, + @SerialName("expires_in") + val expiresIn: Int, +) + +fun Application.test() { + routing { + // Step 0. (call by RP) + get(".well-known/openid-configuration") { + val issuer = "http://localhost:8080" + + val wellKnown = mapOf( + "issuer" to issuer, + "authorization_endpoint" to "$issuer/authorize", + "token_endpoint" to "$issuer/token", + "userinfo_endpoint" to "$issuer/userinfo", + "jwks_uri" to "$issuer/jwks", + "response_types_supported" to listOf("code", "id_token", "token id_token"), + "subject_types_supported" to listOf("public"), + "id_token_signing_alg_values_supported" to listOf("RS256"), + "scopes_supported" to listOf("openid", "profile", "email"), + //"token_endpoint_auth_methods_supported" to listOf("client_secret_basic", "client_secret_post"), + "token_endpoint_auth_methods_supported" to listOf("client_secret_basic"), + "claims_supported" to listOf("sub", "iss", "aud", "iat", "exp", "name", "email") + ).toJsonObject() + call.respond(wellKnown) + } + + // (RP 302 redirects user agent to /authorize with state, nonce, scope, redirect_uri, response_type, client_id) + + val authCache = HashMap() // state -> req + val reqCache = HashMap() + val urlCache = HashMap() + + // Step 1. + get("/authorize") { + val query = call.request.queryParameters + var queryString = query.formUrlEncode() + + val map = query.toMap().mapValues { it.value.joinToString(" ") } + var req = Json.decodeFromJsonElement(Json.encodeToJsonElement(map)) + + if (req.state == null) { + // Generate state + req = req.copy(state = Uuid.random().toString()) + queryString += "&state=${req.state}" + } + + authCache[req.state!!] = req + println("Saved req to authCache: $req") + + + val (url, token) = Verifier.verify("http://localhost:8080/login?state=${req.state!!}") + reqCache[req.state!!] = token + urlCache[req.state!!] = url + + //language=HTML + call.respondText( + """ + +

Present your credential: $url (just imagine real hard that this is a QR code)

+
Click here when presented (just imagine real hard that this is automatic) +

Debug query: $queryString

+ + """.trimIndent(), ContentType.Text.Html + ) + } + + val codeCache = HashMap() + + val verifyResultCache = HashMap>() + + get("/login") { + val state = call.request.queryParameters.getOrFail("state") + + val authReq = authCache[state] ?: error("No such state: $state") + + val requestedClaims = listOf( + "$.name", + "$.credentialSubject.achievement.description", + "$.credentialSubject.achievement.criteria.narrative" + ) + + val verificationResult = Verifier.getVerificationResult(reqCache[state] ?: error("No req for state: $state"), requestedClaims) + + if (verificationResult.state == VerificationStatus.WAITING_FOR_SUBMISSION) { + val url = urlCache[state] ?: error("No such state: $state") + + //language=HTML + call.respondText( + """ + +

Not presented yet, please try again

+

Present your credential: $url (just imagine real hard that this is a QR code)

+ Click here when presented (just imagine real hard that this is automatic) + + """.trimIndent(), ContentType.Text.Html + ) + return@get + } + + if (verificationResult.success == true) { + val generatedCode = Uuid.random().toString() + + codeCache[generatedCode] = state + verifyResultCache[generatedCode] = verificationResult.claims!! + + call.respondRedirect(authReq.redirectUri + "?code=$generatedCode&state=${authReq.state}") // todo handle redirect URIs that already have parameters + } else { + call.respondText("Presentation failed!") + } + } + + + val tokenClaimCache = HashMap>() + + + // Step 2 + post("/token") { + val form = call.receiveParameters() + + + /*val (clientId, clientSecret) = call.request.authorization()?.decodeBase64String()?.split(":") + + throw IllegalArgumentException( + "Client id or client secret missing in basic auth" + )*/ + + val basicAuth = call.request.authorization()?.decodeBase64String()?.split(":") + val clientId = basicAuth?.get(0) ?: form["client_id"] ?: error("No client_id provided") + val clientSecret = basicAuth?.get(1) ?: form["client_secret"] ?: error("No client_secret provided") + + println("Client id: $clientId, client secret: $clientSecret") + + + val grantType = form.getOrFail("grant_type") + val code = form.getOrFail("code") + val redirectUri = form.getOrFail("redirect_uri") + + println("grant type = $grantType") + + val req = authCache[codeCache[code] ?: error("No such code: $code")] ?: error("No such req for state: ${codeCache[code]}") + + check(req.redirectUri == redirectUri) { "Redirect uri does not match: ${req.redirectUri} - $redirectUri" } + + + val accessToken = "access-idpkit_" + Uuid.random().toString() + + + val claims = verifyResultCache[code]!! + + tokenClaimCache[accessToken] = claims + + val tokenResponse = TokenResponse( + idToken = "id token here", + accessToken = accessToken, + tokenType = "Bearer", + expiresIn = 3600 + ) + + + call.respond(tokenResponse) + } + + + get("/userinfo") { + val auth = call.request.authorization()?.removePrefix("Bearer ") + + if (tokenClaimCache.containsKey(auth)) { + val claims = tokenClaimCache[auth]!! + + call.respond( + claims.toJsonObject() + ) + } else { + call.respond(HttpStatusCode.Unauthorized) + } + } + + } +} diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Verifier.kt b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Verifier.kt new file mode 100644 index 000000000..ee180bfd0 --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Verifier.kt @@ -0,0 +1,97 @@ +package id.walt + +import com.nfeld.jsonpathkt.JsonPath +import com.nfeld.jsonpathkt.kotlinx.resolveAsStringOrNull +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.engine.cio.* +import io.ktor.client.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.util.* +import kotlinx.serialization.json.* +import kotlin.io.encoding.Base64 +import kotlin.io.encoding.ExperimentalEncodingApi + +enum class VerificationStatus { + WAITING_FOR_SUBMISSION, + RESPONSE_RECEIVED +} + +data class VerificationResultStatus( + val state: VerificationStatus, + val success: Boolean? = null, + val claims: Map? = null, +) + +object Verifier { + + private val client = HttpClient(CIO) { + install(ContentNegotiation) { + json() + } + defaultRequest { + contentType(ContentType.Application.Json) + } + } + + suspend fun verify(redirectUrl: String): Pair { + val response: HttpResponse = client.post("http://localhost:7003/openid4vc/verify") { + setBody( + mapOf( + "request_credentials" to listOf("OpenBadgeCredential") + ).toJsonObject() + ) + header("successRedirectUri", redirectUrl) + } + + val presentationRequest = response.bodyAsText() + + val state = parseQueryString(presentationRequest).getOrFail("state") + return Pair(presentationRequest, state) + } + + @OptIn(ExperimentalEncodingApi::class) + suspend fun getVerificationResult(id: String, requestedClaims: List): VerificationResultStatus { + val resp = client.get("http://localhost:7003/openid4vc/session/$id").body() + + if (resp["tokenResponse"] == null) { + return VerificationResultStatus(VerificationStatus.WAITING_FOR_SUBMISSION) + } + + val overall = resp["verificationResult"]?.jsonPrimitive?.boolean == true + + + val base64 = Base64.UrlSafe.withPadding(Base64.PaddingOption.ABSENT_OPTIONAL) + + val payload = base64.decode(resp["tokenResponse"]!!.jsonObject["vp_token"]!!.jsonPrimitive.content.split(".")[1]).decodeToString() + val vp = Json.parseToJsonElement(payload).jsonObject + + val did = vp["sub"]!!.jsonPrimitive.content + println(did) + + val credentials = vp["vp"]!!.jsonObject["verifiableCredential"]!!.jsonArray.map { + Json.parseToJsonElement( + base64.decode( + it.jsonPrimitive.content.split(".")[1] + ).decodeToString() + ).jsonObject["vc"]!!.jsonObject + } + println(credentials) + + val vc = credentials.first() + + + val claims = requestedClaims.map { + Pair(it, vc.resolveAsStringOrNull(JsonPath.compile(it))) + }.toMap().toMutableMap().apply { + put("sub", did) + } + println("Claims: $claims") + + return VerificationResultStatus(VerificationStatus.RESPONSE_RECEIVED, overall, claims) + } +} diff --git a/waltid-libraries/waltid-mdoc-credentials/.gitignore b/waltid-libraries/credentials/waltid-mdoc-credentials/.gitignore similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/.gitignore rename to waltid-libraries/credentials/waltid-mdoc-credentials/.gitignore diff --git a/waltid-libraries/waltid-mdoc-credentials/CODE_OF_CONDUCT.md b/waltid-libraries/credentials/waltid-mdoc-credentials/CODE_OF_CONDUCT.md similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/CODE_OF_CONDUCT.md rename to waltid-libraries/credentials/waltid-mdoc-credentials/CODE_OF_CONDUCT.md diff --git a/waltid-libraries/waltid-mdoc-credentials/CONTRIBUTING.md b/waltid-libraries/credentials/waltid-mdoc-credentials/CONTRIBUTING.md similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/CONTRIBUTING.md rename to waltid-libraries/credentials/waltid-mdoc-credentials/CONTRIBUTING.md diff --git a/waltid-libraries/waltid-mdoc-credentials/LICENSE b/waltid-libraries/credentials/waltid-mdoc-credentials/LICENSE similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/LICENSE rename to waltid-libraries/credentials/waltid-mdoc-credentials/LICENSE diff --git a/waltid-libraries/waltid-mdoc-credentials/README.md b/waltid-libraries/credentials/waltid-mdoc-credentials/README.md similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/README.md rename to waltid-libraries/credentials/waltid-mdoc-credentials/README.md diff --git a/waltid-libraries/waltid-mdoc-credentials/build.gradle.kts b/waltid-libraries/credentials/waltid-mdoc-credentials/build.gradle.kts similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/build.gradle.kts rename to waltid-libraries/credentials/waltid-mdoc-credentials/build.gradle.kts diff --git a/waltid-libraries/waltid-mdoc-credentials/cert.der b/waltid-libraries/credentials/waltid-mdoc-credentials/cert.der similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/cert.der rename to waltid-libraries/credentials/waltid-mdoc-credentials/cert.der diff --git a/waltid-libraries/waltid-mdoc-credentials/examples/js/SimpleCOSECryptoProvider.js b/waltid-libraries/credentials/waltid-mdoc-credentials/examples/js/SimpleCOSECryptoProvider.js similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/examples/js/SimpleCOSECryptoProvider.js rename to waltid-libraries/credentials/waltid-mdoc-credentials/examples/js/SimpleCOSECryptoProvider.js diff --git a/waltid-libraries/waltid-mdoc-credentials/examples/js/index.js b/waltid-libraries/credentials/waltid-mdoc-credentials/examples/js/index.js similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/examples/js/index.js rename to waltid-libraries/credentials/waltid-mdoc-credentials/examples/js/index.js diff --git a/waltid-libraries/waltid-mdoc-credentials/examples/js/package-lock.json b/waltid-libraries/credentials/waltid-mdoc-credentials/examples/js/package-lock.json similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/examples/js/package-lock.json rename to waltid-libraries/credentials/waltid-mdoc-credentials/examples/js/package-lock.json diff --git a/waltid-libraries/waltid-mdoc-credentials/examples/js/package.json b/waltid-libraries/credentials/waltid-mdoc-credentials/examples/js/package.json similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/examples/js/package.json rename to waltid-libraries/credentials/waltid-mdoc-credentials/examples/js/package.json diff --git a/waltid-libraries/waltid-mdoc-credentials/gradlew b/waltid-libraries/credentials/waltid-mdoc-credentials/gradlew similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/gradlew rename to waltid-libraries/credentials/waltid-mdoc-credentials/gradlew diff --git a/waltid-libraries/waltid-mdoc-credentials/gradlew.bat b/waltid-libraries/credentials/waltid-mdoc-credentials/gradlew.bat similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/gradlew.bat rename to waltid-libraries/credentials/waltid-mdoc-credentials/gradlew.bat diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/ByteString.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/ByteString.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/ByteString.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/ByteString.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/Cbor.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/Cbor.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/Cbor.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/Cbor.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/ByteArrayInput.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/ByteArrayInput.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/ByteArrayInput.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/ByteArrayInput.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/CborDecodingException.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/CborDecodingException.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/CborDecodingException.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/CborDecodingException.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/SharedHelpers.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/SharedHelpers.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/SharedHelpers.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/SharedHelpers.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/Values.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/Values.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/Values.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/Values.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/decoding/CborDecoder.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/decoding/CborDecoder.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/decoding/CborDecoder.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/decoding/CborDecoder.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/encoding/CborEncoder.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/encoding/CborEncoder.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/encoding/CborEncoder.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/cbor/internal/encoding/CborEncoder.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/Values.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/Values.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/Values.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/Values.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/AsyncCOSECryptoProvider.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/AsyncCOSECryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/AsyncCOSECryptoProvider.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/AsyncCOSECryptoProvider.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSECryptoProvider.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSECryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSECryptoProvider.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSECryptoProvider.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEMac0.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEMac0.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEMac0.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEMac0.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESign1.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESign1.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESign1.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESign1.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESimpleBase.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESimpleBase.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESimpleBase.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSESimpleBase.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEValues.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEValues.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEValues.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/cose/COSEValues.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElement.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElement.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElement.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElement.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementConversion.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementConversion.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementConversion.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementConversion.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementSerializer.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementSerializer.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementSerializer.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/DataElementSerializer.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/MapKey.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/MapKey.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/MapKey.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataelement/MapKey.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceRequest.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceRequest.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceRequest.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceRequest.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponse.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponseStatus.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponseStatus.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponseStatus.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/dataretrieval/DeviceResponseStatus.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceAuth.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceAuth.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceAuth.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceAuth.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceSigned.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceSigned.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceSigned.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/devicesigned/DeviceSigned.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDoc.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDoc.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDoc.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDoc.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocBuilder.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocBuilder.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocBuilder.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocBuilder.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocVerificationParams.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocVerificationParams.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocVerificationParams.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/MDocVerificationParams.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/VerificationType.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/VerificationType.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/VerificationType.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/doc/VerificationType.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/ItemsRequest.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/ItemsRequest.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/ItemsRequest.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/ItemsRequest.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequest.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequest.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequest.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequest.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestBuilder.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestBuilder.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestBuilder.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestBuilder.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestVerificationParams.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestVerificationParams.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestVerificationParams.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/docrequest/MDocRequestVerificationParams.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSigned.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSigned.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSigned.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSigned.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSignedItem.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSignedItem.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSignedItem.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/issuersigned/IssuerSignedItem.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mdocauth/DeviceAuthentication.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mdocauth/DeviceAuthentication.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mdocauth/DeviceAuthentication.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mdocauth/DeviceAuthentication.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DeviceKeyInfo.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DeviceKeyInfo.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DeviceKeyInfo.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DeviceKeyInfo.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DigestAlgorithm.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DigestAlgorithm.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DigestAlgorithm.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/DigestAlgorithm.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/MSO.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/MSO.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/MSO.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/MSO.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/ValidityInfo.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/ValidityInfo.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/ValidityInfo.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/mso/ValidityInfo.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/readerauth/ReaderAuthentication.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/readerauth/ReaderAuthentication.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/readerauth/ReaderAuthentication.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/readerauth/ReaderAuthentication.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonTest/kotlin/id/walt/mdoc/MDocTest.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/commonTest/kotlin/id/walt/mdoc/MDocTest.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/commonTest/kotlin/id/walt/mdoc/MDocTest.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/commonTest/kotlin/id/walt/mdoc/MDocTest.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/JSAsyncCOSECryptoProvider.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/JSAsyncCOSECryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/JSAsyncCOSECryptoProvider.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/JSAsyncCOSECryptoProvider.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/SimpleAsyncCOSECryptoProvider.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/SimpleAsyncCOSECryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/SimpleAsyncCOSECryptoProvider.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/jsMain/kotlin/id/walt/mdoc/SimpleAsyncCOSECryptoProvider.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/jsTest/kotlin/id/walt/mdoc/JSTest.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/jsTest/kotlin/id/walt/mdoc/JSTest.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/jsTest/kotlin/id/walt/mdoc/JSTest.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/jsTest/kotlin/id/walt/mdoc/JSTest.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/COSECryptoProviderKeyInfo.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/COSECryptoProviderKeyInfo.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/COSECryptoProviderKeyInfo.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/COSECryptoProviderKeyInfo.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/SimpleCOSECryptoProvider.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/SimpleCOSECryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/SimpleCOSECryptoProvider.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/jvmMain/kotlin/id/walt/mdoc/SimpleCOSECryptoProvider.kt diff --git a/waltid-libraries/waltid-mdoc-credentials/src/jvmTest/kotlin/id/walt/mdoc/JVMMdocTest.kt b/waltid-libraries/credentials/waltid-mdoc-credentials/src/jvmTest/kotlin/id/walt/mdoc/JVMMdocTest.kt similarity index 100% rename from waltid-libraries/waltid-mdoc-credentials/src/jvmTest/kotlin/id/walt/mdoc/JVMMdocTest.kt rename to waltid-libraries/credentials/waltid-mdoc-credentials/src/jvmTest/kotlin/id/walt/mdoc/JVMMdocTest.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/README.md b/waltid-libraries/credentials/waltid-verifiable-credentials/README.md similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/README.md rename to waltid-libraries/credentials/waltid-verifiable-credentials/README.md diff --git a/waltid-libraries/waltid-verifiable-credentials/build.gradle.kts b/waltid-libraries/credentials/waltid-verifiable-credentials/build.gradle.kts similarity index 98% rename from waltid-libraries/waltid-verifiable-credentials/build.gradle.kts rename to waltid-libraries/credentials/waltid-verifiable-credentials/build.gradle.kts index 485eb3e0f..3000b45a0 100644 --- a/waltid-libraries/waltid-verifiable-credentials/build.gradle.kts +++ b/waltid-libraries/credentials/waltid-verifiable-credentials/build.gradle.kts @@ -111,8 +111,8 @@ kotlin { implementation("io.github.oshai:kotlin-logging:7.0.0") // walt.id - api(project(":waltid-libraries:waltid-crypto")) - api(project(":waltid-libraries:waltid-sdjwt")) + api(project(":waltid-libraries:crypto:waltid-crypto")) + api(project(":waltid-libraries:sdjwt:waltid-sdjwt")) api(project(":waltid-libraries:waltid-did")) // suspend-transform plugin annotations (required in the current version to avoid "compileOnly" warning) diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/Claims.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/Claims.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/Claims.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/Claims.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/CredentialBuilder.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/CredentialBuilder.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/CredentialBuilder.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/CredentialBuilder.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/PresentationBuilder.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/PresentationBuilder.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/PresentationBuilder.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/PresentationBuilder.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/DataFunctions.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/DataFunctions.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/DataFunctions.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/DataFunctions.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/Issuer.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/Issuer.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/Issuer.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/issuance/Issuer.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/JwsSignatureScheme.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/JwsSignatureScheme.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/JwsSignatureScheme.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/JwsSignatureScheme.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/SignatureScheme.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/SignatureScheme.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/SignatureScheme.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/schemes/SignatureScheme.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/EnumUtils.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/EnumUtils.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/EnumUtils.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/EnumUtils.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/ExtensionMethods.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/ExtensionMethods.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/ExtensionMethods.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/ExtensionMethods.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/JsonCanonicalization.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/JsonCanonicalization.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/JsonCanonicalization.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/JsonCanonicalization.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CDataMergeUtils.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CDataMergeUtils.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CDataMergeUtils.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CDataMergeUtils.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CVcUtils.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CVcUtils.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CVcUtils.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/W3CVcUtils.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/randomUUID.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/randomUUID.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/randomUUID.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/utils/randomUUID.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/Credential.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/Credential.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/Credential.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/Credential.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/CredentialDataModel.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/CredentialDataModel.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/CredentialDataModel.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/CredentialDataModel.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/MdocsVC.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/MdocsVC.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/MdocsVC.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/MdocsVC.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CBaseDataModels.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CBaseDataModels.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CBaseDataModels.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CBaseDataModels.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CMetadata.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CMetadata.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CMetadata.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CMetadata.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV11DataModel.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV11DataModel.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV11DataModel.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV11DataModel.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV2DataModel.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV2DataModel.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV2DataModel.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CV2DataModel.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CVC.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CVC.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CVC.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/vc/vcs/W3CVC.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialDataValidatorPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialDataValidatorPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialDataValidatorPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialDataValidatorPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialWrapperValidatorPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialWrapperValidatorPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialWrapperValidatorPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/CredentialWrapperValidatorPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Exceptions.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Exceptions.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Exceptions.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Exceptions.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/JwtVerificationPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/JwtVerificationPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/JwtVerificationPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/JwtVerificationPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/PolicyManager.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/PolicyManager.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/PolicyManager.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/PolicyManager.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/VerificationPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/VerificationPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/VerificationPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/VerificationPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Verifier.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Verifier.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Verifier.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/Verifier.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyRequest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyRequest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyRequest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyRequest.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyResult.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyResult.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyResult.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PolicyResult.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationResultEntry.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationResultEntry.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationResultEntry.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationResultEntry.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationVerificationResponse.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationVerificationResponse.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationVerificationResponse.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/models/PresentationVerificationResponse.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/AllowedIssuerPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/AllowedIssuerPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/AllowedIssuerPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/AllowedIssuerPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JsonSchemaPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JsonSchemaPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JsonSchemaPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JsonSchemaPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JwtSignaturePolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JwtSignaturePolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JwtSignaturePolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/JwtSignaturePolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/WebhookPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/WebhookPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/WebhookPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/WebhookPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/HolderBindingPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/HolderBindingPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/HolderBindingPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/HolderBindingPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MaximumCredentialsPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MaximumCredentialsPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MaximumCredentialsPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MaximumCredentialsPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MinimumCredentialsPolicy.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MinimumCredentialsPolicy.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MinimumCredentialsPolicy.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonMain/kotlin/id/walt/credentials/verification/policies/vp/MinimumCredentialsPolicy.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/DataBuilderTest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/DataBuilderTest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/DataBuilderTest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/DataBuilderTest.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/LocalVcAPITest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/LocalVcAPITest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/LocalVcAPITest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/LocalVcAPITest.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationBuilderTest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationBuilderTest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationBuilderTest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationBuilderTest.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationVerificationTest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationVerificationTest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationVerificationTest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/PresentationVerificationTest.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/VcApiTest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/VcApiTest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/commonTest/kotlin/VcApiTest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/commonTest/kotlin/VcApiTest.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/utils/randomUUID.ios.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/utils/randomUUID.ios.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/utils/randomUUID.ios.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/utils/randomUUID.ios.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.ios.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.ios.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.ios.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/iosMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.ios.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/CredentialBuilderUtils.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/CredentialBuilderUtils.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/CredentialBuilderUtils.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/CredentialBuilderUtils.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/PresentationVerificationUtils.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/PresentationVerificationUtils.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/PresentationVerificationUtils.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/PresentationVerificationUtils.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.js.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.js.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.js.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.js.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/uuid/uuid.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/uuid/uuid.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jsMain/kotlin/uuid/uuid.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jsMain/kotlin/uuid/uuid.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jsTest/kotlin/LocalDidMethodTestJs.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jsTest/kotlin/LocalDidMethodTestJs.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jsTest/kotlin/LocalDidMethodTestJs.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jsTest/kotlin/LocalDidMethodTestJs.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/utils/UUID.jvm.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.jvm.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.jvm.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.jvm.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmMain/kotlin/id/walt/credentials/verification/policies/RevocationPolicy.jvm.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jvmTest/kotlin/LocalDidMethodTest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmTest/kotlin/LocalDidMethodTest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jvmTest/kotlin/LocalDidMethodTest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmTest/kotlin/LocalDidMethodTest.kt diff --git a/waltid-libraries/waltid-crypto-android/README.md b/waltid-libraries/crypto/waltid-crypto-android/README.md similarity index 100% rename from waltid-libraries/waltid-crypto-android/README.md rename to waltid-libraries/crypto/waltid-crypto-android/README.md diff --git a/waltid-libraries/waltid-crypto-android/build.gradle.kts b/waltid-libraries/crypto/waltid-crypto-android/build.gradle.kts similarity index 98% rename from waltid-libraries/waltid-crypto-android/build.gradle.kts rename to waltid-libraries/crypto/waltid-crypto-android/build.gradle.kts index 78210fb31..30067a749 100644 --- a/waltid-libraries/waltid-crypto-android/build.gradle.kts +++ b/waltid-libraries/crypto/waltid-crypto-android/build.gradle.kts @@ -80,7 +80,7 @@ kotlin { sourceSets { val androidMain by getting { dependencies { - api(project(":waltid-libraries:waltid-crypto")) + api(project(":waltid-libraries:crypto:waltid-crypto")) implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") implementation("io.github.oshai:kotlin-logging:7.0.0") } diff --git a/waltid-libraries/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt b/waltid-libraries/crypto/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt rename to waltid-libraries/crypto/waltid-crypto-android/src/androidInstrumentedTest/kotlin/id/walt/crypto/keys/AndroidKeyTest.kt diff --git a/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt b/waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt similarity index 100% rename from waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt rename to waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKey.kt diff --git a/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyCreator.kt b/waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyCreator.kt similarity index 100% rename from waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyCreator.kt rename to waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyCreator.kt diff --git a/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyGenerator.kt b/waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyGenerator.kt similarity index 100% rename from waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyGenerator.kt rename to waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/AndroidKeyGenerator.kt diff --git a/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/KeyAlias.kt b/waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/KeyAlias.kt similarity index 100% rename from waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/KeyAlias.kt rename to waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/KeyAlias.kt diff --git a/waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/jwk/AndroidJWKKey.kt b/waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/jwk/AndroidJWKKey.kt similarity index 100% rename from waltid-libraries/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/jwk/AndroidJWKKey.kt rename to waltid-libraries/crypto/waltid-crypto-android/src/androidMain/kotlin/id/walt/crypto/keys/jwk/AndroidJWKKey.kt diff --git a/waltid-libraries/waltid-crypto-ios/README.md b/waltid-libraries/crypto/waltid-crypto-ios/README.md similarity index 100% rename from waltid-libraries/waltid-crypto-ios/README.md rename to waltid-libraries/crypto/waltid-crypto-ios/README.md diff --git a/waltid-libraries/waltid-crypto-ios/build.gradle.kts b/waltid-libraries/crypto/waltid-crypto-ios/build.gradle.kts similarity index 88% rename from waltid-libraries/waltid-crypto-ios/build.gradle.kts rename to waltid-libraries/crypto/waltid-crypto-ios/build.gradle.kts index 90d544752..f042c06c1 100644 --- a/waltid-libraries/waltid-crypto-ios/build.gradle.kts +++ b/waltid-libraries/crypto/waltid-crypto-ios/build.gradle.kts @@ -18,7 +18,7 @@ kotlin { baseName = "waltid-crypto-ios" isStatic = true export(project(":waltid-libraries:waltid-target-ios")) - export(project(":waltid-libraries:waltid-crypto")) + export(project(":waltid-libraries:crypto:waltid-crypto")) } pod("JOSESwift") { @@ -43,7 +43,7 @@ kotlin { iosArm64Main.dependsOn(this) iosSimulatorArm64Main.dependsOn(this) dependencies { - api(project(":waltid-libraries:waltid-crypto")) + api(project(":waltid-libraries:crypto:waltid-crypto")) api(project(":waltid-libraries:waltid-target-ios")) } } @@ -51,4 +51,4 @@ kotlin { } -task("testClasses") \ No newline at end of file +task("testClasses") diff --git a/waltid-libraries/waltid-crypto-ios/src/iosMain/kotlin/id/walt/crypto/IosKey.kt b/waltid-libraries/crypto/waltid-crypto-ios/src/iosMain/kotlin/id/walt/crypto/IosKey.kt similarity index 100% rename from waltid-libraries/waltid-crypto-ios/src/iosMain/kotlin/id/walt/crypto/IosKey.kt rename to waltid-libraries/crypto/waltid-crypto-ios/src/iosMain/kotlin/id/walt/crypto/IosKey.kt diff --git a/waltid-libraries/waltid-crypto-ios/src/iosTest/kotlin/TestClass.kt b/waltid-libraries/crypto/waltid-crypto-ios/src/iosTest/kotlin/TestClass.kt similarity index 100% rename from waltid-libraries/waltid-crypto-ios/src/iosTest/kotlin/TestClass.kt rename to waltid-libraries/crypto/waltid-crypto-ios/src/iosTest/kotlin/TestClass.kt diff --git a/waltid-libraries/waltid-crypto-ios/waltid-crypto-ios.podspec b/waltid-libraries/crypto/waltid-crypto-ios/waltid-crypto-ios.podspec similarity index 100% rename from waltid-libraries/waltid-crypto-ios/waltid-crypto-ios.podspec rename to waltid-libraries/crypto/waltid-crypto-ios/waltid-crypto-ios.podspec diff --git a/waltid-libraries/waltid-crypto-ios/waltid_crypto_ios.podspec b/waltid-libraries/crypto/waltid-crypto-ios/waltid_crypto_ios.podspec similarity index 100% rename from waltid-libraries/waltid-crypto-ios/waltid_crypto_ios.podspec rename to waltid-libraries/crypto/waltid-crypto-ios/waltid_crypto_ios.podspec diff --git a/waltid-libraries/waltid-crypto-oci/README.md b/waltid-libraries/crypto/waltid-crypto-oci/README.md similarity index 100% rename from waltid-libraries/waltid-crypto-oci/README.md rename to waltid-libraries/crypto/waltid-crypto-oci/README.md diff --git a/waltid-libraries/waltid-crypto-oci/build.gradle.kts b/waltid-libraries/crypto/waltid-crypto-oci/build.gradle.kts similarity index 97% rename from waltid-libraries/waltid-crypto-oci/build.gradle.kts rename to waltid-libraries/crypto/waltid-crypto-oci/build.gradle.kts index c19ffe9d0..b22c3a47d 100644 --- a/waltid-libraries/waltid-crypto-oci/build.gradle.kts +++ b/waltid-libraries/crypto/waltid-crypto-oci/build.gradle.kts @@ -87,7 +87,7 @@ kotlin { implementation("io.github.oshai:kotlin-logging:7.0.0") // walt.id - api(project(":waltid-libraries:waltid-crypto")) + api(project(":waltid-libraries:crypto:waltid-crypto")) } } val commonTest by getting { @@ -109,7 +109,7 @@ kotlin { implementation("com.nimbusds:nimbus-jose-jwt:9.40") // walt.id - api(project(":waltid-libraries:waltid-crypto")) + api(project(":waltid-libraries:crypto:waltid-crypto")) } } val jvmTest by getting { diff --git a/waltid-libraries/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKey.kt b/waltid-libraries/crypto/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKey.kt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKey.kt rename to waltid-libraries/crypto/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKey.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt b/waltid-libraries/crypto/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt rename to waltid-libraries/crypto/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt b/waltid-libraries/crypto/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt rename to waltid-libraries/crypto/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/WaltCryptoOci.kt b/waltid-libraries/crypto/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/WaltCryptoOci.kt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/WaltCryptoOci.kt rename to waltid-libraries/crypto/waltid-crypto-oci/src/commonMain/kotlin/id/walt/crypto/keys/oci/WaltCryptoOci.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIKey.jvm.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmMain/kotlin/id/walt/crypto/keys/oci/OCIsdkMetadata.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/kotlin/OCIKeyTest.kt b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/kotlin/OCIKeyTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/kotlin/OCIKeyTest.kt rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/kotlin/OCIKeyTest.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/kotlin/OCISdkKeyTest.kt b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/kotlin/OCISdkKeyTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/kotlin/OCISdkKeyTest.kt rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/kotlin/OCISdkKeyTest.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/ed25519.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/rsa.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256k1.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/jwk/secp256r1.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519-vault.base64 b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519-vault.base64 similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519-vault.base64 rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519-vault.base64 diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519.bin b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519.bin similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519.bin rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/ed25519.bin diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/rsa.bin b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/rsa.bin similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/rsa.bin rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/rsa.bin diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256k1.bin b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256k1.bin similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256k1.bin rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256k1.bin diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256r1.bin b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256r1.bin similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256r1.bin rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/public-bytes/secp256r1.bin diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/ed25519.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/rsa.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256k1.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/local/secp256r1.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.private.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.private.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.private.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.private.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.public.json b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.public.json similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.public.json rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/serialized/tse/ed25519.public.json diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/signatures/ed25519.txt b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/signatures/ed25519.txt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/signatures/ed25519.txt rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/signatures/ed25519.txt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/signatures/rsa.txt b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/signatures/rsa.txt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/signatures/rsa.txt rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/signatures/rsa.txt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256k1.txt b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256k1.txt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256k1.txt rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256k1.txt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256r1.txt b/waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256r1.txt similarity index 100% rename from waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256r1.txt rename to waltid-libraries/crypto/waltid-crypto-oci/src/jvmTest/resources/signatures/secp256r1.txt diff --git a/waltid-libraries/waltid-crypto/README.md b/waltid-libraries/crypto/waltid-crypto/README.md similarity index 100% rename from waltid-libraries/waltid-crypto/README.md rename to waltid-libraries/crypto/waltid-crypto/README.md diff --git a/waltid-libraries/waltid-crypto/build.gradle.kts b/waltid-libraries/crypto/waltid-crypto/build.gradle.kts similarity index 100% rename from waltid-libraries/waltid-crypto/build.gradle.kts rename to waltid-libraries/crypto/waltid-crypto/build.gradle.kts diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/EccUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/EccUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/EccUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/EccUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/Key.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/Key.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/Key.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/Key.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyCreator.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyCreator.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyCreator.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyCreator.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyGenerationRequest.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyGenerationRequest.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyGenerationRequest.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyGenerationRequest.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyManager.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyManager.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyManager.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyManager.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyMeta.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyMeta.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyMeta.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyMeta.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeySerialization.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeySerialization.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeySerialization.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeySerialization.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyType.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyType.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyType.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/KeyType.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKeyCreator.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKeyCreator.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKeyCreator.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/jwk/JWKKeyCreator.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyMetadata.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/oci/OCIKeyRestApi.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEAuth.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEAuth.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEAuth.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEAuth.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKey.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyCreator.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyCreator.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyCreator.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyCreator.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyMetadata.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyMetadata.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyMetadata.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/keys/tse/TSEKeyMetadata.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base58Utils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base58Utils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base58Utils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base58Utils.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/Base64Utils.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/CryptoUtil.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/CryptoUtil.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/CryptoUtil.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/CryptoUtil.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonCanonicalizationUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonCanonicalizationUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonCanonicalizationUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonCanonicalizationUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JsonUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JweUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JweUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JweUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JweUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt similarity index 94% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt index 9b10f6025..9358b3e33 100644 --- a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt +++ b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/JwsUtils.kt @@ -2,6 +2,7 @@ package id.walt.crypto.utils import id.walt.crypto.keys.KeyType import id.walt.crypto.utils.Base64Utils.base64UrlToBase64 +import id.walt.crypto.utils.Base64Utils.decodeFromBase64Url import id.walt.crypto.utils.Base64Utils.encodeToBase64Url import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -24,9 +25,8 @@ object JwsUtils { KeyType.RSA -> "RS256" // TODO: RS384 RS512 } - @OptIn(ExperimentalEncodingApi::class) fun String.decodeJwsPart(): JsonObject = - Json.parseToJsonElement(Base64.decode(this.base64UrlToBase64()).decodeToString()).jsonObject + Json.parseToJsonElement(this.decodeFromBase64Url().decodeToString()).jsonObject data class JwsParts(val header: JsonObject, val payload: JsonObject, val signature: String) { override fun toString() = "${Json.encodeToString(header).encodeToByteArray().encodeToBase64Url()}.${ diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiCodecUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiCodecUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiCodecUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/kotlin/id/walt/crypto/utils/MultiCodecUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/commonMain/resources/simplelogger.properties b/waltid-libraries/crypto/waltid-crypto/src/commonMain/resources/simplelogger.properties similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonMain/resources/simplelogger.properties rename to waltid-libraries/crypto/waltid-crypto/src/commonMain/resources/simplelogger.properties diff --git a/waltid-libraries/waltid-crypto/src/commonTest/kotlin/TSEKeyTest.kt b/waltid-libraries/crypto/waltid-crypto/src/commonTest/kotlin/TSEKeyTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonTest/kotlin/TSEKeyTest.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonTest/kotlin/TSEKeyTest.kt diff --git a/waltid-libraries/waltid-crypto/src/commonTest/kotlin/TseAuthTest.kt b/waltid-libraries/crypto/waltid-crypto/src/commonTest/kotlin/TseAuthTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/commonTest/kotlin/TseAuthTest.kt rename to waltid-libraries/crypto/waltid-crypto/src/commonTest/kotlin/TseAuthTest.kt diff --git a/waltid-libraries/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.ios.kt b/waltid-libraries/crypto/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.ios.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.ios.kt rename to waltid-libraries/crypto/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.ios.kt diff --git a/waltid-libraries/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/CryptoUtil.ios.kt b/waltid-libraries/crypto/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/CryptoUtil.ios.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/CryptoUtil.ios.kt rename to waltid-libraries/crypto/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/CryptoUtil.ios.kt diff --git a/waltid-libraries/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/JweUtils.ios.kt b/waltid-libraries/crypto/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/JweUtils.ios.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/JweUtils.ios.kt rename to waltid-libraries/crypto/waltid-crypto/src/iosMain/kotlin/id/walt/crypto/utils/JweUtils.ios.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/crypto/crypto.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/crypto/crypto.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/crypto/crypto.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/crypto/crypto.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.js.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.js.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.js.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.js.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.js.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.js.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.js.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.js.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/ArrayUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/ArrayUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/ArrayUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/ArrayUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/CryptoUtil.js.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/CryptoUtil.js.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/CryptoUtil.js.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/CryptoUtil.js.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/JweUtils.js.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/JweUtils.js.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/JweUtils.js.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/JweUtils.js.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/PromiseUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/PromiseUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/PromiseUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/id/walt/crypto/utils/PromiseUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/decode_jwt.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/decode_jwt.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/decode_jwt.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/decode_jwt.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/decode_protected_header.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/decode_protected_header.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/decode_protected_header.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/decode_protected_header.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/decrypt.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/decrypt.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/decrypt.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/decrypt.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/embedded.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/embedded.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/embedded.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/embedded.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/encrypt.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/encrypt.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/encrypt.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/encrypt.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/generate_secret.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/generate_secret.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/generate_secret.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/generate_secret.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/lib.es2015.iterable.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/lib.es2015.iterable.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/lib.es2015.iterable.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/lib.es2015.iterable.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.Intl.module_dukat.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.Intl.module_dukat.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.Intl.module_dukat.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.Intl.module_dukat.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/lib.es5.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/lib.scripthost.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/lib.scripthost.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/lib.scripthost.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/lib.scripthost.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/local.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/local.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/local.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/local.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/produce.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/produce.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/produce.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/produce.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/remote.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/remote.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/remote.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/remote.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/sign.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/sign.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/sign.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/sign.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/types.module_jose.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/types.module_jose.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/jose/types.module_jose.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/jose/types.module_jose.kt diff --git a/waltid-libraries/waltid-crypto/src/jsMain/kotlin/multibase/multibase.kt b/waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/multibase/multibase.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsMain/kotlin/multibase/multibase.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsMain/kotlin/multibase/multibase.kt diff --git a/waltid-libraries/waltid-crypto/src/jsTest/kotlin/ImportTestsJs.kt b/waltid-libraries/crypto/waltid-crypto/src/jsTest/kotlin/ImportTestsJs.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsTest/kotlin/ImportTestsJs.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsTest/kotlin/ImportTestsJs.kt diff --git a/waltid-libraries/waltid-crypto/src/jsTest/kotlin/JWKKeyAndDidManagementTest.kt b/waltid-libraries/crypto/waltid-crypto/src/jsTest/kotlin/JWKKeyAndDidManagementTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsTest/kotlin/JWKKeyAndDidManagementTest.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsTest/kotlin/JWKKeyAndDidManagementTest.kt diff --git a/waltid-libraries/waltid-crypto/src/jsTest/kotlin/KeySignTests.kt b/waltid-libraries/crypto/waltid-crypto/src/jsTest/kotlin/KeySignTests.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsTest/kotlin/KeySignTests.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsTest/kotlin/KeySignTests.kt diff --git a/waltid-libraries/waltid-crypto/src/jsTest/kotlin/TestJs.kt b/waltid-libraries/crypto/waltid-crypto/src/jsTest/kotlin/TestJs.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jsTest/kotlin/TestJs.kt rename to waltid-libraries/crypto/waltid-crypto/src/jsTest/kotlin/TestJs.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/EccUtils.jvm.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/EccUtils.jvm.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/EccUtils.jvm.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/EccUtils.jvm.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.jvm.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.jvm.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.jvm.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JWKKeyGenerator.jvm.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JavaKey.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JavaKey.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JavaKey.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/JavaKey.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/keys/jwk/JWKKey.jvm.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/CryptoUtil.jvm.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/CryptoUtil.jvm.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/CryptoUtil.jvm.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/CryptoUtil.jvm.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JvmEccUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JvmEccUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JvmEccUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JvmEccUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JweUtils.jvm.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JweUtils.jvm.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JweUtils.jvm.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/JweUtils.jvm.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/kotlin/id/walt/crypto/utils/MultiBaseUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmMain/resources/simplelogger.properties b/waltid-libraries/crypto/waltid-crypto/src/jvmMain/resources/simplelogger.properties similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmMain/resources/simplelogger.properties rename to waltid-libraries/crypto/waltid-crypto/src/jvmMain/resources/simplelogger.properties diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/ExportJWKKeyTestsAndDidManagement.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/ExportJWKKeyTestsAndDidManagement.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/ExportJWKKeyTestsAndDidManagement.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/ExportJWKKeyTestsAndDidManagement.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/ImportJWKKeyTestsAndDidManagement.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/ImportJWKKeyTestsAndDidManagement.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/ImportJWKKeyTestsAndDidManagement.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/ImportJWKKeyTestsAndDidManagement.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/JWKKeyAndDidManagementTest.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/JWKKeyAndDidManagementTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/JWKKeyAndDidManagementTest.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/JWKKeyAndDidManagementTest.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/KeySerializationTests.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/KeySerializationTests.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/KeySerializationTests.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/KeySerializationTests.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/KeySignTests.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/LocalJWKKeyAndDidManagementTest.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/LocalJWKKeyAndDidManagementTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/LocalJWKKeyAndDidManagementTest.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/LocalJWKKeyAndDidManagementTest.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/OCIKeyTest.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/OCIKeyTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/OCIKeyTest.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/OCIKeyTest.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/OCISdkKeyTest.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/OCISdkKeyTest.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/OCISdkKeyTest.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/OCISdkKeyTest.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/TestJvm.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/TestJvm.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/TestJvm.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/TestJvm.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/kotlin/TestUtils.kt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/TestUtils.kt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/kotlin/TestUtils.kt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/kotlin/TestUtils.kt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/ed25519.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/ed25519.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/ed25519.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/ed25519.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/ed25519.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/ed25519.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/ed25519.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/ed25519.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/rsa.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/rsa.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/rsa.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/rsa.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/rsa.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/rsa.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/rsa.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/rsa.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/secp256k1.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/jwk/secp256r1.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519-vault.base64 b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519-vault.base64 similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519-vault.base64 rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519-vault.base64 diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519.bin b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519.bin similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519.bin rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/ed25519.bin diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/rsa.bin b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/rsa.bin similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/rsa.bin rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/rsa.bin diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/secp256k1.bin b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/secp256k1.bin similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/secp256k1.bin rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/secp256k1.bin diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/secp256r1.bin b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/secp256r1.bin similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/public-bytes/secp256r1.bin rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/public-bytes/secp256r1.bin diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/ed25519.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/rsa.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/secp256k1.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/local/secp256r1.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.private.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.private.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.private.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.private.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.public.json b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.public.json similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.public.json rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/serialized/tse/ed25519.public.json diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/signatures/ed25519.txt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/signatures/ed25519.txt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/signatures/ed25519.txt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/signatures/ed25519.txt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/signatures/rsa.txt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/signatures/rsa.txt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/signatures/rsa.txt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/signatures/rsa.txt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/signatures/secp256k1.txt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/signatures/secp256k1.txt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/signatures/secp256k1.txt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/signatures/secp256k1.txt diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/signatures/secp256r1.txt b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/signatures/secp256r1.txt similarity index 100% rename from waltid-libraries/waltid-crypto/src/jvmTest/resources/signatures/secp256r1.txt rename to waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/signatures/secp256r1.txt diff --git a/waltid-libraries/waltid-target-ios/README.md b/waltid-libraries/crypto/waltid-target-ios/README.md similarity index 100% rename from waltid-libraries/waltid-target-ios/README.md rename to waltid-libraries/crypto/waltid-target-ios/README.md diff --git a/waltid-libraries/waltid-target-ios/build.gradle.kts b/waltid-libraries/crypto/waltid-target-ios/build.gradle.kts similarity index 100% rename from waltid-libraries/waltid-target-ios/build.gradle.kts rename to waltid-libraries/crypto/waltid-target-ios/build.gradle.kts diff --git a/waltid-libraries/waltid-target-ios/implementation/Podfile b/waltid-libraries/crypto/waltid-target-ios/implementation/Podfile similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/Podfile rename to waltid-libraries/crypto/waltid-target-ios/implementation/Podfile diff --git a/waltid-libraries/waltid-target-ios/implementation/Podfile.lock b/waltid-libraries/crypto/waltid-target-ios/implementation/Podfile.lock similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/Podfile.lock rename to waltid-libraries/crypto/waltid-target-ios/implementation/Podfile.lock diff --git a/waltid-libraries/waltid-target-ios/implementation/build.gradle.kts b/waltid-libraries/crypto/waltid-target-ios/implementation/build.gradle.kts similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/build.gradle.kts rename to waltid-libraries/crypto/waltid-target-ios/implementation/build.gradle.kts diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.pbxproj b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.pbxproj similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.pbxproj rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.pbxproj diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/contents.xcworkspacedata b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/contents.xcworkspacedata similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/contents.xcworkspacedata rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/contents.xcworkspacedata diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils/CryptoUtils.swift b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils/CryptoUtils.swift similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils/CryptoUtils.swift rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils/CryptoUtils.swift diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid.crypto.ios.utils-Bridging-Header.h b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid.crypto.ios.utils-Bridging-Header.h similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid.crypto.ios.utils-Bridging-Header.h rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid.crypto.ios.utils-Bridging-Header.h diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.h b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.h similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.h rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.h diff --git a/waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.m b/waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.m similarity index 100% rename from waltid-libraries/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.m rename to waltid-libraries/crypto/waltid-target-ios/implementation/waltid.crypto.ios.utils/waltid_crypto_ios_utils.m diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFKeychain.kt b/waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFKeychain.kt similarity index 100% rename from waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFKeychain.kt rename to waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFKeychain.kt diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFRetain.kt b/waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFRetain.kt similarity index 100% rename from waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFRetain.kt rename to waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/CFRetain.kt diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt b/waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt similarity index 100% rename from waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt rename to waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Ed25519.kt diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Foundation.kt b/waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Foundation.kt similarity index 100% rename from waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Foundation.kt rename to waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/Foundation.kt diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeyCapabilities.kt b/waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeyCapabilities.kt similarity index 100% rename from waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeyCapabilities.kt rename to waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeyCapabilities.kt diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeychainOperations.kt b/waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeychainOperations.kt similarity index 100% rename from waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeychainOperations.kt rename to waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/KeychainOperations.kt diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/P256.kt b/waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/P256.kt similarity index 100% rename from waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/P256.kt rename to waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/P256.kt diff --git a/waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/RSA.kt b/waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/RSA.kt similarity index 100% rename from waltid-libraries/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/RSA.kt rename to waltid-libraries/crypto/waltid-target-ios/src/iosMain/kotlin/id/walt/target/ios/keys/RSA.kt diff --git a/waltid-libraries/waltid-target-ios/src/nativeInterop/cinterop/implementation.def b/waltid-libraries/crypto/waltid-target-ios/src/nativeInterop/cinterop/implementation.def similarity index 100% rename from waltid-libraries/waltid-target-ios/src/nativeInterop/cinterop/implementation.def rename to waltid-libraries/crypto/waltid-target-ios/src/nativeInterop/cinterop/implementation.def diff --git a/waltid-libraries/waltid-target-ios/waltid-target-ios.podspec b/waltid-libraries/crypto/waltid-target-ios/waltid-target-ios.podspec similarity index 100% rename from waltid-libraries/waltid-target-ios/waltid-target-ios.podspec rename to waltid-libraries/crypto/waltid-target-ios/waltid-target-ios.podspec diff --git a/waltid-libraries/waltid-openid4vc/OpenID4VP.seq b/waltid-libraries/protocols/waltid-openid4vc/OpenID4VP.seq similarity index 100% rename from waltid-libraries/waltid-openid4vc/OpenID4VP.seq rename to waltid-libraries/protocols/waltid-openid4vc/OpenID4VP.seq diff --git a/waltid-libraries/waltid-openid4vc/README.md b/waltid-libraries/protocols/waltid-openid4vc/README.md similarity index 100% rename from waltid-libraries/waltid-openid4vc/README.md rename to waltid-libraries/protocols/waltid-openid4vc/README.md diff --git a/waltid-libraries/waltid-openid4vc/architecture.png b/waltid-libraries/protocols/waltid-openid4vc/architecture.png similarity index 100% rename from waltid-libraries/waltid-openid4vc/architecture.png rename to waltid-libraries/protocols/waltid-openid4vc/architecture.png diff --git a/waltid-libraries/waltid-openid4vc/build.gradle.kts b/waltid-libraries/protocols/waltid-openid4vc/build.gradle.kts similarity index 95% rename from waltid-libraries/waltid-openid4vc/build.gradle.kts rename to waltid-libraries/protocols/waltid-openid4vc/build.gradle.kts index f46d79e5c..ee68596eb 100644 --- a/waltid-libraries/waltid-openid4vc/build.gradle.kts +++ b/waltid-libraries/protocols/waltid-openid4vc/build.gradle.kts @@ -99,10 +99,10 @@ kotlin { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") // walt.id - implementation(project(":waltid-libraries:waltid-crypto")) - implementation(project(":waltid-libraries:waltid-mdoc-credentials")) + implementation(project(":waltid-libraries:crypto:waltid-crypto")) + implementation(project(":waltid-libraries:credentials:waltid-mdoc-credentials")) implementation(project(":waltid-libraries:waltid-did")) - implementation(project(":waltid-libraries:waltid-sdjwt")) + implementation(project(":waltid-libraries:sdjwt:waltid-sdjwt")) // -- Multiplatform -- // Multiplatform / UUID @@ -119,9 +119,9 @@ kotlin { val commonTest by getting { dependencies { implementation(kotlin("test")) - implementation(project(":waltid-libraries:waltid-crypto")) + implementation(project(":waltid-libraries:crypto:waltid-crypto")) implementation(project(":waltid-libraries:waltid-did")) - implementation(project(":waltid-libraries:waltid-verifiable-credentials")) + implementation(project(":waltid-libraries:credentials:waltid-verifiable-credentials")) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1") } } diff --git a/waltid-libraries/waltid-openid4vc/oid4vci.seq b/waltid-libraries/protocols/waltid-openid4vc/oid4vci.seq similarity index 100% rename from waltid-libraries/waltid-openid4vc/oid4vci.seq rename to waltid-libraries/protocols/waltid-openid4vc/oid4vci.seq diff --git a/waltid-libraries/waltid-openid4vc/oid4vp.seq b/waltid-libraries/protocols/waltid-openid4vc/oid4vp.seq similarity index 100% rename from waltid-libraries/waltid-openid4vc/oid4vp.seq rename to waltid-libraries/protocols/waltid-openid4vc/oid4vp.seq diff --git a/waltid-libraries/waltid-openid4vc/openid4vp.png b/waltid-libraries/protocols/waltid-openid4vc/openid4vp.png similarity index 100% rename from waltid-libraries/waltid-openid4vc/openid4vp.png rename to waltid-libraries/protocols/waltid-openid4vc/openid4vp.png diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VP.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VP.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VP.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VP.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/Values.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/Values.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/Values.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/Values.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AccessTokenScope.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AccessTokenScope.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AccessTokenScope.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AccessTokenScope.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AuthorizationDetails.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AuthorizationDetails.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AuthorizationDetails.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/AuthorizationDetails.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClaimDescriptor.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClaimDescriptor.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClaimDescriptor.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClaimDescriptor.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientIdScheme.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientIdScheme.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientIdScheme.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientIdScheme.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientMetadataParameter.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientMetadataParameter.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientMetadataParameter.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ClientMetadataParameter.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialFormat.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialFormat.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialFormat.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialFormat.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialOffer.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialOffer.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialOffer.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialOffer.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialSupported.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialSupported.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialSupported.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/CredentialSupported.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DisplayProperties.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DisplayProperties.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DisplayProperties.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DisplayProperties.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DurationInSecondsSerializer.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DurationInSecondsSerializer.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DurationInSecondsSerializer.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/DurationInSecondsSerializer.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantDetails.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantDetails.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantDetails.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantDetails.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantType.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantType.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantType.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/GrantType.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/HTTPDataObject.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/HTTPDataObject.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/HTTPDataObject.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/HTTPDataObject.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonDataObject.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonDataObject.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonDataObject.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonDataObject.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonLDCredentialDefinition.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonLDCredentialDefinition.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonLDCredentialDefinition.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/JsonLDCredentialDefinition.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/LogoProperties.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/LogoProperties.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/LogoProperties.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/LogoProperties.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OfferedCredential.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OfferedCredential.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OfferedCredential.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OfferedCredential.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDClientMetadata.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDClientMetadata.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDClientMetadata.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDClientMetadata.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDProviderMetadata.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDProviderMetadata.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDProviderMetadata.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenIDProviderMetadata.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenId4VPProfile.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenId4VPProfile.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenId4VPProfile.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/OpenId4VPProfile.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/PresentationDefinitionParameter.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/PresentationDefinitionParameter.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/PresentationDefinitionParameter.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/PresentationDefinitionParameter.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ProofOfPossession.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ProofOfPossession.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ProofOfPossession.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ProofOfPossession.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseMode.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseMode.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseMode.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseMode.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseType.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseType.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseType.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/ResponseType.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SubjectType.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SubjectType.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SubjectType.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SubjectType.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SupportedVPFormat.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SupportedVPFormat.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SupportedVPFormat.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/SupportedVPFormat.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/TxCode.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/TxCode.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/TxCode.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/TxCode.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/VpTokenParameter.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/VpTokenParameter.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/VpTokenParameter.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/VpTokenParameter.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DescriptorMapping.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DescriptorMapping.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DescriptorMapping.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DescriptorMapping.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DisclosureLimitation.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DisclosureLimitation.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DisclosureLimitation.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/DisclosureLimitation.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptor.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptor.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptor.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptor.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorConstraints.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorConstraints.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorConstraints.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorConstraints.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorField.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorField.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorField.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorField.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorSchema.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorSchema.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorSchema.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/InputDescriptorSchema.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/OutputDescriptor.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/OutputDescriptor.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/OutputDescriptor.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/OutputDescriptor.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationDefinition.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationDefinition.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationDefinition.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationDefinition.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationSubmission.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationSubmission.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationSubmission.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/PresentationSubmission.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirement.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirement.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirement.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirement.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirementRule.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirementRule.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirementRule.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/SubmissionRequirementRule.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/VCFormat.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/VCFormat.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/VCFormat.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/data/dif/VCFormat.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/JWTClaims.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/JWTClaims.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/JWTClaims.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/JWTClaims.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/OIDCDefinitions.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/OIDCDefinitions.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/OIDCDefinitions.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/definitions/OIDCDefinitions.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/AuthorizationError.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/AuthorizationError.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/AuthorizationError.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/AuthorizationError.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialError.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialError.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialError.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialError.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialOfferError.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialOfferError.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialOfferError.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/CredentialOfferError.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/PresentationError.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/PresentationError.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/PresentationError.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/PresentationError.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/TokenError.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/TokenError.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/TokenError.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/errors/TokenError.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ICredentialProvider.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ICredentialProvider.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ICredentialProvider.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ICredentialProvider.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IHttpClient.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IHttpClient.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IHttpClient.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IHttpClient.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ISessionCache.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ISessionCache.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ISessionCache.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ISessionCache.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/ITokenProvider.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IVPTokenProvider.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IVPTokenProvider.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IVPTokenProvider.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/interfaces/IVPTokenProvider.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/AuthorizationSession.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/AuthorizationSession.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/AuthorizationSession.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/AuthorizationSession.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialIssuerConfig.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialIssuerConfig.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialIssuerConfig.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialIssuerConfig.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialVerifierConfig.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialVerifierConfig.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialVerifierConfig.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialVerifierConfig.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialWalletConfig.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialWalletConfig.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialWalletConfig.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/CredentialWalletConfig.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/IssuanceSession.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/IssuanceSession.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/IssuanceSession.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/IssuanceSession.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDClientConfig.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDClientConfig.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDClientConfig.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDClientConfig.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialIssuer.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialIssuer.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialIssuer.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialIssuer.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialVerifier.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialVerifier.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialVerifier.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialVerifier.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialWallet.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialWallet.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialWallet.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDCredentialWallet.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProvider.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProvider.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProvider.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProvider.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProviderConfig.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProviderConfig.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProviderConfig.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/OpenIDProviderConfig.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/PresentationSession.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/PresentationSession.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/PresentationSession.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/PresentationSession.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/SIOPSession.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/SIOPSession.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/SIOPSession.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/SIOPSession.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/TokenTarget.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/TokenTarget.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/TokenTarget.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/providers/TokenTarget.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationJSONRequest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationJSONRequest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationJSONRequest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationJSONRequest.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationRequest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationRequest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationRequest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/AuthorizationRequest.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/BatchCredentialRequest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/BatchCredentialRequest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/BatchCredentialRequest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/BatchCredentialRequest.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialOfferRequest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialOfferRequest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialOfferRequest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialOfferRequest.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialRequest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialRequest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialRequest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/CredentialRequest.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/EntraIssuanceRequest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/EntraIssuanceRequest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/EntraIssuanceRequest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/EntraIssuanceRequest.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/TokenRequest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/TokenRequest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/TokenRequest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/requests/TokenRequest.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeIDTokenRequestResponse.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeIDTokenRequestResponse.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeIDTokenRequestResponse.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeIDTokenRequestResponse.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeResponse.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeResponse.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeResponse.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationCodeResponse.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationDirectPostResponse.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationDirectPostResponse.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationDirectPostResponse.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/AuthorizationDirectPostResponse.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/BatchCredentialResponse.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/BatchCredentialResponse.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/BatchCredentialResponse.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/BatchCredentialResponse.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/CredentialResponse.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/CredentialResponse.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/CredentialResponse.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/CredentialResponse.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/EntraIssuanceCompletionResponse.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/EntraIssuanceCompletionResponse.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/EntraIssuanceCompletionResponse.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/EntraIssuanceCompletionResponse.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/PushedAuthorizationResponse.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/PushedAuthorizationResponse.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/PushedAuthorizationResponse.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/PushedAuthorizationResponse.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/TokenResponse.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/TokenResponse.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/TokenResponse.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/responses/TokenResponse.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/HttpUtils.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/HttpUtils.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/HttpUtils.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/HttpUtils.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/ShortIdUtils.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/ShortIdUtils.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/ShortIdUtils.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/ShortIdUtils.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/Sqids.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/Sqids.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/Sqids.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/Sqids.kt diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/UuidUtils.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/UuidUtils.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/UuidUtils.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/UuidUtils.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CITestProvider.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CITestProvider.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CITestProvider.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CITestProvider.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CI_JVM_Test.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CI_JVM_Test.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CI_JVM_Test.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/CI_JVM_Test.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSITestWallet.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSITestWallet.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSITestWallet.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSITestWallet.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Conformance_Test.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Conformance_Test.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Conformance_Test.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Conformance_Test.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Issue_To_Holder.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Issue_To_Holder.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Issue_To_Holder.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/EBSI_Issue_To_Holder.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/MDoc_Test.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/MDoc_Test.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/MDoc_Test.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/MDoc_Test.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/SessionIdUtilTest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/SessionIdUtilTest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/SessionIdUtilTest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/SessionIdUtilTest.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/TestCredentialWallet.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/TestCredentialWallet.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/TestCredentialWallet.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/TestCredentialWallet.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VPTestVerifier.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VPTestVerifier.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VPTestVerifier.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VPTestVerifier.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VP_JVM_Test.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VP_JVM_Test.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VP_JVM_Test.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/VP_JVM_Test.kt diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/wallettest.kt b/waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/wallettest.kt similarity index 100% rename from waltid-libraries/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/wallettest.kt rename to waltid-libraries/protocols/waltid-openid4vc/src/jvmTest/kotlin/id/walt/oid4vc/wallettest.kt diff --git a/waltid-libraries/waltid-openid4vc/waltid_openid4vc.podspec b/waltid-libraries/protocols/waltid-openid4vc/waltid_openid4vc.podspec similarity index 100% rename from waltid-libraries/waltid-openid4vc/waltid_openid4vc.podspec rename to waltid-libraries/protocols/waltid-openid4vc/waltid_openid4vc.podspec diff --git a/waltid-libraries/waltid-sdjwt-ios/build.gradle.kts b/waltid-libraries/sdjwt/waltid-sdjwt-ios/build.gradle.kts similarity index 95% rename from waltid-libraries/waltid-sdjwt-ios/build.gradle.kts rename to waltid-libraries/sdjwt/waltid-sdjwt-ios/build.gradle.kts index a2a9f2a97..707db6f6c 100644 --- a/waltid-libraries/waltid-sdjwt-ios/build.gradle.kts +++ b/waltid-libraries/sdjwt/waltid-sdjwt-ios/build.gradle.kts @@ -44,7 +44,7 @@ kotlin { iosArm64Main.dependsOn(this) iosSimulatorArm64Main.dependsOn(this) dependencies { - api(project(":waltid-libraries:waltid-sdjwt")) + api(project(":waltid-libraries:sdjwt:waltid-sdjwt")) implementation(project(":waltid-libraries:waltid-crypto-ios")) } } @@ -58,4 +58,4 @@ kotlin { iosSimulatorArm64Test.dependsOn(this) } } -} \ No newline at end of file +} diff --git a/waltid-libraries/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/DigitalSignaturesJWTCryptoProvider.kt b/waltid-libraries/sdjwt/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/DigitalSignaturesJWTCryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/DigitalSignaturesJWTCryptoProvider.kt rename to waltid-libraries/sdjwt/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/DigitalSignaturesJWTCryptoProvider.kt diff --git a/waltid-libraries/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/HMACJWTCryptoProvider.kt b/waltid-libraries/sdjwt/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/HMACJWTCryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/HMACJWTCryptoProvider.kt rename to waltid-libraries/sdjwt/waltid-sdjwt-ios/src/iosMain/kotlin/id/walt/sdjwt/HMACJWTCryptoProvider.kt diff --git a/waltid-libraries/waltid-sdjwt-ios/src/iosTest/kotlin/SDJwtTestIOS.kt b/waltid-libraries/sdjwt/waltid-sdjwt-ios/src/iosTest/kotlin/SDJwtTestIOS.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt-ios/src/iosTest/kotlin/SDJwtTestIOS.kt rename to waltid-libraries/sdjwt/waltid-sdjwt-ios/src/iosTest/kotlin/SDJwtTestIOS.kt diff --git a/waltid-libraries/waltid-sdjwt/.gitignore b/waltid-libraries/sdjwt/waltid-sdjwt/.gitignore similarity index 100% rename from waltid-libraries/waltid-sdjwt/.gitignore rename to waltid-libraries/sdjwt/waltid-sdjwt/.gitignore diff --git a/waltid-libraries/waltid-sdjwt/LICENSE b/waltid-libraries/sdjwt/waltid-sdjwt/LICENSE similarity index 100% rename from waltid-libraries/waltid-sdjwt/LICENSE rename to waltid-libraries/sdjwt/waltid-sdjwt/LICENSE diff --git a/waltid-libraries/waltid-sdjwt/README.md b/waltid-libraries/sdjwt/waltid-sdjwt/README.md similarity index 100% rename from waltid-libraries/waltid-sdjwt/README.md rename to waltid-libraries/sdjwt/waltid-sdjwt/README.md diff --git a/waltid-libraries/waltid-sdjwt/build.gradle.kts b/waltid-libraries/sdjwt/waltid-sdjwt/build.gradle.kts similarity index 100% rename from waltid-libraries/waltid-sdjwt/build.gradle.kts rename to waltid-libraries/sdjwt/waltid-sdjwt/build.gradle.kts diff --git a/waltid-libraries/waltid-sdjwt/examples/js/index.js b/waltid-libraries/sdjwt/waltid-sdjwt/examples/js/index.js similarity index 100% rename from waltid-libraries/waltid-sdjwt/examples/js/index.js rename to waltid-libraries/sdjwt/waltid-sdjwt/examples/js/index.js diff --git a/waltid-libraries/waltid-sdjwt/examples/js/package.json b/waltid-libraries/sdjwt/waltid-sdjwt/examples/js/package.json similarity index 100% rename from waltid-libraries/waltid-sdjwt/examples/js/package.json rename to waltid-libraries/sdjwt/waltid-sdjwt/examples/js/package.json diff --git a/waltid-libraries/waltid-sdjwt/gradlew b/waltid-libraries/sdjwt/waltid-sdjwt/gradlew similarity index 100% rename from waltid-libraries/waltid-sdjwt/gradlew rename to waltid-libraries/sdjwt/waltid-sdjwt/gradlew diff --git a/waltid-libraries/waltid-sdjwt/gradlew.bat b/waltid-libraries/sdjwt/waltid-sdjwt/gradlew.bat similarity index 100% rename from waltid-libraries/waltid-sdjwt/gradlew.bat rename to waltid-libraries/sdjwt/waltid-sdjwt/gradlew.bat diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/Values.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/Values.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/Values.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/Values.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/AsyncJWTCryptoProvider.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/AsyncJWTCryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/AsyncJWTCryptoProvider.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/AsyncJWTCryptoProvider.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/DecoyMode.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/DecoyMode.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/DecoyMode.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/DecoyMode.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTCryptoProvider.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTCryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTCryptoProvider.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/JWTCryptoProvider.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDField.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDField.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDField.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDField.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMap.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMap.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMap.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMap.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMapBuilder.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMapBuilder.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMapBuilder.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDMapBuilder.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDPayload.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDisclosure.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SdjwtStringUtils.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/VerificationResult.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/VerificationResult.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/VerificationResult.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/VerificationResult.kt diff --git a/waltid-libraries/waltid-sdjwt/src/commonTest/kotlin/id/walt/sdjwt/SDJwtTest.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonTest/kotlin/id/walt/sdjwt/SDJwtTest.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/commonTest/kotlin/id/walt/sdjwt/SDJwtTest.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/commonTest/kotlin/id/walt/sdjwt/SDJwtTest.kt diff --git a/waltid-libraries/waltid-sdjwt/src/iosMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/iosMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/iosMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/iosMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JSAsyncJWTCryptoProvider.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JSAsyncJWTCryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JSAsyncJWTCryptoProvider.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JSAsyncJWTCryptoProvider.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDJwtJS.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDJwtJS.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDJwtJS.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDJwtJS.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDMapBuilderJS.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDMapBuilderJS.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDMapBuilderJS.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDMapBuilderJS.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDPayloadBuilder.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDPayloadBuilder.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDPayloadBuilder.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SDPayloadBuilder.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SimpleAsyncJWTCryptoProvider.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SimpleAsyncJWTCryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SimpleAsyncJWTCryptoProvider.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/SimpleAsyncJWTCryptoProvider.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/jose.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/jose.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/jose.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jsMain/kotlin/id/walt/sdjwt/jose.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jsTest/kotlin/id.walt.sdjwt/SDJwtTestJS.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jsTest/kotlin/id.walt.sdjwt/SDJwtTestJS.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jsTest/kotlin/id.walt.sdjwt/SDJwtTestJS.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jsTest/kotlin/id.walt.sdjwt/SDJwtTestJS.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/SimpleJWTCryptoProvider.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/SimpleJWTCryptoProvider.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/SimpleJWTCryptoProvider.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jvmMain/kotlin/id/walt/sdjwt/SimpleJWTCryptoProvider.kt diff --git a/waltid-libraries/waltid-sdjwt/src/jvmTest/kotlin/id/walt/sdjwt/SDJwtTestJVM.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/jvmTest/kotlin/id/walt/sdjwt/SDJwtTestJVM.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/jvmTest/kotlin/id/walt/sdjwt/SDJwtTestJVM.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/jvmTest/kotlin/id/walt/sdjwt/SDJwtTestJVM.kt diff --git a/waltid-libraries/waltid-sdjwt/src/nativeMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/nativeMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt similarity index 100% rename from waltid-libraries/waltid-sdjwt/src/nativeMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt rename to waltid-libraries/sdjwt/waltid-sdjwt/src/nativeMain/kotlin/id/walt/sdjwt/JWTClaimsSet.kt diff --git a/waltid-libraries/waltid-sdjwt/waltid_sdjwt.podspec b/waltid-libraries/sdjwt/waltid-sdjwt/waltid_sdjwt.podspec similarity index 100% rename from waltid-libraries/waltid-sdjwt/waltid_sdjwt.podspec rename to waltid-libraries/sdjwt/waltid-sdjwt/waltid_sdjwt.podspec diff --git a/waltid-libraries/waltid-reporting/build.gradle.kts b/waltid-libraries/util/waltid-reporting/build.gradle.kts similarity index 100% rename from waltid-libraries/waltid-reporting/build.gradle.kts rename to waltid-libraries/util/waltid-reporting/build.gradle.kts diff --git a/waltid-libraries/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/ReportingClient.kt b/waltid-libraries/util/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/ReportingClient.kt similarity index 100% rename from waltid-libraries/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/ReportingClient.kt rename to waltid-libraries/util/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/ReportingClient.kt diff --git a/waltid-libraries/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Events.kt b/waltid-libraries/util/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Events.kt similarity index 100% rename from waltid-libraries/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Events.kt rename to waltid-libraries/util/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Events.kt diff --git a/waltid-libraries/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Stats.kt b/waltid-libraries/util/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Stats.kt similarity index 100% rename from waltid-libraries/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Stats.kt rename to waltid-libraries/util/waltid-reporting/src/commonMain/kotlin/id/walt/reporting/models/Stats.kt diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ecdsa-vault.public.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ecdsa-vault.public.pem deleted file mode 100644 index d0a5966b4..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ecdsa-vault.public.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE87jhtMa/W0cHSEukQmKECq3ZstG7Y0ZhOAjNHTDvLA6Chq6RvF1Z/U1sRPTqvoEP65/mVaFVDR9H3+I4toJVcw== ------END PUBLIC KEY----- \ No newline at end of file diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ed25519.private.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ed25519.private.pem deleted file mode 100644 index 42dac5dea..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ed25519.private.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIJpchqgaS5BrgnM/AfWg9DJp6iE/spWXuQhea3+FIlyH ------END PRIVATE KEY----- ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEA51sbDqo0X6YccLaxupF+QCR2Oz853AVGIwbXBOU77rU= ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ed25519.public.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ed25519.public.pem deleted file mode 100644 index f859e806b..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/ed25519.public.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEA51sbDqo0X6YccLaxupF+QCR2Oz853AVGIwbXBOU77rU= ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa-vault.public.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa-vault.public.pem deleted file mode 100644 index 473cbb578..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa-vault.public.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8Lw8l1t6Q037FkOhkeKU1IOtRTRpwvCV2tuHhmH4jm9SVvj1XM4xG0Pb3zFg3by5d/WIijCJdbozHuP4xWARsbm4jMg5mVcpzbdeLww3V0Nzi3kq7cKEJ0A87SDzAlcOhqqyAKdFYD9hzylVMdrSQo/fv02tHKS62wQZKi1fWDiJ8q/Qrj+T7UySRhCp/mBCv5IYDgCz2QMz7BZcEWLCGvrpD4cmP3N0oFEPX7cSexXRJaG0KBuTRE0RtpoClv69XFdvEDkbCZvyI/DfJo1F9UVaFaTarmvSr6uLV1XVV/lm3SJGxZ93p1Z7fLU5I+RrTdgcGSDkmaMO1LyP7ovdJwIDAQAB ------END PUBLIC KEY----- \ No newline at end of file diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa.private.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa.private.pem deleted file mode 100644 index e9541a0a0..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa.private.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAqV+fGqTo8r6L52sIJpt44bxLkODaF0/wvIL/eYYDL55H+Ap+ -b1q4pd4YyZb7pARor/1mob6sMRnnAr5htmO1XucmKBEiNY+12zza0q9smjLm3+eN -qq+8PgsEqBz4lU1YIBeQzsCR0NTa3J3OHfr+bADVystQeonSPoRLqSoO78oAtonQ -WLX1MUfS9778+ECcxlM21+JaUjqMD0nQR6wl8L6oWGcR7PjcjPQAyuS/ASTy7MO0 -SqunpkGzj/H7uFbK9Np/dLIOr9ZqrkCSdioA/PgDyk36E8ayuMnN1HDy4ak/Q7yE -X4R/C75T0JxuuYio06hugwyREgOQNID+DVUoLwIDAQABAoIBAQCGd1HbV11RipGL -0l+QNxJLNLBRfxHmPCMFpoKougpBfcnpVHt4cG/zz1WihemWF6H9RpJ6iuQtv0C1 -3uu4X4SYqa6TVLbyCvv36GJZrcfsy8ibrju8bPRn1VuHFCkOb28tW0gtvJiHUNXJ -HMeM6b2fhTI2ZB+qiUyPMXzX+noNR+mQxwMElKWxOZEoxY8bS7yYWbxoH1l+1uvI -87fpA6fLuDj8zxJkbXLEZNvKmPINM/1aoyYeloL7rqAuzOPLHARtWHr2b4ewMSzt -CD2gxUbYWLC0NJcgCnB8uTa/ZiTj5N4APj2tnPD5BwnTKo95V2rxyDIU6HBf5w+1 -AibxfsCBAoGBANGzaSc8zjoM6amlpG/uT7lIGPQHnVLJ83tuALbpF2jfVWO3uQS2 -HGxNdURnso/JJIaaLb2UOlq2BH70pH8Qb6FXNavOhV4qpacJlC/v4zuAW4BEjivX -mlj9Ylplja2aasHZyHhd1WR3wiKBcUVf02/0qfFDUrnhYAh+iFSZX8EhAoGBAM7E -2q0WKPZSxPF786Rs6Y7azh7Jy7pNp+Rlz+jNl/PQS/MnPP+RaffZvxJvbxgDoWQS -vQHLWbmRBklVYX1dSJhsNe7S8kGUggL0s0KWUmKU/RA3mYJ/6EqK31IDCqaZtV+K -5eWM+5TEdZIZY3Srf1+oBQOgAy9ofwEStWwUY69PAoGBAJTn6k5jfil4i9/ccHTO -66usx5NZaNyl7RCDn1xDDk148UCa8HWo/2vkYNYPMJurgBVYnAxXmkxZnb2s6LYV -rL8Ll2AFiWzBqdmAEssrc9cHoXHmvHHjaoWwf8ui+0UANriqdhEKyIHMDH3GHvHd -Rt3kBVz9qlu17yR4/UPdmUIhAoGAE7TDOpfQE5nT10f+8n7Gy6yi1GBbIEhiZewm -IoPlpYEGnAfzUlAjj1GbWkBwkBNYgFcg2FjvFjZyKO8QOYh4cL5vbXGBUSq8MVfs -9b2p4Gdervr9kGhsVR5jJkfP7gzcMlzkiDoliAopQmFVDzuBCjbTM4M+inglEo8b -508SKRUCgYBomwMGHFAUNulCvbROODEibAGyVU/3Ehq7LedwKaMeLHoVzWXnWAvv -VXU5YaddpK0Z+hbLSAqRScm5Tf9f/ED9DDMBc8lhr6O5GUPwHFN/uuZH8cL5eJV3 -I2eRTdp8e0ridKFLYS43YRc6tgOttCgDXf9roi2T/nm8OkneNyLBLw== ------END RSA PRIVATE KEY----- diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa.public.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa.public.pem deleted file mode 100644 index bf92d7c66..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/rsa.public.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqV+fGqTo8r6L52sIJpt4 -4bxLkODaF0/wvIL/eYYDL55H+Ap+b1q4pd4YyZb7pARor/1mob6sMRnnAr5htmO1 -XucmKBEiNY+12zza0q9smjLm3+eNqq+8PgsEqBz4lU1YIBeQzsCR0NTa3J3OHfr+ -bADVystQeonSPoRLqSoO78oAtonQWLX1MUfS9778+ECcxlM21+JaUjqMD0nQR6wl -8L6oWGcR7PjcjPQAyuS/ASTy7MO0SqunpkGzj/H7uFbK9Np/dLIOr9ZqrkCSdioA -/PgDyk36E8ayuMnN1HDy4ak/Q7yEX4R/C75T0JxuuYio06hugwyREgOQNID+DVUo -LwIDAQAB ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256k1.private.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256k1.private.pem deleted file mode 100644 index 4421e70b0..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256k1.private.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN PRIVATE KEY----- -MEcCAQAwEAYHKoZIzj0CAQYFK4EEAAoEMDAuAgEBBCDhRhzY9+4kOgOm1G2RpZic -YVT21rrpZiGhMcTLFJ1HRaAHBgUrgQQACg== ------END PRIVATE KEY----- ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAErWTFQycS7uhkDiKuOv4RLduQkwsTuuoC -PyEMJwLmBFV5mngn1GEkEJxOi0US0SD+/W/ShHyMPzqlbei99XC4mA== ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256k1.public.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256k1.public.pem deleted file mode 100644 index d2b4ed63d..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256k1.public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIjAomwz3PFqdqjHR5e22P6tfd/VPqEjA -PZ3d+ydEZApySmPqX2CUtSpeB9EGsxF7eDOZv2b9ZLdNTmhyIIrW4w== ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256r1.private.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256r1.private.pem deleted file mode 100644 index 16f60d95d..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256r1.private.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg1K0LxD5eCTxD0RQA -DLbSmdBtr4Mu6pA9uAM9iotuKZKgCgYIKoZIzj0DAQehRANCAAS6jz3oejnvRQ/b -jHLI23t0TdTqoeUM0m2HQdz+7+4nYfT7uBHIgsck4fXlRMWtBZyYiWefM0CmUz53 -yl6VjAra ------END PRIVATE KEY----- ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuo896Ho570UP24xyyNt7dE3U6qHl -DNJth0Hc/u/uJ2H0+7gRyILHJOH15UTFrQWcmIlnnzNAplM+d8pelYwK2g== ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256r1.public.pem b/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256r1.public.pem deleted file mode 100644 index 2de7b065c..000000000 --- a/waltid-libraries/waltid-crypto-oci/src/jvmTest/resources/pem/secp256r1.public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuo896Ho570UP24xyyNt7dE3U6qHl -DNJth0Hc/u/uJ2H0+7gRyILHJOH15UTFrQWcmIlnnzNAplM+d8pelYwK2g== ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ecdsa-vault.public.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ecdsa-vault.public.pem deleted file mode 100644 index d0a5966b4..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ecdsa-vault.public.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE87jhtMa/W0cHSEukQmKECq3ZstG7Y0ZhOAjNHTDvLA6Chq6RvF1Z/U1sRPTqvoEP65/mVaFVDR9H3+I4toJVcw== ------END PUBLIC KEY----- \ No newline at end of file diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ed25519.private.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ed25519.private.pem deleted file mode 100644 index 42dac5dea..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ed25519.private.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIJpchqgaS5BrgnM/AfWg9DJp6iE/spWXuQhea3+FIlyH ------END PRIVATE KEY----- ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEA51sbDqo0X6YccLaxupF+QCR2Oz853AVGIwbXBOU77rU= ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ed25519.public.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ed25519.public.pem deleted file mode 100644 index f859e806b..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/ed25519.public.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEA51sbDqo0X6YccLaxupF+QCR2Oz853AVGIwbXBOU77rU= ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa-vault.public.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa-vault.public.pem deleted file mode 100644 index 473cbb578..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa-vault.public.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8Lw8l1t6Q037FkOhkeKU1IOtRTRpwvCV2tuHhmH4jm9SVvj1XM4xG0Pb3zFg3by5d/WIijCJdbozHuP4xWARsbm4jMg5mVcpzbdeLww3V0Nzi3kq7cKEJ0A87SDzAlcOhqqyAKdFYD9hzylVMdrSQo/fv02tHKS62wQZKi1fWDiJ8q/Qrj+T7UySRhCp/mBCv5IYDgCz2QMz7BZcEWLCGvrpD4cmP3N0oFEPX7cSexXRJaG0KBuTRE0RtpoClv69XFdvEDkbCZvyI/DfJo1F9UVaFaTarmvSr6uLV1XVV/lm3SJGxZ93p1Z7fLU5I+RrTdgcGSDkmaMO1LyP7ovdJwIDAQAB ------END PUBLIC KEY----- \ No newline at end of file diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa.private.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa.private.pem deleted file mode 100644 index e9541a0a0..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa.private.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAqV+fGqTo8r6L52sIJpt44bxLkODaF0/wvIL/eYYDL55H+Ap+ -b1q4pd4YyZb7pARor/1mob6sMRnnAr5htmO1XucmKBEiNY+12zza0q9smjLm3+eN -qq+8PgsEqBz4lU1YIBeQzsCR0NTa3J3OHfr+bADVystQeonSPoRLqSoO78oAtonQ -WLX1MUfS9778+ECcxlM21+JaUjqMD0nQR6wl8L6oWGcR7PjcjPQAyuS/ASTy7MO0 -SqunpkGzj/H7uFbK9Np/dLIOr9ZqrkCSdioA/PgDyk36E8ayuMnN1HDy4ak/Q7yE -X4R/C75T0JxuuYio06hugwyREgOQNID+DVUoLwIDAQABAoIBAQCGd1HbV11RipGL -0l+QNxJLNLBRfxHmPCMFpoKougpBfcnpVHt4cG/zz1WihemWF6H9RpJ6iuQtv0C1 -3uu4X4SYqa6TVLbyCvv36GJZrcfsy8ibrju8bPRn1VuHFCkOb28tW0gtvJiHUNXJ -HMeM6b2fhTI2ZB+qiUyPMXzX+noNR+mQxwMElKWxOZEoxY8bS7yYWbxoH1l+1uvI -87fpA6fLuDj8zxJkbXLEZNvKmPINM/1aoyYeloL7rqAuzOPLHARtWHr2b4ewMSzt -CD2gxUbYWLC0NJcgCnB8uTa/ZiTj5N4APj2tnPD5BwnTKo95V2rxyDIU6HBf5w+1 -AibxfsCBAoGBANGzaSc8zjoM6amlpG/uT7lIGPQHnVLJ83tuALbpF2jfVWO3uQS2 -HGxNdURnso/JJIaaLb2UOlq2BH70pH8Qb6FXNavOhV4qpacJlC/v4zuAW4BEjivX -mlj9Ylplja2aasHZyHhd1WR3wiKBcUVf02/0qfFDUrnhYAh+iFSZX8EhAoGBAM7E -2q0WKPZSxPF786Rs6Y7azh7Jy7pNp+Rlz+jNl/PQS/MnPP+RaffZvxJvbxgDoWQS -vQHLWbmRBklVYX1dSJhsNe7S8kGUggL0s0KWUmKU/RA3mYJ/6EqK31IDCqaZtV+K -5eWM+5TEdZIZY3Srf1+oBQOgAy9ofwEStWwUY69PAoGBAJTn6k5jfil4i9/ccHTO -66usx5NZaNyl7RCDn1xDDk148UCa8HWo/2vkYNYPMJurgBVYnAxXmkxZnb2s6LYV -rL8Ll2AFiWzBqdmAEssrc9cHoXHmvHHjaoWwf8ui+0UANriqdhEKyIHMDH3GHvHd -Rt3kBVz9qlu17yR4/UPdmUIhAoGAE7TDOpfQE5nT10f+8n7Gy6yi1GBbIEhiZewm -IoPlpYEGnAfzUlAjj1GbWkBwkBNYgFcg2FjvFjZyKO8QOYh4cL5vbXGBUSq8MVfs -9b2p4Gdervr9kGhsVR5jJkfP7gzcMlzkiDoliAopQmFVDzuBCjbTM4M+inglEo8b -508SKRUCgYBomwMGHFAUNulCvbROODEibAGyVU/3Ehq7LedwKaMeLHoVzWXnWAvv -VXU5YaddpK0Z+hbLSAqRScm5Tf9f/ED9DDMBc8lhr6O5GUPwHFN/uuZH8cL5eJV3 -I2eRTdp8e0ridKFLYS43YRc6tgOttCgDXf9roi2T/nm8OkneNyLBLw== ------END RSA PRIVATE KEY----- diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa.public.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa.public.pem deleted file mode 100644 index bf92d7c66..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/rsa.public.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqV+fGqTo8r6L52sIJpt4 -4bxLkODaF0/wvIL/eYYDL55H+Ap+b1q4pd4YyZb7pARor/1mob6sMRnnAr5htmO1 -XucmKBEiNY+12zza0q9smjLm3+eNqq+8PgsEqBz4lU1YIBeQzsCR0NTa3J3OHfr+ -bADVystQeonSPoRLqSoO78oAtonQWLX1MUfS9778+ECcxlM21+JaUjqMD0nQR6wl -8L6oWGcR7PjcjPQAyuS/ASTy7MO0SqunpkGzj/H7uFbK9Np/dLIOr9ZqrkCSdioA -/PgDyk36E8ayuMnN1HDy4ak/Q7yEX4R/C75T0JxuuYio06hugwyREgOQNID+DVUo -LwIDAQAB ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256k1.private.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256k1.private.pem deleted file mode 100644 index 4421e70b0..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256k1.private.pem +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN PRIVATE KEY----- -MEcCAQAwEAYHKoZIzj0CAQYFK4EEAAoEMDAuAgEBBCDhRhzY9+4kOgOm1G2RpZic -YVT21rrpZiGhMcTLFJ1HRaAHBgUrgQQACg== ------END PRIVATE KEY----- ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAErWTFQycS7uhkDiKuOv4RLduQkwsTuuoC -PyEMJwLmBFV5mngn1GEkEJxOi0US0SD+/W/ShHyMPzqlbei99XC4mA== ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256k1.public.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256k1.public.pem deleted file mode 100644 index d2b4ed63d..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256k1.public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIjAomwz3PFqdqjHR5e22P6tfd/VPqEjA -PZ3d+ydEZApySmPqX2CUtSpeB9EGsxF7eDOZv2b9ZLdNTmhyIIrW4w== ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256r1.private.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256r1.private.pem deleted file mode 100644 index 16f60d95d..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256r1.private.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg1K0LxD5eCTxD0RQA -DLbSmdBtr4Mu6pA9uAM9iotuKZKgCgYIKoZIzj0DAQehRANCAAS6jz3oejnvRQ/b -jHLI23t0TdTqoeUM0m2HQdz+7+4nYfT7uBHIgsck4fXlRMWtBZyYiWefM0CmUz53 -yl6VjAra ------END PRIVATE KEY----- ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuo896Ho570UP24xyyNt7dE3U6qHl -DNJth0Hc/u/uJ2H0+7gRyILHJOH15UTFrQWcmIlnnzNAplM+d8pelYwK2g== ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256r1.public.pem b/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256r1.public.pem deleted file mode 100644 index 2de7b065c..000000000 --- a/waltid-libraries/waltid-crypto/src/jvmTest/resources/pem/secp256r1.public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuo896Ho570UP24xyyNt7dE3U6qHl -DNJth0Hc/u/uJ2H0+7gRyILHJOH15UTFrQWcmIlnnzNAplM+d8pelYwK2g== ------END PUBLIC KEY----- diff --git a/waltid-libraries/waltid-did/build.gradle.kts b/waltid-libraries/waltid-did/build.gradle.kts index 7736d83e4..821429251 100644 --- a/waltid-libraries/waltid-did/build.gradle.kts +++ b/waltid-libraries/waltid-did/build.gradle.kts @@ -109,7 +109,7 @@ kotlin { implementation("app.softwork:kotlinx-uuid-core:0.0.26") // Crypto - api(project(":waltid-libraries:waltid-crypto")) + api(project(":waltid-libraries:crypto:waltid-crypto")) // Encodings implementation("net.thauvin.erik.urlencoder:urlencoder-lib:1.5.0") diff --git a/waltid-services/waltid-issuer-api/build.gradle.kts b/waltid-services/waltid-issuer-api/build.gradle.kts index 45aee2cfd..7fb9682ba 100644 --- a/waltid-services/waltid-issuer-api/build.gradle.kts +++ b/waltid-services/waltid-issuer-api/build.gradle.kts @@ -95,14 +95,14 @@ dependencies { //testImplementation("io.ktor:ktor-server-tests-jvm:${Versions.KTOR_VERSION}") // OIDC - api(project(":waltid-libraries:waltid-openid4vc")) + api(project(":waltid-libraries:protocols:waltid-openid4vc")) // walt.id - api(project(":waltid-libraries:waltid-crypto")) + api(project(":waltid-libraries:crypto:waltid-crypto")) api(project(":waltid-libraries:waltid-did")) - api(project(":waltid-libraries:waltid-verifiable-credentials")) - api(project(":waltid-libraries:waltid-sdjwt")) + api(project(":waltid-libraries:credentials:waltid-verifiable-credentials")) + api(project(":waltid-libraries:sdjwt:waltid-sdjwt")) } tasks.withType { diff --git a/waltid-services/waltid-verifier-api/build.gradle.kts b/waltid-services/waltid-verifier-api/build.gradle.kts index 94ce12319..82eee2b45 100644 --- a/waltid-services/waltid-verifier-api/build.gradle.kts +++ b/waltid-services/waltid-verifier-api/build.gradle.kts @@ -103,13 +103,13 @@ dependencies { testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.COROUTINES_VERSION}") // OIDC - api(project(":waltid-libraries:waltid-openid4vc")) + api(project(":waltid-libraries:protocols:waltid-openid4vc")) // SSI Kit 2 - api(project(":waltid-libraries:waltid-crypto")) - api(project(":waltid-libraries:waltid-verifiable-credentials")) + api(project(":waltid-libraries:crypto:waltid-crypto")) + api(project(":waltid-libraries:credentials:waltid-verifiable-credentials")) api(project(":waltid-libraries:waltid-did")) - api(project(":waltid-libraries:waltid-mdoc-credentials")) + api(project(":waltid-libraries:credentials:waltid-mdoc-credentials")) } tasks.withType { isZip64 = true diff --git a/waltid-services/waltid-wallet-api/build.gradle.kts b/waltid-services/waltid-wallet-api/build.gradle.kts index c9be6df44..acd0c230c 100644 --- a/waltid-services/waltid-wallet-api/build.gradle.kts +++ b/waltid-services/waltid-wallet-api/build.gradle.kts @@ -115,11 +115,11 @@ dependencies { // OIDC - implementation(project(":waltid-libraries:waltid-openid4vc")) - implementation(project(":waltid-libraries:waltid-sdjwt")) + implementation(project(":waltid-libraries:protocols:waltid-openid4vc")) + implementation(project(":waltid-libraries:sdjwt:waltid-sdjwt")) - implementation(project(":waltid-libraries:waltid-crypto")) - implementation(project(":waltid-libraries:waltid-crypto-oci")) + implementation(project(":waltid-libraries:crypto:waltid-crypto")) + implementation(project(":waltid-libraries:crypto:waltid-crypto-oci")) implementation(project(":waltid-libraries:waltid-did")) testImplementation(project(":waltid-services:waltid-issuer-api")) @@ -174,5 +174,4 @@ dependencies { testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1") testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version") testImplementation("io.mockk:mockk:1.13.12") - testImplementation("io.klogging:klogging-jvm:0.6.1") } From cb0363804325fffac1b7d8b6cd81e4c214a5a9c9 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:00:07 +0200 Subject: [PATCH 09/17] feat: add IDP Kit MVP --- .../auth/waltid-idpkit/.gitignore | 36 ++ .../auth/waltid-idpkit/build.gradle.kts | 52 ++ .../auth/waltid-idpkit/gradle.properties | 1 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + waltid-libraries/auth/waltid-idpkit/gradlew | 234 +++++++ .../auth/waltid-idpkit/gradlew.bat | 89 +++ .../auth/waltid-idpkit/settings.gradle.kts | 1 + .../src/main/kotlin/id/walt/Application.kt | 591 ++++++++++++++++++ .../src/main/resources/logback.xml | 12 + 10 files changed, 1021 insertions(+) create mode 100644 waltid-libraries/auth/waltid-idpkit/.gitignore create mode 100644 waltid-libraries/auth/waltid-idpkit/build.gradle.kts create mode 100644 waltid-libraries/auth/waltid-idpkit/gradle.properties create mode 100644 waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.jar create mode 100644 waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.properties create mode 100755 waltid-libraries/auth/waltid-idpkit/gradlew create mode 100644 waltid-libraries/auth/waltid-idpkit/gradlew.bat create mode 100644 waltid-libraries/auth/waltid-idpkit/settings.gradle.kts create mode 100644 waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Application.kt create mode 100644 waltid-libraries/auth/waltid-idpkit/src/main/resources/logback.xml diff --git a/waltid-libraries/auth/waltid-idpkit/.gitignore b/waltid-libraries/auth/waltid-idpkit/.gitignore new file mode 100644 index 000000000..c426c32f8 --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/.gitignore @@ -0,0 +1,36 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ \ No newline at end of file diff --git a/waltid-libraries/auth/waltid-idpkit/build.gradle.kts b/waltid-libraries/auth/waltid-idpkit/build.gradle.kts new file mode 100644 index 000000000..7d35d0222 --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/build.gradle.kts @@ -0,0 +1,52 @@ +plugins { + kotlin("jvm") + id("io.ktor.plugin") version "2.3.12" + kotlin("plugin.serialization") +} + +group = "id.walt" +version = "0.0.1" + +application { + mainClass.set("id.walt.ApplicationKt") + + val isDevelopment: Boolean = project.ext.has("development") + applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") +} + +repositories { + mavenCentral() +} + +dependencies { + // Ktor server + implementation("io.ktor:ktor-server-core") + implementation("io.ktor:ktor-server-cio") + implementation("io.ktor:ktor-server-sessions") + implementation("io.ktor:ktor-server-status-pages") + implementation("io.ktor:ktor-server-content-negotiation") + implementation("io.ktor:ktor-serialization-kotlinx-json") + implementation("io.ktor:ktor-server-call-logging") + implementation("io.ktor:ktor-server-double-receive") + + // Ktor client + implementation("io.ktor:ktor-client-core") + implementation("io.ktor:ktor-client-cio") + implementation("io.ktor:ktor-client-content-negotiation") + + // JSON + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0") + implementation("com.eygraber:jsonpathkt-kotlinx:3.0.2") + + // OIDC + implementation("com.nimbusds:oauth2-oidc-sdk:11.12") + implementation("com.nimbusds:nimbus-jose-jwt:9.40") + + // Logging + implementation("io.klogging:klogging-jvm:0.7.0") + implementation("io.klogging:slf4j-klogging:0.7.0") + + testImplementation("io.ktor:ktor-server-test-host-jvm") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit") +} diff --git a/waltid-libraries/auth/waltid-idpkit/gradle.properties b/waltid-libraries/auth/waltid-idpkit/gradle.properties new file mode 100644 index 000000000..7fc6f1ff2 --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/gradle.properties @@ -0,0 +1 @@ +kotlin.code.style=official diff --git a/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.jar b/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.properties b/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e411586a5 --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/waltid-libraries/auth/waltid-idpkit/gradlew b/waltid-libraries/auth/waltid-idpkit/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/waltid-libraries/auth/waltid-idpkit/gradlew.bat b/waltid-libraries/auth/waltid-idpkit/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/waltid-libraries/auth/waltid-idpkit/settings.gradle.kts b/waltid-libraries/auth/waltid-idpkit/settings.gradle.kts new file mode 100644 index 000000000..ebecacf52 --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "waltid-idpkit" diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Application.kt b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Application.kt new file mode 100644 index 000000000..f36f992ec --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Application.kt @@ -0,0 +1,591 @@ +package id.walt + +import kotlinx.serialization.json.* + +/* +import com.nimbusds.jose.JWSAlgorithm +import com.nimbusds.jose.JWSHeader +import com.nimbusds.jose.crypto.RSASSASigner +import com.nimbusds.jose.jwk.JWKSet +import com.nimbusds.jose.jwk.RSAKey +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator +import com.nimbusds.jwt.JWTClaimsSet +import com.nimbusds.jwt.SignedJWT +import com.nimbusds.oauth2.sdk.* +import com.nimbusds.oauth2.sdk.auth.ClientAuthentication +import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic +import com.nimbusds.oauth2.sdk.auth.ClientSecretPost +import com.nimbusds.oauth2.sdk.http.HTTPRequest +import com.nimbusds.oauth2.sdk.token.BearerAccessToken +import io.klogging.Level +import io.klogging.config.loggingConfiguration +import io.klogging.logger +import io.klogging.rendering.RENDER_ANSI +import io.klogging.sending.STDERR +import io.klogging.sending.STDOUT +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.application.* +import io.ktor.server.cio.* +import io.ktor.server.engine.* +import io.ktor.server.plugins.callloging.* +import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.plugins.statuspages.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.ktor.server.sessions.* +import io.ktor.server.util.* +import io.ktor.util.* +import kotlinx.datetime.Clock +import kotlinx.datetime.toJavaInstant +import kotlinx.serialization.Serializable +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.* +import java.net.URL +import java.util.Date +import java.util.UUID +import kotlin.time.Duration.Companion.seconds + +private val log = logger("walt.id IDP") + +data class UserSession(val id: String, val state: String) + +@Serializable +data class TokenStore( + val accessToken: String, + val tokenType: String, + val expiresIn: Long, + val idToken: String, + val issueTime: kotlinx.datetime.Instant, + val expirationTime: kotlinx.datetime.Instant, +) {*/ +/*fun toJSON(): String { + return Json.encodeToString(this) + }*//* + +} + +val tokenStore = mutableMapOf() + +fun main() { + loggingConfiguration(true) { + sink("stdout", RENDER_ANSI, STDOUT) + sink("stderr", RENDER_ANSI, STDERR) + + logging { + fromLoggerBase("io.ktor.routing.Routing", stopOnMatch = true) + fromMinLevel(Level.DEBUG) { + toSink("stdout") + } + } + logging { + fromLoggerBase("org.sqlite.core.NativeDB", stopOnMatch = true) + fromMinLevel(Level.DEBUG) { + toSink("stdout") + } + } + logging { + fromMinLevel(Level.ERROR) { + toSink("stderr") + } + inLevelRange(Level.TRACE, Level.WARN) { + toSink("stdout") + } + } + minDirectLogLevel(Level.TRACE) + } + + embeddedServer(CIO, port = 8080) { + install(ContentNegotiation) { + json() + } + + install(CallLogging) { + this.level = org.slf4j.event.Level.DEBUG + } + + install(Sessions) { + cookie("USER_SESSION") { + cookie.path = "/" + cookie.httpOnly = true + cookie.extensions["SameSite"] = "Strict" + } + } + install(StatusPages) { + exception { call, cause -> + cause.printStackTrace() + call.respond(HttpStatusCode.InternalServerError, cause.localizedMessage) + } + } + routing { + get("/") { + call.respondText("OIDC IDP Server", ContentType.Text.Plain) + } + wellKnownConfiguration() + authenticateUser() + handleOIDCRequests() + handleLogout() + } + }.start(wait = true) +} + + +private const val thisIdp = "http://localhost:8080" + + +// Function to get claims from SignedJWT +suspend fun getClaimsFromJWT(idToken: String): JWTClaimsSet? { + log.trace { "Getting claims from idToken: $idToken" } + return try { + val signedJWT = SignedJWT.parse(idToken) + signedJWT.jwtClaimsSet.also { log.trace { "Claims from idToken $idToken are: ${signedJWT.jwtClaimsSet}" } } + } catch (e: ParseException) { + null + } +} + +// Token removal logic +suspend fun removeToken(tokenRequest: String) { + log.trace { "Removing token: $tokenRequest" } + tokenStore.values.removeIf { it.accessToken == tokenRequest || it.idToken == tokenRequest } +} + +fun Routing.handleOIDCRequests() { + get("/authorize") { + val queryParams = call.request.queryParameters + log.trace { "OIDC /authorize: with query: ${queryParams.entries()}" } + val authRequest = AuthorizationRequest.parse(queryParams.toMap()) + log.trace { "OIDC /authorize: validating auth request: (query encoded) ${authRequest.toQueryString()}" } + validateAuthRequest(authRequest) + + //val customLogicResult = performCustomLogic() + val x = queryParams.get("custom-login-stuff") + if (x == null) { + call.respondRedirect("/login?${authRequest.toQueryString()}") + return@get + } + + val customLogicResult = x == "success" + + + if (customLogicResult) { + val authCode = AuthorizationCode() + val redirectURI = authRequest.redirectionURI.toString() + "?code=${authCode.value}" + + log.trace { "OIDC /authorize: validated with custom logic: (query encoded) ${authRequest.toQueryString()}, redirecting to ${redirectURI}, state is ${authRequest.state} (state value ${authRequest.state?.value}" } + + // Store the auth code details and user session + call.sessions.set(UserSession(id = "user-id", state = authRequest.state.value)) + call.respondRedirect(redirectURI) + } else { + log.trace { "OIDC /authorize: validating custom logic failed for $authRequest" } + call.respond(HttpStatusCode.Forbidden, "Custom logic failed") + } + } + + post("/token") { + log.trace { "OIDC /token: Parsing" } + val httpRequest = convertKtorRequestToNimbusHTTPRequest(call.request) + val tokenRequest = TokenRequest.parse(httpRequest) + + log.trace { "OIDC /token: Parsed to token request: $tokenRequest, validating client credentials..." } + + validateClientCredentials(tokenRequest.clientAuthentication) + + when (val grant = tokenRequest.authorizationGrant) { + is AuthorizationCodeGrant -> { + log.trace { "OIDC /token: Grant is AuthorizationCodeGrant!" } + validateTokenRequest(tokenRequest) + val tokens = issueTokens(grant.authorizationCode) + log.trace { "OIDC /token: Issued tokens: $tokens" } + tokenStore[grant.authorizationCode.value] = tokens + log.trace { "OIDC /token: Associate issued tokens with ${grant.authorizationCode.value}" } + call.respond(tokens) + log.trace { "OIDC /token: Returned: ${Json.encodeToString(tokens)}" } + } + + is RefreshTokenGrant -> { + log.trace { "OIDC /token: Grant is RefreshTokenGrant!" } + val refreshToken = grant.refreshToken.value + val tokens = tokenStore.values.find { it.accessToken == refreshToken } + if (tokens != null && tokens.expirationTime > Clock.System.now()) { + val newTokens = issueTokens(AuthorizationCode()) // Issue new tokens + log.trace { "OIDC /token (refresh): New issued tokens: $newTokens" } + tokenStore[refreshToken] = newTokens + log.trace { "OIDC /token: Associate refreshed tokens with $refreshToken" } + call.respond(newTokens) + } else { + log.trace { "OIDC /token (refresh): Invalid or expired refresh token" } + call.respond(HttpStatusCode.BadRequest, "Invalid or expired refresh token") + } + } + + else -> { + log.trace { "OIDC /token: Unsupported grant type: ${grant.type.value}" } + call.respond(HttpStatusCode.BadRequest, "Unsupported grant type") + } + } + } + + get("/userinfo") { + val bearerToken = call.request.headers["Authorization"]?.removePrefix("Bearer ") + log.trace { "OIDC /userinfo: $bearerToken" } + if (bearerToken == null) { + call.respond(HttpStatusCode.Unauthorized, "Missing token") + return@get + } + + val tokenInfo = tokenStore.values.find { it.accessToken == bearerToken || it.idToken == bearerToken } + if (tokenInfo != null && tokenInfo.expirationTime > Clock.System.now()) { + val claims = getClaimsFromJWT(tokenInfo.idToken) + val userInfo = mapOf( + "sub" to (claims?.subject ?: "unknown"), + "name" to (claims?.getClaim("name") ?: "unknown"), + "email" to (claims?.getClaim("email") ?: "unknown") + ) + call.respond(userInfo) + } else { + call.respond(HttpStatusCode.Unauthorized, "Invalid or expired token") + } + } + + post("/introspect") { + val tokenRequest = call.receiveParameters()["token"] + log.trace { "OIDC /introspect: $tokenRequest" } + if (tokenRequest == null) { + call.respond(HttpStatusCode.BadRequest, "Missing token") + return@post + } + + val tokenInfo = tokenStore.values.find { it.accessToken == tokenRequest || it.idToken == tokenRequest } + if (tokenInfo != null) { + val isActive = tokenInfo.expirationTime > Clock.System.now() + val claims = getClaimsFromJWT(tokenInfo.idToken) + val introspectionResponse = mapOf( + "active" to isActive, + "scope" to "openid profile email", + "client_id" to "your-client-id", + "username" to (claims?.subject ?: "unknown"), + "token_type" to "Bearer", + "exp" to tokenInfo.expirationTime.epochSeconds, + "iat" to tokenInfo.issueTime.epochSeconds, + "sub" to (claims?.subject ?: "unknown") + ) + call.respond(introspectionResponse) + } else { + call.respond(mapOf("active" to false)) + } + } + + // Token endpoint with removal logic + post("/revoke") { + val tokenRequest = call.receiveParameters()["token"] + log.trace { "Revoking $tokenRequest" } + if (tokenRequest == null) { + call.respond(HttpStatusCode.BadRequest, "Missing token") + return@post + } + + removeToken(tokenRequest) + call.respond(HttpStatusCode.OK, "Token revoked") + } +} + +suspend fun performCustomLogic(): Boolean { + log.trace { "-- Custom logic here --" } + // Custom backend logic + return true +} + +// TODO FIXME: use authCode +suspend fun issueTokens(authCode: AuthorizationCode): TokenStore { + + log.trace { "Issuing tokens, - but without auth code?" } + + val accessToken = BearerAccessToken(3600) // Token valid for 3600 seconds + val issueTime = Clock.System.now() + val expirationTime = issueTime.plus(3600.seconds) + + val idTokenClaims = JWTClaimsSet.Builder().issuer(thisIdp).subject("user-id").audience("your-client-id") + .issueTime(Date.from(issueTime.toJavaInstant())).expirationTime(Date.from(expirationTime.toJavaInstant())).build() + val idToken = SignedJWT(JWSHeader(JWSAlgorithm.RS256), idTokenClaims) + idToken.sign(RSASSASigner(generateRSAKey().toPrivateKey())) + + return TokenStore( + accessToken = accessToken.value, + tokenType = accessToken.type.value, + expiresIn = 3600, // This represents the lifetime of the access token in seconds + idToken = idToken.serialize(), + issueTime = issueTime, + expirationTime = expirationTime + ).also { log.trace { "Issued: $it" } } +} + +suspend fun generateRSAKey(): RSAKey { + log.trace { "Generating RSA key..." } + return RSAKeyGenerator(2048).keyID("123").generate() +} + +suspend fun validateAuthRequest(authRequest: AuthorizationRequest) { + log.trace { "Validating auth request: (query encoded) ${authRequest.toQueryString()}" } + // Validate client ID, redirect URI, and scopes + val validClientId = "your-client-id" + val validRedirectURI = "https://your-client.com/callback" + val validScopes = setOf("openid", "profile", "email") + + require(authRequest.clientID.value == validClientId) { "Invalid client ID" } + // TODO require(authRequest.redirectionURI.toString() == validRedirectURI) { "Invalid redirect URI" } + // TODO require(validScopes.all { authRequest.scope.contains(it) }) { "Invalid scopes" } + +} + +suspend fun validateTokenRequest(tokenRequest: TokenRequest) { + log.trace { "Validating token request: $tokenRequest" } + // Validate the token request parameters + require(tokenRequest.clientAuthentication.clientID.value == "your-client-id") { "Invalid client ID" } + require(tokenRequest.authorizationGrant.type == GrantType.AUTHORIZATION_CODE) { "Invalid grant type" } +} + +suspend fun validateClientCredentials(clientAuthentication: ClientAuthentication) { + log.trace { "Validating client authentication: $clientAuthentication" } + + val validClientSecret = "your-client-secret" + + when (clientAuthentication) { + is ClientSecretBasic -> { + require(clientAuthentication.clientID.value == "your-client-id") { "Invalid client ID" } + require(clientAuthentication.clientSecret.value == validClientSecret) { "Invalid client secret" } + } + is ClientSecretPost -> { + require(clientAuthentication.clientID.value == "your-client-id") { "Invalid client ID" } + require(clientAuthentication.clientSecret.value == validClientSecret) { "Invalid client secret" } + } + + else -> throw IllegalStateException("OAuth2Error.INVALID_CLIENT, client authentication: $clientAuthentication (clientid = ${clientAuthentication.clientID.value}, method: ${clientAuthentication.method.value}, form: ${clientAuthentication.formParameterNames})") + } +} + +fun Routing.handleLogout() { + get("/logout") { + log.trace { "Logging out" } + call.sessions.clear() + call.respondText("Logged out", ContentType.Text.Plain) + } +} + +fun Routing.authenticateUser() { + get("/login") { + + val query = call.request.queryParameters.formUrlEncode() + + log.trace { "Displaying login form" } + // Display login form + call.respondText( + """ +
+ Present credential:
+ Debug query:
+ +
+ """, ContentType.Text.Html + ) + } + + post("/login") { + log.trace { "Logging in..." } + val post = call.receiveParameters() + val cred = post["cred"] + val query = post["query"] + + if (cred != null) { + // Set user session + + val state = UUID.randomUUID().toString() + + call.sessions.set(UserSession(id = "some-user-id", state = state)) + + val redirect = "/authorize?custom-login-stuff=success&$query&state=$state" + + log.trace { "Redirecting after successful login: $redirect" } + call.respondRedirect(redirect) // Redirect to home page or requested resource + } else { + call.respond(HttpStatusCode.BadRequest, "Missing credentials") + } + } +} + +val jwk = RSAKeyGenerator(2048).keyID("123").generate() + +fun Routing.wellKnownConfiguration() { + get("/.well-known/openid-configuration") { + val issuer = thisIdp + val wellKnown = mapOf( + "issuer" to issuer, + "authorization_endpoint" to "$issuer/authorize", + "token_endpoint" to "$issuer/token", + "userinfo_endpoint" to "$issuer/userinfo", + "jwks_uri" to "$issuer/jwks", + "response_types_supported" to listOf("code", "id_token", "token id_token"), + "subject_types_supported" to listOf("public"), + "id_token_signing_alg_values_supported" to listOf("RS256"), + "scopes_supported" to listOf("openid", "profile", "email"), + "token_endpoint_auth_methods_supported" to listOf("client_secret_basic"), + "claims_supported" to listOf("sub", "iss", "aud", "iat", "exp", "name", "email") + ).toJsonObject() + log.trace { "OIDC /well-known: Well-known is: $wellKnown" } + call.respond(wellKnown) + } + + get("/jwks") { + log.trace { "Handling /jwks..." } + val jwkSet = JWKSet(jwk) + call.respondText(jwkSet.toJSONObject().toString(), ContentType.Application.Json) + } +} + + +suspend fun convertKtorRequestToNimbusHTTPRequest(request: ApplicationRequest): HTTPRequest { + log.trace { "Converting ktor to nimbus http request..." } + val method = HTTPRequest.Method.valueOf(request.httpMethod.value) + + */ +/*val method = when (request.httpMethod.value) { + "GET" -> HTTPRequest.Method.GET + "POST" -> Method.POST + "PUT" -> Method.PUT + "DELETE" -> Method.DELETE + "OPTIONS" -> Method.OPTIONS + "HEAD" -> Method.HEAD + else -> throw IllegalArgumentException("Unsupported HTTP method") + }*//* + + + val url = request.call.url() + + log.trace { "Converting request... Method = $method, url = $url" } + + val httpRequest = HTTPRequest(method, URL(url)) + + // Copy headers + request.headers.forEach { key, values -> + values.forEach { value -> + httpRequest.setHeader(key, value) + } + } + + // Copy query parameters (if any) + val queryParams = request.queryParameters.entries() + if (queryParams.isNotEmpty()) { + val queryString = queryParams.joinToString("&") { "${it.key}=${it.value.joinToString(",")}" } + httpRequest.query = queryString + } + + // Copy body (if any) + if (request.httpMethod == HttpMethod.Post || request.httpMethod == HttpMethod.Put) { + //httpRequest.setContent(request.receiveChannel().toByteArray()) + httpRequest.body = request.receiveChannel().toByteArray().decodeToString() + httpRequest.setContentType(request.contentType().toString()) + } + + log.trace { "Converted ktor to nimbus http request: $httpRequest" } + return httpRequest +} + +*/ +fun Any?.toJsonElement(): JsonElement = + when (this) { + is JsonElement -> this + null -> JsonNull + is String -> JsonPrimitive(this) + is Boolean -> JsonPrimitive(this) + is Number -> JsonPrimitive(this) + + /* + is UByte -> JsonPrimitive(this) + is UInt -> JsonPrimitive(this) + is ULong -> JsonPrimitive(this) + is UShort -> JsonPrimitive(this) + */ + + is Map<*, *> -> JsonObject(map { Pair(it.key.toString(), it.value.toJsonElement()) }.toMap()) + is List<*> -> JsonArray(map { it.toJsonElement() }) + is Array<*> -> JsonArray(map { it.toJsonElement() }) + is Collection<*> -> JsonArray(map { it.toJsonElement() }) + is Enum<*> -> JsonPrimitive(this.toString()) + else -> throw IllegalArgumentException("Unknown type: ${this::class.simpleName}, was: $this") + } + +fun List<*>.toJsonElement(): JsonElement { + return JsonArray(map { it.toJsonElement() }) +} + +fun Map<*, *>.toJsonElement(): JsonElement { + val map: MutableMap = mutableMapOf() + this.forEach { (key, value) -> + map[key as String] = value.toJsonElement() + } + return JsonObject(map) +} + +fun Map<*, *>.toJsonObject() = this.toJsonElement().jsonObject + +private fun toHexChar(i: Int): Char { + val d = i and 0xf + return if (d < 10) (d + '0'.code).toChar() + else (d - 10 + 'a'.code).toChar() +} + +private val ESCAPE_STRINGS: Array = arrayOfNulls(93).apply { + for (c in 0..0x1f) { + val c1 = toHexChar(c shr 12) + val c2 = toHexChar(c shr 8) + val c3 = toHexChar(c shr 4) + val c4 = toHexChar(c) + this[c] = "\\u$c1$c2$c3$c4" + } + this['"'.code] = "\\\"" + this['\\'.code] = "\\\\" + this['\t'.code] = "\\t" + this['\b'.code] = "\\b" + this['\n'.code] = "\\n" + this['\r'.code] = "\\r" + this[0x0c] = "\\f" +} + +private fun StringBuilder.printQuoted(value: String) { + append('"') + var lastPos = 0 + for (i in value.indices) { + val c = value[i].code + if (c < ESCAPE_STRINGS.size && ESCAPE_STRINGS[c] != null) { + append(value, lastPos, i) // flush prev + append(ESCAPE_STRINGS[c]) + lastPos = i + 1 + } + } + + if (lastPos != 0) append(value, lastPos, value.length) + else append(value) + append('"') +} + +fun Map.printAsJson(): String = + this.entries.joinToString( + separator = ",", + prefix = "{", + postfix = "}", + transform = { (k, v) -> + buildString { + printQuoted(k) + append(':') + append(v) + } + } + ) + +fun stringToJsonPrimitive(value: String): JsonPrimitive { + return JsonPrimitive(value) +} + + diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/resources/logback.xml b/waltid-libraries/auth/waltid-idpkit/src/main/resources/logback.xml new file mode 100644 index 000000000..3e11d7811 --- /dev/null +++ b/waltid-libraries/auth/waltid-idpkit/src/main/resources/logback.xml @@ -0,0 +1,12 @@ + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file From f880d23f3e6a87b9edeab8bbba6cf93d572051a9 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:53:17 +0200 Subject: [PATCH 10/17] feat: TOTP and qr code in idp kit --- .../auth/waltid-authkit/build.gradle.kts | 3 +- .../src/main/kotlin/id/walt/methods/TOTP.kt | 51 +++++++++++++++++++ .../src/main/kotlin/id/walt/App2.kt | 22 ++++++-- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/TOTP.kt diff --git a/waltid-libraries/auth/waltid-authkit/build.gradle.kts b/waltid-libraries/auth/waltid-authkit/build.gradle.kts index 118323adc..adcf4f838 100644 --- a/waltid-libraries/auth/waltid-authkit/build.gradle.kts +++ b/waltid-libraries/auth/waltid-authkit/build.gradle.kts @@ -32,7 +32,8 @@ dependencies { //implementation("org.apache.directory.server:apacheds-server-integ:2.0.0.AM27") implementation("org.apache.directory.api:api-all:2.1.6") - + // TOTP/HOTP + implementation("com.atlassian:onetime:2.1.1") // Ktor server implementation("io.ktor:ktor-server-core-jvm") diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/TOTP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/TOTP.kt new file mode 100644 index 000000000..f345ae7e6 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/TOTP.kt @@ -0,0 +1,51 @@ +package id.walt.methods + +import com.atlassian.onetime.core.TOTP +import com.atlassian.onetime.core.TOTPGenerator +import com.atlassian.onetime.model.EmailAddress +import com.atlassian.onetime.model.Issuer +import com.atlassian.onetime.model.TOTPSecret +import com.atlassian.onetime.service.AsciiRangeSecretProvider +import com.atlassian.onetime.service.AsyncSecretProvider +import com.atlassian.onetime.service.DefaultTOTPService +import com.atlassian.onetime.service.TOTPConfiguration +import java.util.concurrent.CompletableFuture + +class AsyncAsciiRangeSecretProvider : AsyncSecretProvider { + + override fun generateSecret(): CompletableFuture = + CompletableFuture.supplyAsync { + AsciiRangeSecretProvider.generateSecret() + } +} + +fun interface CPSSecretProvider { + suspend fun generateSecret(): TOTPSecret +} + +fun main() { + val service = DefaultTOTPService( + totpGenerator = TOTPGenerator(), + totpConfiguration = TOTPConfiguration() + ) + + val secret = TOTPSecret.fromBase32EncodedString("ZIQL3WHUAGCS5FQQDKP74HZCFT56TJHR") + val totpGenerator: TOTPGenerator = TOTPGenerator() + val totp = totpGenerator.generateCurrent(secret) //TOTP(value=123456) + println("totp: $totp") + + val totpUri = service.generateTOTPUrl( + secret, ////NIQXUILREVGHIUKNORKHSJDHKMWS6UTY + EmailAddress("jsmith@acme.com"), + Issuer("Acme Co") + ) + println("URI: $totpUri") + + + val userInput: TOTP = TOTP("123456") //TOTP from user input + val result = service.verify( + userInput, + secret //NIQXUILREVGHIUKNORKHSJDHKMWS6UTY + ) + println("Result: $result") +} diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt index e48cd806a..12d134fd0 100644 --- a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt +++ b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt @@ -187,13 +187,29 @@ fun Application.test() { reqCache[req.state!!] = token urlCache[req.state!!] = url + + val walletUrl = "http://localhost:7101/api/siop/initiatePresentation?" + url.substringAfter("?") + println("Wallet url: $walletUrl") + //language=HTML call.respondText( """ -

Present your credential: $url (just imagine real hard that this is a QR code)

-
Click here when presented (just imagine real hard that this is automatic) +

Present your credential: $url

+
+

+ (just imagine real hard that this is automatic) +

+

+ +

Debug query: $queryString

+ + + + """.trimIndent(), ContentType.Text.Html ) @@ -225,7 +241,7 @@ fun Application.test() {

Not presented yet, please try again

Present your credential: $url (just imagine real hard that this is a QR code)

- Click here when presented (just imagine real hard that this is automatic) + Click here when presented (just imagine real hard that this is automatic) """.trimIndent(), ContentType.Text.Html ) From 1bea6842b9eed2649f6c800c66007c07ee7cc7f4 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Wed, 31 Jul 2024 02:13:26 +0200 Subject: [PATCH 11/17] added virtual stores --- .../main/kotlin/id/walt/accounts/Account.kt | 6 -- .../id/walt/{ => authkit}/Application.kt | 12 ++-- .../kotlin/id/walt/authkit/TestApplication.kt | 41 +++++++++++ .../id/walt/authkit/accounts/Account.kt | 9 +++ .../id/walt/authkit/accounts/AccountStore.kt | 41 +++++++++++ .../accounts/identifiers/AccountIdentifier.kt | 8 +++ .../identifiers/UsernameIdentifier.kt | 3 + .../id/walt/authkit/exceptions/Exceptions.kt | 17 +++++ .../authkit/methods/AuthenticationMethod.kt | 23 ++++++ .../id/walt/authkit/methods/EmailPass.kt | 4 ++ .../id/walt/{ => authkit}/methods/Kerberos.kt | 2 +- .../id/walt/{ => authkit}/methods/LDAP.kt | 2 +- .../id/walt/{ => authkit}/methods/LDAP2.kt | 2 +- .../id/walt/{ => authkit}/methods/RADIUS.kt | 34 +++++++-- .../id/walt/{ => authkit}/methods/TOTP.kt | 2 +- .../id/walt/authkit/methods/UserPass.kt | 36 ++++++++++ .../methods/UserPassBasedAuthMethod.kt | 70 +++++++++++++++++++ .../methods/config/AuthMethodConfiguration.kt | 3 + .../methods/data/AuthMethodStoredData.kt | 3 + .../id/walt/{ => authkit}/plugins/HTTP.kt | 2 +- .../walt/{ => authkit}/plugins/Monitoring.kt | 5 +- .../id/walt/{ => authkit}/plugins/Routing.kt | 18 +---- .../id/walt/{ => authkit}/plugins/Security.kt | 2 +- .../{ => authkit}/plugins/Serialization.kt | 7 +- .../{ => authkit}/sessions/AuthSession.kt | 2 +- .../sessions/AuthSessionResponse.kt | 2 +- .../id/walt/authkit/sessions/SessionStore.kt | 4 ++ .../id/walt/methods/AuthenticationMethod.kt | 7 -- .../main/kotlin/id/walt/methods/EmailPass.kt | 4 -- .../main/kotlin/id/walt/methods/UserPass.kt | 7 -- .../test/kotlin/id/walt/ApplicationTest.kt | 6 +- 31 files changed, 313 insertions(+), 71 deletions(-) delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/accounts/Account.kt rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/Application.kt (84%) create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/TestApplication.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/Account.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/AccountStore.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/AccountIdentifier.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/UsernameIdentifier.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/exceptions/Exceptions.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/AuthenticationMethod.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/EmailPass.kt rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/methods/Kerberos.kt (98%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/methods/LDAP.kt (99%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/methods/LDAP2.kt (96%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/methods/RADIUS.kt (59%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/methods/TOTP.kt (98%) create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPassBasedAuthMethod.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/config/AuthMethodConfiguration.kt create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/data/AuthMethodStoredData.kt rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/plugins/HTTP.kt (96%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/plugins/Monitoring.kt (70%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/plugins/Routing.kt (68%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/plugins/Security.kt (99%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/plugins/Serialization.kt (65%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/sessions/AuthSession.kt (87%) rename waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/{ => authkit}/sessions/AuthSessionResponse.kt (89%) create mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/SessionStore.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/EmailPass.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/accounts/Account.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/accounts/Account.kt deleted file mode 100644 index 1b56b8b79..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/accounts/Account.kt +++ /dev/null @@ -1,6 +0,0 @@ -package id.walt.accounts - -import kotlin.uuid.Uuid - -@OptIn(ExperimentalStdlibApi::class) -data class Account(val id: Uuid) diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/Application.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/Application.kt similarity index 84% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/Application.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/Application.kt index d93ee3489..c394dae1c 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/Application.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/Application.kt @@ -1,6 +1,8 @@ -package id.walt +package id.walt.authkit -import id.walt.plugins.* +import id.walt.authkit.plugins.configureMonitoring +import id.walt.authkit.plugins.configureRouting +import id.walt.authkit.plugins.configureSerialization import io.klogging.Level import io.klogging.config.loggingConfiguration import io.klogging.rendering.RENDER_ANSI @@ -44,9 +46,11 @@ fun main() { } fun Application.module() { - configureSecurity() - configureHTTP() + // configureSecurity() + // configureHTTP() configureMonitoring() configureSerialization() configureRouting() + + testApp() } diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/TestApplication.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/TestApplication.kt new file mode 100644 index 000000000..42d9b18c8 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/TestApplication.kt @@ -0,0 +1,41 @@ +package id.walt.authkit + +import id.walt.authkit.methods.AuthenticationMethod +import id.walt.authkit.methods.UserPass +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.routing.* +import io.ktor.util.pipeline.* + +data class AuthContext( + val tenant: String? = null, +) + +fun Application.testApp() { + routing { + route("auth") { + + val contextFunction: PipelineContext.() -> AuthContext = { + AuthContext( + tenant = call.request.host() + ) + } + + registerAuthenticationMethod(UserPass, contextFunction) + } + } +} + +fun Route.registerAuthenticationMethod(method: AuthenticationMethod, context: PipelineContext.() -> AuthContext) { + method.apply { + register(context) + } +} + +fun Route.registerAuthenticationMethods(methods: List, context: PipelineContext.() -> AuthContext) { + methods.forEach { + it.apply { + register(context) + } + } +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/Account.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/Account.kt new file mode 100644 index 000000000..e1beaf812 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/Account.kt @@ -0,0 +1,9 @@ +package id.walt.authkit.accounts + +import kotlin.uuid.Uuid + +@OptIn(ExperimentalStdlibApi::class) +data class Account( + val id: Uuid, + val name: String? = null +) diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/AccountStore.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/AccountStore.kt new file mode 100644 index 000000000..4beb83a59 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/AccountStore.kt @@ -0,0 +1,41 @@ +package id.walt.authkit.accounts + +import id.walt.authkit.AuthContext +import id.walt.authkit.accounts.identifiers.AccountIdentifier +import id.walt.authkit.accounts.identifiers.UsernameIdentifier +import id.walt.authkit.methods.AuthenticationMethod +import id.walt.authkit.methods.UserPass +import id.walt.authkit.methods.data.AuthMethodStoredData +import kotlin.uuid.Uuid + +@OptIn(ExperimentalStdlibApi::class) +object AccountStore { + + // Account uuid -> account + val wip_accounts = HashMap() + + // AccountIdentifier -> Account uuid + val wip_account_ids = HashMap() + + // Account uuid -> auth mechanisms + val wip_accountAuthMechanisms = HashMap>() + + + init { + val newAccount = Account(Uuid.random(), "Alice") + wip_accounts[newAccount.id] = newAccount + + val accountIdentifier = UsernameIdentifier("alice1") + wip_account_ids[accountIdentifier] = newAccount.id + + wip_accountAuthMechanisms[newAccount.id] = hashMapOf(UserPass to UserPass.UserPassStoredData("123456")) + } + + fun lookupStoredDataFor(identifier: AccountIdentifier, method: AuthenticationMethod): AuthMethodStoredData { + val uuid = wip_account_ids[identifier] ?: error("No account for identifier: $identifier") + val storedData = wip_accountAuthMechanisms[uuid]!![method] ?: error("No stored data for method: $method") + + return storedData + } + +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/AccountIdentifier.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/AccountIdentifier.kt new file mode 100644 index 000000000..0f5e9ed62 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/AccountIdentifier.kt @@ -0,0 +1,8 @@ +package id.walt.authkit.accounts.identifiers + +interface AccountIdentifier { + + + +} + diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/UsernameIdentifier.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/UsernameIdentifier.kt new file mode 100644 index 000000000..8610f7d9c --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/UsernameIdentifier.kt @@ -0,0 +1,3 @@ +package id.walt.authkit.accounts.identifiers + +class UsernameIdentifier(name: String) : AccountIdentifier diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/exceptions/Exceptions.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/exceptions/Exceptions.kt new file mode 100644 index 000000000..f6a74d61e --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/exceptions/Exceptions.kt @@ -0,0 +1,17 @@ +package id.walt.authkit.exceptions + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +data class AuthenticationFailureException(override val message: String) : IllegalArgumentException(message) + +@Suppress("NOTHING_TO_INLINE") +inline fun authFailure(message: String): Nothing = throw AuthenticationFailureException(message) + +@OptIn(ExperimentalContracts::class) +public inline fun authCheck(value: Boolean, lazyMessage: () -> Any): Unit { + contract { + returns() implies value + } + if (!value) authFailure(lazyMessage().toString()) +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/AuthenticationMethod.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/AuthenticationMethod.kt new file mode 100644 index 000000000..50964faf8 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/AuthenticationMethod.kt @@ -0,0 +1,23 @@ +package id.walt.authkit.methods + +import id.walt.authkit.AuthContext +import id.walt.authkit.accounts.AccountStore +import id.walt.authkit.accounts.identifiers.AccountIdentifier +import id.walt.authkit.methods.data.AuthMethodStoredData +import io.ktor.server.application.* +import io.ktor.server.routing.* +import io.ktor.util.pipeline.* + +abstract class AuthenticationMethod { + abstract fun Route.register(context: PipelineContext.() -> AuthContext) + +// abstract val identifier: AccountIdentifier + + inline fun lookupStoredData(identifier: AccountIdentifier): V { + val storedData = AccountStore.lookupStoredDataFor(identifier, this) + return (storedData as? V) ?: error("${storedData::class.simpleName} is not requested ${V::class.simpleName}") + } + + + +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/EmailPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/EmailPass.kt new file mode 100644 index 000000000..ec6507759 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/EmailPass.kt @@ -0,0 +1,4 @@ +package id.walt.authkit.methods + +class EmailPass { +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/Kerberos.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/Kerberos.kt similarity index 98% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/Kerberos.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/Kerberos.kt index 1b32def00..50879cdd5 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/Kerberos.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/Kerberos.kt @@ -1,4 +1,4 @@ -package id.walt.methods +package id.walt.authkit.methods /* import org.ietf.jgss.* diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP.kt similarity index 99% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP.kt index 3c362a686..f6a7290fd 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP.kt @@ -1,4 +1,4 @@ -package id.walt.methods +package id.walt.authkit.methods import io.ktor.server.auth.* import java.util.* diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP2.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP2.kt similarity index 96% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP2.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP2.kt index cda3a44da..78db1ad80 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/LDAP2.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP2.kt @@ -1,4 +1,4 @@ -package id.walt.methods +package id.walt.authkit.methods import org.apache.directory.api.ldap.model.exception.LdapException import org.apache.directory.ldap.client.api.LdapConnection diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/RADIUS.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt similarity index 59% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/RADIUS.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt index d9c8dbc79..7693d40ab 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/RADIUS.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt @@ -1,9 +1,16 @@ -package id.walt.methods +package id.walt.authkit.methods +import id.walt.authkit.AuthContext +import id.walt.authkit.accounts.AccountStore +import id.walt.authkit.accounts.identifiers.UsernameIdentifier +import id.walt.authkit.methods.UserPass.getUsernamePasswordFromRequest +import io.ktor.server.application.* +import io.ktor.server.routing.* +import io.ktor.util.pipeline.* +import kotlinx.serialization.Serializable import org.aaa4j.radius.client.RadiusClient import org.aaa4j.radius.client.RadiusClientException import org.aaa4j.radius.client.clients.UdpRadiusClient -import org.aaa4j.radius.core.attribute.Attribute import org.aaa4j.radius.core.attribute.StringData import org.aaa4j.radius.core.attribute.TextData import org.aaa4j.radius.core.attribute.attributes.NasIdentifier @@ -14,7 +21,15 @@ import org.aaa4j.radius.core.packet.packets.AccessAccept import org.aaa4j.radius.core.packet.packets.AccessRequest import java.net.InetSocketAddress -class RADIUS { +object RADIUS : UserPassBasedAuthMethod() { + + @Serializable + data class RADIUSConfiguration( + val radiusServerHost: String, + val radiusServerPort: Int, + val radiusServerSecret: String, + val radiusNasIdentifier: String + ) val radiusClient: RadiusClient = UdpRadiusClient.newBuilder() .secret("sharedsecret".toByteArray()) @@ -26,7 +41,7 @@ class RADIUS { listOf( UserName(TextData("john.doe")), UserPassword(StringData("hunter2".toByteArray())), - NasIdentifier(TextData("SSID1")) + NasIdentifier(TextData("this is like a client id")) ) ) @@ -46,4 +61,15 @@ class RADIUS { } } + + override fun Route.register(context: PipelineContext.() -> AuthContext) { + post("userpass") { + val credential = call.getUsernamePasswordFromRequest() + + val identifier = UsernameIdentifier(credential.name) + + AccountStore.lookupAccount(identifier, context()) + } + } + } diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/TOTP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/TOTP.kt similarity index 98% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/TOTP.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/TOTP.kt index f345ae7e6..a8bde5299 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/TOTP.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/TOTP.kt @@ -1,4 +1,4 @@ -package id.walt.methods +package id.walt.authkit.methods import com.atlassian.onetime.core.TOTP import com.atlassian.onetime.core.TOTPGenerator diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt new file mode 100644 index 000000000..c85c53a39 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt @@ -0,0 +1,36 @@ +package id.walt.authkit.methods + +import id.walt.authkit.AuthContext +import id.walt.authkit.accounts.identifiers.UsernameIdentifier +import id.walt.authkit.exceptions.authCheck +import id.walt.authkit.methods.data.AuthMethodStoredData +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.routing.* +import io.ktor.util.pipeline.* +import kotlinx.serialization.Serializable + +object UserPass : UserPassBasedAuthMethod() { + + @Serializable + data class UserPassStoredData( + val password: String, + ) : AuthMethodStoredData + + override suspend fun auth(credential: UserPasswordCredential) { + val identifier = UsernameIdentifier(credential.name) + + val storedData: UserPassStoredData = lookupStoredData(identifier /*context()*/) + + authCheck(credential.password == storedData.password) { "Invalid password" } + } + + override fun Route.register(context: PipelineContext.() -> AuthContext) { + post("userpass") { + val credential = call.getUsernamePasswordFromRequest() + + auth(credential) + } + } + +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPassBasedAuthMethod.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPassBasedAuthMethod.kt new file mode 100644 index 000000000..626027c7b --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPassBasedAuthMethod.kt @@ -0,0 +1,70 @@ +package id.walt.authkit.methods + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.auth.* +import io.ktor.server.request.* +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive + +/** + * Authentication method based on an id (username, email) and password + * + * Handles passing the auth credential as basic auth header, as JSON document body, or as form post. + */ +abstract class UserPassBasedAuthMethod(val usernameName: String = DEFAULT_USER_NAME, val passwordName: String = DEFAULT_PASSWORD_NAME) : AuthenticationMethod() { + + companion object { + const val DEFAULT_USER_NAME = "username" + const val DEFAULT_PASSWORD_NAME = "password" + } + + val EXPLANATION_MESSAGE by lazy { + """Pass authentication credential either as 1) Basic Auth header (`Authorization: Basic `) as per RFC 7617; OR 2) JSON document (`{"$usernameName": "<$usernameName>", "$passwordName": "<$passwordName>"}`); OR 3) Form post ($usernameName=<$usernameName>&$passwordName=<$passwordName>)!""" + } + + /** + * Handle username and password as: + * 1. Basic auth header + * 2. JSON document body + * 3. Form post + */ + internal suspend fun ApplicationCall.getUsernamePasswordFromRequest(): UserPasswordCredential { + when (val contentType = request.contentType()) { + // Basic auth (fallback) + ContentType.Any -> { + val basicAuth = request.basicAuthenticationCredentials() + if (basicAuth != null) + return basicAuth + else error("No basic auth credential header found. $EXPLANATION_MESSAGE") + } + // As JSON document + ContentType.Application.Json -> { + val body = receive() + + val username = body[usernameName] as? JsonPrimitive ?: body[DEFAULT_USER_NAME] as? JsonPrimitive + val password = body[passwordName] as? JsonPrimitive ?: body[DEFAULT_PASSWORD_NAME] as? JsonPrimitive + + check(username?.isString == true) { "Invalid or missing $usernameName in JSON request. $EXPLANATION_MESSAGE" } + check(password?.isString == true) { "Invalid or missing $passwordName in JSON request. $EXPLANATION_MESSAGE" } + username!! + password!! + + return UserPasswordCredential(username.content, password.content) + } + // As form post + ContentType.Application.FormUrlEncoded -> { + val form = receiveParameters() + + val username = form[usernameName] ?: form[DEFAULT_USER_NAME] ?: error("Invalid or missing $usernameName in form post request. $EXPLANATION_MESSAGE") + val password = form[passwordName] ?: form[DEFAULT_PASSWORD_NAME] ?: error("Invalid or missing $passwordName in form post request. $EXPLANATION_MESSAGE") + + return UserPasswordCredential(username, password) + } + + else -> error("Invalid content type: $contentType. $EXPLANATION_MESSAGE") + } + } + + abstract suspend fun auth(credential: UserPasswordCredential) +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/config/AuthMethodConfiguration.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/config/AuthMethodConfiguration.kt new file mode 100644 index 000000000..358744139 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/config/AuthMethodConfiguration.kt @@ -0,0 +1,3 @@ +package id.walt.authkit.methods.config + +interface AuthMethodConfiguration diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/data/AuthMethodStoredData.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/data/AuthMethodStoredData.kt new file mode 100644 index 000000000..9e2d01ff5 --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/data/AuthMethodStoredData.kt @@ -0,0 +1,3 @@ +package id.walt.authkit.methods.data + +interface AuthMethodStoredData diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/HTTP.kt similarity index 96% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/HTTP.kt index 84b2d0813..8d3bda6e4 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/HTTP.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/HTTP.kt @@ -1,4 +1,4 @@ -package id.walt.plugins +package id.walt.authkit.plugins import io.ktor.http.* import io.ktor.server.application.* diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Monitoring.kt similarity index 70% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Monitoring.kt index 77cdb7bca..bbb299031 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Monitoring.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Monitoring.kt @@ -1,4 +1,4 @@ -package id.walt.plugins +package id.walt.authkit.plugins import io.ktor.server.application.* import io.ktor.server.plugins.callloging.* @@ -9,7 +9,6 @@ import org.slf4j.event.* fun Application.configureMonitoring() { install(CallLogging) { - level = Level.INFO - filter { call -> call.request.path().startsWith("/") } + level = Level.DEBUG } } diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Routing.kt similarity index 68% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Routing.kt index c6f5e9b82..86209a9ea 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Routing.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Routing.kt @@ -1,4 +1,4 @@ -package id.walt.plugins +package id.walt.authkit.plugins import io.github.smiley4.ktorswaggerui.SwaggerUI import io.ktor.http.* @@ -16,9 +16,6 @@ import io.ktor.server.webjars.* fun Application.configureRouting() { install(AutoHeadResponse) install(DoubleReceive) - install(Webjars) { - path = "/webjars" //defaults to /webjars - } install(SwaggerUI) { swagger { // swaggerUrl = "swagger-ui" @@ -39,17 +36,4 @@ fun Application.configureRouting() { call.respondText(text = "500: $cause" , status = HttpStatusCode.InternalServerError) } } - routing { - get("/") { - call.respondText("Hello World!") - } - post("/double-receive") { - val first = call.receiveText() - val theSame = call.receiveText() - call.respondText(first + " " + theSame) - } - get("/webjars") { - call.respondText("", ContentType.Text.Html) - } - } } diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Security.kt similarity index 99% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Security.kt index 9018421d2..4e0624827 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Security.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Security.kt @@ -1,4 +1,4 @@ -package id.walt.plugins +package id.walt.authkit.plugins import io.ktor.server.application.* diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Serialization.kt similarity index 65% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Serialization.kt index 62a9e6812..6c179577f 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/plugins/Serialization.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Serialization.kt @@ -1,4 +1,4 @@ -package id.walt.plugins +package id.walt.authkit.plugins import io.ktor.serialization.kotlinx.json.* import io.ktor.server.application.* @@ -10,9 +10,4 @@ fun Application.configureSerialization() { install(ContentNegotiation) { json() } - routing { - get("/json/kotlinx-serialization") { - call.respond(mapOf("hello" to "world")) - } - } } diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSession.kt similarity index 87% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSession.kt index 2f5b088ed..91d5147b5 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSession.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSession.kt @@ -1,4 +1,4 @@ -package id.walt.sessions +package id.walt.authkit.sessions import kotlin.uuid.Uuid diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSessionResponse.kt similarity index 89% rename from waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt rename to waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSessionResponse.kt index a206d1467..9b4c50862 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/sessions/AuthSessionResponse.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSessionResponse.kt @@ -1,4 +1,4 @@ -package id.walt.sessions +package id.walt.authkit.sessions import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/SessionStore.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/SessionStore.kt new file mode 100644 index 000000000..5cdbe2aea --- /dev/null +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/SessionStore.kt @@ -0,0 +1,4 @@ +package id.walt.authkit.sessions + +object SessionStore { +} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt deleted file mode 100644 index 91c012ee8..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/AuthenticationMethod.kt +++ /dev/null @@ -1,7 +0,0 @@ -package id.walt.methods - -abstract class AuthenticationMethod { - - - -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/EmailPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/EmailPass.kt deleted file mode 100644 index 0780c1a1f..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/EmailPass.kt +++ /dev/null @@ -1,4 +0,0 @@ -package id.walt.methods - -class EmailPass { -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt deleted file mode 100644 index d0e5d5dd1..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/methods/UserPass.kt +++ /dev/null @@ -1,7 +0,0 @@ -package id.walt.methods - -class UserPass : AuthenticationMethod() { - - - -} diff --git a/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt b/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt index 0e501377b..e587664e5 100644 --- a/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt +++ b/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt @@ -1,14 +1,10 @@ package id.walt -import id.walt.plugins.* +import id.walt.authkit.plugins.configureRouting import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.request.* import io.ktor.server.testing.* -import kotlinx.serialization.json.JsonObject import kotlin.test.* class ApplicationTest { From 0421ed987ffc9d939548d1e918ef615d25998a1a Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Wed, 31 Jul 2024 02:20:09 +0200 Subject: [PATCH 12/17] feat: updated auth methods --- .../kotlin/id/walt/authkit/methods/RADIUS.kt | 38 +++++++------------ .../id/walt/authkit/methods/UserPass.kt | 2 + 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt index 7693d40ab..100bf0a37 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt @@ -1,15 +1,14 @@ package id.walt.authkit.methods import id.walt.authkit.AuthContext -import id.walt.authkit.accounts.AccountStore -import id.walt.authkit.accounts.identifiers.UsernameIdentifier -import id.walt.authkit.methods.UserPass.getUsernamePasswordFromRequest +import id.walt.authkit.exceptions.authCheck +import id.walt.authkit.methods.data.AuthMethodStoredData import io.ktor.server.application.* +import io.ktor.server.auth.* import io.ktor.server.routing.* import io.ktor.util.pipeline.* import kotlinx.serialization.Serializable import org.aaa4j.radius.client.RadiusClient -import org.aaa4j.radius.client.RadiusClientException import org.aaa4j.radius.client.clients.UdpRadiusClient import org.aaa4j.radius.core.attribute.StringData import org.aaa4j.radius.core.attribute.TextData @@ -28,37 +27,28 @@ object RADIUS : UserPassBasedAuthMethod() { val radiusServerHost: String, val radiusServerPort: Int, val radiusServerSecret: String, - val radiusNasIdentifier: String - ) + val radiusNasIdentifier: String, + ): AuthMethodStoredData val radiusClient: RadiusClient = UdpRadiusClient.newBuilder() .secret("sharedsecret".toByteArray()) .address(InetSocketAddress("10.1.1.10", 1812)) .build() - fun auth(): Result { + // Todo: Move to configuration (is not stored data) + + override suspend fun auth(credential: UserPasswordCredential) { val accessRequest = AccessRequest( listOf( - UserName(TextData("john.doe")), - UserPassword(StringData("hunter2".toByteArray())), + UserName(TextData(credential.name)), + UserPassword(StringData(credential.password.toByteArray())), NasIdentifier(TextData("this is like a client id")) ) ) - try { - val responsePacket: Packet = radiusClient.send(accessRequest) + val responsePacket: Packet = radiusClient.send(accessRequest) + authCheck(responsePacket is AccessAccept) { "RADIUS server did not accept authentication" } - if (responsePacket is AccessAccept) { - println(responsePacket) - return Result.success(true) - } else { - return Result.failure(NotImplementedError("no exception here yet")) - TODO("todo") - } - } catch (e: RadiusClientException) { - e.printStackTrace() - return Result.failure(e) - } } @@ -66,9 +56,7 @@ object RADIUS : UserPassBasedAuthMethod() { post("userpass") { val credential = call.getUsernamePasswordFromRequest() - val identifier = UsernameIdentifier(credential.name) - - AccountStore.lookupAccount(identifier, context()) + auth(credential) } } diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt index c85c53a39..f7aaeddeb 100644 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt +++ b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt @@ -23,6 +23,8 @@ object UserPass : UserPassBasedAuthMethod() { val storedData: UserPassStoredData = lookupStoredData(identifier /*context()*/) authCheck(credential.password == storedData.password) { "Invalid password" } + + // TODO: Open session } override fun Route.register(context: PipelineContext.() -> AuthContext) { From 549ae9504cbab9dfeeb0eb5bc885e85527420a63 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Wed, 31 Jul 2024 02:22:16 +0200 Subject: [PATCH 13/17] fix: base64 in sdjwt --- .../src/test/kotlin/id/walt/ApplicationTest.kt | 11 +---------- .../src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt | 3 ++- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt b/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt index e587664e5..fa8f55655 100644 --- a/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt +++ b/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt @@ -8,7 +8,7 @@ import io.ktor.server.testing.* import kotlin.test.* class ApplicationTest { - @Test + // @Test fun testRoot() = testApplication { application { @@ -21,14 +21,5 @@ class ApplicationTest { client.post("/auth/userpass") { basicAuth("user1", "pass1") } - - - - - - client.get("/").apply { - assertEquals(HttpStatusCode.OK, status) - assertEquals("Hello World!", bodyAsText()) - } } } diff --git a/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt index 966660238..5203dba04 100644 --- a/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt +++ b/waltid-libraries/sdjwt/waltid-sdjwt/src/commonMain/kotlin/id/walt/sdjwt/SDJwt.kt @@ -1,5 +1,6 @@ package id.walt.sdjwt +import id.walt.sdjwt.SdjwtStringUtils.decodeFromBase64Url import kotlinx.serialization.json.* import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi @@ -158,7 +159,7 @@ open class SDJwt internal constructor( val disclosures = matchedGroups["disclosures"]?.value?.trim(SEPARATOR)?.split(SEPARATOR)?.toSet() ?: setOf() return SDJwt( matchedGroups["sdjwt"]!!.value, - Json.parseToJsonElement(Base64.UrlSafe.decode(matchedGroups["header"]!!.value).decodeToString()).jsonObject, + Json.parseToJsonElement(matchedGroups["header"]!!.value.decodeFromBase64Url().decodeToString()).jsonObject, SDPayload.parse( matchedGroups["body"]!!.value, disclosures From 9603a5612bbb666fa2034d29fc0e26d7cf126254 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Wed, 31 Jul 2024 22:01:29 +0200 Subject: [PATCH 14/17] build: update dockefiles, fix test paths --- .../policies/DatePolicyTestBase.kt | 0 .../policies/ExpirationDatePolicyTest.kt | 0 .../policies/NotBeforeDatePolicyTest.kt | 0 waltid-services/waltid-issuer-api/Dockerfile | 20 +++++++++---------- .../waltid-verifier-api/Dockerfile | 20 +++++++++---------- waltid-services/waltid-wallet-api/Dockerfile | 20 +++++++++---------- 6 files changed, 30 insertions(+), 30 deletions(-) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/DatePolicyTestBase.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicyTest.kt (100%) rename waltid-libraries/{ => credentials}/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicyTest.kt (100%) diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/DatePolicyTestBase.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/DatePolicyTestBase.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/DatePolicyTestBase.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/DatePolicyTestBase.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicyTest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicyTest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicyTest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/ExpirationDatePolicyTest.kt diff --git a/waltid-libraries/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicyTest.kt b/waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicyTest.kt similarity index 100% rename from waltid-libraries/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicyTest.kt rename to waltid-libraries/credentials/waltid-verifiable-credentials/src/jvmTest/kotlin/id/walt/credentials/verification/policies/NotBeforeDatePolicyTest.kt diff --git a/waltid-services/waltid-issuer-api/Dockerfile b/waltid-services/waltid-issuer-api/Dockerfile index f397732a9..978787ece 100644 --- a/waltid-services/waltid-issuer-api/Dockerfile +++ b/waltid-services/waltid-issuer-api/Dockerfile @@ -3,12 +3,12 @@ FROM docker.io/gradle:jdk17 as buildstage COPY gradle/ /work/gradle COPY settings.gradle.kts build.gradle.kts gradle.properties gradlew /work/ -COPY waltid-libraries/waltid-verifiable-credentials/build.gradle.kts /work/waltid-libraries/waltid-verifiable-credentials/ -COPY waltid-libraries/waltid-crypto/build.gradle.kts /work/waltid-libraries/waltid-crypto/ +COPY waltid-libraries/credentials/waltid-verifiable-credentials/build.gradle.kts /work/waltid-libraries/credentials/waltid-verifiable-credentials/ +COPY waltid-libraries/crypto/waltid-crypto/build.gradle.kts /work/waltid-libraries/crypto/waltid-crypto/ COPY waltid-libraries/waltid-did/build.gradle.kts /work/waltid-libraries/waltid-did/ -COPY waltid-libraries/waltid-openid4vc/build.gradle.kts /work/waltid-libraries/waltid-openid4vc/ -COPY waltid-libraries/waltid-sdjwt/build.gradle.kts /work/waltid-libraries/waltid-sdjwt/ -COPY waltid-libraries/waltid-mdoc-credentials/build.gradle.kts /work/waltid-libraries/waltid-mdoc-credentials/ +COPY waltid-libraries/protocols/waltid-openid4vc/build.gradle.kts /work/waltid-libraries/protocols/waltid-openid4vc/ +COPY waltid-libraries/sdjwt/waltid-sdjwt/build.gradle.kts /work/waltid-libraries/sdjwt/waltid-sdjwt/ +COPY waltid-libraries/credentials/waltid-mdoc-credentials/build.gradle.kts /work/waltid-libraries/credentials/waltid-mdoc-credentials/ COPY waltid-services/waltid-service-commons/build.gradle.kts /work/waltid-services/waltid-service-commons/ COPY waltid-services/waltid-issuer-api/build.gradle.kts /work/waltid-services/waltid-issuer-api/ @@ -16,12 +16,12 @@ COPY waltid-services/waltid-issuer-api/build.gradle.kts /work/waltid-services/wa WORKDIR /work/waltid-services/waltid-issuer-api/ RUN gradle build || return 0 -COPY waltid-libraries/waltid-verifiable-credentials/. /work/waltid-libraries/waltid-verifiable-credentials -COPY waltid-libraries/waltid-crypto/. /work/waltid-libraries/waltid-crypto +COPY waltid-libraries/credentials/waltid-verifiable-credentials/. /work/waltid-libraries/credentials/waltid-verifiable-credentials +COPY waltid-libraries/crypto/waltid-crypto/. /work/waltid-libraries/crypto/waltid-crypto COPY waltid-libraries/waltid-did/. /work/waltid-libraries/waltid-did -COPY waltid-libraries/waltid-openid4vc/. /work/waltid-libraries/waltid-openid4vc -COPY waltid-libraries/waltid-sdjwt/. /work/waltid-libraries/waltid-sdjwt -COPY waltid-libraries/waltid-mdoc-credentials/. /work/waltid-libraries/waltid-mdoc-credentials +COPY waltid-libraries/protocols/waltid-openid4vc/. /work/waltid-libraries/protocols/waltid-openid4vc +COPY waltid-libraries/sdjwt/waltid-sdjwt/. /work/waltid-libraries/sdjwt/waltid-sdjwt +COPY waltid-libraries/credentials/waltid-mdoc-credentials/. /work/waltid-libraries/credentials/waltid-mdoc-credentials COPY waltid-services/waltid-service-commons/. /work/waltid-services/waltid-service-commons COPY waltid-services/waltid-issuer-api/. /work/waltid-services/waltid-issuer-api diff --git a/waltid-services/waltid-verifier-api/Dockerfile b/waltid-services/waltid-verifier-api/Dockerfile index 5b91a2d71..eda491b45 100644 --- a/waltid-services/waltid-verifier-api/Dockerfile +++ b/waltid-services/waltid-verifier-api/Dockerfile @@ -3,12 +3,12 @@ FROM docker.io/gradle:jdk17 as buildstage COPY gradle/ /work/gradle COPY settings.gradle.kts build.gradle.kts gradle.properties gradlew /work/ -COPY waltid-libraries/waltid-verifiable-credentials/build.gradle.kts /work/waltid-libraries/waltid-verifiable-credentials/ -COPY waltid-libraries/waltid-crypto/build.gradle.kts /work/waltid-libraries/waltid-crypto/ +COPY waltid-libraries/credentials/waltid-verifiable-credentials/build.gradle.kts /work/waltid-libraries/credentials/waltid-verifiable-credentials/ +COPY waltid-libraries/crypto/waltid-crypto/build.gradle.kts /work/waltid-libraries/crypto/waltid-crypto/ COPY waltid-libraries/waltid-did/build.gradle.kts /work/waltid-libraries/waltid-did/ -COPY waltid-libraries/waltid-openid4vc/build.gradle.kts /work/waltid-libraries/waltid-openid4vc/ -COPY waltid-libraries/waltid-sdjwt/build.gradle.kts /work/waltid-libraries/waltid-sdjwt/ -COPY waltid-libraries/waltid-mdoc-credentials/build.gradle.kts /work/waltid-libraries/waltid-mdoc-credentials/ +COPY waltid-libraries/protocols/waltid-openid4vc/build.gradle.kts /work/waltid-libraries/protocols/waltid-openid4vc/ +COPY waltid-libraries/sdjwt/waltid-sdjwt/build.gradle.kts /work/waltid-libraries/sdjwt/waltid-sdjwt/ +COPY waltid-libraries/credentials/waltid-mdoc-credentials/build.gradle.kts /work/waltid-libraries/credentials/waltid-mdoc-credentials/ COPY waltid-services/waltid-service-commons/build.gradle.kts /work/waltid-services/waltid-service-commons/ COPY waltid-services/waltid-verifier-api/build.gradle.kts /work/waltid-services/waltid-verifier-api/ @@ -16,12 +16,12 @@ COPY waltid-services/waltid-verifier-api/build.gradle.kts /work/waltid-services/ WORKDIR /work/waltid-services/waltid-verifier-api/ RUN gradle build || return 0 -COPY waltid-libraries/waltid-verifiable-credentials/. /work/waltid-libraries/waltid-verifiable-credentials -COPY waltid-libraries/waltid-crypto/. /work/waltid-libraries/waltid-crypto +COPY waltid-libraries/credentials/waltid-verifiable-credentials/. /work/waltid-libraries/credentials/waltid-verifiable-credentials +COPY waltid-libraries/crypto/waltid-crypto/. /work/waltid-libraries/crypto/waltid-crypto COPY waltid-libraries/waltid-did/. /work/waltid-libraries/waltid-did -COPY waltid-libraries/waltid-openid4vc/. /work/waltid-libraries/waltid-openid4vc -COPY waltid-libraries/waltid-sdjwt/. /work/waltid-libraries/waltid-sdjwt -COPY waltid-libraries/waltid-mdoc-credentials/. /work/waltid-libraries/waltid-mdoc-credentials +COPY waltid-libraries/protocols/waltid-openid4vc/. /work/waltid-libraries/protocols/waltid-openid4vc +COPY waltid-libraries/sdjwt/waltid-sdjwt/. /work/waltid-libraries/sdjwt/waltid-sdjwt +COPY waltid-libraries/credentials/waltid-mdoc-credentials/. /work/waltid-libraries/credentials/waltid-mdoc-credentials COPY waltid-services/waltid-service-commons/. /work/waltid-services/waltid-service-commons COPY waltid-services/waltid-verifier-api/. /work/waltid-services/waltid-verifier-api diff --git a/waltid-services/waltid-wallet-api/Dockerfile b/waltid-services/waltid-wallet-api/Dockerfile index 333bee746..78bebf322 100644 --- a/waltid-services/waltid-wallet-api/Dockerfile +++ b/waltid-services/waltid-wallet-api/Dockerfile @@ -3,12 +3,12 @@ FROM docker.io/gradle:jdk17 as buildstage COPY gradle/ /work/gradle COPY settings.gradle.kts build.gradle.kts gradle.properties gradlew /work/ -COPY waltid-libraries/waltid-openid4vc/build.gradle.kts /work/waltid-libraries/waltid-openid4vc/ -COPY waltid-libraries/waltid-sdjwt/build.gradle.kts /work/waltid-libraries/waltid-sdjwt/ -COPY waltid-libraries/waltid-crypto/build.gradle.kts /work/waltid-libraries/waltid-crypto/ -COPY waltid-libraries/waltid-crypto-oci/build.gradle.kts /work/waltid-libraries/waltid-crypto-oci/ +COPY waltid-libraries/protocols/waltid-openid4vc/build.gradle.kts /work/waltid-libraries/protocols/waltid-openid4vc/ +COPY waltid-libraries/sdjwt/waltid-sdjwt/build.gradle.kts /work/waltid-libraries/sdjwt/waltid-sdjwt/ +COPY waltid-libraries/crypto/waltid-crypto/build.gradle.kts /work/waltid-libraries/crypto/waltid-crypto/ +COPY waltid-libraries/crypto/waltid-crypto-oci/build.gradle.kts /work/waltid-libraries/crypto/waltid-crypto-oci/ COPY waltid-libraries/waltid-did/build.gradle.kts /work/waltid-libraries/waltid-did/ -COPY waltid-libraries/waltid-mdoc-credentials/build.gradle.kts /work/waltid-libraries/waltid-mdoc-credentials/ +COPY waltid-libraries/credentials/waltid-mdoc-credentials/build.gradle.kts /work/waltid-libraries/credentials/waltid-mdoc-credentials/ COPY waltid-services/waltid-service-commons/build.gradle.kts /work/waltid-services/waltid-service-commons/ COPY waltid-services/waltid-wallet-api/build.gradle.kts /work/waltid-services/waltid-wallet-api/ @@ -16,12 +16,12 @@ COPY waltid-services/waltid-wallet-api/build.gradle.kts /work/waltid-services/wa WORKDIR /work/waltid-services/waltid-wallet-api/ RUN gradle build || return 0 -COPY waltid-libraries/waltid-openid4vc/. /work/waltid-libraries/waltid-openid4vc -COPY waltid-libraries/waltid-sdjwt/. /work/waltid-libraries/waltid-sdjwt -COPY waltid-libraries/waltid-crypto/. /work/waltid-libraries/waltid-crypto -COPY waltid-libraries/waltid-crypto-oci/. /work/waltid-libraries/waltid-crypto-oci +COPY waltid-libraries/protocols/waltid-openid4vc/. /work/waltid-libraries/protocols/waltid-openid4vc +COPY waltid-libraries/sdjwt/waltid-sdjwt/. /work/waltid-libraries/sdjwt/waltid-sdjwt +COPY waltid-libraries/crypto/waltid-crypto/. /work/waltid-libraries/crypto/waltid-crypto +COPY waltid-libraries/crypto/waltid-crypto-oci/. /work/waltid-libraries/crypto/waltid-crypto-oci COPY waltid-libraries/waltid-did/. /work/waltid-libraries/waltid-did -COPY waltid-libraries/waltid-mdoc-credentials/. /work/waltid-libraries/waltid-mdoc-credentials +COPY waltid-libraries/credentials/waltid-mdoc-credentials/. /work/waltid-libraries/credentials/waltid-mdoc-credentials COPY waltid-services/waltid-service-commons/. /work/waltid-services/waltid-service-commons COPY waltid-services/waltid-wallet-api/src/ /work/waltid-services/waltid-wallet-api/src From 2df4e25c9f6983636a49987ad22b5477eb554403 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Thu, 8 Aug 2024 01:20:07 +0200 Subject: [PATCH 15/17] feat: add presentation definition parser module --- settings.gradle.kts | 5 - .../auth/waltid-authkit/.gitignore | 36 - .../auth/waltid-authkit/build.gradle.kts | 74 -- .../auth/waltid-authkit/docs/base.md | 17 - .../waltid-authkit/docs/methods/1_userpass.md | 49 -- .../auth/waltid-authkit/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - waltid-libraries/auth/waltid-authkit/gradlew | 234 ------ .../auth/waltid-authkit/gradlew.bat | 89 -- .../auth/waltid-authkit/settings.gradle.kts | 1 - .../kotlin/id/walt/authkit/Application.kt | 56 -- .../kotlin/id/walt/authkit/TestApplication.kt | 41 - .../id/walt/authkit/accounts/Account.kt | 9 - .../id/walt/authkit/accounts/AccountStore.kt | 41 - .../accounts/identifiers/AccountIdentifier.kt | 8 - .../identifiers/UsernameIdentifier.kt | 3 - .../id/walt/authkit/exceptions/Exceptions.kt | 17 - .../authkit/methods/AuthenticationMethod.kt | 23 - .../id/walt/authkit/methods/EmailPass.kt | 4 - .../id/walt/authkit/methods/Kerberos.kt | 56 -- .../kotlin/id/walt/authkit/methods/LDAP.kt | 124 --- .../kotlin/id/walt/authkit/methods/LDAP2.kt | 30 - .../kotlin/id/walt/authkit/methods/RADIUS.kt | 63 -- .../kotlin/id/walt/authkit/methods/TOTP.kt | 51 -- .../id/walt/authkit/methods/UserPass.kt | 38 - .../methods/UserPassBasedAuthMethod.kt | 70 -- .../methods/config/AuthMethodConfiguration.kt | 3 - .../methods/data/AuthMethodStoredData.kt | 3 - .../kotlin/id/walt/authkit/plugins/HTTP.kt | 25 - .../id/walt/authkit/plugins/Monitoring.kt | 14 - .../kotlin/id/walt/authkit/plugins/Routing.kt | 39 - .../id/walt/authkit/plugins/Security.kt | 122 --- .../id/walt/authkit/plugins/Serialization.kt | 13 - .../id/walt/authkit/sessions/AuthSession.kt | 14 - .../authkit/sessions/AuthSessionResponse.kt | 14 - .../id/walt/authkit/sessions/SessionStore.kt | 4 - .../src/main/resources/logback.xml | 12 - .../test/kotlin/id/walt/ApplicationTest.kt | 25 - .../auth/waltid-idpkit/.gitignore | 36 - .../auth/waltid-idpkit/build.gradle.kts | 52 -- .../auth/waltid-idpkit/gradle.properties | 1 - .../gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - waltid-libraries/auth/waltid-idpkit/gradlew | 234 ------ .../auth/waltid-idpkit/gradlew.bat | 89 -- .../auth/waltid-idpkit/settings.gradle.kts | 1 - .../src/main/kotlin/id/walt/App2.kt | 330 -------- .../src/main/kotlin/id/walt/Application.kt | 591 ------------- .../src/main/kotlin/id/walt/Verifier.kt | 97 --- .../src/main/resources/logback.xml | 12 - .../build.gradle.kts | 65 ++ .../PresentationDefinition.kt | 87 ++ .../PresentationDefinitionParser.kt | 324 ++++++++ .../PresentationSubmission.kt | 27 + .../SubmissionRequirement.kt | 36 + .../PresentationDefinitionTest.kt | 779 ++++++++++++++++++ .../PresentationSubmissionTest.kt | 70 ++ .../SubmissionRequirementTest.kt | 96 +++ .../kotlin/id/walt/mdoc/utils/Base64Utils.kt | 22 - .../kotlin/id/walt/oid4vc/util/JwtUtils.kt | 19 - .../jvmTest/resources/simplelogger.properties | 3 - 62 files changed, 1484 insertions(+), 2928 deletions(-) delete mode 100644 waltid-libraries/auth/waltid-authkit/.gitignore delete mode 100644 waltid-libraries/auth/waltid-authkit/build.gradle.kts delete mode 100644 waltid-libraries/auth/waltid-authkit/docs/base.md delete mode 100644 waltid-libraries/auth/waltid-authkit/docs/methods/1_userpass.md delete mode 100644 waltid-libraries/auth/waltid-authkit/gradle.properties delete mode 100644 waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.jar delete mode 100644 waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.properties delete mode 100755 waltid-libraries/auth/waltid-authkit/gradlew delete mode 100644 waltid-libraries/auth/waltid-authkit/gradlew.bat delete mode 100644 waltid-libraries/auth/waltid-authkit/settings.gradle.kts delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/Application.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/TestApplication.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/Account.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/AccountStore.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/AccountIdentifier.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/UsernameIdentifier.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/exceptions/Exceptions.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/AuthenticationMethod.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/EmailPass.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/Kerberos.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP2.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/TOTP.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPassBasedAuthMethod.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/config/AuthMethodConfiguration.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/data/AuthMethodStoredData.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/HTTP.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Monitoring.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Routing.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Security.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Serialization.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSession.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSessionResponse.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/SessionStore.kt delete mode 100644 waltid-libraries/auth/waltid-authkit/src/main/resources/logback.xml delete mode 100644 waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt delete mode 100644 waltid-libraries/auth/waltid-idpkit/.gitignore delete mode 100644 waltid-libraries/auth/waltid-idpkit/build.gradle.kts delete mode 100644 waltid-libraries/auth/waltid-idpkit/gradle.properties delete mode 100644 waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.jar delete mode 100644 waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.properties delete mode 100755 waltid-libraries/auth/waltid-idpkit/gradlew delete mode 100644 waltid-libraries/auth/waltid-idpkit/gradlew.bat delete mode 100644 waltid-libraries/auth/waltid-idpkit/settings.gradle.kts delete mode 100644 waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt delete mode 100644 waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Application.kt delete mode 100644 waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Verifier.kt delete mode 100644 waltid-libraries/auth/waltid-idpkit/src/main/resources/logback.xml create mode 100644 waltid-libraries/credentials/waltid-dif-presentation-exchange/build.gradle.kts create mode 100644 waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationDefinition.kt create mode 100644 waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationDefinitionParser.kt create mode 100644 waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationSubmission.kt create mode 100644 waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/SubmissionRequirement.kt create mode 100644 waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/PresentationDefinitionTest.kt create mode 100644 waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/PresentationSubmissionTest.kt create mode 100644 waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/SubmissionRequirementTest.kt delete mode 100644 waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/utils/Base64Utils.kt delete mode 100644 waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt delete mode 100644 waltid-libraries/waltid-openid4vc/src/jvmTest/resources/simplelogger.properties diff --git a/settings.gradle.kts b/settings.gradle.kts index d10c007b2..83cdd6827 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,11 +31,6 @@ val modules = listOf( "waltid-credentials-base" ), - * "$libraries:auth".group( - "waltid-authkit", - "waltid-idpkit" - ), - * "$libraries:protocols".group( "waltid-openid4vc" ), diff --git a/waltid-libraries/auth/waltid-authkit/.gitignore b/waltid-libraries/auth/waltid-authkit/.gitignore deleted file mode 100644 index c426c32f8..000000000 --- a/waltid-libraries/auth/waltid-authkit/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ \ No newline at end of file diff --git a/waltid-libraries/auth/waltid-authkit/build.gradle.kts b/waltid-libraries/auth/waltid-authkit/build.gradle.kts deleted file mode 100644 index adcf4f838..000000000 --- a/waltid-libraries/auth/waltid-authkit/build.gradle.kts +++ /dev/null @@ -1,74 +0,0 @@ -plugins { - kotlin("jvm") - kotlin("plugin.serialization") - id("io.ktor.plugin") version "2.3.12" - - application - - id("com.github.ben-manes.versions") -} - -group = "id.walt" -version = "0.0.1" - -application { - mainClass.set("id.walt.ApplicationKt") - - val isDevelopment: Boolean = project.ext.has("development") - applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") -} - -repositories { - mavenCentral() -} - -dependencies { - // Auth methods - - // RADIUS - implementation("org.aaa4j.radius:aaa4j-radius-client:0.3.0") - - // LDAP - //implementation("org.apache.directory.server:apacheds-server-integ:2.0.0.AM27") - implementation("org.apache.directory.api:api-all:2.1.6") - - // TOTP/HOTP - implementation("com.atlassian:onetime:2.1.1") - - // Ktor server - implementation("io.ktor:ktor-server-core-jvm") - implementation("io.ktor:ktor-server-auth-jvm") - implementation("io.ktor:ktor-server-auth-jwt-jvm") - //implementation("io.ktor:ktor-server-auth-ldap-jvm") - implementation("io.ktor:ktor-client-core-jvm") - implementation("io.ktor:ktor-client-apache-jvm") - implementation("io.ktor:ktor-server-sessions-jvm") - implementation("io.ktor:ktor-server-auto-head-response-jvm") - implementation("io.ktor:ktor-server-double-receive-jvm") - implementation("io.ktor:ktor-server-webjars-jvm") - implementation("io.ktor:ktor-server-host-common-jvm") - implementation("io.ktor:ktor-server-status-pages-jvm") - implementation("io.ktor:ktor-server-cors-jvm") - implementation("io.ktor:ktor-server-default-headers-jvm") - implementation("io.ktor:ktor-server-forwarded-header-jvm") - implementation("io.ktor:ktor-server-call-logging-jvm") - implementation("io.ktor:ktor-server-content-negotiation-jvm") - implementation("io.ktor:ktor-serialization-kotlinx-json-jvm") - implementation("io.ktor:ktor-server-cio-jvm") - - // Ktor server external - implementation("io.github.smiley4:ktor-swagger-ui:3.2.0") - - // Logging - implementation("io.klogging:klogging-jvm:0.7.0") - implementation("io.klogging:slf4j-klogging:0.7.0") - - /* --- Testing --- */ - - // Ktor - testImplementation("io.ktor:ktor-server-cio-jvm") - testImplementation("io.ktor:ktor-server-tests-jvm") - - // Kotlin - testImplementation("org.jetbrains.kotlin:kotlin-test-junit") -} diff --git a/waltid-libraries/auth/waltid-authkit/docs/base.md b/waltid-libraries/auth/waltid-authkit/docs/base.md deleted file mode 100644 index b0dedd7ee..000000000 --- a/waltid-libraries/auth/waltid-authkit/docs/base.md +++ /dev/null @@ -1,17 +0,0 @@ -# walt.id Auth Kit library - -## Model - -The walt.id Auth Kit provides a vast set of authentication mechanisms -that can be reused by a Ktor based service. -It provides all features necessary for authentication and -session management, while retaining flexibility for service implementations. - -In practice, this means that the Auth Kit works - -- as an abstraction layer around various - authentication mechanisms and protocols (e.g. Username/Email + Password, OAuth2/OIDC, SAML, LDAP, RADIUS, WebAuthn, TOTP) -- distributed session management -- MFA (multi-factor authentication, e.g. Email+Password and TOTP) -- distributed authentication storage -- stored authentication mutation (password reset, add WebAuthn device, etc.) diff --git a/waltid-libraries/auth/waltid-authkit/docs/methods/1_userpass.md b/waltid-libraries/auth/waltid-authkit/docs/methods/1_userpass.md deleted file mode 100644 index 43e6a2b82..000000000 --- a/waltid-libraries/auth/waltid-authkit/docs/methods/1_userpass.md +++ /dev/null @@ -1,49 +0,0 @@ -## Most simple auth - -### 1. Request (Client -> AuthKit): UserPass - -Choose from: - -### 1.1 Plain -```http request -POST /auth/userpass -``` -```json -{ - "username": "abc", - "password": "xyz" -} -``` - -### 1.2 Basic -```http request -POST /auth/userpass/basic -Authorization: Basic YWJjOnh5eg== -``` - -### 1.3 Form -```http request -POST /auth/userpass/form -Content-Type: application/x-www-form-urlencoded - -username=abc&password=xyz -``` - -### 2. Response (AuthKit -> Client): AuthSession -```json5 -{ - "session": "a662b620-7d89-41bf-a823-63d0179d82f1", // Session ID - "status": "ok", // ok, continue_next_step, fail - - // Due to success, the following is available: - "user": "dcedede5-b4e1-49e4-b62b-4801b8343311", - "auth_token": "einahf0Gohng4phoob9aeso3ilethaef5eec", // Token generated, used for subsequent authentication - //"valid_until": "2024-07-25T21:53:47Z" -} -``` - -### 3. Use authentication (Client -> Server): SomeRequest -```http request -GET /my-secure-service/xyz -Authorization: Bearer einahf0Gohng4phoob9aeso3ilethaef5eec -``` diff --git a/waltid-libraries/auth/waltid-authkit/gradle.properties b/waltid-libraries/auth/waltid-authkit/gradle.properties deleted file mode 100644 index 1ab15d0c1..000000000 --- a/waltid-libraries/auth/waltid-authkit/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -kotlin.code.style=official -ktor_version=2.3.12 -kotlin_version=2.0.0 -logback_version=1.4.14 diff --git a/waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.jar b/waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL diff --git a/waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.properties b/waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e411586a5..000000000 --- a/waltid-libraries/auth/waltid-authkit/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/waltid-libraries/auth/waltid-authkit/gradlew b/waltid-libraries/auth/waltid-authkit/gradlew deleted file mode 100755 index 1b6c78733..000000000 --- a/waltid-libraries/auth/waltid-authkit/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/waltid-libraries/auth/waltid-authkit/gradlew.bat b/waltid-libraries/auth/waltid-authkit/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/waltid-libraries/auth/waltid-authkit/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/waltid-libraries/auth/waltid-authkit/settings.gradle.kts b/waltid-libraries/auth/waltid-authkit/settings.gradle.kts deleted file mode 100644 index 920e4dbe9..000000000 --- a/waltid-libraries/auth/waltid-authkit/settings.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = "waltid-authkit" diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/Application.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/Application.kt deleted file mode 100644 index c394dae1c..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/Application.kt +++ /dev/null @@ -1,56 +0,0 @@ -package id.walt.authkit - -import id.walt.authkit.plugins.configureMonitoring -import id.walt.authkit.plugins.configureRouting -import id.walt.authkit.plugins.configureSerialization -import io.klogging.Level -import io.klogging.config.loggingConfiguration -import io.klogging.rendering.RENDER_ANSI -import io.klogging.sending.STDERR -import io.klogging.sending.STDOUT -import io.ktor.server.application.* -import io.ktor.server.cio.* -import io.ktor.server.engine.* - -fun main() { - - loggingConfiguration(true) { - sink("stdout", RENDER_ANSI, STDOUT) - sink("stderr", RENDER_ANSI, STDERR) - - logging { - fromLoggerBase("io.ktor.routing.Routing", stopOnMatch = true) - fromMinLevel(Level.DEBUG) { - toSink("stdout") - } - } - logging { - fromLoggerBase("org.sqlite.core.NativeDB", stopOnMatch = true) - fromMinLevel(Level.DEBUG) { - toSink("stdout") - } - } - logging { - fromMinLevel(Level.ERROR) { - toSink("stderr") - } - inLevelRange(Level.TRACE, Level.WARN) { - toSink("stdout") - } - } - minDirectLogLevel(Level.TRACE) - } - - embeddedServer(CIO, port = 8080, host = "0.0.0.0", module = Application::module) - .start(wait = true) -} - -fun Application.module() { - // configureSecurity() - // configureHTTP() - configureMonitoring() - configureSerialization() - configureRouting() - - testApp() -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/TestApplication.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/TestApplication.kt deleted file mode 100644 index 42d9b18c8..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/TestApplication.kt +++ /dev/null @@ -1,41 +0,0 @@ -package id.walt.authkit - -import id.walt.authkit.methods.AuthenticationMethod -import id.walt.authkit.methods.UserPass -import io.ktor.server.application.* -import io.ktor.server.request.* -import io.ktor.server.routing.* -import io.ktor.util.pipeline.* - -data class AuthContext( - val tenant: String? = null, -) - -fun Application.testApp() { - routing { - route("auth") { - - val contextFunction: PipelineContext.() -> AuthContext = { - AuthContext( - tenant = call.request.host() - ) - } - - registerAuthenticationMethod(UserPass, contextFunction) - } - } -} - -fun Route.registerAuthenticationMethod(method: AuthenticationMethod, context: PipelineContext.() -> AuthContext) { - method.apply { - register(context) - } -} - -fun Route.registerAuthenticationMethods(methods: List, context: PipelineContext.() -> AuthContext) { - methods.forEach { - it.apply { - register(context) - } - } -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/Account.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/Account.kt deleted file mode 100644 index e1beaf812..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/Account.kt +++ /dev/null @@ -1,9 +0,0 @@ -package id.walt.authkit.accounts - -import kotlin.uuid.Uuid - -@OptIn(ExperimentalStdlibApi::class) -data class Account( - val id: Uuid, - val name: String? = null -) diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/AccountStore.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/AccountStore.kt deleted file mode 100644 index 4beb83a59..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/AccountStore.kt +++ /dev/null @@ -1,41 +0,0 @@ -package id.walt.authkit.accounts - -import id.walt.authkit.AuthContext -import id.walt.authkit.accounts.identifiers.AccountIdentifier -import id.walt.authkit.accounts.identifiers.UsernameIdentifier -import id.walt.authkit.methods.AuthenticationMethod -import id.walt.authkit.methods.UserPass -import id.walt.authkit.methods.data.AuthMethodStoredData -import kotlin.uuid.Uuid - -@OptIn(ExperimentalStdlibApi::class) -object AccountStore { - - // Account uuid -> account - val wip_accounts = HashMap() - - // AccountIdentifier -> Account uuid - val wip_account_ids = HashMap() - - // Account uuid -> auth mechanisms - val wip_accountAuthMechanisms = HashMap>() - - - init { - val newAccount = Account(Uuid.random(), "Alice") - wip_accounts[newAccount.id] = newAccount - - val accountIdentifier = UsernameIdentifier("alice1") - wip_account_ids[accountIdentifier] = newAccount.id - - wip_accountAuthMechanisms[newAccount.id] = hashMapOf(UserPass to UserPass.UserPassStoredData("123456")) - } - - fun lookupStoredDataFor(identifier: AccountIdentifier, method: AuthenticationMethod): AuthMethodStoredData { - val uuid = wip_account_ids[identifier] ?: error("No account for identifier: $identifier") - val storedData = wip_accountAuthMechanisms[uuid]!![method] ?: error("No stored data for method: $method") - - return storedData - } - -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/AccountIdentifier.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/AccountIdentifier.kt deleted file mode 100644 index 0f5e9ed62..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/AccountIdentifier.kt +++ /dev/null @@ -1,8 +0,0 @@ -package id.walt.authkit.accounts.identifiers - -interface AccountIdentifier { - - - -} - diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/UsernameIdentifier.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/UsernameIdentifier.kt deleted file mode 100644 index 8610f7d9c..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/accounts/identifiers/UsernameIdentifier.kt +++ /dev/null @@ -1,3 +0,0 @@ -package id.walt.authkit.accounts.identifiers - -class UsernameIdentifier(name: String) : AccountIdentifier diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/exceptions/Exceptions.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/exceptions/Exceptions.kt deleted file mode 100644 index f6a74d61e..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/exceptions/Exceptions.kt +++ /dev/null @@ -1,17 +0,0 @@ -package id.walt.authkit.exceptions - -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.contract - -data class AuthenticationFailureException(override val message: String) : IllegalArgumentException(message) - -@Suppress("NOTHING_TO_INLINE") -inline fun authFailure(message: String): Nothing = throw AuthenticationFailureException(message) - -@OptIn(ExperimentalContracts::class) -public inline fun authCheck(value: Boolean, lazyMessage: () -> Any): Unit { - contract { - returns() implies value - } - if (!value) authFailure(lazyMessage().toString()) -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/AuthenticationMethod.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/AuthenticationMethod.kt deleted file mode 100644 index 50964faf8..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/AuthenticationMethod.kt +++ /dev/null @@ -1,23 +0,0 @@ -package id.walt.authkit.methods - -import id.walt.authkit.AuthContext -import id.walt.authkit.accounts.AccountStore -import id.walt.authkit.accounts.identifiers.AccountIdentifier -import id.walt.authkit.methods.data.AuthMethodStoredData -import io.ktor.server.application.* -import io.ktor.server.routing.* -import io.ktor.util.pipeline.* - -abstract class AuthenticationMethod { - abstract fun Route.register(context: PipelineContext.() -> AuthContext) - -// abstract val identifier: AccountIdentifier - - inline fun lookupStoredData(identifier: AccountIdentifier): V { - val storedData = AccountStore.lookupStoredDataFor(identifier, this) - return (storedData as? V) ?: error("${storedData::class.simpleName} is not requested ${V::class.simpleName}") - } - - - -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/EmailPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/EmailPass.kt deleted file mode 100644 index ec6507759..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/EmailPass.kt +++ /dev/null @@ -1,4 +0,0 @@ -package id.walt.authkit.methods - -class EmailPass { -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/Kerberos.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/Kerberos.kt deleted file mode 100644 index 50879cdd5..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/Kerberos.kt +++ /dev/null @@ -1,56 +0,0 @@ -package id.walt.authkit.methods - -/* -import org.ietf.jgss.* - -fun auth(kerberosRealm: String, kerberosKdc: String, servicePrincipal: String, username: String, password: String): Boolean { - System.setProperty("java.security.krb5.realm", kerberosRealm) - System.setProperty("java.security.krb5.kdc", kerberosKdc) - System.setProperty("javax.security.auth.useSubjectCredsOnly", "false") - - val gssManager = GSSManager.getInstance() - val clientPrincipalName = "user@$kerberosRealm" - val clientPrincipal = GSSName.NT_USER_NAME.apply { - gssManager.createName(clientPrincipalName, this) - } - - val credentials = gssManager.createCredential( - clientPrincipal, - GSSCredential.DEFAULT_LIFETIME, - null, - GSSCredential.INITIATE_ONLY - ) - - val serverPrincipal = gssManager.createName(servicePrincipal, GSSName.NT_HOSTBASED_SERVICE) - - val context = gssManager.createContext( - serverPrincipal, - GSSUtil.GSS_KRB5_MECH_OID, - credentials, - GSSContext.DEFAULT_LIFETIME - ) - - return try { - context.requestMutualAuth(true) - context.requestConf(true) - context.requestInteg(true) - - val token = ByteArray(0) - val outToken = context.initSecContext(token, 0, token.size) - - // This is where you would send the outToken to the server and get a response token back - // For the purposes of this example, we'll assume the server accepted the token - context.isEstablished - } catch (e: GSSException) { - e.printStackTrace() - false - } finally { - context.dispose() - } -} - -// Example usage -fun main() { - val result = auth("EXAMPLE.COM", "kerberos.example.com", "HTTP/kerberos.example.com", "user1", "pass1") - println("Authentication result: $result") -}*/ diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP.kt deleted file mode 100644 index f6a7290fd..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP.kt +++ /dev/null @@ -1,124 +0,0 @@ -package id.walt.authkit.methods - -import io.ktor.server.auth.* -import java.util.* -import javax.naming.* -import javax.naming.directory.* - -/** - * Provides the ability to authenticate an LDAP user. - * This function accepts a credential and validates it against a specified LDAP server. - * - * To learn more about LDAP authentication in Ktor, see [LDAP](https://ktor.io/docs/ldap.html). - */ -public fun ldapAuthenticate( - credential: K, - ldapServerURL: String, - ldapEnvironmentBuilder: (MutableMap) -> Unit = {}, - doVerify: InitialDirContext.(K) -> P? -): P? { - return try { - val root = ldapLogin(ldapServerURL, ldapEnvironmentBuilder) - try { - root.doVerify(credential) - } finally { - root.close() - } - } catch (ne: NamingException) { - null - } -} - -/** - * Provides the ability to authenticates an LDAP user. - * This function accepts [UserPasswordCredential] and validates it against a specified LDAP server. - * - * To learn more about LDAP authentication in Ktor, see [LDAP](https://ktor.io/docs/ldap.html). - */ -public fun

ldapAuthenticate( - credential: UserPasswordCredential, - ldapServerURL: String, - userDNFormat: String, - validate: InitialDirContext.(UserPasswordCredential) -> P? -): P? { - val configurator: (MutableMap) -> Unit = { env -> - env[Context.SECURITY_AUTHENTICATION] = "simple" - env[Context.SECURITY_PRINCIPAL] = userDNFormat.format(ldapEscape(credential.name)) - env[Context.SECURITY_CREDENTIALS] = credential.password - } - - return ldapAuthenticate(credential, ldapServerURL, configurator, validate) -} - -/** - * Provides the ability to authenticates an LDAP user. - * This function accepts [UserPasswordCredential] and validates it against a specified LDAP server. - * - * To learn more about LDAP authentication in Ktor, see [LDAP](https://ktor.io/docs/ldap.html). - */ -public fun ldapAuthenticate( - credential: UserPasswordCredential, - ldapServerURL: String, - userDNFormat: String -): UserIdPrincipal? { - return ldapAuthenticate(credential, ldapServerURL, userDNFormat) { UserIdPrincipal(it.name) } -} - -private fun ldapLogin(ldapURL: String, ldapEnvironmentBuilder: (MutableMap) -> Unit): InitialDirContext { - val env = Hashtable() - env[Context.INITIAL_CONTEXT_FACTORY] = "com.sun.jndi.ldap.LdapCtxFactory" - env[Context.PROVIDER_URL] = ldapURL - - ldapEnvironmentBuilder(env) - - return InitialDirContext(env) -} - -internal fun ldapEscape(string: String): String { - for (index in 0..string.lastIndex) { - val character = string[index] - if (character.shouldEscape()) { - return ldapEscapeImpl(string, index) - } - } - - return string -} - -private fun ldapEscapeImpl(string: String, firstIndex: Int): String = buildString { - var lastIndex = 0 - for (index in firstIndex..string.lastIndex) { - val character = string[index] - if (character.shouldEscape()) { - append(string, lastIndex, index) - if (character in ESCAPE_CHARACTERS) { - append('\\') - append(character) - } else { - character.toString().toByteArray().let { encoded -> - for (byteIndex in 0 until encoded.size) { - val unsignedValue = encoded[byteIndex].toInt() and 0xff - append('\\') - append(unsignedValue.toString(16).padStart(2, '0')) - } - } - } - - lastIndex = index + 1 - } - } - - append(string, lastIndex, string.length) -} - -private val ESCAPE_CHARACTERS = charArrayOf(' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\') - -private fun Char.shouldEscape(): Boolean = this.code.let { codepoint -> - when (codepoint) { - in 0x3f..0x7e -> codepoint == 0x5c // the only forbidden character is backslash - in 0x2d..0x3a -> false // minus, point, slash (allowed), digits + colon : - in 0x24..0x2a -> false // $%&'()* - 0x21 -> false // exclamation - else -> true - } -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP2.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP2.kt deleted file mode 100644 index 78db1ad80..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/LDAP2.kt +++ /dev/null @@ -1,30 +0,0 @@ -package id.walt.authkit.methods - -import org.apache.directory.api.ldap.model.exception.LdapException -import org.apache.directory.ldap.client.api.LdapConnection -import org.apache.directory.ldap.client.api.LdapNetworkConnection - -fun auth(ldapServerUrl: String, userDNFormat: String, username: String, password: String): Boolean { - val (hostname, port) = ldapServerUrl.removePrefix("ldap://").split(":") - val userDN = userDNFormat.format(username) - - var connection: LdapConnection? = null - - return try { - connection = LdapNetworkConnection(hostname, port.toInt()) - connection.bind(userDN, password) - true - } catch (e: LdapException) { - e.printStackTrace() - false - } finally { - connection?.unBind() - connection?.close() - } -} - -// Example usage -fun main() { - val result = auth("ldap://localhost:3893", "cn=%s,ou=superheros,dc=glauth,dc=com", "hackers", "dogood") - println("Authentication result: $result") -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt deleted file mode 100644 index 100bf0a37..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/RADIUS.kt +++ /dev/null @@ -1,63 +0,0 @@ -package id.walt.authkit.methods - -import id.walt.authkit.AuthContext -import id.walt.authkit.exceptions.authCheck -import id.walt.authkit.methods.data.AuthMethodStoredData -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.routing.* -import io.ktor.util.pipeline.* -import kotlinx.serialization.Serializable -import org.aaa4j.radius.client.RadiusClient -import org.aaa4j.radius.client.clients.UdpRadiusClient -import org.aaa4j.radius.core.attribute.StringData -import org.aaa4j.radius.core.attribute.TextData -import org.aaa4j.radius.core.attribute.attributes.NasIdentifier -import org.aaa4j.radius.core.attribute.attributes.UserName -import org.aaa4j.radius.core.attribute.attributes.UserPassword -import org.aaa4j.radius.core.packet.Packet -import org.aaa4j.radius.core.packet.packets.AccessAccept -import org.aaa4j.radius.core.packet.packets.AccessRequest -import java.net.InetSocketAddress - -object RADIUS : UserPassBasedAuthMethod() { - - @Serializable - data class RADIUSConfiguration( - val radiusServerHost: String, - val radiusServerPort: Int, - val radiusServerSecret: String, - val radiusNasIdentifier: String, - ): AuthMethodStoredData - - val radiusClient: RadiusClient = UdpRadiusClient.newBuilder() - .secret("sharedsecret".toByteArray()) - .address(InetSocketAddress("10.1.1.10", 1812)) - .build() - - // Todo: Move to configuration (is not stored data) - - override suspend fun auth(credential: UserPasswordCredential) { - val accessRequest = AccessRequest( - listOf( - UserName(TextData(credential.name)), - UserPassword(StringData(credential.password.toByteArray())), - NasIdentifier(TextData("this is like a client id")) - ) - ) - - val responsePacket: Packet = radiusClient.send(accessRequest) - authCheck(responsePacket is AccessAccept) { "RADIUS server did not accept authentication" } - - } - - - override fun Route.register(context: PipelineContext.() -> AuthContext) { - post("userpass") { - val credential = call.getUsernamePasswordFromRequest() - - auth(credential) - } - } - -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/TOTP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/TOTP.kt deleted file mode 100644 index a8bde5299..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/TOTP.kt +++ /dev/null @@ -1,51 +0,0 @@ -package id.walt.authkit.methods - -import com.atlassian.onetime.core.TOTP -import com.atlassian.onetime.core.TOTPGenerator -import com.atlassian.onetime.model.EmailAddress -import com.atlassian.onetime.model.Issuer -import com.atlassian.onetime.model.TOTPSecret -import com.atlassian.onetime.service.AsciiRangeSecretProvider -import com.atlassian.onetime.service.AsyncSecretProvider -import com.atlassian.onetime.service.DefaultTOTPService -import com.atlassian.onetime.service.TOTPConfiguration -import java.util.concurrent.CompletableFuture - -class AsyncAsciiRangeSecretProvider : AsyncSecretProvider { - - override fun generateSecret(): CompletableFuture = - CompletableFuture.supplyAsync { - AsciiRangeSecretProvider.generateSecret() - } -} - -fun interface CPSSecretProvider { - suspend fun generateSecret(): TOTPSecret -} - -fun main() { - val service = DefaultTOTPService( - totpGenerator = TOTPGenerator(), - totpConfiguration = TOTPConfiguration() - ) - - val secret = TOTPSecret.fromBase32EncodedString("ZIQL3WHUAGCS5FQQDKP74HZCFT56TJHR") - val totpGenerator: TOTPGenerator = TOTPGenerator() - val totp = totpGenerator.generateCurrent(secret) //TOTP(value=123456) - println("totp: $totp") - - val totpUri = service.generateTOTPUrl( - secret, ////NIQXUILREVGHIUKNORKHSJDHKMWS6UTY - EmailAddress("jsmith@acme.com"), - Issuer("Acme Co") - ) - println("URI: $totpUri") - - - val userInput: TOTP = TOTP("123456") //TOTP from user input - val result = service.verify( - userInput, - secret //NIQXUILREVGHIUKNORKHSJDHKMWS6UTY - ) - println("Result: $result") -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt deleted file mode 100644 index f7aaeddeb..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPass.kt +++ /dev/null @@ -1,38 +0,0 @@ -package id.walt.authkit.methods - -import id.walt.authkit.AuthContext -import id.walt.authkit.accounts.identifiers.UsernameIdentifier -import id.walt.authkit.exceptions.authCheck -import id.walt.authkit.methods.data.AuthMethodStoredData -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.routing.* -import io.ktor.util.pipeline.* -import kotlinx.serialization.Serializable - -object UserPass : UserPassBasedAuthMethod() { - - @Serializable - data class UserPassStoredData( - val password: String, - ) : AuthMethodStoredData - - override suspend fun auth(credential: UserPasswordCredential) { - val identifier = UsernameIdentifier(credential.name) - - val storedData: UserPassStoredData = lookupStoredData(identifier /*context()*/) - - authCheck(credential.password == storedData.password) { "Invalid password" } - - // TODO: Open session - } - - override fun Route.register(context: PipelineContext.() -> AuthContext) { - post("userpass") { - val credential = call.getUsernamePasswordFromRequest() - - auth(credential) - } - } - -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPassBasedAuthMethod.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPassBasedAuthMethod.kt deleted file mode 100644 index 626027c7b..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/UserPassBasedAuthMethod.kt +++ /dev/null @@ -1,70 +0,0 @@ -package id.walt.authkit.methods - -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.auth.* -import io.ktor.server.request.* -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive - -/** - * Authentication method based on an id (username, email) and password - * - * Handles passing the auth credential as basic auth header, as JSON document body, or as form post. - */ -abstract class UserPassBasedAuthMethod(val usernameName: String = DEFAULT_USER_NAME, val passwordName: String = DEFAULT_PASSWORD_NAME) : AuthenticationMethod() { - - companion object { - const val DEFAULT_USER_NAME = "username" - const val DEFAULT_PASSWORD_NAME = "password" - } - - val EXPLANATION_MESSAGE by lazy { - """Pass authentication credential either as 1) Basic Auth header (`Authorization: Basic `) as per RFC 7617; OR 2) JSON document (`{"$usernameName": "<$usernameName>", "$passwordName": "<$passwordName>"}`); OR 3) Form post ($usernameName=<$usernameName>&$passwordName=<$passwordName>)!""" - } - - /** - * Handle username and password as: - * 1. Basic auth header - * 2. JSON document body - * 3. Form post - */ - internal suspend fun ApplicationCall.getUsernamePasswordFromRequest(): UserPasswordCredential { - when (val contentType = request.contentType()) { - // Basic auth (fallback) - ContentType.Any -> { - val basicAuth = request.basicAuthenticationCredentials() - if (basicAuth != null) - return basicAuth - else error("No basic auth credential header found. $EXPLANATION_MESSAGE") - } - // As JSON document - ContentType.Application.Json -> { - val body = receive() - - val username = body[usernameName] as? JsonPrimitive ?: body[DEFAULT_USER_NAME] as? JsonPrimitive - val password = body[passwordName] as? JsonPrimitive ?: body[DEFAULT_PASSWORD_NAME] as? JsonPrimitive - - check(username?.isString == true) { "Invalid or missing $usernameName in JSON request. $EXPLANATION_MESSAGE" } - check(password?.isString == true) { "Invalid or missing $passwordName in JSON request. $EXPLANATION_MESSAGE" } - username!! - password!! - - return UserPasswordCredential(username.content, password.content) - } - // As form post - ContentType.Application.FormUrlEncoded -> { - val form = receiveParameters() - - val username = form[usernameName] ?: form[DEFAULT_USER_NAME] ?: error("Invalid or missing $usernameName in form post request. $EXPLANATION_MESSAGE") - val password = form[passwordName] ?: form[DEFAULT_PASSWORD_NAME] ?: error("Invalid or missing $passwordName in form post request. $EXPLANATION_MESSAGE") - - return UserPasswordCredential(username, password) - } - - else -> error("Invalid content type: $contentType. $EXPLANATION_MESSAGE") - } - } - - abstract suspend fun auth(credential: UserPasswordCredential) -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/config/AuthMethodConfiguration.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/config/AuthMethodConfiguration.kt deleted file mode 100644 index 358744139..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/config/AuthMethodConfiguration.kt +++ /dev/null @@ -1,3 +0,0 @@ -package id.walt.authkit.methods.config - -interface AuthMethodConfiguration diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/data/AuthMethodStoredData.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/data/AuthMethodStoredData.kt deleted file mode 100644 index 9e2d01ff5..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/methods/data/AuthMethodStoredData.kt +++ /dev/null @@ -1,3 +0,0 @@ -package id.walt.authkit.methods.data - -interface AuthMethodStoredData diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/HTTP.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/HTTP.kt deleted file mode 100644 index 8d3bda6e4..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/HTTP.kt +++ /dev/null @@ -1,25 +0,0 @@ -package id.walt.authkit.plugins - -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.plugins.cors.routing.* -import io.ktor.server.plugins.defaultheaders.* -import io.ktor.server.plugins.forwardedheaders.* -import io.ktor.server.response.* - -fun Application.configureHTTP() { - install(CORS) { - allowMethod(HttpMethod.Options) - allowMethod(HttpMethod.Put) - allowMethod(HttpMethod.Delete) - allowMethod(HttpMethod.Patch) - allowHeader(HttpHeaders.Authorization) - allowHeader("MyCustomHeader") - anyHost() // @TODO: Don't do this in production if possible. Try to limit it. - } - install(DefaultHeaders) { - header("X-Engine", "Ktor") // will send this header with each response - } - install(ForwardedHeaders) // WARNING: for security, do not include this if not behind a reverse proxy - install(XForwardedHeaders) // WARNING: for security, do not include this if not behind a reverse proxy -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Monitoring.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Monitoring.kt deleted file mode 100644 index bbb299031..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Monitoring.kt +++ /dev/null @@ -1,14 +0,0 @@ -package id.walt.authkit.plugins - -import io.ktor.server.application.* -import io.ktor.server.plugins.callloging.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import org.slf4j.event.* - -fun Application.configureMonitoring() { - install(CallLogging) { - level = Level.DEBUG - } -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Routing.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Routing.kt deleted file mode 100644 index 86209a9ea..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Routing.kt +++ /dev/null @@ -1,39 +0,0 @@ -package id.walt.authkit.plugins - -import io.github.smiley4.ktorswaggerui.SwaggerUI -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.application.Application -import io.ktor.server.application.install -import io.ktor.server.plugins.autohead.* -import io.ktor.server.plugins.doublereceive.* -import io.ktor.server.plugins.statuspages.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import io.ktor.server.webjars.* - -fun Application.configureRouting() { - install(AutoHeadResponse) - install(DoubleReceive) - install(SwaggerUI) { - swagger { -// swaggerUrl = "swagger-ui" -// forwardRoot = true - } - info { - title = "Example API" - version = "latest" - description = "Example API for testing and demonstration purposes." - } - server { - url = "http://localhost:8080" - description = "Development Server" - } - } - install(StatusPages) { - exception { call, cause -> - call.respondText(text = "500: $cause" , status = HttpStatusCode.InternalServerError) - } - } -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Security.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Security.kt deleted file mode 100644 index 4e0624827..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Security.kt +++ /dev/null @@ -1,122 +0,0 @@ -package id.walt.authkit.plugins - -import io.ktor.server.application.* - -fun Application.configureSecurity() { - - -} - /*authentication { - basic(name = "myauth1") { - realm = "Ktor Server" - validate { credentials -> - if (credentials.name == credentials.password) { - UserIdPrincipal(credentials.name) - } else { - null - } - } - } - - form(name = "myauth2") { - userParamName = "user" - passwordParamName = "password" - challenge { - *//**//* - } - } - } - // Please read the jwt property from the config file if you are using EngineMain - val jwtAudience = "jwt-audience" - val jwtDomain = "https://jwt-provider-domain/" - val jwtRealm = "ktor sample app" - val jwtSecret = "secret" - authentication { - jwt { - realm = jwtRealm - verifier( - JWT - .require(Algorithm.HMAC256(jwtSecret)) - .withAudience(jwtAudience) - .withIssuer(jwtDomain) - .build() - ) - validate { credential -> - if (credential.payload.audience.contains(jwtAudience)) JWTPrincipal(credential.payload) else null - } - } - }*/ - /* val localhost = "localhost" - val ldapServerPort = 3893 // TODO: change to real value! - authentication { - basic("auth-ldap") { - realm = "realm" - validate { credential -> - println("Validating LDAP credential: $credential") - ldapAuthenticate(credential, "ldap://$localhost:${ldapServerPort}", "cn=%s,ou=superheros,dc=glauth,dc=com") - } - } - }*/ - /*authentication { - oauth("auth-oauth-google") { - urlProvider = { "http://localhost:8080/callback" } - providerLookup = { - OAuthServerSettings.OAuth2ServerSettings( - name = "google", - authorizeUrl = "https://accounts.google.com/o/oauth2/auth", - accessTokenUrl = "https://accounts.google.com/o/oauth2/token", - requestMethod = HttpMethod.Post, - clientId = System.getenv("GOOGLE_CLIENT_ID"), - clientSecret = System.getenv("GOOGLE_CLIENT_SECRET"), - defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile") - ) - } - client = HttpClient(Apache) - } - } - data class MySession(val count: Int = 0) - install(Sessions) { - cookie("MY_SESSION") { - cookie.extensions["SameSite"] = "lax" - } - }*/ - /* routing { - authenticate("auth-ldap") { - get("/") { - call.respondText("Hello, ${call.principal()?.name}!") - } - }*/ - /*authenticate("myauth1") { - get("/protected/route/basic") { - val principal = call.principal()!! - call.respondText("Hello ${principal.name}") - } - } - authenticate("myauth2") { - get("/protected/route/form") { - val principal = call.principal()!! - call.respondText("Hello ${principal.name}") - } - } - authenticate("auth-oauth-google") { - get("login") { - call.respondRedirect("/callback") - } - - get("/callback") { - val principal: OAuthAccessTokenResponse.OAuth2? = call.authentication.principal() - call.sessions.set(UserSession(principal?.accessToken.toString())) - call.respondRedirect("/hello") - } - } - get("/session/increment") { - val session = call.sessions.get() ?: MySession() - call.sessions.set(session.copy(count = session.count + 1)) - call.respondText("Counter is ${session.count}. Refresh to increment.") - }*/ -/* - } -} - -class UserSession(accessToken: String) -*/ diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Serialization.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Serialization.kt deleted file mode 100644 index 6c179577f..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/plugins/Serialization.kt +++ /dev/null @@ -1,13 +0,0 @@ -package id.walt.authkit.plugins - -import io.ktor.serialization.kotlinx.json.* -import io.ktor.server.application.* -import io.ktor.server.plugins.contentnegotiation.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -fun Application.configureSerialization() { - install(ContentNegotiation) { - json() - } -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSession.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSession.kt deleted file mode 100644 index 91d5147b5..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSession.kt +++ /dev/null @@ -1,14 +0,0 @@ -package id.walt.authkit.sessions - -import kotlin.uuid.Uuid - -enum class AuthSessionStatus(val value: String) { - OK("ok"), - CONTINUE_NEXT_STEP("continue_next_step"), - FAIL("fail"), -} - -@OptIn(ExperimentalStdlibApi::class) -data class AuthSession( - val id: Uuid -) diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSessionResponse.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSessionResponse.kt deleted file mode 100644 index 9b4c50862..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/AuthSessionResponse.kt +++ /dev/null @@ -1,14 +0,0 @@ -package id.walt.authkit.sessions - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class AuthSessionResponse( - val session: String, // Session ID - val status: AuthSessionStatus, - - val user: String, - @SerialName("auth_token") - val authToken: String -) diff --git a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/SessionStore.kt b/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/SessionStore.kt deleted file mode 100644 index 5cdbe2aea..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/kotlin/id/walt/authkit/sessions/SessionStore.kt +++ /dev/null @@ -1,4 +0,0 @@ -package id.walt.authkit.sessions - -object SessionStore { -} diff --git a/waltid-libraries/auth/waltid-authkit/src/main/resources/logback.xml b/waltid-libraries/auth/waltid-authkit/src/main/resources/logback.xml deleted file mode 100644 index 3e11d7811..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/main/resources/logback.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt b/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt deleted file mode 100644 index fa8f55655..000000000 --- a/waltid-libraries/auth/waltid-authkit/src/test/kotlin/id/walt/ApplicationTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -package id.walt - -import id.walt.authkit.plugins.configureRouting -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import io.ktor.server.testing.* -import kotlin.test.* - -class ApplicationTest { - // @Test - fun testRoot() = testApplication { - application { - - - - configureRouting() - } - - - client.post("/auth/userpass") { - basicAuth("user1", "pass1") - } - } -} diff --git a/waltid-libraries/auth/waltid-idpkit/.gitignore b/waltid-libraries/auth/waltid-idpkit/.gitignore deleted file mode 100644 index c426c32f8..000000000 --- a/waltid-libraries/auth/waltid-idpkit/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ \ No newline at end of file diff --git a/waltid-libraries/auth/waltid-idpkit/build.gradle.kts b/waltid-libraries/auth/waltid-idpkit/build.gradle.kts deleted file mode 100644 index 7d35d0222..000000000 --- a/waltid-libraries/auth/waltid-idpkit/build.gradle.kts +++ /dev/null @@ -1,52 +0,0 @@ -plugins { - kotlin("jvm") - id("io.ktor.plugin") version "2.3.12" - kotlin("plugin.serialization") -} - -group = "id.walt" -version = "0.0.1" - -application { - mainClass.set("id.walt.ApplicationKt") - - val isDevelopment: Boolean = project.ext.has("development") - applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") -} - -repositories { - mavenCentral() -} - -dependencies { - // Ktor server - implementation("io.ktor:ktor-server-core") - implementation("io.ktor:ktor-server-cio") - implementation("io.ktor:ktor-server-sessions") - implementation("io.ktor:ktor-server-status-pages") - implementation("io.ktor:ktor-server-content-negotiation") - implementation("io.ktor:ktor-serialization-kotlinx-json") - implementation("io.ktor:ktor-server-call-logging") - implementation("io.ktor:ktor-server-double-receive") - - // Ktor client - implementation("io.ktor:ktor-client-core") - implementation("io.ktor:ktor-client-cio") - implementation("io.ktor:ktor-client-content-negotiation") - - // JSON - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0") - implementation("com.eygraber:jsonpathkt-kotlinx:3.0.2") - - // OIDC - implementation("com.nimbusds:oauth2-oidc-sdk:11.12") - implementation("com.nimbusds:nimbus-jose-jwt:9.40") - - // Logging - implementation("io.klogging:klogging-jvm:0.7.0") - implementation("io.klogging:slf4j-klogging:0.7.0") - - testImplementation("io.ktor:ktor-server-test-host-jvm") - testImplementation("org.jetbrains.kotlin:kotlin-test-junit") -} diff --git a/waltid-libraries/auth/waltid-idpkit/gradle.properties b/waltid-libraries/auth/waltid-idpkit/gradle.properties deleted file mode 100644 index 7fc6f1ff2..000000000 --- a/waltid-libraries/auth/waltid-idpkit/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -kotlin.code.style=official diff --git a/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.jar b/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL diff --git a/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.properties b/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e411586a5..000000000 --- a/waltid-libraries/auth/waltid-idpkit/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/waltid-libraries/auth/waltid-idpkit/gradlew b/waltid-libraries/auth/waltid-idpkit/gradlew deleted file mode 100755 index 1b6c78733..000000000 --- a/waltid-libraries/auth/waltid-idpkit/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/waltid-libraries/auth/waltid-idpkit/gradlew.bat b/waltid-libraries/auth/waltid-idpkit/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/waltid-libraries/auth/waltid-idpkit/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/waltid-libraries/auth/waltid-idpkit/settings.gradle.kts b/waltid-libraries/auth/waltid-idpkit/settings.gradle.kts deleted file mode 100644 index ebecacf52..000000000 --- a/waltid-libraries/auth/waltid-idpkit/settings.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = "waltid-idpkit" diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt deleted file mode 100644 index 12d134fd0..000000000 --- a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/App2.kt +++ /dev/null @@ -1,330 +0,0 @@ -@file:OptIn(ExperimentalStdlibApi::class) - -package id.walt - -import io.klogging.Level -import io.klogging.config.loggingConfiguration -import io.klogging.rendering.RENDER_ANSI -import io.klogging.sending.STDERR -import io.klogging.sending.STDOUT -import io.ktor.http.* -import io.ktor.serialization.kotlinx.json.* -import io.ktor.server.application.* -import io.ktor.server.cio.* -import io.ktor.server.engine.* -import io.ktor.server.plugins.callloging.* -import io.ktor.server.plugins.contentnegotiation.* -import io.ktor.server.plugins.doublereceive.* -import io.ktor.server.plugins.statuspages.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import io.ktor.server.util.* -import io.ktor.util.* -import kotlinx.coroutines.runBlocking -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromJsonElement -import kotlinx.serialization.json.encodeToJsonElement -import kotlin.uuid.Uuid - -fun main() { - loggingConfiguration(true) { - sink("stdout", RENDER_ANSI, STDOUT) - sink("stderr", RENDER_ANSI, STDERR) - - logging { - fromLoggerBase("io.ktor", stopOnMatch = true) - fromMinLevel(Level.INFO) { - toSink("stdout") - } - } - logging { - fromLoggerBase("org.sqlite.core.NativeDB", stopOnMatch = true) - fromMinLevel(Level.DEBUG) { - toSink("stdout") - } - } - logging { - fromMinLevel(Level.ERROR) { - toSink("stderr") - } - inLevelRange(Level.TRACE, Level.WARN) { - toSink("stdout") - } - } - minDirectLogLevel(Level.TRACE) - } - - embeddedServer(CIO, port = 8080) { - install(ContentNegotiation) { - json() - } - - install(DoubleReceive) - - install(CallLogging) { - level = org.slf4j.event.Level.DEBUG - format { call -> - """ - -v-v-v- - > Request: - ${call.request.httpMethod.value} ${call.request.uri} - Headers: ${call.request.headers.toMap().dropCommonHeaders()} - ${if ((call.request.contentLength() ?: 0) > 0) "Body: ${runBlocking { call.receiveText() }}" else "No body"} - - > Response: - ${call.response.status()} (${call.response.responseType?.type?.simpleName}) - -^-^-^- - """.trimIndent() - } - } - - install(StatusPages) { - exception { call, cause -> - cause.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, cause.localizedMessage) - } - } - - test() - }.start(wait = true) -} - -private fun Map>.dropCommonHeaders(): Map> = - this.toMutableMap().apply { - keys.removeIf { it.startsWith("Sec-") || it.startsWith("Upgrade-") || it.startsWith("Accept") } - keys.removeAll( - listOf( - "Connection", - "Cookie", - "DNT", - "User-Agent", "Priority" - ) - ) - } - -@Serializable -data class AuthorizeRequest( - /** CSRF protection */ - val state: String? = null, - /** server-side relay protection */ - val nonce: String? = null, - /** scope */ - //val scope: List, - val scope: String, - /** OIDC Provider will redirect here */ - @SerialName("redirect_uri") - val redirectUri: String, - @SerialName("response_type") - val responseType: String = "code", - /** Relying Party identifier */ - @SerialName("client_id") - val clientId: String, -) - -@Serializable -data class TokenResponse( - @SerialName("id_token") - val idToken: String, - @SerialName("access_token") - val accessToken: String, - @SerialName("token_type") - val tokenType: String, - @SerialName("expires_in") - val expiresIn: Int, -) - -fun Application.test() { - routing { - // Step 0. (call by RP) - get(".well-known/openid-configuration") { - val issuer = "http://localhost:8080" - - val wellKnown = mapOf( - "issuer" to issuer, - "authorization_endpoint" to "$issuer/authorize", - "token_endpoint" to "$issuer/token", - "userinfo_endpoint" to "$issuer/userinfo", - "jwks_uri" to "$issuer/jwks", - "response_types_supported" to listOf("code", "id_token", "token id_token"), - "subject_types_supported" to listOf("public"), - "id_token_signing_alg_values_supported" to listOf("RS256"), - "scopes_supported" to listOf("openid", "profile", "email"), - //"token_endpoint_auth_methods_supported" to listOf("client_secret_basic", "client_secret_post"), - "token_endpoint_auth_methods_supported" to listOf("client_secret_basic"), - "claims_supported" to listOf("sub", "iss", "aud", "iat", "exp", "name", "email") - ).toJsonObject() - call.respond(wellKnown) - } - - // (RP 302 redirects user agent to /authorize with state, nonce, scope, redirect_uri, response_type, client_id) - - val authCache = HashMap() // state -> req - val reqCache = HashMap() - val urlCache = HashMap() - - // Step 1. - get("/authorize") { - val query = call.request.queryParameters - var queryString = query.formUrlEncode() - - val map = query.toMap().mapValues { it.value.joinToString(" ") } - var req = Json.decodeFromJsonElement(Json.encodeToJsonElement(map)) - - if (req.state == null) { - // Generate state - req = req.copy(state = Uuid.random().toString()) - queryString += "&state=${req.state}" - } - - authCache[req.state!!] = req - println("Saved req to authCache: $req") - - - val (url, token) = Verifier.verify("http://localhost:8080/login?state=${req.state!!}") - reqCache[req.state!!] = token - urlCache[req.state!!] = url - - - val walletUrl = "http://localhost:7101/api/siop/initiatePresentation?" + url.substringAfter("?") - println("Wallet url: $walletUrl") - - //language=HTML - call.respondText( - """ - -

Present your credential: $url

-
-

- (just imagine real hard that this is automatic) -

-

- -

-

Debug query: $queryString

- - - - - - """.trimIndent(), ContentType.Text.Html - ) - } - - val codeCache = HashMap() - - val verifyResultCache = HashMap>() - - get("/login") { - val state = call.request.queryParameters.getOrFail("state") - - val authReq = authCache[state] ?: error("No such state: $state") - - val requestedClaims = listOf( - "$.name", - "$.credentialSubject.achievement.description", - "$.credentialSubject.achievement.criteria.narrative" - ) - - val verificationResult = Verifier.getVerificationResult(reqCache[state] ?: error("No req for state: $state"), requestedClaims) - - if (verificationResult.state == VerificationStatus.WAITING_FOR_SUBMISSION) { - val url = urlCache[state] ?: error("No such state: $state") - - //language=HTML - call.respondText( - """ - -

Not presented yet, please try again

-

Present your credential: $url (just imagine real hard that this is a QR code)

- Click here when presented (just imagine real hard that this is automatic) - - """.trimIndent(), ContentType.Text.Html - ) - return@get - } - - if (verificationResult.success == true) { - val generatedCode = Uuid.random().toString() - - codeCache[generatedCode] = state - verifyResultCache[generatedCode] = verificationResult.claims!! - - call.respondRedirect(authReq.redirectUri + "?code=$generatedCode&state=${authReq.state}") // todo handle redirect URIs that already have parameters - } else { - call.respondText("Presentation failed!") - } - } - - - val tokenClaimCache = HashMap>() - - - // Step 2 - post("/token") { - val form = call.receiveParameters() - - - /*val (clientId, clientSecret) = call.request.authorization()?.decodeBase64String()?.split(":") - - throw IllegalArgumentException( - "Client id or client secret missing in basic auth" - )*/ - - val basicAuth = call.request.authorization()?.decodeBase64String()?.split(":") - val clientId = basicAuth?.get(0) ?: form["client_id"] ?: error("No client_id provided") - val clientSecret = basicAuth?.get(1) ?: form["client_secret"] ?: error("No client_secret provided") - - println("Client id: $clientId, client secret: $clientSecret") - - - val grantType = form.getOrFail("grant_type") - val code = form.getOrFail("code") - val redirectUri = form.getOrFail("redirect_uri") - - println("grant type = $grantType") - - val req = authCache[codeCache[code] ?: error("No such code: $code")] ?: error("No such req for state: ${codeCache[code]}") - - check(req.redirectUri == redirectUri) { "Redirect uri does not match: ${req.redirectUri} - $redirectUri" } - - - val accessToken = "access-idpkit_" + Uuid.random().toString() - - - val claims = verifyResultCache[code]!! - - tokenClaimCache[accessToken] = claims - - val tokenResponse = TokenResponse( - idToken = "id token here", - accessToken = accessToken, - tokenType = "Bearer", - expiresIn = 3600 - ) - - - call.respond(tokenResponse) - } - - - get("/userinfo") { - val auth = call.request.authorization()?.removePrefix("Bearer ") - - if (tokenClaimCache.containsKey(auth)) { - val claims = tokenClaimCache[auth]!! - - call.respond( - claims.toJsonObject() - ) - } else { - call.respond(HttpStatusCode.Unauthorized) - } - } - - } -} diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Application.kt b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Application.kt deleted file mode 100644 index f36f992ec..000000000 --- a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Application.kt +++ /dev/null @@ -1,591 +0,0 @@ -package id.walt - -import kotlinx.serialization.json.* - -/* -import com.nimbusds.jose.JWSAlgorithm -import com.nimbusds.jose.JWSHeader -import com.nimbusds.jose.crypto.RSASSASigner -import com.nimbusds.jose.jwk.JWKSet -import com.nimbusds.jose.jwk.RSAKey -import com.nimbusds.jose.jwk.gen.RSAKeyGenerator -import com.nimbusds.jwt.JWTClaimsSet -import com.nimbusds.jwt.SignedJWT -import com.nimbusds.oauth2.sdk.* -import com.nimbusds.oauth2.sdk.auth.ClientAuthentication -import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic -import com.nimbusds.oauth2.sdk.auth.ClientSecretPost -import com.nimbusds.oauth2.sdk.http.HTTPRequest -import com.nimbusds.oauth2.sdk.token.BearerAccessToken -import io.klogging.Level -import io.klogging.config.loggingConfiguration -import io.klogging.logger -import io.klogging.rendering.RENDER_ANSI -import io.klogging.sending.STDERR -import io.klogging.sending.STDOUT -import io.ktor.http.* -import io.ktor.serialization.kotlinx.json.* -import io.ktor.server.application.* -import io.ktor.server.cio.* -import io.ktor.server.engine.* -import io.ktor.server.plugins.callloging.* -import io.ktor.server.plugins.contentnegotiation.* -import io.ktor.server.plugins.statuspages.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import io.ktor.server.sessions.* -import io.ktor.server.util.* -import io.ktor.util.* -import kotlinx.datetime.Clock -import kotlinx.datetime.toJavaInstant -import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.* -import java.net.URL -import java.util.Date -import java.util.UUID -import kotlin.time.Duration.Companion.seconds - -private val log = logger("walt.id IDP") - -data class UserSession(val id: String, val state: String) - -@Serializable -data class TokenStore( - val accessToken: String, - val tokenType: String, - val expiresIn: Long, - val idToken: String, - val issueTime: kotlinx.datetime.Instant, - val expirationTime: kotlinx.datetime.Instant, -) {*/ -/*fun toJSON(): String { - return Json.encodeToString(this) - }*//* - -} - -val tokenStore = mutableMapOf() - -fun main() { - loggingConfiguration(true) { - sink("stdout", RENDER_ANSI, STDOUT) - sink("stderr", RENDER_ANSI, STDERR) - - logging { - fromLoggerBase("io.ktor.routing.Routing", stopOnMatch = true) - fromMinLevel(Level.DEBUG) { - toSink("stdout") - } - } - logging { - fromLoggerBase("org.sqlite.core.NativeDB", stopOnMatch = true) - fromMinLevel(Level.DEBUG) { - toSink("stdout") - } - } - logging { - fromMinLevel(Level.ERROR) { - toSink("stderr") - } - inLevelRange(Level.TRACE, Level.WARN) { - toSink("stdout") - } - } - minDirectLogLevel(Level.TRACE) - } - - embeddedServer(CIO, port = 8080) { - install(ContentNegotiation) { - json() - } - - install(CallLogging) { - this.level = org.slf4j.event.Level.DEBUG - } - - install(Sessions) { - cookie("USER_SESSION") { - cookie.path = "/" - cookie.httpOnly = true - cookie.extensions["SameSite"] = "Strict" - } - } - install(StatusPages) { - exception { call, cause -> - cause.printStackTrace() - call.respond(HttpStatusCode.InternalServerError, cause.localizedMessage) - } - } - routing { - get("/") { - call.respondText("OIDC IDP Server", ContentType.Text.Plain) - } - wellKnownConfiguration() - authenticateUser() - handleOIDCRequests() - handleLogout() - } - }.start(wait = true) -} - - -private const val thisIdp = "http://localhost:8080" - - -// Function to get claims from SignedJWT -suspend fun getClaimsFromJWT(idToken: String): JWTClaimsSet? { - log.trace { "Getting claims from idToken: $idToken" } - return try { - val signedJWT = SignedJWT.parse(idToken) - signedJWT.jwtClaimsSet.also { log.trace { "Claims from idToken $idToken are: ${signedJWT.jwtClaimsSet}" } } - } catch (e: ParseException) { - null - } -} - -// Token removal logic -suspend fun removeToken(tokenRequest: String) { - log.trace { "Removing token: $tokenRequest" } - tokenStore.values.removeIf { it.accessToken == tokenRequest || it.idToken == tokenRequest } -} - -fun Routing.handleOIDCRequests() { - get("/authorize") { - val queryParams = call.request.queryParameters - log.trace { "OIDC /authorize: with query: ${queryParams.entries()}" } - val authRequest = AuthorizationRequest.parse(queryParams.toMap()) - log.trace { "OIDC /authorize: validating auth request: (query encoded) ${authRequest.toQueryString()}" } - validateAuthRequest(authRequest) - - //val customLogicResult = performCustomLogic() - val x = queryParams.get("custom-login-stuff") - if (x == null) { - call.respondRedirect("/login?${authRequest.toQueryString()}") - return@get - } - - val customLogicResult = x == "success" - - - if (customLogicResult) { - val authCode = AuthorizationCode() - val redirectURI = authRequest.redirectionURI.toString() + "?code=${authCode.value}" - - log.trace { "OIDC /authorize: validated with custom logic: (query encoded) ${authRequest.toQueryString()}, redirecting to ${redirectURI}, state is ${authRequest.state} (state value ${authRequest.state?.value}" } - - // Store the auth code details and user session - call.sessions.set(UserSession(id = "user-id", state = authRequest.state.value)) - call.respondRedirect(redirectURI) - } else { - log.trace { "OIDC /authorize: validating custom logic failed for $authRequest" } - call.respond(HttpStatusCode.Forbidden, "Custom logic failed") - } - } - - post("/token") { - log.trace { "OIDC /token: Parsing" } - val httpRequest = convertKtorRequestToNimbusHTTPRequest(call.request) - val tokenRequest = TokenRequest.parse(httpRequest) - - log.trace { "OIDC /token: Parsed to token request: $tokenRequest, validating client credentials..." } - - validateClientCredentials(tokenRequest.clientAuthentication) - - when (val grant = tokenRequest.authorizationGrant) { - is AuthorizationCodeGrant -> { - log.trace { "OIDC /token: Grant is AuthorizationCodeGrant!" } - validateTokenRequest(tokenRequest) - val tokens = issueTokens(grant.authorizationCode) - log.trace { "OIDC /token: Issued tokens: $tokens" } - tokenStore[grant.authorizationCode.value] = tokens - log.trace { "OIDC /token: Associate issued tokens with ${grant.authorizationCode.value}" } - call.respond(tokens) - log.trace { "OIDC /token: Returned: ${Json.encodeToString(tokens)}" } - } - - is RefreshTokenGrant -> { - log.trace { "OIDC /token: Grant is RefreshTokenGrant!" } - val refreshToken = grant.refreshToken.value - val tokens = tokenStore.values.find { it.accessToken == refreshToken } - if (tokens != null && tokens.expirationTime > Clock.System.now()) { - val newTokens = issueTokens(AuthorizationCode()) // Issue new tokens - log.trace { "OIDC /token (refresh): New issued tokens: $newTokens" } - tokenStore[refreshToken] = newTokens - log.trace { "OIDC /token: Associate refreshed tokens with $refreshToken" } - call.respond(newTokens) - } else { - log.trace { "OIDC /token (refresh): Invalid or expired refresh token" } - call.respond(HttpStatusCode.BadRequest, "Invalid or expired refresh token") - } - } - - else -> { - log.trace { "OIDC /token: Unsupported grant type: ${grant.type.value}" } - call.respond(HttpStatusCode.BadRequest, "Unsupported grant type") - } - } - } - - get("/userinfo") { - val bearerToken = call.request.headers["Authorization"]?.removePrefix("Bearer ") - log.trace { "OIDC /userinfo: $bearerToken" } - if (bearerToken == null) { - call.respond(HttpStatusCode.Unauthorized, "Missing token") - return@get - } - - val tokenInfo = tokenStore.values.find { it.accessToken == bearerToken || it.idToken == bearerToken } - if (tokenInfo != null && tokenInfo.expirationTime > Clock.System.now()) { - val claims = getClaimsFromJWT(tokenInfo.idToken) - val userInfo = mapOf( - "sub" to (claims?.subject ?: "unknown"), - "name" to (claims?.getClaim("name") ?: "unknown"), - "email" to (claims?.getClaim("email") ?: "unknown") - ) - call.respond(userInfo) - } else { - call.respond(HttpStatusCode.Unauthorized, "Invalid or expired token") - } - } - - post("/introspect") { - val tokenRequest = call.receiveParameters()["token"] - log.trace { "OIDC /introspect: $tokenRequest" } - if (tokenRequest == null) { - call.respond(HttpStatusCode.BadRequest, "Missing token") - return@post - } - - val tokenInfo = tokenStore.values.find { it.accessToken == tokenRequest || it.idToken == tokenRequest } - if (tokenInfo != null) { - val isActive = tokenInfo.expirationTime > Clock.System.now() - val claims = getClaimsFromJWT(tokenInfo.idToken) - val introspectionResponse = mapOf( - "active" to isActive, - "scope" to "openid profile email", - "client_id" to "your-client-id", - "username" to (claims?.subject ?: "unknown"), - "token_type" to "Bearer", - "exp" to tokenInfo.expirationTime.epochSeconds, - "iat" to tokenInfo.issueTime.epochSeconds, - "sub" to (claims?.subject ?: "unknown") - ) - call.respond(introspectionResponse) - } else { - call.respond(mapOf("active" to false)) - } - } - - // Token endpoint with removal logic - post("/revoke") { - val tokenRequest = call.receiveParameters()["token"] - log.trace { "Revoking $tokenRequest" } - if (tokenRequest == null) { - call.respond(HttpStatusCode.BadRequest, "Missing token") - return@post - } - - removeToken(tokenRequest) - call.respond(HttpStatusCode.OK, "Token revoked") - } -} - -suspend fun performCustomLogic(): Boolean { - log.trace { "-- Custom logic here --" } - // Custom backend logic - return true -} - -// TODO FIXME: use authCode -suspend fun issueTokens(authCode: AuthorizationCode): TokenStore { - - log.trace { "Issuing tokens, - but without auth code?" } - - val accessToken = BearerAccessToken(3600) // Token valid for 3600 seconds - val issueTime = Clock.System.now() - val expirationTime = issueTime.plus(3600.seconds) - - val idTokenClaims = JWTClaimsSet.Builder().issuer(thisIdp).subject("user-id").audience("your-client-id") - .issueTime(Date.from(issueTime.toJavaInstant())).expirationTime(Date.from(expirationTime.toJavaInstant())).build() - val idToken = SignedJWT(JWSHeader(JWSAlgorithm.RS256), idTokenClaims) - idToken.sign(RSASSASigner(generateRSAKey().toPrivateKey())) - - return TokenStore( - accessToken = accessToken.value, - tokenType = accessToken.type.value, - expiresIn = 3600, // This represents the lifetime of the access token in seconds - idToken = idToken.serialize(), - issueTime = issueTime, - expirationTime = expirationTime - ).also { log.trace { "Issued: $it" } } -} - -suspend fun generateRSAKey(): RSAKey { - log.trace { "Generating RSA key..." } - return RSAKeyGenerator(2048).keyID("123").generate() -} - -suspend fun validateAuthRequest(authRequest: AuthorizationRequest) { - log.trace { "Validating auth request: (query encoded) ${authRequest.toQueryString()}" } - // Validate client ID, redirect URI, and scopes - val validClientId = "your-client-id" - val validRedirectURI = "https://your-client.com/callback" - val validScopes = setOf("openid", "profile", "email") - - require(authRequest.clientID.value == validClientId) { "Invalid client ID" } - // TODO require(authRequest.redirectionURI.toString() == validRedirectURI) { "Invalid redirect URI" } - // TODO require(validScopes.all { authRequest.scope.contains(it) }) { "Invalid scopes" } - -} - -suspend fun validateTokenRequest(tokenRequest: TokenRequest) { - log.trace { "Validating token request: $tokenRequest" } - // Validate the token request parameters - require(tokenRequest.clientAuthentication.clientID.value == "your-client-id") { "Invalid client ID" } - require(tokenRequest.authorizationGrant.type == GrantType.AUTHORIZATION_CODE) { "Invalid grant type" } -} - -suspend fun validateClientCredentials(clientAuthentication: ClientAuthentication) { - log.trace { "Validating client authentication: $clientAuthentication" } - - val validClientSecret = "your-client-secret" - - when (clientAuthentication) { - is ClientSecretBasic -> { - require(clientAuthentication.clientID.value == "your-client-id") { "Invalid client ID" } - require(clientAuthentication.clientSecret.value == validClientSecret) { "Invalid client secret" } - } - is ClientSecretPost -> { - require(clientAuthentication.clientID.value == "your-client-id") { "Invalid client ID" } - require(clientAuthentication.clientSecret.value == validClientSecret) { "Invalid client secret" } - } - - else -> throw IllegalStateException("OAuth2Error.INVALID_CLIENT, client authentication: $clientAuthentication (clientid = ${clientAuthentication.clientID.value}, method: ${clientAuthentication.method.value}, form: ${clientAuthentication.formParameterNames})") - } -} - -fun Routing.handleLogout() { - get("/logout") { - log.trace { "Logging out" } - call.sessions.clear() - call.respondText("Logged out", ContentType.Text.Plain) - } -} - -fun Routing.authenticateUser() { - get("/login") { - - val query = call.request.queryParameters.formUrlEncode() - - log.trace { "Displaying login form" } - // Display login form - call.respondText( - """ -
- Present credential:
- Debug query:
- -
- """, ContentType.Text.Html - ) - } - - post("/login") { - log.trace { "Logging in..." } - val post = call.receiveParameters() - val cred = post["cred"] - val query = post["query"] - - if (cred != null) { - // Set user session - - val state = UUID.randomUUID().toString() - - call.sessions.set(UserSession(id = "some-user-id", state = state)) - - val redirect = "/authorize?custom-login-stuff=success&$query&state=$state" - - log.trace { "Redirecting after successful login: $redirect" } - call.respondRedirect(redirect) // Redirect to home page or requested resource - } else { - call.respond(HttpStatusCode.BadRequest, "Missing credentials") - } - } -} - -val jwk = RSAKeyGenerator(2048).keyID("123").generate() - -fun Routing.wellKnownConfiguration() { - get("/.well-known/openid-configuration") { - val issuer = thisIdp - val wellKnown = mapOf( - "issuer" to issuer, - "authorization_endpoint" to "$issuer/authorize", - "token_endpoint" to "$issuer/token", - "userinfo_endpoint" to "$issuer/userinfo", - "jwks_uri" to "$issuer/jwks", - "response_types_supported" to listOf("code", "id_token", "token id_token"), - "subject_types_supported" to listOf("public"), - "id_token_signing_alg_values_supported" to listOf("RS256"), - "scopes_supported" to listOf("openid", "profile", "email"), - "token_endpoint_auth_methods_supported" to listOf("client_secret_basic"), - "claims_supported" to listOf("sub", "iss", "aud", "iat", "exp", "name", "email") - ).toJsonObject() - log.trace { "OIDC /well-known: Well-known is: $wellKnown" } - call.respond(wellKnown) - } - - get("/jwks") { - log.trace { "Handling /jwks..." } - val jwkSet = JWKSet(jwk) - call.respondText(jwkSet.toJSONObject().toString(), ContentType.Application.Json) - } -} - - -suspend fun convertKtorRequestToNimbusHTTPRequest(request: ApplicationRequest): HTTPRequest { - log.trace { "Converting ktor to nimbus http request..." } - val method = HTTPRequest.Method.valueOf(request.httpMethod.value) - - */ -/*val method = when (request.httpMethod.value) { - "GET" -> HTTPRequest.Method.GET - "POST" -> Method.POST - "PUT" -> Method.PUT - "DELETE" -> Method.DELETE - "OPTIONS" -> Method.OPTIONS - "HEAD" -> Method.HEAD - else -> throw IllegalArgumentException("Unsupported HTTP method") - }*//* - - - val url = request.call.url() - - log.trace { "Converting request... Method = $method, url = $url" } - - val httpRequest = HTTPRequest(method, URL(url)) - - // Copy headers - request.headers.forEach { key, values -> - values.forEach { value -> - httpRequest.setHeader(key, value) - } - } - - // Copy query parameters (if any) - val queryParams = request.queryParameters.entries() - if (queryParams.isNotEmpty()) { - val queryString = queryParams.joinToString("&") { "${it.key}=${it.value.joinToString(",")}" } - httpRequest.query = queryString - } - - // Copy body (if any) - if (request.httpMethod == HttpMethod.Post || request.httpMethod == HttpMethod.Put) { - //httpRequest.setContent(request.receiveChannel().toByteArray()) - httpRequest.body = request.receiveChannel().toByteArray().decodeToString() - httpRequest.setContentType(request.contentType().toString()) - } - - log.trace { "Converted ktor to nimbus http request: $httpRequest" } - return httpRequest -} - -*/ -fun Any?.toJsonElement(): JsonElement = - when (this) { - is JsonElement -> this - null -> JsonNull - is String -> JsonPrimitive(this) - is Boolean -> JsonPrimitive(this) - is Number -> JsonPrimitive(this) - - /* - is UByte -> JsonPrimitive(this) - is UInt -> JsonPrimitive(this) - is ULong -> JsonPrimitive(this) - is UShort -> JsonPrimitive(this) - */ - - is Map<*, *> -> JsonObject(map { Pair(it.key.toString(), it.value.toJsonElement()) }.toMap()) - is List<*> -> JsonArray(map { it.toJsonElement() }) - is Array<*> -> JsonArray(map { it.toJsonElement() }) - is Collection<*> -> JsonArray(map { it.toJsonElement() }) - is Enum<*> -> JsonPrimitive(this.toString()) - else -> throw IllegalArgumentException("Unknown type: ${this::class.simpleName}, was: $this") - } - -fun List<*>.toJsonElement(): JsonElement { - return JsonArray(map { it.toJsonElement() }) -} - -fun Map<*, *>.toJsonElement(): JsonElement { - val map: MutableMap = mutableMapOf() - this.forEach { (key, value) -> - map[key as String] = value.toJsonElement() - } - return JsonObject(map) -} - -fun Map<*, *>.toJsonObject() = this.toJsonElement().jsonObject - -private fun toHexChar(i: Int): Char { - val d = i and 0xf - return if (d < 10) (d + '0'.code).toChar() - else (d - 10 + 'a'.code).toChar() -} - -private val ESCAPE_STRINGS: Array = arrayOfNulls(93).apply { - for (c in 0..0x1f) { - val c1 = toHexChar(c shr 12) - val c2 = toHexChar(c shr 8) - val c3 = toHexChar(c shr 4) - val c4 = toHexChar(c) - this[c] = "\\u$c1$c2$c3$c4" - } - this['"'.code] = "\\\"" - this['\\'.code] = "\\\\" - this['\t'.code] = "\\t" - this['\b'.code] = "\\b" - this['\n'.code] = "\\n" - this['\r'.code] = "\\r" - this[0x0c] = "\\f" -} - -private fun StringBuilder.printQuoted(value: String) { - append('"') - var lastPos = 0 - for (i in value.indices) { - val c = value[i].code - if (c < ESCAPE_STRINGS.size && ESCAPE_STRINGS[c] != null) { - append(value, lastPos, i) // flush prev - append(ESCAPE_STRINGS[c]) - lastPos = i + 1 - } - } - - if (lastPos != 0) append(value, lastPos, value.length) - else append(value) - append('"') -} - -fun Map.printAsJson(): String = - this.entries.joinToString( - separator = ",", - prefix = "{", - postfix = "}", - transform = { (k, v) -> - buildString { - printQuoted(k) - append(':') - append(v) - } - } - ) - -fun stringToJsonPrimitive(value: String): JsonPrimitive { - return JsonPrimitive(value) -} - - diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Verifier.kt b/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Verifier.kt deleted file mode 100644 index ee180bfd0..000000000 --- a/waltid-libraries/auth/waltid-idpkit/src/main/kotlin/id/walt/Verifier.kt +++ /dev/null @@ -1,97 +0,0 @@ -package id.walt - -import com.nfeld.jsonpathkt.JsonPath -import com.nfeld.jsonpathkt.kotlinx.resolveAsStringOrNull -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.engine.cio.* -import io.ktor.client.plugins.* -import io.ktor.client.plugins.contentnegotiation.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import io.ktor.serialization.kotlinx.json.* -import io.ktor.server.util.* -import kotlinx.serialization.json.* -import kotlin.io.encoding.Base64 -import kotlin.io.encoding.ExperimentalEncodingApi - -enum class VerificationStatus { - WAITING_FOR_SUBMISSION, - RESPONSE_RECEIVED -} - -data class VerificationResultStatus( - val state: VerificationStatus, - val success: Boolean? = null, - val claims: Map? = null, -) - -object Verifier { - - private val client = HttpClient(CIO) { - install(ContentNegotiation) { - json() - } - defaultRequest { - contentType(ContentType.Application.Json) - } - } - - suspend fun verify(redirectUrl: String): Pair { - val response: HttpResponse = client.post("http://localhost:7003/openid4vc/verify") { - setBody( - mapOf( - "request_credentials" to listOf("OpenBadgeCredential") - ).toJsonObject() - ) - header("successRedirectUri", redirectUrl) - } - - val presentationRequest = response.bodyAsText() - - val state = parseQueryString(presentationRequest).getOrFail("state") - return Pair(presentationRequest, state) - } - - @OptIn(ExperimentalEncodingApi::class) - suspend fun getVerificationResult(id: String, requestedClaims: List): VerificationResultStatus { - val resp = client.get("http://localhost:7003/openid4vc/session/$id").body() - - if (resp["tokenResponse"] == null) { - return VerificationResultStatus(VerificationStatus.WAITING_FOR_SUBMISSION) - } - - val overall = resp["verificationResult"]?.jsonPrimitive?.boolean == true - - - val base64 = Base64.UrlSafe.withPadding(Base64.PaddingOption.ABSENT_OPTIONAL) - - val payload = base64.decode(resp["tokenResponse"]!!.jsonObject["vp_token"]!!.jsonPrimitive.content.split(".")[1]).decodeToString() - val vp = Json.parseToJsonElement(payload).jsonObject - - val did = vp["sub"]!!.jsonPrimitive.content - println(did) - - val credentials = vp["vp"]!!.jsonObject["verifiableCredential"]!!.jsonArray.map { - Json.parseToJsonElement( - base64.decode( - it.jsonPrimitive.content.split(".")[1] - ).decodeToString() - ).jsonObject["vc"]!!.jsonObject - } - println(credentials) - - val vc = credentials.first() - - - val claims = requestedClaims.map { - Pair(it, vc.resolveAsStringOrNull(JsonPath.compile(it))) - }.toMap().toMutableMap().apply { - put("sub", did) - } - println("Claims: $claims") - - return VerificationResultStatus(VerificationStatus.RESPONSE_RECEIVED, overall, claims) - } -} diff --git a/waltid-libraries/auth/waltid-idpkit/src/main/resources/logback.xml b/waltid-libraries/auth/waltid-idpkit/src/main/resources/logback.xml deleted file mode 100644 index 3e11d7811..000000000 --- a/waltid-libraries/auth/waltid-idpkit/src/main/resources/logback.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/waltid-libraries/credentials/waltid-dif-presentation-exchange/build.gradle.kts b/waltid-libraries/credentials/waltid-dif-presentation-exchange/build.gradle.kts new file mode 100644 index 000000000..c7bbf90e1 --- /dev/null +++ b/waltid-libraries/credentials/waltid-dif-presentation-exchange/build.gradle.kts @@ -0,0 +1,65 @@ +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + kotlin("multiplatform") + kotlin("plugin.serialization") + id("maven-publish") + id("dev.petuska.npm.publish") version "3.4.3" + // id("love.forte.plugin.suspend-transform") version "2.0.20-Beta1-0.9.2" + id("com.github.ben-manes.versions") +} + +group = "id.walt.dif-presentation-exchange" + +repositories { + mavenCentral() +} + +kotlin { + jvmToolchain(17) + + jvm { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget = JvmTarget.JVM_17 + } + withJava() + tasks.withType().configureEach { + useJUnitPlatform() + } + } + + js(IR) { + moduleName = "presentation-exchange" + nodejs { + generateTypeScriptDefinitions() + } + binaries.library() + } + + sourceSets { + val commonMain by getting { + dependencies { + implementation("com.eygraber:jsonpathkt-kotlinx:3.0.2") + // JSON + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + implementation("io.github.optimumcode:json-schema-validator:0.2.2") + + implementation(project(":waltid-libraries:credentials:waltid-verifiable-credentials")) + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + //implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1") + } + } + val jvmTest by getting { + dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + implementation("org.slf4j:slf4j-simple:2.0.13") + } + } + } +} diff --git a/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationDefinition.kt b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationDefinition.kt new file mode 100644 index 000000000..8dfbf8887 --- /dev/null +++ b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationDefinition.kt @@ -0,0 +1,87 @@ +package id.walt.presentationexchange + +import kotlinx.serialization.* +import kotlinx.serialization.json.* + +@Serializable +data class PresentationDefinition( + val id: String, + val name: String? = null, + val purpose: String? = null, + val format: JsonObject? = null, + val frame: Map? = null, + @SerialName("submission_requirements") + val submissionRequirements: List? = null, + @SerialName("input_descriptors") + val inputDescriptors: List +) { + @Serializable + data class InputDescriptor( + val id: String, + val name: String? = null, + val purpose: String? = null, + val format: JsonElement? = null, + val group: List? = null, + val constraints: Constraints + ) { + @Suppress("EnumEntryName") + enum class Directive { + required, + preferred, + disallowed + } + + @Serializable + data class Constraints( + @SerialName("limit_disclosure") + val limitDisclosure: Directive? = null, + val statuses: Statuses? = null, + val fields: List? = null, + @SerialName("subject_is_issuer") + val subjectIsIssuer: String? = null, + @SerialName("is_holder") + val isHolder: List? = null, + @SerialName("same_subject") + val sameSubject: List? = null + ) { + + + @Serializable + data class Statuses( + val active: StatusDirective? = null, + val suspended: StatusDirective? = null, + val revoked: StatusDirective? = null + ) + + @Serializable + data class Field( + val id: String? = null, + val optional: Boolean? = null, + val path: List, + val purpose: String? = null, + val name: String? = null, + @SerialName("intent_to_retain") + val intentToRetain: Boolean? = null, + val filter: JsonElement? = null, + val predicate: String? = null + ) + + @Serializable + data class Subject( + @SerialName("field_id") + val fieldId: List, + val directive: Directive + ) + + @Serializable + data class StatusDirective( + val type: List, + val directive: Directive, + ) { + init { + check(type.isNotEmpty()) + } + } + } + } +} diff --git a/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationDefinitionParser.kt b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationDefinitionParser.kt new file mode 100644 index 000000000..acdc0457b --- /dev/null +++ b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationDefinitionParser.kt @@ -0,0 +1,324 @@ +package id.walt.presentationexchange + +import com.nfeld.jsonpathkt.JsonPath +import com.nfeld.jsonpathkt.kotlinx.resolveOrNull +import id.walt.credentials.vc.vcs.W3CVC +import io.github.optimumcode.json.schema.JsonSchema +import io.github.optimumcode.json.schema.ValidationError +import kotlinx.serialization.json.Json + +object PresentationDefinitionParser { + + fun matchCredentialsForInputDescriptor(credentials: List, inputDescriptor: PresentationDefinition.InputDescriptor): List { + + println("--- Checking descriptor ${inputDescriptor.name} --") + + return credentials.filter { credential -> + println("\nChecking credential ${credential["type"]}") + inputDescriptor.constraints.fields!!.all { field -> + // println("Field: ${field.path} - ${field.filter}") + val credentialJson = credential.toJsonObject() + val resolvedPath = field.path.firstNotNullOfOrNull { credentialJson.resolveOrNull(JsonPath.compile(it)) } + + if (resolvedPath == null) { + println("Stop - did not resolve any of ${field.path.joinToString()}") + false + } else { + if (field.filter != null) { + val schema = JsonSchema.fromJsonElement(field.filter) + + val errors = mutableListOf() + schema.validate(resolvedPath, errors::add) + + errors.isEmpty() + } + true + } + } + } + } + + fun matchCredentialsForDefinition(credentials: List, definition: PresentationDefinition) { + + } + +} + + +fun main() { + //language=JSON + val credentials = """ + [ + { + "@context": "https://www.w3.org/2018/credentials/v1", + "id": "https://business-standards.org/schemas/employment-history.json", + "type": [ + "VerifiableCredential", + "GenericEmploymentCredential" + ], + "issuer": "did:foo:123", + "issuanceDate": "2010-01-01T19:73:24Z", + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "active": true + }, + "proof": { + "type": "EcdsaSecp256k1VerificationKey2019", + "created": "2017-06-18T21:19:10Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://example.edu/issuers/keys/1", + "jws": "..." + } + }, + { + "@context": "https://www.w3.org/2018/credentials/v1", + "id": "https://eu.com/claims/DriversLicense", + "type": [ + "EUDriversLicense" + ], + "issuer": "did:foo:123", + "issuanceDate": "2010-01-01T19:73:24Z", + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "license": { + "number": "34DGE352", + "dob": "07/13/80" + } + }, + "proof": { + "type": "RsaSignature2018", + "created": "2017-06-18T21:19:10Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://example.edu/issuers/keys/1", + "jws": "..." + } + } + ] + """.trimIndent() + + //language=JSON + val inputDescriptors = """ + [ + { + "id": "banking_input_1", + "name": "Bank Account Information", + "purpose": "Bank Account required to remit payment.", + "group": [ + "A" + ], + "constraints": { + "limit_disclosure": "required", + "fields": [ + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only verify bank accounts if they are attested by a trusted bank, auditor or regulatory authority.", + "filter": { + "type": "string", + "pattern": "^did:example:123${'$'}|^did:example:456${'$'}" + } + }, + { + "path": [ + "${'$'}.credentialSubject.account[*].account_number", + "${'$'}.vc.credentialSubject.account[*].account_number", + "${'$'}.account[*].account_number" + ], + "purpose": "We can only remit payment to a currently-valid bank account in the US, France, or Germany, submitted as an ABA Acct # or IBAN.", + "filter": { + "type": "string", + "pattern": "^[0-9]{10-12}|^(DE|FR)[0-9]{2}\\s?([0-9a-zA-Z]{4}\\s?){4}[0-9a-zA-Z]{2}${'$'}" + }, + "intent_to_retain": true + }, + { + "path": [ + "${'$'}.credentialSubject.portfolio_value", + "${'$'}.vc.credentialSubject.portfolio_value", + "${'$'}.portfolio_value" + ], + "purpose": "A current portfolio value of at least one million dollars is required to insure your application", + "filter": { + "type": "number", + "minimum": 1000000 + }, + "intent_to_retain": true + } + ] + } + }, + { + "id": "banking_input_2", + "name": "Bank Account Information", + "purpose": "We can only remit payment to a currently-valid bank account.", + "group": [ + "A" + ], + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only verify bank accounts if they are attested by a trusted bank, auditor or regulatory authority.", + "filter": { + "type": "string", + "pattern": "^did:example:123${'$'}|^did:example:456${'$'}" + } + }, + { + "path": [ + "${'$'}.credentialSubject.account[*].id", + "${'$'}.vc.credentialSubject.account[*].id", + "${'$'}.account[*].id" + ], + "purpose": "We can only remit payment to a currently-valid bank account in the US, France, or Germany, submitted as an ABA Acct # or IBAN.", + "filter": { + "type": "string", + "pattern": "^[0-9]{10-12}|^(DE|FR)[0-9]{2}\\s?([0-9a-zA-Z]{4}\\s?){4}[0-9a-zA-Z]{2}${'$'}" + }, + "intent_to_retain": true + }, + { + "path": [ + "${'$'}.credentialSubject.account[*].route", + "${'$'}.vc.credentialSubject.account[*].route", + "${'$'}.account[*].route" + ], + "purpose": "We can only remit payment to a currently-valid account at a US, Japanese, or German federally-accredited bank, submitted as an ABA RTN or SWIFT code.", + "filter": { + "type": "string", + "pattern": "^[0-9]{9}|^([a-zA-Z]){4}([a-zA-Z]){2}([0-9a-zA-Z]){2}([0-9a-zA-Z]{3})?${'$'}" + }, + "intent_to_retain": true + } + ] + } + }, + { + "id": "employment_input", + "name": "Employment History", + "purpose": "We are only verifying one current employment relationship, not any other information about employment.", + "group": [ + "B" + ], + "constraints": { + "limit_disclosure": "required", + "fields": [ + { + "path": [ + "${'$'}.jobs[*].active" + ], + "filter": { + "type": "boolean", + "pattern": "true" + } + } + ] + } + }, + { + "id": "drivers_license_input_1", + "name": "EU Driver's License", + "group": [ + "C" + ], + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only accept digital driver's licenses issued by national authorities of EU member states or trusted notarial auditors.", + "filter": { + "type": "string", + "pattern": "did:example:gov1|did:example:gov2" + } + }, + { + "path": [ + "${'$'}.credentialSubject.dob", + "${'$'}.credentialSubject.license.dob", + "${'$'}.vc.credentialSubject.dob", + "${'$'}.dob" + ], + "purpose": "We must confirm that the driver was at least 21 years old on April 16, 2020.", + "filter": { + "type": "string", + "format": "date" + } + } + ] + } + }, + { + "id": "drivers_license_input_2", + "name": "Driver's License from one of 50 US States", + "group": [ + "C" + ], + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only accept digital driver's licenses issued by the 50 US states' automative affairs agencies.", + "filter": { + "type": "string", + "pattern": "did:example:gov1|did:web:dmv.ca.gov|did:example:oregonDMV" + } + }, + { + "path": [ + "${'$'}.credentialSubject.birth_date", + "${'$'}.vc.credentialSubject.birth_date", + "${'$'}.birth_date" + ], + "purpose": "We must confirm that the driver was at least 21 years old on April 16, 2020.", + "filter": { + "type": "string", + "format": "date", + "forrmatMaximum": "1999-05-16" + } + } + ] + } + }, + { + "id": "wa_driver_license", + "name": "Washington State Business License", + "purpose": "We can only allow licensed Washington State business representatives into the WA Business Conference", + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.credentialSubject.dateOfBirth", + "${'$'}.credentialSubject.dob", + "${'$'}.vc.credentialSubject.dateOfBirth", + "${'$'}.vc.credentialSubject.dob" + ] + } + ] + } + } + ] + """.trimIndent() + + val credentialList = Json.decodeFromString>(credentials) + val inputDescriptorList = Json.decodeFromString>(inputDescriptors) + + inputDescriptorList.forEach { + val matched = PresentationDefinitionParser.matchCredentialsForInputDescriptor(credentialList, it) + println("Matched for ${it.name}: $matched") + } +} diff --git a/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationSubmission.kt b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationSubmission.kt new file mode 100644 index 000000000..6a77d7be2 --- /dev/null +++ b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/PresentationSubmission.kt @@ -0,0 +1,27 @@ +package id.walt.presentationexchange + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement + +@Serializable +data class PresentationSubmission( + val id: String, + + @SerialName("definition_id") + val definitionId: String, + + @SerialName("descriptor_map") + val descriptorMap: List +) { + @Serializable + data class Descriptor( + val id: String, + val format: JsonElement, + val path: String, + + @SerialName("path_nested") + val pathNested: Descriptor? = null + ) +} + diff --git a/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/SubmissionRequirement.kt b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/SubmissionRequirement.kt new file mode 100644 index 000000000..6497c9e8f --- /dev/null +++ b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonMain/kotlin/id/walt/presentationexchange/SubmissionRequirement.kt @@ -0,0 +1,36 @@ +package id.walt.presentationexchange + +import kotlinx.serialization.* + +@Serializable +data class SubmissionRequirement( + val name: String? = null, + val purpose: String? = null, + val rule: Rule, + val count: Int? = null, + val min: Int? = null, + val max: Int? = null, + val from: String? = null, + @SerialName("from_nested") + val fromNested: List? = null +) { + init { + count?.let { check(it >= 1) { "count must be at least 1" } } + min?.let { check(it >= 0) { "min must be at least 0" } } + max?.let { check(it >= 0) { "max must be at least 0" } } + + if (from != null) { + check(from.isNotBlank()) { "from must not be blank" } + } else { + checkNotNull(fromNested) { "Either 'from' or 'from_nested' must be provided" } + check(fromNested.isNotEmpty()) { "from_nested must not be empty" } + } + } + + + @Suppress("EnumEntryName") + enum class Rule { + all, + pick + } +} diff --git a/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/PresentationDefinitionTest.kt b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/PresentationDefinitionTest.kt new file mode 100644 index 000000000..a3c9cd791 --- /dev/null +++ b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/PresentationDefinitionTest.kt @@ -0,0 +1,779 @@ +package id.walt.presentationexchange + +import kotlinx.serialization.json.Json +import kotlin.test.Test + +class PresentationDefinitionTest { + + //language=JSON + val minimalExample = """ +{ + "id": "32f54163-7166-48f1-93d8-ff217bdb0653", + "input_descriptors": [ + { + "id": "wa_driver_license", + "name": "Washington State Business License", + "purpose": "We can only allow licensed Washington State business representatives into the WA Business Conference", + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.credentialSubject.dateOfBirth", + "${'$'}.credentialSubject.dob", + "${'$'}.vc.credentialSubject.dateOfBirth", + "${'$'}.vc.credentialSubject.dob" + ] + } + ] + } + } + ] +} +""".trimIndent() + + //language=JSON + val filterByCredentialType = """ +{ + "id": "first simple example", + "input_descriptors": [ + { + "id": "A specific type of VC", + "name": "A specific type of VC", + "purpose": "We want a VC of this type", + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.type" + ], + "filter": { + "type": "array", + "contains": { + "type": "string", + "pattern": "^${'$'}" + } + } + } + ] + } + } + ] +} +""".trimIndent() + + //language=JSON + val twoFiltersSimplified = """ +{ + "id": "Scalable trust example", + "input_descriptors": [ + { + "id": "any type of credit card from any bank", + "name": "any type of credit card from any bank", + "purpose": "Please provide your credit card details", + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.termsOfUse.type" + ], + "filter": { + "type": "string", + "pattern": "^https://train.trust-scheme.de/info${'$'}" + } + }, + { + "path": [ + "${'$'}.termsOfUse.trustScheme" + ], + "filter": { + "type": "string", + "pattern": "^worldbankfederation.com${'$'}" + } + }, + { + "path": [ + "${'$'}.type" + ], + "filter": { + "type": "string", + "pattern": "^creditCard${'$'}" + } + } + ] + } + } + ] +} +""" + + //language=JSON + val twoFiltersRealWorld = """ +{ + "id": "Scalable trust example", + "input_descriptors": [ + { + "id": "any type of credit card from any bank", + "name": "any type of credit card from any bank", + "purpose": "Please provide your credit card details", + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.termsOfUse" + ], + "filter": { + "${'$'}defs": { + "typeString": { + "type": "string", + "pattern": "^https://train.trust-scheme.de/info${'$'}" + }, + "typeStringOrArray": { + "anyOf": [ + { + "${'$'}ref": "#/${'$'}defs/typeString" + }, + { + "type": "array", + "contains": { + "${'$'}ref": "#/${'$'}defs/typeString" + } + } + ] + }, + "trustSchemeString": { + "type": "string", + "pattern": "^worldbankfederation.com${'$'}" + }, + "trustSchemeStringOrArray": { + "anyOf": [ + { + "${'$'}ref": "#/${'$'}defs/trustSchemeString" + }, + { + "type": "array", + "contains": { + "${'$'}ref": "#/${'$'}defs/trustSchemeString" + } + } + ] + }, + "tosObject": { + "type": "object", + "required": [ + "type", + "trustScheme" + ], + "properties": { + "type": { + "${'$'}ref": "#/${'$'}defs/typeStringOrArray" + }, + "trustScheme": { + "${'$'}ref": "#/${'$'}defs/trustSchemeStringOrArray" + } + } + }, + "tosObjectOrArray": { + "anyOf": [ + { + "${'$'}ref": "#/${'$'}defs/tosObject" + }, + { + "type": "array", + "contains": { + "${'$'}ref": "#/${'$'}defs/tosObject" + } + } + ] + } + }, + "${'$'}ref": "#/${'$'}defs/tosObjectOrArray" + } + }, + { + "path": [ + "${'$'}.type" + ], + "filter": { + "type": "array", + "contains": { + "type": "string", + "pattern": "^creditCard${'$'}" + } + } + } + ] + } + } + ] +} +""".trimIndent() + + //language=JSON + val formats = """ +{ + "id": "32f54163-7166-48f1-93d8-ff217bdb0653", + "input_descriptors": [], + "format": { + "jwt": { + "alg": [ + "EdDSA", + "ES256K", + "ES384" + ] + }, + "jwt_vc": { + "alg": [ + "ES256K", + "ES384" + ] + }, + "jwt_vp": { + "alg": [ + "EdDSA", + "ES256K" + ] + }, + "ldp_vc": { + "proof_type": [ + "JsonWebSignature2020", + "Ed25519Signature2018", + "EcdsaSecp256k1Signature2019", + "RsaSignature2018" + ] + }, + "ldp_vp": { + "proof_type": [ + "Ed25519Signature2018" + ] + }, + "ldp": { + "proof_type": [ + "RsaSignature2018" + ] + } + } +} +""".trimIndent() + + //language=JSON + val singleGroupExample = """ + { + "id": "32f54163-7166-48f1-93d8-ff217bdb0653", + "submission_requirements": [ + { + "name": "Citizenship Information", + "rule": "pick", + "count": 1, + "from": "A" + } + ], + "input_descriptors": [ + { + "id": "citizenship_input_1", + "name": "EU Driver's License", + "group": [ + "A" + ], + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.credentialSchema.id", + "${'$'}.vc.credentialSchema.id" + ], + "filter": { + "type": "string", + "const": "https://eu.com/claims/DriversLicense.json" + } + }, + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only accept digital driver's licenses issued by national authorities of member states or trusted notarial auditors.", + "filter": { + "type": "string", + "pattern": "^did:example:gov1${'$'}|^did:example:gov2${'$'}" + } + }, + { + "path": [ + "${'$'}.credentialSubject.dob", + "${'$'}.vc.credentialSubject.dob", + "${'$'}.dob" + ], + "filter": { + "type": "string", + "format": "date" + } + } + ] + } + }, + { + "id": "citizenship_input_2", + "name": "US Passport", + "group": [ + "A" + ], + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.credentialSchema.id", + "${'$'}.vc.credentialSchema.id" + ], + "filter": { + "type": "string", + "const": "hub://did:foo:123/Collections/schema.us.gov/passport.json" + } + }, + { + "path": [ + "${'$'}.credentialSubject.birth_date", + "${'$'}.vc.credentialSubject.birth_date", + "${'$'}.birth_date" + ], + "filter": { + "type": "string", + "format": "date" + } + } + ] + } + } + ] + } + """.trimIndent() + + //language=JSON + val multiGroupExample = """ + { + "id": "32f54163-7166-48f1-93d8-ff217bdb0653", + "submission_requirements": [ + { + "name": "Banking Information", + "purpose": "We can only remit payment to a currently-valid bank account in the US, Germany or France.", + "rule": "pick", + "count": 1, + "from": "A" + }, + { + "name": "Employment Information", + "purpose": "We are only verifying one current employment relationship, not any other information about employment.", + "rule": "all", + "from": "B" + }, + { + "name": "Eligibility to Drive on US Roads", + "purpose": "We need to verify eligibility to drive on US roads via US or EU driver's license, but no biometric or identifying information contained there.", + "rule": "pick", + "count": 1, + "from": "C" + } + ], + "input_descriptors": [ + { + "id": "banking_input_1", + "name": "Bank Account Information", + "purpose": "Bank Account required to remit payment.", + "group": [ + "A" + ], + "constraints": { + "limit_disclosure": "required", + "fields": [ + { + "path": [ + "${'$'}.credentialSchema", + "${'$'}.vc.credentialSchema" + ], + "filter": { + "allOf": [ + { + "type": "array", + "contains": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^https://bank-standards.example.com#accounts${'$'}" + } + }, + "required": [ + "id" + ] + } + }, + { + "type": "array", + "contains": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^https://bank-standards.example.com#investments${'$'}" + } + }, + "required": [ + "id" + ] + } + } + ] + } + }, + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only verify bank accounts if they are attested by a trusted bank, auditor or regulatory authority.", + "filter": { + "type": "string", + "pattern": "^did:example:123${'$'}|^did:example:456${'$'}" + } + }, + { + "path": [ + "${'$'}.credentialSubject.account[*].account_number", + "${'$'}.vc.credentialSubject.account[*].account_number", + "${'$'}.account[*].account_number" + ], + "purpose": "We can only remit payment to a currently-valid bank account in the US, France, or Germany, submitted as an ABA Acct # or IBAN.", + "filter": { + "type": "string", + "pattern": "^[0-9]{10-12}|^(DE|FR)[0-9]{2}\\s?([0-9a-zA-Z]{4}\\s?){4}[0-9a-zA-Z]{2}${'$'}" + }, + "intent_to_retain": true + }, + { + "path": [ + "${'$'}.credentialSubject.portfolio_value", + "${'$'}.vc.credentialSubject.portfolio_value", + "${'$'}.portfolio_value" + ], + "purpose": "A current portfolio value of at least one million dollars is required to insure your application", + "filter": { + "type": "number", + "minimum": 1000000 + }, + "intent_to_retain": true + } + ] + } + }, + { + "id": "banking_input_2", + "name": "Bank Account Information", + "purpose": "We can only remit payment to a currently-valid bank account.", + "group": [ + "A" + ], + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.credentialSchema.id", + "${'$'}.vc.credentialSchema.id" + ], + "filter": { + "type": "string", + "pattern": "^https://bank-schemas.org/1.0.0/accounts.json|https://bank-schemas.org/2.0.0/accounts.json${'$'}" + } + }, + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only verify bank accounts if they are attested by a trusted bank, auditor or regulatory authority.", + "filter": { + "type": "string", + "pattern": "^did:example:123${'$'}|^did:example:456${'$'}" + } + }, + { + "path": [ + "${'$'}.credentialSubject.account[*].id", + "${'$'}.vc.credentialSubject.account[*].id", + "${'$'}.account[*].id" + ], + "purpose": "We can only remit payment to a currently-valid bank account in the US, France, or Germany, submitted as an ABA Acct # or IBAN.", + "filter": { + "type": "string", + "pattern": "^[0-9]{10-12}|^(DE|FR)[0-9]{2}\\s?([0-9a-zA-Z]{4}\\s?){4}[0-9a-zA-Z]{2}${'$'}" + }, + "intent_to_retain": true + }, + { + "path": [ + "${'$'}.credentialSubject.account[*].route", + "${'$'}.vc.credentialSubject.account[*].route", + "${'$'}.account[*].route" + ], + "purpose": "We can only remit payment to a currently-valid account at a US, Japanese, or German federally-accredited bank, submitted as an ABA RTN or SWIFT code.", + "filter": { + "type": "string", + "pattern": "^[0-9]{9}|^([a-zA-Z]){4}([a-zA-Z]){2}([0-9a-zA-Z]){2}([0-9a-zA-Z]{3})?${'$'}" + }, + "intent_to_retain": true + } + ] + } + }, + { + "id": "employment_input", + "name": "Employment History", + "purpose": "We are only verifying one current employment relationship, not any other information about employment.", + "group": [ + "B" + ], + "constraints": { + "limit_disclosure": "required", + "fields": [ + { + "path": [ + "${'$'}.credentialSchema", + "${'$'}.vc.credentialSchema" + ], + "filter": { + "type": "string", + "const": "https://business-standards.org/schemas/employment-history.json" + } + }, + { + "path": [ + "${'$'}.jobs[*].active" + ], + "filter": { + "type": "boolean", + "pattern": "true" + } + } + ] + } + }, + { + "id": "drivers_license_input_1", + "name": "EU Driver's License", + "group": [ + "C" + ], + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.credentialSchema.id", + "${'$'}.vc.credentialSchema.id" + ], + "filter": { + "type": "string", + "const": "https://schema.eu/claims/DriversLicense.json" + } + }, + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only accept digital driver's licenses issued by national authorities of EU member states or trusted notarial auditors.", + "filter": { + "type": "string", + "pattern": "did:example:gov1|did:example:gov2" + } + }, + { + "path": [ + "${'$'}.credentialSubject.dob", + "${'$'}.vc.credentialSubject.dob", + "${'$'}.dob" + ], + "purpose": "We must confirm that the driver was at least 21 years old on April 16, 2020.", + "filter": { + "type": "string", + "format": "date" + } + } + ] + } + }, + { + "id": "drivers_license_input_2", + "name": "Driver's License from one of 50 US States", + "group": [ + "C" + ], + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.credentialSchema.id", + "${'$'}.vc.credentialSchema.id" + ], + "filter": { + "type": "string", + "const": "hub://did:foo:123/Collections/schema.us.gov/american_drivers_license.json" + } + }, + { + "path": [ + "${'$'}.issuer", + "${'$'}.vc.issuer", + "${'$'}.iss" + ], + "purpose": "We can only accept digital driver's licenses issued by the 50 US states' automative affairs agencies.", + "filter": { + "type": "string", + "pattern": "did:example:gov1|did:web:dmv.ca.gov|did:example:oregonDMV" + } + }, + { + "path": [ + "${'$'}.credentialSubject.birth_date", + "${'$'}.vc.credentialSubject.birth_date", + "${'$'}.birth_date" + ], + "purpose": "We must confirm that the driver was at least 21 years old on April 16, 2020.", + "filter": { + "type": "string", + "format": "date", + "forrmatMaximum": "1999-05-16" + } + } + ] + } + } + ] + } + """.trimIndent() + + //language=JSON + val descriptorIdToken = """ + { + "id": "32f54163-7166-48f1-93d8-ff217bdb0653", + "input_descriptors": [ + { + "id": "employment_input_xyz_gov", + "group": [ + "B" + ], + "name": "Verify XYZ Government Employment", + "purpose": "Verifying current employment at XYZ Government agency as proxy for permission to access this resource", + "constraints": { + "fields": [ + { + "path": [ + "${'$'}.credentialSchema.id", + "${'$'}.vc.credentialSchema.id" + ], + "filter": { + "type": "string", + "const": "https://login.idp.com/xyz.gov/.well-known/openid-configuration" + } + }, + { + "path": [ + "${'$'}.status" + ], + "filter": { + "type": "string", + "pattern": "^active${'$'}" + } + } + ] + } + } + ] + } + """.trimIndent() + + //language=JSON + val verifiableCredentialExpiration = """ + { + "id": "drivers_license_information", + "name": "Verify Valid License", + "purpose": "We need you to show that your driver's license will be valid through December of this year.", + "constraints": { + "fields": [ + { + "path": ["${'$'}.credentialSchema.id", "${'$'}.vc.credentialSchema.id"], + "filter": { + "type": "string", + "const": "https://yourwatchful.gov/drivers-license-schema.json" + } + }, + { + "path": ["${'$'}.expirationDate"], + "filter": { + "type": "string", + "format": "date-time" + } + } + ] + } + } + """.trimIndent() + + //language=JSON + val verifiableCredentialRevocationStatus = """ + { + "id": "drivers_license_information", + "name": "Verify Valid License", + "purpose": "We need to know that your license has not been revoked.", + "constraints": { + "fields": [ + { + "path": ["${'$'}.credentialSchema.id", "${'$'}.vc.credentialSchema.id"], + "filter": { + "type": "string", + "const": "https://yourwatchful.gov/drivers-license-schema.json" + } + }, + { + "path": ["${'$'}.credentialStatus"] + } + ] + } + } + """.trimIndent() + + @Test + fun testPresentationDefinitionParsing() { + println("minimalExample") + Json.decodeFromString(minimalExample) + + println("filterByCredentialType") + Json.decodeFromString(filterByCredentialType) + + println("twoFiltersSimplified") + Json.decodeFromString(twoFiltersSimplified) + + println("twoFiltersRealWorld") + Json.decodeFromString(twoFiltersRealWorld) + + println("formats") + Json.decodeFromString(formats) + + + println("singleGroupExample") + Json.decodeFromString(singleGroupExample) + + println("multiGroupExample") + Json.decodeFromString(multiGroupExample) + + println("descriptorIdToken") + Json.decodeFromString(descriptorIdToken) + + println("verifiableCredentialExpiration") + Json.decodeFromString(verifiableCredentialExpiration) + println("verifiableCredentialRevocationStatus") + Json.decodeFromString(verifiableCredentialRevocationStatus) + } + +} diff --git a/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/PresentationSubmissionTest.kt b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/PresentationSubmissionTest.kt new file mode 100644 index 000000000..7491002a7 --- /dev/null +++ b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/PresentationSubmissionTest.kt @@ -0,0 +1,70 @@ +package id.walt.presentationexchange + +import kotlinx.serialization.json.Json +import kotlin.test.Test + +class PresentationSubmissionTest { + + //language=JSON + val presentationSubmission = """ + { + "id": "a30e3b91-fb77-4d22-95fa-871689c322e2", + "definition_id": "32f54163-7166-48f1-93d8-ff217bdb0653", + "descriptor_map": [ + { + "id": "banking_input_2", + "format": "jwt_vc", + "path": "${'$'}.verifiableCredential[0]" + }, + { + "id": "employment_input", + "format": "ldp_vc", + "path": "${'$'}.verifiableCredential[1]" + }, + { + "id": "citizenship_input_1", + "format": "ldp_vc", + "path": "${'$'}.verifiableCredential[2]" + } + ] + } + """.trimIndent() + + //language=JSON + val nestedSubmission = """ + { + "id": "a30e3b91-fb77-4d22-95fa-871689c322e2", + "definition_id": "32f54163-7166-48f1-93d8-ff217bdb0653", + "descriptor_map": [ + { + "id": "banking_input_2", + "format": "jwt_vp", + "path": "${'$'}.outerClaim[0]", + "path_nested": { + "id": "banking_input_2", + "format": "ldp_vc", + "path": "${'$'}.innerClaim[1]", + "path_nested": { + "id": "banking_input_2", + "format": "jwt_vc", + "path": "${'$'}.mostInnerClaim[2]" + } + } + } + ] + } + """.trimIndent() + + + + @Test + fun testPresentationSubmissionParsing() { + println("presentationSubmission") + Json.decodeFromString(presentationSubmission) + + println("nestedSubmission") + Json.decodeFromString(nestedSubmission) + + } + +} diff --git a/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/SubmissionRequirementTest.kt b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/SubmissionRequirementTest.kt new file mode 100644 index 000000000..b322fcd7d --- /dev/null +++ b/waltid-libraries/credentials/waltid-dif-presentation-exchange/src/commonTest/kotlin/id/walt/presentationexchange/SubmissionRequirementTest.kt @@ -0,0 +1,96 @@ +package id.walt.presentationexchange + +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlin.test.Test + +class SubmissionRequirementTest { + + //language=JSON + val submissionRequirement = """ + [ + { + "name": "Submission of educational transcripts", + "purpose": "We need your complete educational transcripts to process your application", + "rule": "all", + "from": "A" + }, + { + "name": "Citizenship Proof", + "purpose": "We need to confirm you are a citizen of one of the following countries before accepting your application", + "rule": "pick", + "count": 1, + "from": "B" + }, + { + "name": "Eligibility to Work Proof", + "purpose": "We need to prove you are eligible for full-time employment in 2 or more of the following countries", + "rule": "pick", + "min": 2, + "from": "B" + }, + { + "name": "Confirm banking relationship or employment and residence proofs", + "purpose": "Recent bank statements or proofs of both employment and residence will be validated to initiate your loan application but not stored", + "rule": "pick", + "count": 1, + "from_nested": [ + { + "rule": "all", + "from": "A" + }, + { + "rule": "pick", + "count": 2, + "from": "B" + } + ] + } + ] + """.trimIndent() + + //language=JSON + val submissionRequirements = """ + [ + { + "name": "Banking Information", + "purpose": "We need you to prove you currently hold a bank account older than 12months.", + "rule": "pick", + "count": 1, + "from": "A" + }, + { + "name": "Employment Information", + "purpose": "We are only verifying one current employment relationship, not any other information about employment.", + "rule": "all", + "from": "B" + }, + { + "name": "Citizenship Information", + "rule": "pick", + "count": 1, + "from_nested": [ + { + "name": "United States Citizenship Proofs", + "purpose": "We need you to prove your US citizenship.", + "rule": "all", + "from": "C" + }, + { + "name": "European Union Citizenship Proofs", + "purpose": "We need you to prove you are a citizen of an EU member state.", + "rule": "all", + "from": "D" + } + ] + } + ] + """.trimIndent() + + @Test + fun submissionRequirementParsing() { + Json.decodeFromString>(submissionRequirement) + Json.decodeFromString>(submissionRequirements) + } + +} diff --git a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/utils/Base64Utils.kt b/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/utils/Base64Utils.kt deleted file mode 100644 index d42936755..000000000 --- a/waltid-libraries/waltid-mdoc-credentials/src/commonMain/kotlin/id/walt/mdoc/utils/Base64Utils.kt +++ /dev/null @@ -1,22 +0,0 @@ -package id.walt.mdoc.utils - -import kotlin.io.encoding.Base64 -import kotlin.io.encoding.ExperimentalEncodingApi -import kotlin.js.ExperimentalJsExport -import kotlin.js.JsExport - -@OptIn(ExperimentalJsExport::class, ExperimentalEncodingApi::class) -@JsExport -object Base64Utils { - - fun String.base64toBase64Url() = this.replace("+", "-").replace("/", "_").trimEnd('=') - fun String.base64UrlToBase64() = this.replace("-", "+").replace("_", "/") - - fun ByteArray.encodeToBase64Url() = Base64.UrlSafe.encode(this).trimEnd('=') - - fun String.base64UrlDecode()= base64.decode(this) - - fun String.base64Decode() = Base64.decode(this) - - val base64 = Base64.UrlSafe.withPadding(Base64.PaddingOption.ABSENT_OPTIONAL) -} diff --git a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt b/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt deleted file mode 100644 index 525d72f39..000000000 --- a/waltid-libraries/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/util/JwtUtils.kt +++ /dev/null @@ -1,19 +0,0 @@ -package id.walt.oid4vc.util - -import id.walt.crypto.utils.Base64Utils.base64UrlDecode -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject - -object JwtUtils { - fun parseJWTPayload(token: String): JsonObject { - return token.substringAfter(".").substringBefore(".").let { - Json.decodeFromString(it.base64UrlDecode().decodeToString()) - } - } - - fun parseJWTHeader(token: String): JsonObject { - return token.substringBefore(".").let { - Json.decodeFromString(it.base64UrlDecode().decodeToString()) - } - } -} \ No newline at end of file diff --git a/waltid-libraries/waltid-openid4vc/src/jvmTest/resources/simplelogger.properties b/waltid-libraries/waltid-openid4vc/src/jvmTest/resources/simplelogger.properties deleted file mode 100644 index e6ab6ec3b..000000000 --- a/waltid-libraries/waltid-openid4vc/src/jvmTest/resources/simplelogger.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.slf4j.simpleLogger.defaultLogLevel=debug -org.slf4j.simpleLogger.log.io.netty=info -org.slf4j.simpleLogger.showDateTime=true From d2d763a88b5715bf97760a2a757979e0093e2d9b Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Thu, 8 Aug 2024 01:37:15 +0200 Subject: [PATCH 16/17] fix: update .gitignore and add required pem files --- .gitignore | 3 ++- .../resources/pem/ecdsa-vault.public.pem | 3 +++ .../jvmTest/resources/pem/ed25519.private.pem | 6 +++++ .../jvmTest/resources/pem/ed25519.public.pem | 3 +++ .../resources/pem/rsa-vault.public.pem | 3 +++ .../src/jvmTest/resources/pem/rsa.private.pem | 27 +++++++++++++++++++ .../src/jvmTest/resources/pem/rsa.public.pem | 9 +++++++ .../resources/pem/secp256k1.private.pem | 8 ++++++ .../resources/pem/secp256k1.public.pem | 4 +++ .../resources/pem/secp256r1.private.pem | 10 +++++++ .../resources/pem/secp256r1.public.pem | 4 +++ 11 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ecdsa-vault.public.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ed25519.private.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ed25519.public.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa-vault.public.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa.private.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa.public.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256k1.private.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256k1.public.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256r1.private.pem create mode 100644 waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256r1.public.pem diff --git a/.gitignore b/.gitignore index c85aeb99e..050735f5d 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,8 @@ secret* **/.kotlin -**/*.pem +**/issuer-*.pem +**/root-*.pem # Created by https://www.toptal.com/developers/gitignore/api/xcode,swift,cocoapods # Edit at https://www.toptal.com/developers/gitignore?templates=xcode,swift,cocoapods diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ecdsa-vault.public.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ecdsa-vault.public.pem new file mode 100644 index 000000000..d0a5966b4 --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ecdsa-vault.public.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE87jhtMa/W0cHSEukQmKECq3ZstG7Y0ZhOAjNHTDvLA6Chq6RvF1Z/U1sRPTqvoEP65/mVaFVDR9H3+I4toJVcw== +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ed25519.private.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ed25519.private.pem new file mode 100644 index 000000000..42dac5dea --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ed25519.private.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIJpchqgaS5BrgnM/AfWg9DJp6iE/spWXuQhea3+FIlyH +-----END PRIVATE KEY----- +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA51sbDqo0X6YccLaxupF+QCR2Oz853AVGIwbXBOU77rU= +-----END PUBLIC KEY----- diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ed25519.public.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ed25519.public.pem new file mode 100644 index 000000000..f859e806b --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/ed25519.public.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA51sbDqo0X6YccLaxupF+QCR2Oz853AVGIwbXBOU77rU= +-----END PUBLIC KEY----- diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa-vault.public.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa-vault.public.pem new file mode 100644 index 000000000..473cbb578 --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa-vault.public.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8Lw8l1t6Q037FkOhkeKU1IOtRTRpwvCV2tuHhmH4jm9SVvj1XM4xG0Pb3zFg3by5d/WIijCJdbozHuP4xWARsbm4jMg5mVcpzbdeLww3V0Nzi3kq7cKEJ0A87SDzAlcOhqqyAKdFYD9hzylVMdrSQo/fv02tHKS62wQZKi1fWDiJ8q/Qrj+T7UySRhCp/mBCv5IYDgCz2QMz7BZcEWLCGvrpD4cmP3N0oFEPX7cSexXRJaG0KBuTRE0RtpoClv69XFdvEDkbCZvyI/DfJo1F9UVaFaTarmvSr6uLV1XVV/lm3SJGxZ93p1Z7fLU5I+RrTdgcGSDkmaMO1LyP7ovdJwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa.private.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa.private.pem new file mode 100644 index 000000000..e9541a0a0 --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa.private.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAqV+fGqTo8r6L52sIJpt44bxLkODaF0/wvIL/eYYDL55H+Ap+ +b1q4pd4YyZb7pARor/1mob6sMRnnAr5htmO1XucmKBEiNY+12zza0q9smjLm3+eN +qq+8PgsEqBz4lU1YIBeQzsCR0NTa3J3OHfr+bADVystQeonSPoRLqSoO78oAtonQ +WLX1MUfS9778+ECcxlM21+JaUjqMD0nQR6wl8L6oWGcR7PjcjPQAyuS/ASTy7MO0 +SqunpkGzj/H7uFbK9Np/dLIOr9ZqrkCSdioA/PgDyk36E8ayuMnN1HDy4ak/Q7yE +X4R/C75T0JxuuYio06hugwyREgOQNID+DVUoLwIDAQABAoIBAQCGd1HbV11RipGL +0l+QNxJLNLBRfxHmPCMFpoKougpBfcnpVHt4cG/zz1WihemWF6H9RpJ6iuQtv0C1 +3uu4X4SYqa6TVLbyCvv36GJZrcfsy8ibrju8bPRn1VuHFCkOb28tW0gtvJiHUNXJ +HMeM6b2fhTI2ZB+qiUyPMXzX+noNR+mQxwMElKWxOZEoxY8bS7yYWbxoH1l+1uvI +87fpA6fLuDj8zxJkbXLEZNvKmPINM/1aoyYeloL7rqAuzOPLHARtWHr2b4ewMSzt +CD2gxUbYWLC0NJcgCnB8uTa/ZiTj5N4APj2tnPD5BwnTKo95V2rxyDIU6HBf5w+1 +AibxfsCBAoGBANGzaSc8zjoM6amlpG/uT7lIGPQHnVLJ83tuALbpF2jfVWO3uQS2 +HGxNdURnso/JJIaaLb2UOlq2BH70pH8Qb6FXNavOhV4qpacJlC/v4zuAW4BEjivX +mlj9Ylplja2aasHZyHhd1WR3wiKBcUVf02/0qfFDUrnhYAh+iFSZX8EhAoGBAM7E +2q0WKPZSxPF786Rs6Y7azh7Jy7pNp+Rlz+jNl/PQS/MnPP+RaffZvxJvbxgDoWQS +vQHLWbmRBklVYX1dSJhsNe7S8kGUggL0s0KWUmKU/RA3mYJ/6EqK31IDCqaZtV+K +5eWM+5TEdZIZY3Srf1+oBQOgAy9ofwEStWwUY69PAoGBAJTn6k5jfil4i9/ccHTO +66usx5NZaNyl7RCDn1xDDk148UCa8HWo/2vkYNYPMJurgBVYnAxXmkxZnb2s6LYV +rL8Ll2AFiWzBqdmAEssrc9cHoXHmvHHjaoWwf8ui+0UANriqdhEKyIHMDH3GHvHd +Rt3kBVz9qlu17yR4/UPdmUIhAoGAE7TDOpfQE5nT10f+8n7Gy6yi1GBbIEhiZewm +IoPlpYEGnAfzUlAjj1GbWkBwkBNYgFcg2FjvFjZyKO8QOYh4cL5vbXGBUSq8MVfs +9b2p4Gdervr9kGhsVR5jJkfP7gzcMlzkiDoliAopQmFVDzuBCjbTM4M+inglEo8b +508SKRUCgYBomwMGHFAUNulCvbROODEibAGyVU/3Ehq7LedwKaMeLHoVzWXnWAvv +VXU5YaddpK0Z+hbLSAqRScm5Tf9f/ED9DDMBc8lhr6O5GUPwHFN/uuZH8cL5eJV3 +I2eRTdp8e0ridKFLYS43YRc6tgOttCgDXf9roi2T/nm8OkneNyLBLw== +-----END RSA PRIVATE KEY----- diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa.public.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa.public.pem new file mode 100644 index 000000000..bf92d7c66 --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/rsa.public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqV+fGqTo8r6L52sIJpt4 +4bxLkODaF0/wvIL/eYYDL55H+Ap+b1q4pd4YyZb7pARor/1mob6sMRnnAr5htmO1 +XucmKBEiNY+12zza0q9smjLm3+eNqq+8PgsEqBz4lU1YIBeQzsCR0NTa3J3OHfr+ +bADVystQeonSPoRLqSoO78oAtonQWLX1MUfS9778+ECcxlM21+JaUjqMD0nQR6wl +8L6oWGcR7PjcjPQAyuS/ASTy7MO0SqunpkGzj/H7uFbK9Np/dLIOr9ZqrkCSdioA +/PgDyk36E8ayuMnN1HDy4ak/Q7yEX4R/C75T0JxuuYio06hugwyREgOQNID+DVUo +LwIDAQAB +-----END PUBLIC KEY----- diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256k1.private.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256k1.private.pem new file mode 100644 index 000000000..4421e70b0 --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256k1.private.pem @@ -0,0 +1,8 @@ +-----BEGIN PRIVATE KEY----- +MEcCAQAwEAYHKoZIzj0CAQYFK4EEAAoEMDAuAgEBBCDhRhzY9+4kOgOm1G2RpZic +YVT21rrpZiGhMcTLFJ1HRaAHBgUrgQQACg== +-----END PRIVATE KEY----- +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAErWTFQycS7uhkDiKuOv4RLduQkwsTuuoC +PyEMJwLmBFV5mngn1GEkEJxOi0US0SD+/W/ShHyMPzqlbei99XC4mA== +-----END PUBLIC KEY----- diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256k1.public.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256k1.public.pem new file mode 100644 index 000000000..d2b4ed63d --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256k1.public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIjAomwz3PFqdqjHR5e22P6tfd/VPqEjA +PZ3d+ydEZApySmPqX2CUtSpeB9EGsxF7eDOZv2b9ZLdNTmhyIIrW4w== +-----END PUBLIC KEY----- diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256r1.private.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256r1.private.pem new file mode 100644 index 000000000..16f60d95d --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256r1.private.pem @@ -0,0 +1,10 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg1K0LxD5eCTxD0RQA +DLbSmdBtr4Mu6pA9uAM9iotuKZKgCgYIKoZIzj0DAQehRANCAAS6jz3oejnvRQ/b +jHLI23t0TdTqoeUM0m2HQdz+7+4nYfT7uBHIgsck4fXlRMWtBZyYiWefM0CmUz53 +yl6VjAra +-----END PRIVATE KEY----- +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuo896Ho570UP24xyyNt7dE3U6qHl +DNJth0Hc/u/uJ2H0+7gRyILHJOH15UTFrQWcmIlnnzNAplM+d8pelYwK2g== +-----END PUBLIC KEY----- diff --git a/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256r1.public.pem b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256r1.public.pem new file mode 100644 index 000000000..2de7b065c --- /dev/null +++ b/waltid-libraries/crypto/waltid-crypto/src/jvmTest/resources/pem/secp256r1.public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuo896Ho570UP24xyyNt7dE3U6qHl +DNJth0Hc/u/uJ2H0+7gRyILHJOH15UTFrQWcmIlnnzNAplM+d8pelYwK2g== +-----END PUBLIC KEY----- From d7cbe4ffd656544dc6affdbce28603e13c767441 Mon Sep 17 00:00:00 2001 From: waltkb <68587968+waltkb@users.noreply.github.com> Date: Thu, 8 Aug 2024 02:17:56 +0200 Subject: [PATCH 17/17] fix: fix dockerfile to include new path --- settings.gradle.kts | 3 +-- waltid-services/waltid-wallet-api/Dockerfile | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 83cdd6827..f6503f48f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,8 +27,7 @@ val modules = listOf( * "$libraries:credentials".group( "waltid-verifiable-credentials", "waltid-mdoc-credentials", - "waltid-dif-presentation-exchange", - "waltid-credentials-base" + "waltid-dif-presentation-exchange" ), * "$libraries:protocols".group( diff --git a/waltid-services/waltid-wallet-api/Dockerfile b/waltid-services/waltid-wallet-api/Dockerfile index 454fcdf22..d9a60e584 100644 --- a/waltid-services/waltid-wallet-api/Dockerfile +++ b/waltid-services/waltid-wallet-api/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/gradle:jdk17 as buildstage +FROM docker.io/gradle:jdk17 AS buildstage COPY gradle/ /work/gradle COPY settings.gradle.kts build.gradle.kts gradle.properties gradlew /work/ @@ -9,7 +9,7 @@ COPY waltid-libraries/crypto/waltid-crypto/build.gradle.kts /work/waltid-librari COPY waltid-libraries/crypto/waltid-crypto-oci/build.gradle.kts /work/waltid-libraries/crypto/waltid-crypto-oci/ COPY waltid-libraries/waltid-did/build.gradle.kts /work/waltid-libraries/waltid-did/ COPY waltid-libraries/credentials/waltid-mdoc-credentials/build.gradle.kts /work/waltid-libraries/credentials/waltid-mdoc-credentials/ -COPY waltid-libraries/credentials/waltid-verifiable-credentials//build.gradle.kts /work/waltid-libraries/waltid-verifiable-credentials/ +COPY waltid-libraries/credentials/waltid-verifiable-credentials//build.gradle.kts /work/waltid-libraries/credentials/waltid-verifiable-credentials/ COPY waltid-services/waltid-service-commons/build.gradle.kts /work/waltid-services/waltid-service-commons/ COPY waltid-services/waltid-wallet-api/build.gradle.kts /work/waltid-services/waltid-wallet-api/ @@ -23,7 +23,7 @@ COPY waltid-libraries/crypto/waltid-crypto/. /work/waltid-libraries/crypto/walti COPY waltid-libraries/crypto/waltid-crypto-oci/. /work/waltid-libraries/crypto/waltid-crypto-oci COPY waltid-libraries/waltid-did/. /work/waltid-libraries/waltid-did COPY waltid-libraries/credentials/waltid-mdoc-credentials/. /work/waltid-libraries/credentials/waltid-mdoc-credentials -COPY waltid-libraries/credentials/waltid-verifiable-credentials/. /work/waltid-libraries/waltid-verifiable-credentials +COPY waltid-libraries/credentials/waltid-verifiable-credentials/. /work/waltid-libraries/credentials/waltid-verifiable-credentials COPY waltid-services/waltid-service-commons/. /work/waltid-services/waltid-service-commons COPY waltid-services/waltid-wallet-api/src/ /work/waltid-services/waltid-wallet-api/src