From db3031f680482da00c723d69e081cdb2fa3e4ba5 Mon Sep 17 00:00:00 2001 From: Thomas Diesler Date: Tue, 20 Dec 2022 17:21:25 +0100 Subject: [PATCH] Restructure project and integrate didcomm-jvm with multi-recipient support --- .gitignore | 4 + README.md | 20 +- core/pom.xml | 86 +++++++ .../org/nessus/didcomm/aries/AriesAgent.kt | 102 ++++++++ .../kotlin/org/nessus/didcomm/wallet/Did.kt | 23 ++ .../org/nessus/didcomm/wallet/Wallet.kt | 76 ++++++ .../didcomm/test}/diddoc/DIDDocAlice.kt | 5 +- .../didcomm/test}/diddoc/DIDDocBob.kt | 5 +- .../didcomm/test}/diddoc/DIDDocCharlie.kt | 5 +- .../didcomm/test}/diddoc/DIDDocEllie.kt | 4 +- .../didcomm/test}/diddoc/DIDDocMediator1.kt | 4 +- .../didcomm/test}/diddoc/DIDDocMediator2.kt | 5 +- .../didcomm/test}/fixtures/Fixtures.kt | 9 +- .../didcomm/test}/messages/DIDCommMessages.kt | 4 +- .../test}/mock/AliceNewSecretResolverMock.kt | 4 +- ...AliceRotatedToCharlieSecretResolverMock.kt | 4 +- .../test}/mock/AliceSecretResolverMock.kt | 4 +- .../test}/mock/BobSecretResolverMock.kt | 4 +- .../test}/mock/CharlieSecretResolverMock.kt | 4 +- .../didcomm/test}/mock/DIDDocResolverMock.kt | 20 +- .../test}/mock/Mediator1SecretResolverMock.kt | 4 +- .../test}/mock/Mediator2SecretResolverMock.kt | 4 +- .../test}/mock/SecretResolverInMemoryMock.kt | 2 +- .../org/nessus/didcomm/test/did/DidKeyTest.kt | 21 ++ .../test/message/EncryptedMessageTest.kt | 8 +- .../test/message/PlaintextMessageTest.kt | 8 +- .../didcomm/test/message/SignedMessageTest.kt | 25 +- .../didcomm/test/wallet/InMemoryWalletTest.kt | 19 ++ core/src/test/resources/logback-test.xml | 23 ++ docker-compose.yml | 203 ++++++++++++++++ itests/pom.xml | 63 +++++ .../nessus/didcomm/itest/AbstractAriesTest.kt | 56 +++++ .../didcomm/itest/features/Scenario001Test.kt | 18 ++ itests/src/test/resources/logback-test.xml | 23 ++ pom.xml | 175 +++++++++----- python/README.md | 4 + python/didcomm/crypto.py | 148 ++++++++++++ python/didcomm/did_info.py | 20 ++ python/didcomm/did_key.py | 221 ++++++++++++++++++ python/didcomm/did_method.py | 87 +++++++ python/didcomm/error.py | 3 + python/didcomm/key_type.py | 78 +++++++ python/didcomm/wallet.py | 112 +++++++++ python/poetry.lock | 137 +++++++++++ python/pyproject.toml | 16 ++ services/agent/pom.xml | 41 ++++ services/pom.xml | 43 ++++ services/resolver/pom.xml | 41 ++++ services/wallet/pom.xml | 41 ++++ src/main/kotlin/Main.kt | 8 - 50 files changed, 1931 insertions(+), 113 deletions(-) create mode 100644 core/pom.xml create mode 100644 core/src/main/kotlin/org/nessus/didcomm/aries/AriesAgent.kt create mode 100644 core/src/main/kotlin/org/nessus/didcomm/wallet/Did.kt create mode 100644 core/src/main/kotlin/org/nessus/didcomm/wallet/Wallet.kt rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/diddoc/DIDDocAlice.kt (97%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/diddoc/DIDDocBob.kt (98%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/diddoc/DIDDocCharlie.kt (94%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/diddoc/DIDDocEllie.kt (69%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/diddoc/DIDDocMediator1.kt (96%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/diddoc/DIDDocMediator2.kt (95%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/fixtures/Fixtures.kt (99%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/messages/DIDCommMessages.kt (92%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/AliceNewSecretResolverMock.kt (99%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/AliceRotatedToCharlieSecretResolverMock.kt (99%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/AliceSecretResolverMock.kt (98%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/BobSecretResolverMock.kt (99%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/CharlieSecretResolverMock.kt (97%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/DIDDocResolverMock.kt (64%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/Mediator1SecretResolverMock.kt (98%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/Mediator2SecretResolverMock.kt (98%) rename {src/test/kotlin/org/didcommx/didcomm => core/src/test/kotlin/org/didcommx/didcomm/test}/mock/SecretResolverInMemoryMock.kt (85%) create mode 100644 core/src/test/kotlin/org/nessus/didcomm/test/did/DidKeyTest.kt rename {src => core/src}/test/kotlin/org/nessus/didcomm/test/message/EncryptedMessageTest.kt (90%) rename {src => core/src}/test/kotlin/org/nessus/didcomm/test/message/PlaintextMessageTest.kt (84%) rename {src => core/src}/test/kotlin/org/nessus/didcomm/test/message/SignedMessageTest.kt (67%) create mode 100644 core/src/test/kotlin/org/nessus/didcomm/test/wallet/InMemoryWalletTest.kt create mode 100644 core/src/test/resources/logback-test.xml create mode 100644 docker-compose.yml create mode 100644 itests/pom.xml create mode 100644 itests/src/test/kotlin/org/nessus/didcomm/itest/AbstractAriesTest.kt create mode 100644 itests/src/test/kotlin/org/nessus/didcomm/itest/features/Scenario001Test.kt create mode 100644 itests/src/test/resources/logback-test.xml create mode 100644 python/README.md create mode 100644 python/didcomm/crypto.py create mode 100644 python/didcomm/did_info.py create mode 100644 python/didcomm/did_key.py create mode 100644 python/didcomm/did_method.py create mode 100644 python/didcomm/error.py create mode 100644 python/didcomm/key_type.py create mode 100644 python/didcomm/wallet.py create mode 100644 python/poetry.lock create mode 100644 python/pyproject.toml create mode 100644 services/agent/pom.xml create mode 100644 services/pom.xml create mode 100644 services/resolver/pom.xml create mode 100644 services/wallet/pom.xml delete mode 100644 src/main/kotlin/Main.kt diff --git a/.gitignore b/.gitignore index 940c3ce2..3bc0789e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,10 @@ ### Mac OS ### .DS_Store +data/ ### Maven target/ + +### Python +__pycache__/ diff --git a/README.md b/README.md index 1cc09fb1..82dfe12c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,27 @@ -# Nessus DIDComm +## Nessus DIDComm Nessus DIDComm is about digital identy and VCs based on [DIDComm](https://identity.foundation/didcomm-messaging/spec/v2.0). [self sovereign identity](https://www.manning.com/books/self-sovereign-identity) -## External Documentation +### External Documentation * [The Story of Open SSI Standards](https://www.youtube.com/watch?v=RllH91rcFdE) * [DIDComm Messaging](https://identity.foundation/didcomm-messaging/spec/v2.0) * [DIDComm JVM](https://github.com/sicpa-dlab/didcomm-jvm) +* [Aries Cloud Agent](https://github.com/hyperledger/aries-cloudagent-python) +* [Aries Protocol RFCs](https://github.com/hyperledger/aries-rfcs/tree/main/features) + +### Ledger with VON-Network + +This project requires access to a Hyperledger Indy Network. Is is recommended to use the [VON Network](https://github.com/bcgov/von-network), developed as a portable Indy Node Network implementation for local development. Instructions for setting up the von-network can be viewed [here](https://github.com/bcgov/von-network#running-the-network-locally). + +Basic instructions for using the VON Network are [here](https://github.com/bcgov/von-network/blob/main/docs/UsingVONNetwork.md). + +### Start Hyperledger Aries Cloud Agent + +Use this when you want to run the tests. + +``` +docker compose up --detach && docker compose logs -f acapy +``` diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 00000000..f168f363 --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,86 @@ + + + + + + + 4.0.0 + + + org.nessus.didcomm + nessus-didcomm + 1.0-SNAPSHOT + + + Nessus DIDComm :: Core + + nessus-didcomm-core + jar + + + + org.jetbrains.kotlin + kotlin-stdlib + + + com.google.crypto.tink + tink + + + id.walt + waltid-ssi-kit + + + io.github.microutils + kotlin-logging-jvm + + + network.idu.acapy + aries-client-python + + + org.didcommx + didcomm + + + org.slf4j + slf4j-api + + + + + ch.qos.logback + logback-classic + test + + + ch.qos.logback + logback-core + test + + + org.jetbrains.kotlin + kotlin-test-junit5 + test + + + + diff --git a/core/src/main/kotlin/org/nessus/didcomm/aries/AriesAgent.kt b/core/src/main/kotlin/org/nessus/didcomm/aries/AriesAgent.kt new file mode 100644 index 00000000..4701d16d --- /dev/null +++ b/core/src/main/kotlin/org/nessus/didcomm/aries/AriesAgent.kt @@ -0,0 +1,102 @@ +package org.nessus.didcomm.aries + +import org.hyperledger.aries.AriesClient +import org.hyperledger.aries.api.multitenancy.WalletRecord +import java.net.MalformedURLException +import java.net.URL + +class AgentConfiguration(val adminUrl: String?, val userUrl: String?, val apiKey: String?) { + + companion object { + private val host = System.getenv("ACAPY_HOSTNAME") ?: "localhost" + private val adminPort = System.getenv("ACAPY_ADMIN_PORT") ?: "8031" + private val userPort = System.getenv("ACAPY_USER_PORT") ?: "8030" + private val apiKey = System.getenv("ACAPY_ADMIN_API_KEY") ?: "adminkey" + val defaultConfiguration= AgentConfigurationBuilder() + .adminUrl(String.format("http://%s:%s", host, adminPort)) + .userUrl(String.format("http://%s:%s", host, userPort)) + .apiKey(apiKey) + .build() + } + + val webSocketUrl: String + get() = try { + val url = URL(adminUrl) + String.format("ws://%s:%d/ws", url.host, url.port) + } catch (ex: MalformedURLException) { + throw IllegalArgumentException(ex) + } + + override fun toString(): String { + val reductedApiKey = if (apiKey != null) apiKey.substring(0, 4) + "..." else null + return "AgentConfiguration [agentAdminUrl=$adminUrl, agentUserUrl=$userUrl, agentApiKey=$reductedApiKey]" + } + + fun builder(): AgentConfigurationBuilder { + return AgentConfigurationBuilder() + } + + class AgentConfigurationBuilder { + private var adminUrl: String? = null + private var userUrl: String? = null + private var apiKey: String? = null + fun adminUrl(adminUrl: String?): AgentConfigurationBuilder { + this.adminUrl = adminUrl + return this + } + + fun userUrl(userUrl: String?): AgentConfigurationBuilder { + this.userUrl = userUrl + return this + } + + fun apiKey(apiKey: String?): AgentConfigurationBuilder { + this.apiKey = apiKey + return this + } + + fun build(): AgentConfiguration { + return AgentConfiguration(adminUrl, userUrl, apiKey) + } + } + + private fun getSystemEnv(key: String?, defaultValue: String?): String? { + var value = System.getenv(key) + if (value == null || value.isBlank() || value.isEmpty()) value = defaultValue + return value + } +} + +object AriesClientFactory { + /** + * Create a client for the admin wallet + */ + fun adminClient(): AriesClient { + return createClient(AgentConfiguration.defaultConfiguration, null) + } + + /** + * Create a client for the admin wallet + */ + fun adminClient(config: AgentConfiguration): AriesClient { + return createClient(config, null) + } + + /** + * Create a client for a multitenant wallet + */ + fun createClient(wallet: WalletRecord?): AriesClient { + return createClient(AgentConfiguration.defaultConfiguration, wallet) + } + + /** + * Create a client for a multitenant wallet + */ + fun createClient(config: AgentConfiguration, wallet: WalletRecord?): AriesClient { + return AriesClient.builder() + .url(config.adminUrl) + .apiKey(config.apiKey) + .bearerToken(wallet?.token) + .build() + } +} diff --git a/core/src/main/kotlin/org/nessus/didcomm/wallet/Did.kt b/core/src/main/kotlin/org/nessus/didcomm/wallet/Did.kt new file mode 100644 index 00000000..600f39a9 --- /dev/null +++ b/core/src/main/kotlin/org/nessus/didcomm/wallet/Did.kt @@ -0,0 +1,23 @@ +package org.nessus.didcomm.wallet + +import id.walt.crypto.KeyAlgorithm + +val DEFAULT_KEY_ALGORITHM = KeyAlgorithm.EdDSA_Ed25519 + +enum class DidMethod(mname : String) { + KEY("key"), + SOV("sov"); + + fun supportedAlgorithms() : Set { + return setOf(KeyAlgorithm.EdDSA_Ed25519) + } +} + +open class Did(method: DidMethod) { +} + +class DidKey() : Did(DidMethod.KEY) { +} + +class DidSov() : Did(DidMethod.SOV) { +} diff --git a/core/src/main/kotlin/org/nessus/didcomm/wallet/Wallet.kt b/core/src/main/kotlin/org/nessus/didcomm/wallet/Wallet.kt new file mode 100644 index 00000000..2d0ad4b8 --- /dev/null +++ b/core/src/main/kotlin/org/nessus/didcomm/wallet/Wallet.kt @@ -0,0 +1,76 @@ + +package org.nessus.didcomm.wallet + +import id.walt.crypto.KeyAlgorithm +import id.walt.crypto.decBase64 +import id.walt.crypto.keyPairGeneratorEd25519 +import id.walt.crypto.toBase64 +import id.walt.crypto.toHexString +import io.ipfs.multibase.Base58 +import mu.KotlinLogging +import java.security.SecureRandom + + +class WalletError(message: String) : Exception(message) + +fun ByteArray.encodeBase58(): String = Base58.encode(this) + +fun String.decodeBase58(): ByteArray = Base58.decode(this) + +class Wallet { + + private val log = KotlinLogging.logger {} + + /** + * Create and store a new local DID. + */ + fun createLocalDID(method: String, keyType: String = DEFAULT_KEY_ALGORITHM.name, seed: String? = null) { + + val didMethod = DidMethod.valueOf(method.uppercase()) + val keyAlgorithm = KeyAlgorithm.fromString(keyType) + var seedBytes = validateSeed(seed) + log.info(seedBytes.toHexString()) + + // validate key_type + if (keyAlgorithm !in didMethod.supportedAlgorithms()) + throw WalletError("Invalid key type $keyType for method $method") + + var secureRandom = SecureRandom.getInstance("SHA1PRNG") + secureRandom.setSeed(seedBytes) + + val randomBytes = ByteArray(32) + secureRandom.nextBytes(randomBytes) + log.info(randomBytes.toHexString()) + + val keyPairGenerator = keyPairGeneratorEd25519() + keyPairGenerator.initialize(255, secureRandom) + + val keypair = keyPairGenerator.generateKeyPair() + log.info("pubk {}", keypair.public.encoded.toHexString()) + val verkey64 = keypair.public.toBase64() + val verkeyBytes = decBase64(verkey64) + val verkey58 = verkeyBytes.encodeBase58() + + log.info("$verkey64") + log.info("$verkey58") + } + + /** + * Convert a seed parameter to standard format and check length. + * + * @property seed the seed to validate. + * @return The validated and encoded seed + */ + private fun validateSeed(seed: String? = null): ByteArray { + var byteArray = ByteArray(32); + if (seed != null) { + byteArray = seed.toByteArray(Charsets.UTF_8) + } else { + SecureRandom().nextBytes(byteArray); + } + if (byteArray.size != 32) { + throw WalletError("Seed value must be 32 bytes in length") + } + return byteArray + } +} diff --git a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocAlice.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocAlice.kt similarity index 97% rename from src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocAlice.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocAlice.kt index 1fc6b7d3..87984c25 100644 --- a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocAlice.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocAlice.kt @@ -1,8 +1,11 @@ -package org.didcommx.didcomm.diddoc +package org.didcommx.didcomm.test.diddoc import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType +import org.didcommx.didcomm.diddoc.DIDCommService +import org.didcommx.didcomm.diddoc.DIDDoc +import org.didcommx.didcomm.diddoc.VerificationMethod import org.didcommx.didcomm.protocols.routing.PROFILE_DIDCOMM_AIP2_ENV_RFC587 import org.didcommx.didcomm.protocols.routing.PROFILE_DIDCOMM_V2 diff --git a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocBob.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocBob.kt similarity index 98% rename from src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocBob.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocBob.kt index 6808b1cf..cbb38956 100644 --- a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocBob.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocBob.kt @@ -1,8 +1,11 @@ -package org.didcommx.didcomm.diddoc +package org.didcommx.didcomm.test.diddoc import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType +import org.didcommx.didcomm.diddoc.DIDCommService +import org.didcommx.didcomm.diddoc.DIDDoc +import org.didcommx.didcomm.diddoc.VerificationMethod import org.didcommx.didcomm.protocols.routing.PROFILE_DIDCOMM_AIP2_ENV_RFC587 import org.didcommx.didcomm.protocols.routing.PROFILE_DIDCOMM_V2 diff --git a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocCharlie.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocCharlie.kt similarity index 94% rename from src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocCharlie.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocCharlie.kt index 4b05ef2a..1f92b06d 100644 --- a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocCharlie.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocCharlie.kt @@ -1,8 +1,11 @@ -package org.didcommx.didcomm.diddoc +package org.didcommx.didcomm.test.diddoc import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType +import org.didcommx.didcomm.diddoc.DIDCommService +import org.didcommx.didcomm.diddoc.DIDDoc +import org.didcommx.didcomm.diddoc.VerificationMethod import org.didcommx.didcomm.protocols.routing.PROFILE_DIDCOMM_AIP2_ENV_RFC587 import org.didcommx.didcomm.protocols.routing.PROFILE_DIDCOMM_V2 diff --git a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocEllie.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocEllie.kt similarity index 69% rename from src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocEllie.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocEllie.kt index 870edfcd..7a0d5db3 100644 --- a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocEllie.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocEllie.kt @@ -1,4 +1,6 @@ -package org.didcommx.didcomm.diddoc +package org.didcommx.didcomm.test.diddoc + +import org.didcommx.didcomm.diddoc.DIDDoc val DID_DOC_ELLIE = DIDDoc( did = "did:example:ellie", diff --git a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocMediator1.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocMediator1.kt similarity index 96% rename from src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocMediator1.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocMediator1.kt index 6d38fa7c..20d9489d 100644 --- a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocMediator1.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocMediator1.kt @@ -1,8 +1,10 @@ -package org.didcommx.didcomm.diddoc +package org.didcommx.didcomm.test.diddoc import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType +import org.didcommx.didcomm.diddoc.DIDDoc +import org.didcommx.didcomm.diddoc.VerificationMethod val MEDIATOR1_VERIFICATION_METHOD_KEY_AGREEM_X25519_1 = VerificationMethod( id = "did:example:mediator1#key-x25519-1", diff --git a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocMediator2.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocMediator2.kt similarity index 95% rename from src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocMediator2.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocMediator2.kt index 6c970be8..b528ee29 100644 --- a/src/test/kotlin/org/didcommx/didcomm/diddoc/DIDDocMediator2.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/diddoc/DIDDocMediator2.kt @@ -1,8 +1,11 @@ -package org.didcommx.didcomm.diddoc +package org.didcommx.didcomm.test.diddoc import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType +import org.didcommx.didcomm.diddoc.DIDCommService +import org.didcommx.didcomm.diddoc.DIDDoc +import org.didcommx.didcomm.diddoc.VerificationMethod import org.didcommx.didcomm.protocols.routing.PROFILE_DIDCOMM_AIP2_ENV_RFC587 import org.didcommx.didcomm.protocols.routing.PROFILE_DIDCOMM_V2 diff --git a/src/test/kotlin/org/didcommx/didcomm/fixtures/Fixtures.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/fixtures/Fixtures.kt similarity index 99% rename from src/test/kotlin/org/didcommx/didcomm/fixtures/Fixtures.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/fixtures/Fixtures.kt index b3b873e7..89895850 100644 --- a/src/test/kotlin/org/didcommx/didcomm/fixtures/Fixtures.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/fixtures/Fixtures.kt @@ -1,4 +1,4 @@ -package org.didcommx.didcomm.fixtures +package org.didcommx.didcomm.test.fixtures import org.didcommx.didcomm.common.AnonCryptAlg import org.didcommx.didcomm.common.AuthCryptAlg @@ -12,6 +12,12 @@ import org.didcommx.didcomm.model.Metadata import org.didcommx.didcomm.model.UnpackParams import kotlin.reflect.KClass +fun isJDK15Plus() = + System.getProperty("java.version")?.let { + val major = it.split(".")[0].toInt() + return major >= 15 + } ?: false + class JWM { data class WrongMessage(val json: String, val expectedMessage: String) @@ -540,6 +546,7 @@ class JWS { ), // ES256K digital signature + // Note, supported on JDK18 TestVector( from = "did:example:alice#key-3", expected = """ diff --git a/src/test/kotlin/org/didcommx/didcomm/messages/DIDCommMessages.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/messages/DIDCommMessages.kt similarity index 92% rename from src/test/kotlin/org/didcommx/didcomm/messages/DIDCommMessages.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/messages/DIDCommMessages.kt index 52ece98a..ad05a194 100644 --- a/src/test/kotlin/org/didcommx/didcomm/messages/DIDCommMessages.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/messages/DIDCommMessages.kt @@ -1,8 +1,8 @@ -package org.didcommx.didcomm.messages +package org.didcommx.didcomm.test.messages -import org.didcommx.didcomm.fixtures.JWM import org.didcommx.didcomm.message.Attachment import org.didcommx.didcomm.message.Message +import org.didcommx.didcomm.test.fixtures.JWM fun attachmentMulti1msg(): Message { val msg = JWM.PLAINTEXT_MESSAGE.copy( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/AliceNewSecretResolverMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceNewSecretResolverMock.kt similarity index 99% rename from src/test/kotlin/org/didcommx/didcomm/mock/AliceNewSecretResolverMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceNewSecretResolverMock.kt index c3bff09b..ff6b6905 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/AliceNewSecretResolverMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceNewSecretResolverMock.kt @@ -1,11 +1,11 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolverInMemory -import java.util.Optional +import java.util.* class AliceNewSecretResolverMock : SecretResolverInMemoryMock { private val secrets = listOf( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/AliceRotatedToCharlieSecretResolverMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceRotatedToCharlieSecretResolverMock.kt similarity index 99% rename from src/test/kotlin/org/didcommx/didcomm/mock/AliceRotatedToCharlieSecretResolverMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceRotatedToCharlieSecretResolverMock.kt index a69835eb..4e539d81 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/AliceRotatedToCharlieSecretResolverMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceRotatedToCharlieSecretResolverMock.kt @@ -1,4 +1,4 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat @@ -6,7 +6,7 @@ import org.didcommx.didcomm.common.VerificationMethodType import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolver import org.didcommx.didcomm.secret.SecretResolverInMemory -import java.util.Optional +import java.util.* class AliceRotatedToCharlieSecretResolverMock : SecretResolver { private val secretResolver = SecretResolverInMemory( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/AliceSecretResolverMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceSecretResolverMock.kt similarity index 98% rename from src/test/kotlin/org/didcommx/didcomm/mock/AliceSecretResolverMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceSecretResolverMock.kt index ad6248e5..c4a70019 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/AliceSecretResolverMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/AliceSecretResolverMock.kt @@ -1,11 +1,11 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolverInMemory -import java.util.Optional +import java.util.* class AliceSecretResolverMock : SecretResolverInMemoryMock { private val secrets = listOf( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/BobSecretResolverMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/BobSecretResolverMock.kt similarity index 99% rename from src/test/kotlin/org/didcommx/didcomm/mock/BobSecretResolverMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/BobSecretResolverMock.kt index c18873ce..780dbce9 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/BobSecretResolverMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/BobSecretResolverMock.kt @@ -1,11 +1,11 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolverInMemory -import java.util.Optional +import java.util.* class BobSecretResolverMock : SecretResolverInMemoryMock { private val secrets = listOf( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/CharlieSecretResolverMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/CharlieSecretResolverMock.kt similarity index 97% rename from src/test/kotlin/org/didcommx/didcomm/mock/CharlieSecretResolverMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/CharlieSecretResolverMock.kt index 1865d88f..753a478d 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/CharlieSecretResolverMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/CharlieSecretResolverMock.kt @@ -1,11 +1,11 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolverInMemory -import java.util.Optional +import java.util.* class CharlieSecretResolverMock : SecretResolverInMemoryMock { private val secrets = listOf( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/DIDDocResolverMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/DIDDocResolverMock.kt similarity index 64% rename from src/test/kotlin/org/didcommx/didcomm/mock/DIDDocResolverMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/DIDDocResolverMock.kt index b218a606..c2ddfe02 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/DIDDocResolverMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/DIDDocResolverMock.kt @@ -1,17 +1,17 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.diddoc.DIDDoc import org.didcommx.didcomm.diddoc.DIDDocResolver import org.didcommx.didcomm.diddoc.DIDDocResolverInMemory -import org.didcommx.didcomm.diddoc.DID_DOC_ALICE_SPEC_TEST_VECTORS -import org.didcommx.didcomm.diddoc.DID_DOC_ALICE_WITH_NO_SECRETS -import org.didcommx.didcomm.diddoc.DID_DOC_BOB_SPEC_TEST_VECTORS -import org.didcommx.didcomm.diddoc.DID_DOC_BOB_WITH_NO_SECRETS -import org.didcommx.didcomm.diddoc.DID_DOC_CHARLIE -import org.didcommx.didcomm.diddoc.DID_DOC_ELLIE -import org.didcommx.didcomm.diddoc.DID_DOC_MEDIATOR1 -import org.didcommx.didcomm.diddoc.DID_DOC_MEDIATOR2 -import java.util.Optional +import org.didcommx.didcomm.test.diddoc.DID_DOC_ALICE_SPEC_TEST_VECTORS +import org.didcommx.didcomm.test.diddoc.DID_DOC_ALICE_WITH_NO_SECRETS +import org.didcommx.didcomm.test.diddoc.DID_DOC_BOB_SPEC_TEST_VECTORS +import org.didcommx.didcomm.test.diddoc.DID_DOC_BOB_WITH_NO_SECRETS +import org.didcommx.didcomm.test.diddoc.DID_DOC_CHARLIE +import org.didcommx.didcomm.test.diddoc.DID_DOC_ELLIE +import org.didcommx.didcomm.test.diddoc.DID_DOC_MEDIATOR1 +import org.didcommx.didcomm.test.diddoc.DID_DOC_MEDIATOR2 +import java.util.* class DIDDocResolverMock : DIDDocResolver { private val didDocResolver = DIDDocResolverInMemory( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/Mediator1SecretResolverMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/Mediator1SecretResolverMock.kt similarity index 98% rename from src/test/kotlin/org/didcommx/didcomm/mock/Mediator1SecretResolverMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/Mediator1SecretResolverMock.kt index c06ddcad..18a3c0fe 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/Mediator1SecretResolverMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/Mediator1SecretResolverMock.kt @@ -1,11 +1,11 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolverInMemory -import java.util.Optional +import java.util.* class Mediator1SecretResolverMock : SecretResolverInMemoryMock { private val secrets = listOf( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/Mediator2SecretResolverMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/Mediator2SecretResolverMock.kt similarity index 98% rename from src/test/kotlin/org/didcommx/didcomm/mock/Mediator2SecretResolverMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/Mediator2SecretResolverMock.kt index 483defd7..c92944f2 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/Mediator2SecretResolverMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/Mediator2SecretResolverMock.kt @@ -1,11 +1,11 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.common.VerificationMaterial import org.didcommx.didcomm.common.VerificationMaterialFormat import org.didcommx.didcomm.common.VerificationMethodType import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolverInMemory -import java.util.Optional +import java.util.* class Mediator2SecretResolverMock : SecretResolverInMemoryMock { private val secrets = listOf( diff --git a/src/test/kotlin/org/didcommx/didcomm/mock/SecretResolverInMemoryMock.kt b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/SecretResolverInMemoryMock.kt similarity index 85% rename from src/test/kotlin/org/didcommx/didcomm/mock/SecretResolverInMemoryMock.kt rename to core/src/test/kotlin/org/didcommx/didcomm/test/mock/SecretResolverInMemoryMock.kt index 8718a32c..fb272fff 100644 --- a/src/test/kotlin/org/didcommx/didcomm/mock/SecretResolverInMemoryMock.kt +++ b/core/src/test/kotlin/org/didcommx/didcomm/test/mock/SecretResolverInMemoryMock.kt @@ -1,4 +1,4 @@ -package org.didcommx.didcomm.mock +package org.didcommx.didcomm.test.mock import org.didcommx.didcomm.secret.Secret import org.didcommx.didcomm.secret.SecretResolver diff --git a/core/src/test/kotlin/org/nessus/didcomm/test/did/DidKeyTest.kt b/core/src/test/kotlin/org/nessus/didcomm/test/did/DidKeyTest.kt new file mode 100644 index 00000000..71f895a7 --- /dev/null +++ b/core/src/test/kotlin/org/nessus/didcomm/test/did/DidKeyTest.kt @@ -0,0 +1,21 @@ +package org.nessus.didcomm.test.did + +import id.walt.crypto.KeyAlgorithm +import id.walt.services.crypto.TinkCryptoService +import org.junit.jupiter.api.Test + +class DidKeyTest { + + @Test + fun testCreateLocalDID() { + + // Wallet().createLocalDID("sov") + // Wallet().createLocalDID("sov", seed = "000000000000000000000000Trustee1") + + val data = "some data".toByteArray() + val tinkCryptoService = TinkCryptoService() + val keyId = tinkCryptoService.generateKey(KeyAlgorithm.EdDSA_Ed25519) + val sig = tinkCryptoService.sign(keyId, data) + val res = tinkCryptoService.verify(keyId, sig, data) + } +} \ No newline at end of file diff --git a/src/test/kotlin/org/nessus/didcomm/test/message/EncryptedMessageTest.kt b/core/src/test/kotlin/org/nessus/didcomm/test/message/EncryptedMessageTest.kt similarity index 90% rename from src/test/kotlin/org/nessus/didcomm/test/message/EncryptedMessageTest.kt rename to core/src/test/kotlin/org/nessus/didcomm/test/message/EncryptedMessageTest.kt index 8a4012b9..758326c0 100644 --- a/src/test/kotlin/org/nessus/didcomm/test/message/EncryptedMessageTest.kt +++ b/core/src/test/kotlin/org/nessus/didcomm/test/message/EncryptedMessageTest.kt @@ -2,11 +2,11 @@ package org.nessus.didcomm.test.message import com.nimbusds.jose.util.JSONObjectUtils import org.didcommx.didcomm.DIDComm -import org.didcommx.didcomm.fixtures.JWE -import org.didcommx.didcomm.fixtures.JWM -import org.didcommx.didcomm.mock.BobSecretResolverMock -import org.didcommx.didcomm.mock.DIDDocResolverMock import org.didcommx.didcomm.model.UnpackParams +import org.didcommx.didcomm.test.fixtures.JWE +import org.didcommx.didcomm.test.fixtures.JWM +import org.didcommx.didcomm.test.mock.BobSecretResolverMock +import org.didcommx.didcomm.test.mock.DIDDocResolverMock import org.junit.jupiter.api.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals diff --git a/src/test/kotlin/org/nessus/didcomm/test/message/PlaintextMessageTest.kt b/core/src/test/kotlin/org/nessus/didcomm/test/message/PlaintextMessageTest.kt similarity index 84% rename from src/test/kotlin/org/nessus/didcomm/test/message/PlaintextMessageTest.kt rename to core/src/test/kotlin/org/nessus/didcomm/test/message/PlaintextMessageTest.kt index be5d7786..1746b25f 100644 --- a/src/test/kotlin/org/nessus/didcomm/test/message/PlaintextMessageTest.kt +++ b/core/src/test/kotlin/org/nessus/didcomm/test/message/PlaintextMessageTest.kt @@ -1,13 +1,13 @@ package org.nessus.didcomm.test.message import org.didcommx.didcomm.DIDComm -import org.didcommx.didcomm.fixtures.JWM.Companion.ALICE_DID -import org.didcommx.didcomm.fixtures.JWM.Companion.BOB_DID import org.didcommx.didcomm.message.Message -import org.didcommx.didcomm.mock.AliceSecretResolverMock -import org.didcommx.didcomm.mock.DIDDocResolverMock import org.didcommx.didcomm.model.PackPlaintextParams import org.didcommx.didcomm.model.UnpackParams +import org.didcommx.didcomm.test.fixtures.JWM.Companion.ALICE_DID +import org.didcommx.didcomm.test.fixtures.JWM.Companion.BOB_DID +import org.didcommx.didcomm.test.mock.AliceSecretResolverMock +import org.didcommx.didcomm.test.mock.DIDDocResolverMock import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test diff --git a/src/test/kotlin/org/nessus/didcomm/test/message/SignedMessageTest.kt b/core/src/test/kotlin/org/nessus/didcomm/test/message/SignedMessageTest.kt similarity index 67% rename from src/test/kotlin/org/nessus/didcomm/test/message/SignedMessageTest.kt rename to core/src/test/kotlin/org/nessus/didcomm/test/message/SignedMessageTest.kt index 1911bf91..a26fef40 100644 --- a/src/test/kotlin/org/nessus/didcomm/test/message/SignedMessageTest.kt +++ b/core/src/test/kotlin/org/nessus/didcomm/test/message/SignedMessageTest.kt @@ -2,25 +2,40 @@ package org.nessus.didcomm.test.message import com.nimbusds.jose.JWSObjectJSON import com.nimbusds.jose.util.JSONObjectUtils +import mu.KotlinLogging import org.didcommx.didcomm.DIDComm -import org.didcommx.didcomm.fixtures.JWM -import org.didcommx.didcomm.fixtures.JWS -import org.didcommx.didcomm.mock.AliceSecretResolverMock -import org.didcommx.didcomm.mock.DIDDocResolverMock +import org.didcommx.didcomm.common.SignAlg import org.didcommx.didcomm.model.PackSignedParams import org.didcommx.didcomm.model.UnpackParams +import org.didcommx.didcomm.test.fixtures.JWM +import org.didcommx.didcomm.test.fixtures.JWS +import org.didcommx.didcomm.test.fixtures.isJDK15Plus +import org.didcommx.didcomm.test.mock.AliceSecretResolverMock +import org.didcommx.didcomm.test.mock.DIDDocResolverMock import org.junit.jupiter.api.Test import kotlin.test.assertEquals class SignedMessageTest { + private val log = KotlinLogging.logger {} + @Test fun testSignedPackUnpack() { val didComm = DIDComm(DIDDocResolverMock(), AliceSecretResolverMock()) for (test in JWS.TEST_VECTORS) { + val signAlg = test.expectedMetadata.signAlg + + // TODO: secp256k1 is not supported with JDK 15+ + if (isJDK15Plus() && signAlg == SignAlg.ES256K) { + log.debug("Signing skip $signAlg") + continue + } + + log.debug("Signing with $signAlg") + val packed = didComm.packSigned( PackSignedParams.builder(JWM.PLAINTEXT_MESSAGE, test.from).build() ) @@ -44,7 +59,7 @@ class SignedMessageTest { assertEquals(true, unpacked.metadata.nonRepudiation) assertEquals(false, unpacked.metadata.anonymousSender) assertEquals(test.expectedMetadata.signFrom, unpacked.metadata.signFrom) - assertEquals(test.expectedMetadata.signAlg, unpacked.metadata.signAlg) + assertEquals(signAlg, unpacked.metadata.signAlg) } } } diff --git a/core/src/test/kotlin/org/nessus/didcomm/test/wallet/InMemoryWalletTest.kt b/core/src/test/kotlin/org/nessus/didcomm/test/wallet/InMemoryWalletTest.kt new file mode 100644 index 00000000..cbe79e43 --- /dev/null +++ b/core/src/test/kotlin/org/nessus/didcomm/test/wallet/InMemoryWalletTest.kt @@ -0,0 +1,19 @@ +package org.nessus.didcomm.test.wallet + +import mu.KotlinLogging +import org.junit.jupiter.api.Test +import org.nessus.didcomm.wallet.Wallet +import kotlin.test.Ignore + +@Ignore +class InMemoryWalletTest { + + private val log = KotlinLogging.logger {} + + @Test + fun testCreateLocalDID() { + + // Wallet().createLocalDID("sov") + Wallet().createLocalDID("sov", seed = "000000000000000000000000Trustee1") + } +} diff --git a/core/src/test/resources/logback-test.xml b/core/src/test/resources/logback-test.xml new file mode 100644 index 00000000..913be84c --- /dev/null +++ b/core/src/test/resources/logback-test.xml @@ -0,0 +1,23 @@ + + + + target/test.log + + %date %level [%thread] %logger{10} [%file:%line] -%kvp- %msg%n + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n + + + WARN + + + + + + + + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..7f8bb97d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,203 @@ +# --------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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 +# +# http://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. +# --------------------------------------------------------------------------- + +version: '3' + +networks: + von-network: + +services: + + # + # Webserver + # + webserver: + image: nessusio/von-network:${VON_NETWORK_VERSION:-1.7.2} + container_name: indy-webserver + command: bash -c 'sleep 10 && ./scripts/start_webserver.sh' + environment: + - IP=${IP} + - IPS=${IPS} + - DOCKERHOST=${DOCKERHOST:-host.docker.internal} + - LOG_LEVEL=${LOG_LEVEL:-info} + - RUST_LOG=${RUST_LOG:-warn} + - GENESIS_URL=${GENESIS_URL} + - ANONYMOUS=${ANONYMOUS} + - LEDGER_SEED=${LEDGER_SEED} + - LEDGER_CACHE_PATH=${LEDGER_CACHE_PATH} + - MAX_FETCH=${MAX_FETCH:-50000} + - RESYNC_TIME=${RESYNC_TIME:-120} + - REGISTER_NEW_DIDS=${REGISTER_NEW_DIDS:-True} + - LEDGER_INSTANCE_NAME=${LEDGER_INSTANCE_NAME:-localhost} + - WEB_ANALYTICS_SCRIPT=${WEB_ANALYTICS_SCRIPT} + - INFO_SITE_TEXT=${INFO_SITE_TEXT} + - INFO_SITE_URL=${INFO_SITE_URL} + extra_hosts: + - host.docker.internal:host-gateway + networks: + - von-network + ports: + - ${WEB_SERVER_HOST_PORT:-9000}:8000 + volumes: + - webserver-cli:/home/indy/.indy-cli + - webserver-ledger:/home/indy/ledger + + # + # Nodes + # + node1: + image: nessusio/von-network:${VON_NETWORK_VERSION:-1.7.2} + container_name: indy-node1 + command: ./scripts/start_node.sh 1 + networks: + - von-network + ports: + - 9701:9701 + - 9702:9702 + environment: + - IP=${IP} + - IPS=${IPS} + - DOCKERHOST=${DOCKERHOST:-host.docker.internal} + - LOG_LEVEL=${LOG_LEVEL:-info} + - RUST_LOG=${RUST_LOG:-warn} + extra_hosts: + - host.docker.internal:host-gateway + volumes: + - node1-data:/home/indy/ledger + + node2: + image: nessusio/von-network:${VON_NETWORK_VERSION:-1.7.2} + container_name: indy-node2 + command: ./scripts/start_node.sh 2 + networks: + - von-network + ports: + - 9703:9703 + - 9704:9704 + environment: + - IP=${IP} + - IPS=${IPS} + - DOCKERHOST=${DOCKERHOST:-host.docker.internal} + - LOG_LEVEL=${LOG_LEVEL:-info} + - RUST_LOG=${RUST_LOG:-warn} + extra_hosts: + - host.docker.internal:host-gateway + volumes: + - node2-data:/home/indy/ledger + + node3: + image: nessusio/von-network:${VON_NETWORK_VERSION:-1.7.2} + container_name: indy-node3 + command: ./scripts/start_node.sh 3 + networks: + - von-network + ports: + - 9705:9705 + - 9706:9706 + environment: + - IP=${IP} + - IPS=${IPS} + - DOCKERHOST=${DOCKERHOST:-host.docker.internal} + - LOG_LEVEL=${LOG_LEVEL:-info} + - RUST_LOG=${RUST_LOG:-warn} + extra_hosts: + - host.docker.internal:host-gateway + volumes: + - node3-data:/home/indy/ledger + + node4: + image: nessusio/von-network:${VON_NETWORK_VERSION:-1.7.2} + container_name: indy-node4 + command: ./scripts/start_node.sh 4 + networks: + - von-network + ports: + - 9707:9707 + - 9708:9708 + environment: + - IP=${IP} + - IPS=${IPS} + - DOCKERHOST=${DOCKERHOST:-host.docker.internal} + - LOG_LEVEL=${LOG_LEVEL:-info} + - RUST_LOG=${RUST_LOG:-warn} + extra_hosts: + - host.docker.internal:host-gateway + volumes: + - node4-data:/home/indy/ledger + + tails-server: + image: nessusio/indy-tails-server:${TAILS_SERVER_VERSION:-1.0.0} + container_name: tails-server + ports: + - 6543:6543 + networks: + - von-network + extra_hosts: + - host.docker.internal:host-gateway + command: > + tails-server + --host 0.0.0.0 + --port 6543 + --storage-path ${STORAGE_PATH:-/tmp/tails-files} + --log-level ${LOG_LEVEL:-info} + + acapy: + image: nessusio/aries-cloudagent-python:${ACAPY_VERSION:-0.7.5} + container_name: acapy + ports: + - ${ACAPY_USER_PORT:-8030}:${ACAPY_USER_PORT:-8030} + - ${ACAPY_ADMIN_PORT:-8031}:${ACAPY_ADMIN_PORT:-8031} + networks: + - von-network + extra_hosts: + - host.docker.internal:host-gateway + command: > + start + --genesis-url http://${DOCKERHOST:-host.docker.internal}:9000/genesis + --endpoint http://${ACAPY_HOSTNAME:-localhost}:${ACAPY_USER_PORT:-8030} + --inbound-transport http 0.0.0.0 ${ACAPY_USER_PORT:-8030} + --outbound-transport http + --tails-server-base-url http://tails-server:6543 + --admin 0.0.0.0 ${ACAPY_ADMIN_PORT:-8031} + --admin-api-key ${ACAPY_ADMIN_API_KEY:-adminkey} + --seed 000000000000000000000000Trustee1 + --wallet-storage-type default + --wallet-key trusteewkey + --wallet-name trustee + --wallet-type indy + --storage-type indy + --recreate-wallet + --auto-provision + --auto-ping-connection + --auto-accept-requests + --log-level info + depends_on: + - node1 + - node2 + - node3 + - node4 + - webserver + - tails-server + +volumes: + webserver-cli: + webserver-ledger: + node1-data: + node2-data: + node3-data: + node4-data: + nodes-data: diff --git a/itests/pom.xml b/itests/pom.xml new file mode 100644 index 00000000..2306ee78 --- /dev/null +++ b/itests/pom.xml @@ -0,0 +1,63 @@ + + + + + + + 4.0.0 + + + org.nessus.didcomm + nessus-didcomm + 1.0-SNAPSHOT + + + Nessus DIDComm :: ITests + + nessus-didcomm-itests + jar + + + + org.nessus.didcomm + nessus-didcomm-core + ${project.version} + + + + + ch.qos.logback + logback-classic + test + + + ch.qos.logback + logback-core + test + + + org.jetbrains.kotlin + kotlin-test-junit5 + test + + + + diff --git a/itests/src/test/kotlin/org/nessus/didcomm/itest/AbstractAriesTest.kt b/itests/src/test/kotlin/org/nessus/didcomm/itest/AbstractAriesTest.kt new file mode 100644 index 00000000..76a978fe --- /dev/null +++ b/itests/src/test/kotlin/org/nessus/didcomm/itest/AbstractAriesTest.kt @@ -0,0 +1,56 @@ +package org.nessus.didcomm.itest + +import com.google.gson.JsonSyntaxException +import mu.KotlinLogging +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import org.hyperledger.aries.AriesClient +import org.hyperledger.aries.config.GsonConfig +import org.nessus.didcomm.aries.AgentConfiguration +import java.util.concurrent.TimeUnit + +abstract class AbstractAriesTest { + + val log = KotlinLogging.logger {} + + private val gson = GsonConfig.defaultConfig() + + private fun messageLoggingInterceptor(): HttpLoggingInterceptor { + val pretty = GsonConfig.prettyPrinter() + val logging = HttpLoggingInterceptor { msg: String -> + if (log.isDebugEnabled && msg.isNotEmpty()) { + if (msg.startsWith("{")) { + try { + val json: Any = gson.fromJson(msg, Any::class.java) + log.debug("\n{}", pretty.toJson(json)) + } catch (e: JsonSyntaxException) { + log.debug("{}", msg) + } + } else { + log.debug("{}", msg) + } + } + } + logging.level = HttpLoggingInterceptor.Level.BODY + logging.redactHeader("X-API-Key") + logging.redactHeader("Authorization") + return logging + } + + fun adminClient(loggingInterceptor: HttpLoggingInterceptor? = null): AriesClient { + val loggingInterceptor = loggingInterceptor ?: messageLoggingInterceptor() + val httpClient = OkHttpClient.Builder() + .writeTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .connectTimeout(60, TimeUnit.SECONDS) + .callTimeout(60, TimeUnit.SECONDS) + .addInterceptor(loggingInterceptor) + .build() + val config = AgentConfiguration.defaultConfiguration + return AriesClient.builder() + .url(config.adminUrl) + .apiKey(config.apiKey) + .client(httpClient) + .build() + } +} diff --git a/itests/src/test/kotlin/org/nessus/didcomm/itest/features/Scenario001Test.kt b/itests/src/test/kotlin/org/nessus/didcomm/itest/features/Scenario001Test.kt new file mode 100644 index 00000000..c2f86528 --- /dev/null +++ b/itests/src/test/kotlin/org/nessus/didcomm/itest/features/Scenario001Test.kt @@ -0,0 +1,18 @@ +package org.nessus.didcomm.itest.features + +import org.hyperledger.aries.api.out_of_band.InvitationCreateRequest +import org.junit.jupiter.api.Test +import org.nessus.didcomm.itest.AbstractAriesTest + +class Scenario001Test : AbstractAriesTest() { + + @Test + fun testFaberInvitesAlice() { + val client = adminClient() + val invitationRequest = InvitationCreateRequest.builder() + .alias("Faber") + .build() + val invitationResponse = client.outOfBandCreateInvitation(invitationRequest, null).get() + log.info("{}", invitationResponse) + } +} diff --git a/itests/src/test/resources/logback-test.xml b/itests/src/test/resources/logback-test.xml new file mode 100644 index 00000000..913be84c --- /dev/null +++ b/itests/src/test/resources/logback-test.xml @@ -0,0 +1,23 @@ + + + + target/test.log + + %date %level [%thread] %logger{10} [%file:%line] -%kvp- %msg%n + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n + + + WARN + + + + + + + + diff --git a/pom.xml b/pom.xml index e7f6fd1c..3328e4b3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,27 +4,79 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - nessus-didcom - org.nessus.didcom + nessus-didcomm + org.nessus.didcomm 1.0-SNAPSHOT - jar + pom + 1.7.20 + - 0.3.2 + 0.7.25 + 0.3.3-SNAPSHOT + 1.7.0 + 3.0.4 + 1.12.0 + 5.9.1 + 1.4.5 + 2.0.6 + 2.22.2 UTF-8 official 1.8 + + core + services + itests + + + + ch.qos.logback + logback-classic + ${version.logback} + + + ch.qos.logback + logback-core + ${version.logback} + + + com.google.crypto.tink + tink + ${version.google.crypto.tink} + + + id.walt + waltid-ssi-kit + ${version.waltid} + + + org.slf4j + slf4j-simple + + + + + io.github.microutils + kotlin-logging-jvm + ${version.kotlin.logging} + + + network.idu.acapy + aries-client-python + ${version.acapy.client} + org.didcommx didcomm @@ -33,88 +85,99 @@ org.junit junit-bom - 5.9.1 + ${version.junit} pom import org.jetbrains.kotlin kotlin-test-junit5 - 1.7.20 + ${version.kotlin} org.jetbrains.kotlin - kotlin-stdlib-jdk8 - 1.7.20 + kotlin-stdlib + ${version.kotlin} + + + org.slf4j + slf4j-api + ${version.slf4j} + + + org.slf4j + slf4j-reload4j + ${version.slf4j} - - - org.didcommx - didcomm - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - - - org.jetbrains.kotlin - kotlin-test-junit5 - test - - - src/main/kotlin src/test/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${version.kotlin} + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${version-maven-surefire-plugin} + + + org.jetbrains.kotlin kotlin-maven-plugin - 1.7.20 - - - compile - compile - - compile - - - - test-compile - test-compile - - test-compile - - - + org.apache.maven.plugins maven-surefire-plugin - 2.22.2 - - - maven-failsafe-plugin - 2.22.2 - - - org.codehaus.mojo - exec-maven-plugin - 1.6.0 - - MainKt - - mavenCentral + maven-central https://repo1.maven.org/maven2/ + + danubetech-maven-public + https://repo.danubetech.com/repository/maven-public/ + + + jitpack.io + https://jitpack.io + + + waltid-maven-public + https://maven.walt.id/repository/waltid/ + + + waltid-ssi-kit-maven-public + https://maven.walt.id/repository/waltid-ssi-kit/ + - \ No newline at end of file + diff --git a/python/README.md b/python/README.md new file mode 100644 index 00000000..3c6d0064 --- /dev/null +++ b/python/README.md @@ -0,0 +1,4 @@ + +``` +poetry run python -m didcomm.wallet +``` \ No newline at end of file diff --git a/python/didcomm/crypto.py b/python/didcomm/crypto.py new file mode 100644 index 00000000..a68e31ec --- /dev/null +++ b/python/didcomm/crypto.py @@ -0,0 +1,148 @@ +import base58 +import base64 +import nacl.utils +import nacl.bindings + +from .error import WalletError +from .key_type import KeyType + +from typing import Tuple, Union + + +def b58_to_bytes(val: str) -> bytes: + """Convert a base 58 string to bytes.""" + return base58.b58decode(val) + + +def bytes_to_b58(val: bytes) -> str: + """Convert a byte string to base 58.""" + return base58.b58encode(val).decode("ascii") + + +def b64_to_bytes(val: str, urlsafe=False) -> bytes: + """Convert a base 64 string to bytes.""" + if urlsafe: + return base64.urlsafe_b64decode(pad(val)) + return base64.b64decode(pad(val)) + + +def b64_to_str(val: str, urlsafe=False, encoding=None) -> str: + """Convert a base 64 string to string on input encoding (default utf-8).""" + return b64_to_bytes(val, urlsafe).decode(encoding or "utf-8") + + +def bytes_to_b64(val: bytes, urlsafe=False, pad=True, encoding: str = "ascii") -> str: + """Convert a byte string to base 64.""" + b64 = ( + base64.urlsafe_b64encode(val).decode(encoding) + if urlsafe + else base64.b64encode(val).decode(encoding) + ) + return b64 if pad else unpad(b64) + + +def pad(val: str) -> str: + """Pad base64 values if need be: JWT calls to omit trailing padding.""" + padlen = 4 - len(val) % 4 + return val if padlen > 2 else (val + "=" * padlen) + + +def unpad(val: str) -> str: + """Remove padding from base64 values if need be.""" + return val.rstrip("=") + + +def random_seed() -> bytes: + """ + Generate a random seed value. + + Returns: + A new random seed + + """ + return nacl.utils.random(nacl.bindings.crypto_box_SEEDBYTES) + + +def create_keypair(key_type: KeyType, seed: bytes = None) -> Tuple[bytes, bytes]: + """ + Create a public and private keypair from a seed value. + + Args: + key_type: The type of key to generate + seed: Seed for keypair + + Raises: + WalletError: If the key type is not supported + + Returns: + A tuple of (public key, secret key) + + """ + if key_type == KeyType.ED25519: + return create_ed25519_keypair(seed) + else: + raise WalletError(f"Unsupported key type: {key_type.key_type}") + + +def create_ed25519_keypair(seed: bytes = None) -> Tuple[bytes, bytes]: + """ + Create a public and private ed25519 keypair from a seed value. + + Args: + seed: Seed for keypair + + Returns: + A tuple of (public key, secret key) + + """ + if not seed: + seed = random_seed() + pk, sk = nacl.bindings.crypto_sign_seed_keypair(seed) + return pk, sk + + +def ed25519_pk_to_curve25519(public_key: bytes) -> bytes: + """Covert a public Ed25519 key to a public Curve25519 key as bytes.""" + return nacl.bindings.crypto_sign_ed25519_pk_to_curve25519(public_key) + + +def seed_to_did(seed: str) -> str: + """ + Derive a DID from a seed value. + + Args: + seed: The seed to derive + + Returns: + The DID derived from the seed + + """ + seed = validate_seed(seed) + verkey, _ = create_ed25519_keypair(seed) + did = bytes_to_b58(verkey[:16]) + return did + + +def validate_seed(seed: Union[str, bytes]) -> bytes: + """ + Convert a seed parameter to standard format and check length. + + Args: + seed: The seed to validate + + Returns: + The validated and encoded seed + + """ + if not seed: + return None + if isinstance(seed, str): + if "=" in seed: + seed = b64_to_bytes(seed) + else: + seed = seed.encode("ascii") + if not isinstance(seed, bytes): + raise Exception("Seed value is not a string or bytes") + if len(seed) != 32: + raise Exception("Seed value must be 32 bytes in length") + return seed diff --git a/python/didcomm/did_info.py b/python/didcomm/did_info.py new file mode 100644 index 00000000..2f5ebbdc --- /dev/null +++ b/python/didcomm/did_info.py @@ -0,0 +1,20 @@ +"""KeyInfo, DIDInfo.""" + +from typing import NamedTuple + +from .did_method import DIDMethod +from .key_type import KeyType + +KeyInfo = NamedTuple( + "KeyInfo", [("verkey", str), ("metadata", dict), ("key_type", KeyType)] +) +DIDInfo = NamedTuple( + "DIDInfo", + [ + ("did", str), + ("verkey", str), + ("metadata", dict), + ("method", DIDMethod), + ("key_type", KeyType), + ], +) diff --git a/python/didcomm/did_key.py b/python/didcomm/did_key.py new file mode 100644 index 00000000..b06512ff --- /dev/null +++ b/python/didcomm/did_key.py @@ -0,0 +1,221 @@ +"""DID Key class and resolver methods.""" + +from .key_type import KeyType +from .crypto import b58_to_bytes, bytes_to_b58, ed25519_pk_to_curve25519 + +DID_V1_CONTEXT_URL = "https://www.w3.org/ns/did/v1" + + +class DIDKey: + """DID Key parser and resolver.""" + + _key_type: KeyType + _public_key: bytes + + def __init__(self, public_key: bytes, key_type: KeyType) -> None: + """Initialize new DIDKey instance.""" + self._public_key = public_key + self._key_type = key_type + + @classmethod + def from_public_key(cls, public_key: bytes, key_type: KeyType) -> "DIDKey": + """Initialize new DIDKey instance from public key and key type.""" + + return cls(public_key, key_type) + + @classmethod + def from_public_key_b58(cls, public_key: str, key_type: KeyType) -> "DIDKey": + """Initialize new DIDKey instance from base58 encoded public key and key type.""" + public_key_bytes = b58_to_bytes(public_key) + return cls.from_public_key(public_key_bytes, key_type) + + @classmethod + def from_fingerprint(cls, fingerprint: str) -> "DIDKey": + """Initialize new DIDKey instance from multibase encoded fingerprint. + + The fingerprint contains both the public key and key type. + """ + # Assert fingerprint is in multibase format + assert fingerprint[0] == "z" + + # Get key bytes, remove multicodec prefix + key_bytes_with_prefix = b58_to_bytes(fingerprint[1:]) + + # Get associated key type with prefixed bytes + key_type = KeyType.from_prefixed_bytes(key_bytes_with_prefix) + + if not key_type: + raise Exception( + f"No key type for prefixed public key '{key_bytes_with_prefix}' found." + ) + + # Remove the prefix bytes to get the public key + prefix_len = len(key_type.multicodec_prefix) + public_key_bytes = key_bytes_with_prefix[prefix_len:] + + return cls(public_key_bytes, key_type) + + @classmethod + def from_did(cls, did: str) -> "DIDKey": + """Initialize a new DIDKey instance from a fully qualified did:key string. + + Extracts the fingerprint from the did:key and uses that to constrcut the did:key. + """ + did_parts = did.split("#") + _, fingerprint = did_parts[0].split("did:key:") + + return cls.from_fingerprint(fingerprint) + + @property + def prefixed_public_key(self) -> bytes: + """Getter for multicodec prefixed public key.""" + return b"".join([self.key_type.multicodec_prefix, self.public_key]) + + @property + def fingerprint(self) -> str: + """Getter for did key fingerprint.""" + return f"z{bytes_to_b58(self.prefixed_public_key)}" + + @property + def did(self) -> str: + """Getter for full did:key string.""" + return f"did:key:{self.fingerprint}" + + @property + def did_doc(self) -> dict: + """Getter for did document associated with did:key.""" + resolver = DID_KEY_RESOLVERS[self.key_type] + return resolver(self) + + @property + def public_key(self) -> bytes: + """Getter for public key.""" + return self._public_key + + @property + def public_key_b58(self) -> str: + """Getter for base58 encoded public key.""" + return bytes_to_b58(self.public_key) + + @property + def key_type(self) -> KeyType: + """Getter for key type.""" + return self._key_type + + @property + def key_id(self) -> str: + """Getter for key id.""" + return f"{self.did}#{self.fingerprint}" + + +def construct_did_key_bls12381g2(did_key: "DIDKey") -> dict: + """Construct BLS12381G2 did:key. + + Args: + did_key (DIDKey): did key instance to parse bls12381g2 did:key document from + + Returns: + dict: The bls12381g2 did:key did document + + """ + + return construct_did_signature_key_base( + id=did_key.did, + key_id=did_key.key_id, + verification_method={ + "id": did_key.key_id, + "type": "Bls12381G2Key2020", + "controller": did_key.did, + "publicKeyBase58": did_key.public_key_b58, + }, + ) + + +def construct_did_key_bls12381g1(did_key: "DIDKey") -> dict: + """Construct BLS12381G1 did:key. + + Args: + did_key (DIDKey): did key instance to parse bls12381g1 did:key document from + + Returns: + dict: The bls12381g1 did:key did document + + """ + + return construct_did_signature_key_base( + id=did_key.did, + key_id=did_key.key_id, + verification_method={ + "id": did_key.key_id, + "type": "Bls12381G1Key2020", + "controller": did_key.did, + "publicKeyBase58": did_key.public_key_b58, + }, + ) + + +def construct_did_key_ed25519(did_key: "DIDKey") -> dict: + """Construct Ed25519 did:key. + + Args: + did_key (DIDKey): did key instance to parse ed25519 did:key document from + + Returns: + dict: The ed25519 did:key did document + + """ + curve25519 = ed25519_pk_to_curve25519(did_key.public_key) + x25519 = DIDKey.from_public_key(curve25519, KeyType.X25519) + + did_doc = construct_did_signature_key_base( + id=did_key.did, + key_id=did_key.key_id, + verification_method={ + "id": did_key.key_id, + "type": "Ed25519VerificationKey2018", + "controller": did_key.did, + "publicKeyBase58": did_key.public_key_b58, + }, + ) + + # Ed25519 has pair with X25519 + did_doc["keyAgreement"].append( + { + "id": f"{did_key.did}#{x25519.fingerprint}", + "type": "X25519KeyAgreementKey2019", + "controller": did_key.did, + "publicKeyBase58": bytes_to_b58(curve25519), + } + ) + + return did_doc + + +def construct_did_signature_key_base( + *, id: str, key_id: str, verification_method: dict +): + """Create base did key structure to use for most signature keys. + + May not be suitable for all did key types + + """ + + return { + "@context": DID_V1_CONTEXT_URL, + "id": id, + "verificationMethod": [verification_method], + "authentication": [key_id], + "assertionMethod": [key_id], + "capabilityDelegation": [key_id], + "capabilityInvocation": [key_id], + "keyAgreement": [], + } + + +DID_KEY_RESOLVERS = { + KeyType.ED25519: construct_did_key_ed25519, + # KeyType.X25519: construct_did_key_x25519, + # KeyType.BLS12381G2: construct_did_key_bls12381g2, + # KeyType.BLS12381G1: construct_did_key_bls12381g1, + # KeyType.BLS12381G1G2: construct_did_key_bls12381g1g2, +} diff --git a/python/didcomm/did_method.py b/python/didcomm/did_method.py new file mode 100644 index 00000000..83ed69f5 --- /dev/null +++ b/python/didcomm/did_method.py @@ -0,0 +1,87 @@ +"""Did method enum.""" + +from typing import List, Mapping, NamedTuple, Optional +from enum import Enum + +from .key_type import KeyType + +DIDMethodSpec = NamedTuple( + "DIDMethodSpec", + [ + ("method_name", str), + ("supported_key_types", List[KeyType]), + ("supports_rotation", bool), + ], +) + + +class DIDMethod(Enum): + """DID Method class specifying DID methods with supported key types.""" + + SOV = DIDMethodSpec( + method_name="sov", supported_key_types=[KeyType.ED25519], supports_rotation=True + ) + KEY = DIDMethodSpec( + method_name="key", + supported_key_types=[KeyType.ED25519, KeyType.BLS12381G2], + supports_rotation=False, + ) + + @property + def method_name(self) -> str: + """Getter for did method name. e.g. sov or key.""" + return self.value.method_name + + @property + def supported_key_types(self) -> List[KeyType]: + """Getter for supported key types of method.""" + return self.value.supported_key_types + + @property + def supports_rotation(self) -> bool: + """Check whether the current method supports key rotation.""" + return self.value.supports_rotation + + def supports_key_type(self, key_type: KeyType) -> bool: + """Check whether the current method supports the key type.""" + return key_type in self.supported_key_types + + def from_metadata(metadata: Mapping) -> "DIDMethod": + """Get DID method instance from metadata object. + + Returns SOV if no metadata was found for backwards compatability. + """ + method = metadata.get("method") + + # extract from metadata object + if method: + for did_method in DIDMethod: + if method == did_method.method_name: + return did_method + + # return default SOV for backward compat + return DIDMethod.SOV + + def from_method(method: str) -> Optional["DIDMethod"]: + """Get DID method instance from the method name.""" + for did_method in DIDMethod: + if method == did_method.method_name: + return did_method + + return None + + def from_did(did: str) -> "DIDMethod": + """Get DID method instance from the method name.""" + if not did.startswith("did:"): + # sov has no prefix + return DIDMethod.SOV + + parts = did.split(":") + method_str = parts[1] + + method = DIDMethod.from_method(method_str) + + if not method: + raise Exception(f"Unsupported did method: {method_str}") + + return method diff --git a/python/didcomm/error.py b/python/didcomm/error.py new file mode 100644 index 00000000..ea1ece11 --- /dev/null +++ b/python/didcomm/error.py @@ -0,0 +1,3 @@ + +class WalletError(Exception): + """General wallet exception.""" diff --git a/python/didcomm/key_type.py b/python/didcomm/key_type.py new file mode 100644 index 00000000..57defdb5 --- /dev/null +++ b/python/didcomm/key_type.py @@ -0,0 +1,78 @@ +"""Key type enum.""" + +from enum import Enum +from typing import NamedTuple, Optional + +# Define keys +KeySpec = NamedTuple( + "KeySpec", + [("key_type", str), ("multicodec_name", str), ("multicodec_prefix", int)], +) + + +class KeyTypeException(BaseException): + """Key type exception.""" + + +class KeyType(Enum): + """KeyType Enum specifying key types with multicodec name.""" + + # NOTE: the py_multicodec library is outdated. We use hardcoded prefixes here + # until this PR gets released: https://github.com/multiformats/py-multicodec/pull/14 + # multicodec is also not used now, but may be used again if py_multicodec is updated + ED25519 = KeySpec("ed25519", "ed25519-pub", b"\xed\x01") + X25519 = KeySpec("x25519", "x25519-pub", b"\xec\x01") + BLS12381G1 = KeySpec("bls12381g1", "bls12_381-g1-pub", b"\xea\x01") + BLS12381G2 = KeySpec("bls12381g2", "bls12_381-g2-pub", b"\xeb\x01") + BLS12381G1G2 = KeySpec("bls12381g1g2", "bls12_381-g1g2-pub", b"\xee\x01") + + @property + def key_type(self) -> str: + """Getter for key type identifier.""" + return self.value.key_type + + @property + def multicodec_name(self) -> str: + """Getter for multicodec name.""" + return self.value.multicodec_name + + @property + def multicodec_prefix(self) -> bytes: + """Getter for multicodec prefix.""" + return self.value.multicodec_prefix + + @classmethod + def from_multicodec_name(cls, multicodec_name: str) -> Optional["KeyType"]: + """Get KeyType instance based on multicodec name. Returns None if not found.""" + for key_type in KeyType: + if key_type.multicodec_name == multicodec_name: + return key_type + + return None + + @classmethod + def from_multicodec_prefix(cls, multicodec_prefix: bytes) -> Optional["KeyType"]: + """Get KeyType instance based on multicodec prefix. Returns None if not found.""" + for key_type in KeyType: + if key_type.multicodec_prefix == multicodec_prefix: + return key_type + + return None + + @classmethod + def from_prefixed_bytes(cls, prefixed_bytes: bytes) -> Optional["KeyType"]: + """Get KeyType instance based on prefix in bytes. Returns None if not found.""" + for key_type in KeyType: + if prefixed_bytes.startswith(key_type.multicodec_prefix): + return key_type + + return None + + @classmethod + def from_key_type(cls, key_type: str) -> Optional["KeyType"]: + """Get KeyType instance from the key type identifier.""" + for _key_type in KeyType: + if _key_type.key_type == key_type: + return _key_type + + return None diff --git a/python/didcomm/wallet.py b/python/didcomm/wallet.py new file mode 100644 index 00000000..bb4874d9 --- /dev/null +++ b/python/didcomm/wallet.py @@ -0,0 +1,112 @@ +import sys + +from .crypto import bytes_to_b58, bytes_to_b64, create_ed25519_keypair, create_keypair, random_seed, validate_seed +from .did_info import DIDInfo +from .did_key import DIDKey +from .did_method import DIDMethod +from .error import WalletError +from .key_type import KeyType + + +def create_local_did( + method: DIDMethod, + key_type: KeyType, + seed: str = None, + did: str = None, + metadata: dict = None, +) -> DIDInfo: + """ + Create and store a new local DID. + + Args: + method: The method to use for the DID + key_type: The key type to use for the DID + seed: Optional seed to use for DID + did: The DID to use + metadata: Metadata to store with DID + + Returns: + A `DIDInfo` instance representing the created DID + + Raises: + WalletDuplicateError: If the DID already exists in the wallet + + """ + seed = validate_seed(seed) or random_seed() + + # validate key_type + if not method.supports_key_type(key_type): + raise WalletError( + f"Invalid key type {key_type.key_type} for method {method.method_name}" + ) + + verkey, secret = create_keypair(key_type, seed) + verkey_enc = bytes_to_b58(verkey) + + # We need some did method specific handling. If more did methods + # are added it is probably better create a did method specific handler + if method == DIDMethod.KEY: + if did: + raise WalletError("Not allowed to set DID for DID method 'key'") + + did = DIDKey.from_public_key(verkey, key_type).did + elif method == DIDMethod.SOV: + if not did: + did = bytes_to_b58(verkey[:16]) + else: + raise WalletError(f"Unsupported DID method: {method.method_name}") + + # if (did in self.profile.local_dids + # and self.profile.local_dids[did]["verkey"] != verkey_enc): + # raise WalletDuplicateError("DID already exists in wallet") + + # self.profile.local_dids[did] = { + # "seed": seed, + # "secret": secret, + # "verkey": verkey_enc, + # "metadata": metadata.copy() if metadata else {}, + # "key_type": key_type, + # "method": method, + # } + + return DIDInfo( + did=did, + verkey=verkey_enc, + metadata=metadata, + method=method, + key_type=key_type, + ) + + +def main(): + + seed = validate_seed("000000000000000000000000Trustee1") + print(f"seed: {seed.hex()}") + + verkey, prvkey = create_ed25519_keypair(seed) + print(f"pubk: {verkey.hex()}") + print(f"prvk: {prvkey.hex()}") + + verkey64 = bytes_to_b64(verkey) + verkey58 = bytes_to_b58(verkey) + # print(f"verkey64: {verkey64}") + # print(f"verkey58: {verkey58}") + + did = bytes_to_b58(verkey[:16]) + didinfo = create_local_did(DIDMethod.SOV, KeyType.ED25519, seed=seed) + print(f"did:sov:{didinfo.did}") + print(f"verkey: {didinfo.verkey}") + assert didinfo.verkey == verkey58 + assert didinfo.did == did + print("") + + didinfo = create_local_did(DIDMethod.KEY, KeyType.ED25519, seed=seed) + print(f"{didinfo.did}") + print(f"verkey: {didinfo.verkey}") + assert didinfo.verkey == verkey58 + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/python/poetry.lock b/python/poetry.lock new file mode 100644 index 00000000..89be8ba6 --- /dev/null +++ b/python/poetry.lock @@ -0,0 +1,137 @@ +[[package]] +name = "base58" +version = "2.1.1" +description = "Base58 and Base58Check implementation." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-flake8"] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "PyNaCl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx_rtd_theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] + +[metadata] +lock-version = "1.1" +python-versions = "^3.10" +content-hash = "7b480cc7802e88fd4507f673008baf72e84704cfe416ad145dc28d9d8381af72" + +[metadata.files] +base58 = [ + {file = "base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2"}, + {file = "base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c"}, +] +cffi = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] +pycparser = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] +PyNaCl = [ + {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, + {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, +] diff --git a/python/pyproject.toml b/python/pyproject.toml new file mode 100644 index 00000000..f6acfdec --- /dev/null +++ b/python/pyproject.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "didcomm" +version = "0.1.0" +description = "" +authors = ["Thomas Diesler "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.10" +pynacl = "^1.5.0" +base58 = "^2.1.1" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/services/agent/pom.xml b/services/agent/pom.xml new file mode 100644 index 00000000..1f462b44 --- /dev/null +++ b/services/agent/pom.xml @@ -0,0 +1,41 @@ + + + + + + + 4.0.0 + + + org.nessus.didcomm + nessus-didcomm-services + 1.0-SNAPSHOT + + + Nessus DIDComm :: Services :: Agent + + nessus-didcomm-agent + jar + + + + + diff --git a/services/pom.xml b/services/pom.xml new file mode 100644 index 00000000..1a6573d2 --- /dev/null +++ b/services/pom.xml @@ -0,0 +1,43 @@ + + + + + + + 4.0.0 + + + org.nessus.didcomm + nessus-didcomm + 1.0-SNAPSHOT + + + Nessus DIDComm :: Services + + nessus-didcomm-services + pom + + + agent + resolver + wallet + + diff --git a/services/resolver/pom.xml b/services/resolver/pom.xml new file mode 100644 index 00000000..aa3004a9 --- /dev/null +++ b/services/resolver/pom.xml @@ -0,0 +1,41 @@ + + + + + + + 4.0.0 + + + org.nessus.didcomm + nessus-didcomm-services + 1.0-SNAPSHOT + + + Nessus DIDComm :: Services :: Resolver + + nessus-didcomm-resolver + jar + + + + + diff --git a/services/wallet/pom.xml b/services/wallet/pom.xml new file mode 100644 index 00000000..f83b9e76 --- /dev/null +++ b/services/wallet/pom.xml @@ -0,0 +1,41 @@ + + + + + + + 4.0.0 + + + org.nessus.didcomm + nessus-didcomm-services + 1.0-SNAPSHOT + + + Nessus DIDComm :: Services :: Wallet + + nessus-didcomm-wallet + jar + + + + + diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt deleted file mode 100644 index 405ca9c7..00000000 --- a/src/main/kotlin/Main.kt +++ /dev/null @@ -1,8 +0,0 @@ - -fun main(args: Array) { - println("Hello World!") - - // Try adding program arguments via Run/Debug configuration. - // Learn more about running applications: https://www.jetbrains.com/help/idea/running-applications.html. - println("Program arguments: ${args.joinToString()}") -} \ No newline at end of file