-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #826 from walt-id/core-wallet
Core wallet
- Loading branch information
Showing
65 changed files
with
4,376 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
plugins { | ||
kotlin("multiplatform") | ||
kotlin("plugin.serialization") | ||
id("maven-publish") | ||
} | ||
|
||
group = "id.walt.wallet" | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
kotlin { | ||
jvm { | ||
withJava() | ||
} | ||
|
||
jvmToolchain(21) | ||
|
||
sourceSets { | ||
val ktor_version = "2.3.12" | ||
|
||
val commonMain by getting { | ||
dependencies { | ||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") | ||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1") | ||
|
||
implementation("io.github.oshai:kotlin-logging-jvm:7.0.0") | ||
|
||
implementation(project(":waltid-libraries:crypto:waltid-crypto")) | ||
implementation(project(":waltid-libraries:waltid-did")) | ||
|
||
implementation(project(":waltid-libraries:protocols:waltid-openid4vc")) | ||
implementation(project(":waltid-libraries:sdjwt:waltid-sdjwt")) | ||
implementation(project(":waltid-libraries:credentials:waltid-mdoc-credentials")) | ||
implementation(project(":waltid-libraries:credentials:waltid-verifiable-credentials")) | ||
|
||
// Ktor client | ||
implementation("io.ktor:ktor-client-core:$ktor_version") | ||
implementation("io.ktor:ktor-client-serialization:$ktor_version") | ||
implementation("io.ktor:ktor-client-content-negotiation:$ktor_version") | ||
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version") | ||
implementation("io.ktor:ktor-client-json:$ktor_version") | ||
implementation("io.ktor:ktor-client-logging:$ktor_version") | ||
|
||
// Bouncy Castle | ||
implementation("org.bouncycastle:bcprov-lts8on:2.73.6") | ||
implementation("org.bouncycastle:bcpkix-lts8on:2.73.6") | ||
|
||
// Problematic libraries: | ||
implementation("com.nimbusds:nimbus-jose-jwt:9.41.1") | ||
implementation("com.augustcellars.cose:cose-java:1.1.0") | ||
} | ||
} | ||
val jvmMain by getting { | ||
dependencies { | ||
// Ktor client | ||
implementation("io.ktor:ktor-client-okhttp-jvm:$ktor_version") | ||
} | ||
} | ||
val commonTest by getting { | ||
dependencies { | ||
implementation(kotlin("test")) | ||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0") | ||
} | ||
} | ||
val jvmTest by getting { | ||
dependencies { | ||
implementation("org.junit.jupiter:junit-jupiter-api:5.11.0") | ||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") | ||
implementation("org.slf4j:slf4j-simple:2.0.16") | ||
} | ||
} | ||
} | ||
} | ||
|
||
publishing { | ||
repositories { | ||
maven { | ||
url = uri("https://maven.waltid.dev/releases") | ||
val envUsername = System.getenv("MAVEN_USERNAME") | ||
val envPassword = System.getenv("MAVEN_PASSWORD") | ||
|
||
val usernameFile = File("$rootDir/secret_maven_username.txt") | ||
val passwordFile = File("$rootDir/secret_maven_password.txt") | ||
|
||
val secretMavenUsername = envUsername ?: usernameFile.let { if (it.isFile) it.readLines().first() else "" } | ||
//println("Deploy username length: ${secretMavenUsername.length}") | ||
val secretMavenPassword = envPassword ?: passwordFile.let { if (it.isFile) it.readLines().first() else "" } | ||
|
||
//if (secretMavenPassword.isBlank()) { | ||
// println("WARNING: Password is blank!") | ||
//} | ||
|
||
credentials { | ||
username = secretMavenUsername | ||
password = secretMavenPassword | ||
} | ||
} | ||
} | ||
} |
144 changes: 144 additions & 0 deletions
144
waltid-libraries/waltid-core-wallet/src/jvmMain/java/id/walt/wallet/core/CoreWallet.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package id.walt.wallet.core | ||
|
||
import id.walt.crypto.keys.Key | ||
import id.walt.oid4vc.data.CredentialOffer | ||
import id.walt.oid4vc.data.dif.PresentationDefinition | ||
import id.walt.sdjwt.SDJWTVCTypeMetadata | ||
import id.walt.wallet.core.service.SSIKit2WalletService | ||
import id.walt.wallet.core.service.WalletServiceManager | ||
import id.walt.wallet.core.service.WalletServiceManager.getWalletService | ||
import id.walt.wallet.core.service.WalletServiceManager.httpClient | ||
import id.walt.wallet.core.service.exchange.* | ||
import id.walt.wallet.core.utils.WalletCredential | ||
import id.walt.webwallet.usecase.exchange.FilterData | ||
import io.ktor.http.* | ||
import io.ktor.util.* | ||
|
||
object CoreWallet { | ||
|
||
val wallet = SSIKit2WalletService( | ||
http = httpClient | ||
) | ||
|
||
/** | ||
* Claim credential(s) from an issuer | ||
* @param offer The offer request to use | ||
* @param did The DID to issue the credential(s) to | ||
* | ||
* @return List of credentials | ||
*/ | ||
suspend fun useOfferRequest(offer: String, did: String, key: Key): List<CredentialDataResult> { | ||
return IssuanceService.useOfferRequest( | ||
offer = offer, | ||
credentialWallet = SSIKit2WalletService.getCredentialWallet(did = did), | ||
clientId = SSIKit2WalletService.testCIClientConfig.clientID, | ||
key = key, | ||
did = did | ||
) | ||
} | ||
|
||
/** | ||
* Present credential(s) to a Relying Party | ||
* | ||
*/ | ||
suspend fun usePresentationRequest( | ||
did: String, | ||
presentationRequest: String, | ||
selectedCredentials: List<CredentialDataResult>, | ||
disclosures: Map<CredentialDataResult, List<String>>? = null, | ||
key: Key, | ||
): UsePresentationResponse { | ||
val wallet = getWalletService() | ||
|
||
val result = wallet.usePresentationRequest( | ||
PresentationRequestParameter( | ||
key = key, | ||
did = did, | ||
request = presentationRequest, | ||
selectedCredentials = selectedCredentials, | ||
disclosures = disclosures, | ||
) | ||
) // TODO add disclosures here | ||
|
||
if (result.isSuccess) { | ||
return UsePresentationResponse(ok = true, redirectUri = result.getOrThrow()) | ||
} else { | ||
val err = result.exceptionOrNull() | ||
println("Presentation failed: $err") | ||
|
||
return when (err) { | ||
is SSIKit2WalletService.PresentationError -> | ||
UsePresentationResponse(ok = false, redirectUri = err.redirectUri, errorMessage = err.message) | ||
|
||
else -> UsePresentationResponse(ok = false, redirectUri = null, errorMessage = err?.message) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Returns the credentials stored in the wallet that match the passed presentation definition | ||
* | ||
* @param presentationDefinition Presentation definition to match credentials against | ||
* | ||
* @return Credentials that match the presentation definition | ||
*/ | ||
fun matchCredentialsForPresentationDefinition( | ||
credentials: List<WalletCredential>, | ||
presentationDefinition: PresentationDefinition | ||
): List<WalletCredential> { | ||
val matchedCredentials = | ||
WalletServiceManager.matchPresentationDefinitionCredentialsUseCase.match(credentials, presentationDefinition) | ||
return matchedCredentials | ||
} | ||
|
||
/** | ||
* Returns the credentials that are required by the presentation definition but not found in the wallet | ||
* | ||
* @param presentationDefinition Presentation definition to match credentials against | ||
* | ||
* @return Filters that failed to fulfill the presentation definition | ||
*/ | ||
fun unmatchedCredentialsForPresentationDefinition( | ||
credentials: List<WalletCredential>, | ||
presentationDefinition: PresentationDefinition | ||
): List<FilterData> { | ||
val unmatchedCredentialTypes = WalletServiceManager.unmatchedPresentationDefinitionCredentialsUseCase.find( | ||
credentials, presentationDefinition | ||
) | ||
return unmatchedCredentialTypes | ||
} | ||
|
||
/** | ||
* Return resolved / parsed presentation request | ||
* @param request PresentationRequest to resolve/parse | ||
*/ | ||
suspend fun resolvePresentationRequest(request: String): String { | ||
val wallet = getWalletService() | ||
val parsedRequest = wallet.resolvePresentationRequest(request) | ||
return parsedRequest | ||
} | ||
|
||
/** | ||
* Return resolved / parsed credential offer | ||
* @param offer Credential offer request to resolve/parse | ||
* @return Resolved credential offer | ||
*/ | ||
suspend fun resolveCredentialOffer(offer: String): CredentialOffer { | ||
val wallet = getWalletService() | ||
val reqParams = Url(offer).parameters.toMap() | ||
val parsedOffer = wallet.resolveCredentialOffer(id.walt.oid4vc.requests.CredentialOfferRequest.fromHttpParameters(reqParams)) | ||
return parsedOffer | ||
} | ||
|
||
/** | ||
* Receive an verifiable credential type (VCT) URL and return resolved vct object as described in IETF SD-JWT VC | ||
* @param vct The value of the vct in URL format, e.g. https://example.com/mycustomvct | ||
* @return Resolved VCT | ||
*/ | ||
suspend fun resolveVctUrl(vct: String): SDJWTVCTypeMetadata { | ||
val wallet = getWalletService() | ||
return wallet.resolveVct(vct) | ||
} | ||
|
||
|
||
} |
Oops, something went wrong.