From aaab3fd1c7b3ffa92a0c5e57e76280e6e4f29102 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Thu, 10 Nov 2022 12:36:18 +0400 Subject: [PATCH 01/21] add .gitignore --- .gitignore | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..73b2bf092 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +.idea +.DS_Store +build +*/build +captures +.externalNativeBuild +.cxx +local.properties +xcuserdata/ +Pods/ +/androidApp/key +*.jks +*yarn.lock \ No newline at end of file From c08d436ee4f1d89a34cac03eccf3d59e4b2914a8 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Thu, 10 Nov 2022 12:36:30 +0400 Subject: [PATCH 02/21] update: readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a0a12c04c..b007c56b4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Atala Prism Wallet SDK - Kotlin Multiplatform (Android/JVM/JS/Apple) + [![Kotlin](https://img.shields.io/badge/kotlin-1.7.20-blue.svg?logo=kotlin)](http://kotlinlang.org) ![android](https://camo.githubusercontent.com/b1d9ad56ab51c4ad1417e9a5ad2a8fe63bcc4755e584ec7defef83755c23f923/687474703a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d616e64726f69642d3645444238442e7376673f7374796c653d666c6174) @@ -12,6 +13,7 @@ ![watchos](https://camo.githubusercontent.com/135dbadae40f9cabe7a3a040f9380fb485cff36c90909f3c1ae36b81c304426b/687474703a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d77617463686f732d4330433043302e7376673f7374796c653d666c6174) The wallet SDK will have the following features: + - Secure Local Storage - Key Managment - DIDComm Operations From 29f62bbc8a6fd779c5c7b3db5a10427e84527c53 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Thu, 10 Nov 2022 12:36:56 +0400 Subject: [PATCH 03/21] feat: project init --- build.gradle.kts | 62 ++++++ gradle.properties | 14 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59821 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 234 +++++++++++++++++++++++ gradlew.bat | 89 +++++++++ settings.gradle.kts | 10 + wallet-sdk/build.gradle.kts | 204 ++++++++++++++++++++ wallet-sdk/wallet_sdk.podspec | 42 ++++ 9 files changed, 660 insertions(+) create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts create mode 100644 wallet-sdk/build.gradle.kts create mode 100644 wallet-sdk/wallet_sdk.podspec diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..275d65b19 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,62 @@ +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin + +plugins { + id("maven-publish") + id("org.jetbrains.dokka") version "1.7.10" + id("org.jlleitschuh.gradle.ktlint") version "11.0.0" +} + +buildscript { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20") + classpath("com.android.tools.build:gradle:7.2.2") + } +} + +version = "1.0.0-alpha" +group = "io.iohk.atala.prism" + +allprojects { + repositories { + google() + mavenCentral() + } + +// apply(plugin = "org.gradle.maven-publish") + +// publishing { +// repositories { +// maven { +// this.name = "GitHubPackages" +// this.url = uri("https://maven.pkg.github.com/input-output-hk/atala-prism-wallet-sdk-kmm/") +// credentials { +// this.username = System.getenv("ATALA_GITHUB_ACTOR") +// this.password = System.getenv("ATALA_GITHUB_TOKEN") +// } +// } +// } +// } +} + +subprojects { + apply(plugin = "org.jlleitschuh.gradle.ktlint") + + configure { + verbose.set(true) + outputToConsole.set(true) + } +} + +rootProject.plugins.withType(NodeJsRootPlugin::class.java) { + rootProject.extensions.getByType(NodeJsRootExtension::class.java).nodeVersion = "16.17.0" +} + +tasks.dokkaGfmMultiModule.configure { + outputDirectory.set(buildDir.resolve("dokkaCustomMultiModuleOutput")) +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..d859a10f8 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,14 @@ +#Gradle +org.gradle.jvmargs=-Xmx3072M -Dkotlin.daemon.jvm.options\="-Xmx3072M" + +#Kotlin +kotlin.code.style=official + +#Android +android.useAndroidX=true + +#MPP +# kotlin.mpp.enableGranularSourceSetsMetadata=true +# kotlin.native.enableDependencyPropagation=false +kotlin.mpp.enableCInteropCommonization=true +kotlin.native.cacheKind.iosSimulatorArm64=none \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..41d9927a4d4fb3f96a785543079b8df6723c946b GIT binary patch literal 59821 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..41dfb8790 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..136c74c2b --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + google() + gradlePluginPortal() + mavenCentral() + } +} + +rootProject.name = "wallet-sdk" +include(":wallet-sdk") diff --git a/wallet-sdk/build.gradle.kts b/wallet-sdk/build.gradle.kts new file mode 100644 index 000000000..9ba79bacb --- /dev/null +++ b/wallet-sdk/build.gradle.kts @@ -0,0 +1,204 @@ +import org.gradle.internal.os.OperatingSystem +import org.jetbrains.dokka.gradle.DokkaTask +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target + +version = rootProject.version +val currentModuleName: String = "wallet-sdk" +val os: OperatingSystem = OperatingSystem.current() + +plugins { + kotlin("multiplatform") + kotlin("native.cocoapods") + id("com.android.library") + id("org.jetbrains.dokka") +} + +kotlin { + android { + publishAllLibraryVariants() + } + jvm { + compilations.all { + kotlinOptions { + jvmTarget = "11" + } + } + testRuns["test"].executionTask.configure { + useJUnitPlatform() + } + } + if (os.isMacOsX) { + ios() + tvos() + watchos() + macosX64() + if (System.getProperty("os.arch") != "x86_64") { // M1Chip + iosSimulatorArm64() + tvosSimulatorArm64() + watchosSimulatorArm64() + macosArm64() + } + } + js(IR) { + this.moduleName = currentModuleName + this.binaries.executable() + this.useCommonJs() + this.compilations["main"].packageJson { + this.version = rootProject.version.toString() + } + this.compilations["test"].packageJson { + this.version = rootProject.version.toString() + } + browser { + this.webpackTask { + this.output.library = currentModuleName + this.output.libraryTarget = Target.VAR + } + this.commonWebpackConfig { + this.cssSupport { + this.enabled = true + } + } + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } + } + nodejs { + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } + } + } + + if (os.isMacOsX) { + cocoapods { + this.summary = "Wallet-SDK - DIDComm V2 operation" + this.version = rootProject.version.toString() + this.authors = "IOG" + this.ios.deploymentTarget = "13.0" + this.osx.deploymentTarget = "12.0" + this.tvos.deploymentTarget = "13.0" + this.watchos.deploymentTarget = "8.0" + framework { + this.baseName = currentModuleName + } + } + } + + sourceSets { + val commonMain by getting + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + } + } + val jvmMain by getting + val jvmTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val androidMain by getting + val androidTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val jsMain by getting + val jsTest by getting + if (os.isMacOsX) { + val iosMain by getting + val iosTest by getting + val tvosMain by getting + val tvosTest by getting + val watchosMain by getting + val watchosTest by getting + val macosX64Main by getting + val macosX64Test by getting + if (System.getProperty("os.arch") != "x86_64") { // M1Chip + val iosSimulatorArm64Main by getting { + this.dependsOn(iosMain) + } + val iosSimulatorArm64Test by getting { + this.dependsOn(iosTest) + } + val tvosSimulatorArm64Main by getting { + this.dependsOn(tvosMain) + } + val tvosSimulatorArm64Test by getting { + this.dependsOn(tvosTest) + } + val watchosSimulatorArm64Main by getting { + this.dependsOn(watchosMain) + } + val watchosSimulatorArm64Test by getting { + this.dependsOn(watchosTest) + } + val macosArm64Main by getting { + this.dependsOn(macosX64Main) + } + val macosArm64Test by getting { + this.dependsOn(macosX64Test) + } + } + } + all { + languageSettings.optIn("kotlin.RequiresOptIn") + } + } +} + +android { + compileSdk = 32 + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdk = 21 + targetSdk = 32 + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + /** + * Because Software Components will not be created automatically for Maven publishing from + * Android Gradle Plugin 8.0. To opt-in to the future behavior, set the Gradle property android. + * disableAutomaticComponentCreation=true in the `gradle.properties` file or use the new + * publishing DSL. + */ + publishing { + multipleVariants { + withSourcesJar() + withJavadocJar() + allVariants() + } + } +} + +// Dokka implementation +tasks.withType { + moduleName.set(project.name) + moduleVersion.set(rootProject.version.toString()) + description = """ + This is a Kotlin Multiplatform Wallet-SDK Library + """.trimIndent() + dokkaSourceSets { + // TODO: Figure out how to include files to the documentations + named("commonMain") { + includes.from("Module.md", "docs/Module.md") + } + } +} + +// afterEvaluate { +// tasks.withType { +// testLogging { +// events("passed", "skipped", "failed", "standard_out", "standard_error") +// showExceptions = true +// showStackTraces = true +// } +// } +// } \ No newline at end of file diff --git a/wallet-sdk/wallet_sdk.podspec b/wallet-sdk/wallet_sdk.podspec new file mode 100644 index 000000000..ac8400b10 --- /dev/null +++ b/wallet-sdk/wallet_sdk.podspec @@ -0,0 +1,42 @@ +Pod::Spec.new do |spec| + spec.name = 'wallet_sdk' + spec.version = '1.0.0-alpha' + spec.homepage = '' + spec.source = { :http=> ''} + spec.authors = 'IOG' + spec.license = '' + spec.summary = 'Wallet-SDK - DIDComm V2 operation' + spec.vendored_frameworks = 'build/cocoapods/framework/wallet-sdk.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '13.0' + spec.osx.deployment_target = '12.0' + spec.tvos.deployment_target = '13.0' + spec.watchos.deployment_target = '8.0' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':wallet-sdk', + 'PRODUCT_MODULE_NAME' => 'wallet-sdk', + } + + spec.script_phases = [ + { + :name => 'Build wallet_sdk', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file From 1f03a35540a6ca5bfb8c3ce3081c82cf2c6b3c11 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Thu, 10 Nov 2022 13:17:10 +0400 Subject: [PATCH 04/21] feat: wallet-core module init --- settings.gradle.kts | 1 + wallet-core-sdk/build.gradle.kts | 204 ++++++++++++++++++ .../src/androidMain/AndroidManifest.xml | 2 + .../iohk/atala/prism/walletcore/Platform.kt | 6 + .../Platform.kt | 5 + .../iohk/atala/prism/walletcore/Platform.kt | 8 + .../iohk/atala/prism/walletcore/Platform.kt | 8 + .../iohk/atala/prism/walletcore/Platform.kt | 11 + .../iohk/atala/prism/walletcore/Platform.kt | 6 + .../iohk/atala/prism/walletcore/Platform.kt | 11 + .../iohk/atala/prism/walletcore/Platform.kt | 8 + .../iohk/atala/prism/walletcore/Platform.kt | 8 + .../iohk/atala/prism/walletcore/Platform.kt | 11 + .../iohk/atala/prism/walletcore/Platform.kt | 11 + .../iohk/atala/prism/walletcore/Platform.kt | 11 + wallet-core-sdk/wallet_core_sdk.podspec | 42 ++++ wallet-sdk/build.gradle.kts | 6 +- 17 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 wallet-core-sdk/build.gradle.kts create mode 100644 wallet-core-sdk/src/androidMain/AndroidManifest.xml create mode 100644 wallet-core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/iosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/iosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/tvosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/tvosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/watchosArm32Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/watchosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/src/watchosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt create mode 100644 wallet-core-sdk/wallet_core_sdk.podspec diff --git a/settings.gradle.kts b/settings.gradle.kts index 136c74c2b..55885de55 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,3 +8,4 @@ pluginManagement { rootProject.name = "wallet-sdk" include(":wallet-sdk") +include(":wallet-core-sdk") \ No newline at end of file diff --git a/wallet-core-sdk/build.gradle.kts b/wallet-core-sdk/build.gradle.kts new file mode 100644 index 000000000..a37bd05fa --- /dev/null +++ b/wallet-core-sdk/build.gradle.kts @@ -0,0 +1,204 @@ +import org.gradle.internal.os.OperatingSystem +import org.jetbrains.dokka.gradle.DokkaTask +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target + +version = rootProject.version +val currentModuleName: String = "wallet-core-sdk" +val os: OperatingSystem = OperatingSystem.current() + +plugins { + kotlin("multiplatform") + kotlin("native.cocoapods") + id("com.android.library") + id("org.jetbrains.dokka") +} + +kotlin { + android { + publishAllLibraryVariants() + } + jvm { + compilations.all { + kotlinOptions { + jvmTarget = "11" + } + } + testRuns["test"].executionTask.configure { + useJUnitPlatform() + } + } + if (os.isMacOsX) { + ios() + tvos() + watchos() + macosX64() + if (System.getProperty("os.arch") != "x86_64") { // M1Chip + iosSimulatorArm64() + tvosSimulatorArm64() + watchosSimulatorArm64() + macosArm64() + } + } + js(IR) { + this.moduleName = currentModuleName + this.binaries.executable() + this.useCommonJs() + this.compilations["main"].packageJson { + this.version = rootProject.version.toString() + } + this.compilations["test"].packageJson { + this.version = rootProject.version.toString() + } + browser { + this.webpackTask { + this.output.library = currentModuleName + this.output.libraryTarget = Target.VAR + } + this.commonWebpackConfig { + this.cssSupport { + this.enabled = true + } + } + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } + } + nodejs { + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } + } + } + + if (os.isMacOsX) { + cocoapods { + this.summary = "Wallet-Core-SDK" + this.version = rootProject.version.toString() + this.authors = "IOG" + this.ios.deploymentTarget = "13.0" + this.osx.deploymentTarget = "12.0" + this.tvos.deploymentTarget = "13.0" + this.watchos.deploymentTarget = "8.0" + framework { + this.baseName = currentModuleName + } + } + } + + sourceSets { + val commonMain by getting + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + } + } + val jvmMain by getting + val jvmTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val androidMain by getting + val androidTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val jsMain by getting + val jsTest by getting + if (os.isMacOsX) { + val iosMain by getting + val iosTest by getting + val tvosMain by getting + val tvosTest by getting + val watchosMain by getting + val watchosTest by getting + val macosX64Main by getting + val macosX64Test by getting + if (System.getProperty("os.arch") != "x86_64") { // M1Chip + val iosSimulatorArm64Main by getting { + this.dependsOn(iosMain) + } + val iosSimulatorArm64Test by getting { + this.dependsOn(iosTest) + } + val tvosSimulatorArm64Main by getting { + this.dependsOn(tvosMain) + } + val tvosSimulatorArm64Test by getting { + this.dependsOn(tvosTest) + } + val watchosSimulatorArm64Main by getting { + this.dependsOn(watchosMain) + } + val watchosSimulatorArm64Test by getting { + this.dependsOn(watchosTest) + } + val macosArm64Main by getting { + this.dependsOn(macosX64Main) + } + val macosArm64Test by getting { + this.dependsOn(macosX64Test) + } + } + } + all { + languageSettings.optIn("kotlin.RequiresOptIn") + } + } +} + +android { + compileSdk = 32 + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdk = 21 + targetSdk = 32 + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + /** + * Because Software Components will not be created automatically for Maven publishing from + * Android Gradle Plugin 8.0. To opt-in to the future behavior, set the Gradle property android. + * disableAutomaticComponentCreation=true in the `gradle.properties` file or use the new + * publishing DSL. + */ + publishing { + multipleVariants { + withSourcesJar() + withJavadocJar() + allVariants() + } + } +} + +// Dokka implementation +tasks.withType { + moduleName.set(project.name) + moduleVersion.set(rootProject.version.toString()) + description = """ + This is a Kotlin Multiplatform Wallet-Core-SDK Library + """.trimIndent() + dokkaSourceSets { + // TODO: Figure out how to include files to the documentations + named("commonMain") { + includes.from("Module.md", "docs/Module.md") + } + } +} + +// afterEvaluate { +// tasks.withType { +// testLogging { +// events("passed", "skipped", "failed", "standard_out", "standard_error") +// showExceptions = true +// showStackTraces = true +// } +// } +// } \ No newline at end of file diff --git a/wallet-core-sdk/src/androidMain/AndroidManifest.xml b/wallet-core-sdk/src/androidMain/AndroidManifest.xml new file mode 100644 index 000000000..944130a5c --- /dev/null +++ b/wallet-core-sdk/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/wallet-core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..c46a58a8e --- /dev/null +++ b/wallet-core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,6 @@ +package io.iohk.atala.prism.walletcore + +internal actual object Platform { + actual val OS: String + get() = "Android ${android.os.Build.VERSION.SDK_INT}" +} \ No newline at end of file diff --git a/wallet-core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/wallet-core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt new file mode 100644 index 000000000..36165f8e0 --- /dev/null +++ b/wallet-core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt @@ -0,0 +1,5 @@ +package io.iohk.atala.prism.walletcore + +internal expect object Platform { + val OS: String +} \ No newline at end of file diff --git a/wallet-core-sdk/src/iosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/iosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..90dc2403d --- /dev/null +++ b/wallet-core-sdk/src/iosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,8 @@ +package io.iohk.atala.prism.walletcore + +import platform.UIKit.UIDevice + +internal actual object Platform { + actual val OS: String + get() = "${UIDevice.currentDevice.systemName()}-${UIDevice.currentDevice.systemVersion}" +} \ No newline at end of file diff --git a/wallet-core-sdk/src/iosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/iosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..90dc2403d --- /dev/null +++ b/wallet-core-sdk/src/iosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,8 @@ +package io.iohk.atala.prism.walletcore + +import platform.UIKit.UIDevice + +internal actual object Platform { + actual val OS: String + get() = "${UIDevice.currentDevice.systemName()}-${UIDevice.currentDevice.systemVersion}" +} \ No newline at end of file diff --git a/wallet-core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..aeacb5434 --- /dev/null +++ b/wallet-core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,11 @@ +package io.iohk.atala.prism.walletcore + +internal actual object Platform { + private val isNodeJs by lazy { js("(typeof process === 'object' && typeof require === 'function')").unsafeCast() } + actual val OS: String + get() = if (isNodeJs) { + "NodeJS" + } else { + "JS" + } +} \ No newline at end of file diff --git a/wallet-core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..21a5caa50 --- /dev/null +++ b/wallet-core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,6 @@ +package io.iohk.atala.prism.walletcore + +internal actual object Platform { + actual val OS: String + get() = "JVM - ${System.getProperty("java.version")}" +} \ No newline at end of file diff --git a/wallet-core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..b605c884c --- /dev/null +++ b/wallet-core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,11 @@ +package io.iohk.atala.prism.walletcore + +import platform.Foundation.NSProcessInfo + +internal actual object Platform { + actual val OS: String + get() { + val processInfo = NSProcessInfo.processInfo() + return "${processInfo.operatingSystemName()}-${processInfo.operatingSystemVersionString()}" + } +} \ No newline at end of file diff --git a/wallet-core-sdk/src/tvosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/tvosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..90dc2403d --- /dev/null +++ b/wallet-core-sdk/src/tvosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,8 @@ +package io.iohk.atala.prism.walletcore + +import platform.UIKit.UIDevice + +internal actual object Platform { + actual val OS: String + get() = "${UIDevice.currentDevice.systemName()}-${UIDevice.currentDevice.systemVersion}" +} \ No newline at end of file diff --git a/wallet-core-sdk/src/tvosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/tvosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..90dc2403d --- /dev/null +++ b/wallet-core-sdk/src/tvosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,8 @@ +package io.iohk.atala.prism.walletcore + +import platform.UIKit.UIDevice + +internal actual object Platform { + actual val OS: String + get() = "${UIDevice.currentDevice.systemName()}-${UIDevice.currentDevice.systemVersion}" +} \ No newline at end of file diff --git a/wallet-core-sdk/src/watchosArm32Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/watchosArm32Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..2212c6bd7 --- /dev/null +++ b/wallet-core-sdk/src/watchosArm32Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,11 @@ +package io.iohk.atala.prism.walletcore + +import platform.WatchKit.WKInterfaceDevice + +internal actual object Platform { + actual val OS: String + get() { + val wkInterfaceDevice = WKInterfaceDevice.currentDevice() + return "${wkInterfaceDevice.systemName}-${wkInterfaceDevice.systemVersion}" + } +} \ No newline at end of file diff --git a/wallet-core-sdk/src/watchosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/watchosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..2212c6bd7 --- /dev/null +++ b/wallet-core-sdk/src/watchosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,11 @@ +package io.iohk.atala.prism.walletcore + +import platform.WatchKit.WKInterfaceDevice + +internal actual object Platform { + actual val OS: String + get() { + val wkInterfaceDevice = WKInterfaceDevice.currentDevice() + return "${wkInterfaceDevice.systemName}-${wkInterfaceDevice.systemVersion}" + } +} \ No newline at end of file diff --git a/wallet-core-sdk/src/watchosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/watchosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt new file mode 100644 index 000000000..2212c6bd7 --- /dev/null +++ b/wallet-core-sdk/src/watchosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -0,0 +1,11 @@ +package io.iohk.atala.prism.walletcore + +import platform.WatchKit.WKInterfaceDevice + +internal actual object Platform { + actual val OS: String + get() { + val wkInterfaceDevice = WKInterfaceDevice.currentDevice() + return "${wkInterfaceDevice.systemName}-${wkInterfaceDevice.systemVersion}" + } +} \ No newline at end of file diff --git a/wallet-core-sdk/wallet_core_sdk.podspec b/wallet-core-sdk/wallet_core_sdk.podspec new file mode 100644 index 000000000..75ebb1469 --- /dev/null +++ b/wallet-core-sdk/wallet_core_sdk.podspec @@ -0,0 +1,42 @@ +Pod::Spec.new do |spec| + spec.name = 'wallet_core_sdk' + spec.version = '1.0.0-alpha' + spec.homepage = '' + spec.source = { :http=> ''} + spec.authors = 'IOG' + spec.license = '' + spec.summary = 'Wallet-Core-SDK' + spec.vendored_frameworks = 'build/cocoapods/framework/wallet-core-sdk.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '13.0' + spec.osx.deployment_target = '12.0' + spec.tvos.deployment_target = '13.0' + spec.watchos.deployment_target = '8.0' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':wallet-core-sdk', + 'PRODUCT_MODULE_NAME' => 'wallet-core-sdk', + } + + spec.script_phases = [ + { + :name => 'Build wallet_core_sdk', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file diff --git a/wallet-sdk/build.gradle.kts b/wallet-sdk/build.gradle.kts index 9ba79bacb..8506abaa4 100644 --- a/wallet-sdk/build.gradle.kts +++ b/wallet-sdk/build.gradle.kts @@ -90,7 +90,11 @@ kotlin { } sourceSets { - val commonMain by getting + val commonMain by getting { + dependencies { + implementation(project(":wallet-core-sdk")) + } + } val commonTest by getting { dependencies { implementation(kotlin("test")) From a7087cce7c1947a43ed5859805e014a4026a0d47 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Thu, 10 Nov 2022 13:34:01 +0400 Subject: [PATCH 05/21] util: structure update --- .../io.iohk.atala.prism.walletcore}/Platform.kt | 0 .../kotlin/io/iohk/atala/prism/walletcore/Platform.kt | 8 -------- .../io.iohk.atala.prism.walletcore}/Platform.kt | 0 .../kotlin/io/iohk/atala/prism/walletcore/Platform.kt | 8 -------- .../kotlin/io/iohk/atala/prism/walletcore/Platform.kt | 11 ----------- .../io.iohk.atala.prism.walletcore}/Platform.kt | 0 .../kotlin/io/iohk/atala/prism/walletcore/Platform.kt | 11 ----------- 7 files changed, 38 deletions(-) rename wallet-core-sdk/src/{iosArm64Main/kotlin/io/iohk/atala/prism/walletcore => iosMain/kotlin/io.iohk.atala.prism.walletcore}/Platform.kt (100%) delete mode 100644 wallet-core-sdk/src/tvosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename wallet-core-sdk/src/{iosX64Main/kotlin/io/iohk/atala/prism/walletcore => tvosMain/kotlin/io.iohk.atala.prism.walletcore}/Platform.kt (100%) delete mode 100644 wallet-core-sdk/src/tvosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt delete mode 100644 wallet-core-sdk/src/watchosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename wallet-core-sdk/src/{watchosArm32Main/kotlin/io/iohk/atala/prism/walletcore => watchosMain/kotlin/io.iohk.atala.prism.walletcore}/Platform.kt (100%) delete mode 100644 wallet-core-sdk/src/watchosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt diff --git a/wallet-core-sdk/src/iosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/iosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename to wallet-core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt diff --git a/wallet-core-sdk/src/tvosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/tvosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt deleted file mode 100644 index 90dc2403d..000000000 --- a/wallet-core-sdk/src/tvosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.iohk.atala.prism.walletcore - -import platform.UIKit.UIDevice - -internal actual object Platform { - actual val OS: String - get() = "${UIDevice.currentDevice.systemName()}-${UIDevice.currentDevice.systemVersion}" -} \ No newline at end of file diff --git a/wallet-core-sdk/src/iosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/iosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename to wallet-core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt diff --git a/wallet-core-sdk/src/tvosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/tvosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt deleted file mode 100644 index 90dc2403d..000000000 --- a/wallet-core-sdk/src/tvosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.iohk.atala.prism.walletcore - -import platform.UIKit.UIDevice - -internal actual object Platform { - actual val OS: String - get() = "${UIDevice.currentDevice.systemName()}-${UIDevice.currentDevice.systemVersion}" -} \ No newline at end of file diff --git a/wallet-core-sdk/src/watchosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/watchosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt deleted file mode 100644 index 2212c6bd7..000000000 --- a/wallet-core-sdk/src/watchosArm64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.iohk.atala.prism.walletcore - -import platform.WatchKit.WKInterfaceDevice - -internal actual object Platform { - actual val OS: String - get() { - val wkInterfaceDevice = WKInterfaceDevice.currentDevice() - return "${wkInterfaceDevice.systemName}-${wkInterfaceDevice.systemVersion}" - } -} \ No newline at end of file diff --git a/wallet-core-sdk/src/watchosArm32Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/watchosArm32Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename to wallet-core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt diff --git a/wallet-core-sdk/src/watchosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/wallet-core-sdk/src/watchosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt deleted file mode 100644 index 2212c6bd7..000000000 --- a/wallet-core-sdk/src/watchosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.iohk.atala.prism.walletcore - -import platform.WatchKit.WKInterfaceDevice - -internal actual object Platform { - actual val OS: String - get() { - val wkInterfaceDevice = WKInterfaceDevice.currentDevice() - return "${wkInterfaceDevice.systemName}-${wkInterfaceDevice.systemVersion}" - } -} \ No newline at end of file From 4eeea4c953e59961bcfe95534ca267a7834b97eb Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Fri, 11 Nov 2022 16:36:20 +0400 Subject: [PATCH 06/21] feat: Wallet SDK init --- .../build.gradle.kts | 50 ++++++++++--- .../core_sdk.podspec | 6 +- .../src/androidMain/AndroidManifest.xml | 0 .../atala/prism/walletcore/AtalaClient.kt | 8 +++ .../iohk/atala/prism/walletcore/Platform.kt | 0 .../AtalaClient.kt | 72 +++++++++++++++++++ .../Platform.kt | 0 .../AtalaClient.kt | 13 ++++ .../Platform.kt | 0 .../atala/prism/walletcore/AtalaClient.kt | 8 +++ .../iohk/atala/prism/walletcore/Platform.kt | 0 .../atala/prism/walletcore/AtalaClient.kt | 8 +++ .../iohk/atala/prism/walletcore/Platform.kt | 0 .../atala/prism/walletcore/AtalaClient.kt | 13 ++++ .../iohk/atala/prism/walletcore/Platform.kt | 0 .../AtalaClient.kt | 13 ++++ .../Platform.kt | 0 .../AtalaClient.kt | 13 ++++ .../Platform.kt | 0 settings.gradle.kts | 2 +- wallet-sdk/build.gradle.kts | 4 +- .../WalletSDK.kt | 5 ++ wallet-sdk/wallet_sdk.podspec | 4 +- 23 files changed, 203 insertions(+), 16 deletions(-) rename {wallet-core-sdk => core-sdk}/build.gradle.kts (79%) rename wallet-core-sdk/wallet_core_sdk.podspec => core-sdk/core_sdk.podspec (91%) rename {wallet-core-sdk => core-sdk}/src/androidMain/AndroidManifest.xml (100%) create mode 100644 core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt rename {wallet-core-sdk => core-sdk}/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt (100%) create mode 100644 core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt rename {wallet-core-sdk => core-sdk}/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt (100%) create mode 100644 core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt rename {wallet-core-sdk => core-sdk}/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt (100%) create mode 100644 core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt rename {wallet-core-sdk => core-sdk}/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt (100%) create mode 100644 core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt rename {wallet-core-sdk => core-sdk}/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt (100%) create mode 100644 core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt rename {wallet-core-sdk => core-sdk}/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt (100%) create mode 100644 core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt rename {wallet-core-sdk => core-sdk}/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt (100%) create mode 100644 core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt rename {wallet-core-sdk => core-sdk}/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt (100%) create mode 100644 wallet-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletsdk/WalletSDK.kt diff --git a/wallet-core-sdk/build.gradle.kts b/core-sdk/build.gradle.kts similarity index 79% rename from wallet-core-sdk/build.gradle.kts rename to core-sdk/build.gradle.kts index a37bd05fa..518586b6c 100644 --- a/wallet-core-sdk/build.gradle.kts +++ b/core-sdk/build.gradle.kts @@ -90,34 +90,68 @@ kotlin { } sourceSets { - val commonMain by getting + val commonMain by getting { + dependencies { + implementation("io.ktor:ktor-client-core:2.1.3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + } + } val commonTest by getting { dependencies { implementation(kotlin("test")) } } - val jvmMain by getting + val jvmMain by getting { + dependencies { + implementation("io.ktor:ktor-client-okhttp:2.1.3") + } + } val jvmTest by getting { dependencies { implementation("junit:junit:4.13.2") } } - val androidMain by getting + val androidMain by getting { + dependencies { + implementation("io.ktor:ktor-client-okhttp:2.1.3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") + } + } val androidTest by getting { dependencies { implementation("junit:junit:4.13.2") } } - val jsMain by getting + val jsMain by getting { + dependencies { + implementation("io.ktor:ktor-client-js:2.1.3") + } + } val jsTest by getting if (os.isMacOsX) { - val iosMain by getting + val iosMain by getting { + dependencies { + implementation("io.ktor:ktor-client-darwin:2.1.3") + } + } val iosTest by getting - val tvosMain by getting + val tvosMain by getting { + dependencies { + implementation("io.ktor:ktor-client-darwin:2.1.3") + } + } val tvosTest by getting - val watchosMain by getting + val watchosMain by getting { + dependencies { + implementation("io.ktor:ktor-client-darwin:2.1.3") + } + } val watchosTest by getting - val macosX64Main by getting + val macosX64Main by getting { + dependencies { + implementation("io.ktor:ktor-client-darwin:2.1.3") + } + } val macosX64Test by getting if (System.getProperty("os.arch") != "x86_64") { // M1Chip val iosSimulatorArm64Main by getting { diff --git a/wallet-core-sdk/wallet_core_sdk.podspec b/core-sdk/core_sdk.podspec similarity index 91% rename from wallet-core-sdk/wallet_core_sdk.podspec rename to core-sdk/core_sdk.podspec index 75ebb1469..3f27f1b9a 100644 --- a/wallet-core-sdk/wallet_core_sdk.podspec +++ b/core-sdk/core_sdk.podspec @@ -1,5 +1,5 @@ Pod::Spec.new do |spec| - spec.name = 'wallet_core_sdk' + spec.name = 'core_sdk' spec.version = '1.0.0-alpha' spec.homepage = '' spec.source = { :http=> ''} @@ -15,13 +15,13 @@ Pod::Spec.new do |spec| spec.pod_target_xcconfig = { - 'KOTLIN_PROJECT_PATH' => ':wallet-core-sdk', + 'KOTLIN_PROJECT_PATH' => ':core-sdk', 'PRODUCT_MODULE_NAME' => 'wallet-core-sdk', } spec.script_phases = [ { - :name => 'Build wallet_core_sdk', + :name => 'Build core_sdk', :execution_position => :before_compile, :shell_path => '/bin/sh', :script => <<-SCRIPT diff --git a/wallet-core-sdk/src/androidMain/AndroidManifest.xml b/core-sdk/src/androidMain/AndroidManifest.xml similarity index 100% rename from wallet-core-sdk/src/androidMain/AndroidManifest.xml rename to core-sdk/src/androidMain/AndroidManifest.xml diff --git a/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt b/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt new file mode 100644 index 000000000..d7d70a450 --- /dev/null +++ b/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt @@ -0,0 +1,8 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { + config(this) +} \ No newline at end of file diff --git a/wallet-core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename to core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt diff --git a/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt new file mode 100644 index 000000000..290fa0187 --- /dev/null +++ b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt @@ -0,0 +1,72 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* + +internal expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClient + +class AtalaClient( + private val baseURL: String, + private val client: HttpClient = httpClient() +) { + // TODO("We can add all endpoint calls here") + + suspend fun prepareRequest( + httpMethod: HttpMethod, + path: String, + urlParameters: Map = mapOf(), + httpHeaders: Map = mapOf() + ): HttpStatement { + return client.prepareRequest { + for(header in httpHeaders) { + if ( + httpMethod == HttpMethod.Get && + header.key == HttpHeaders.ContentType && + header.value.contains(ContentType.Application.Json.contentSubtype) + ) { + continue + } + headers.append(header.key, header.value) + } + url { + method = httpMethod + protocol = URLProtocol.HTTPS + host = baseURL + path(path) + for (parameter in urlParameters) { + parameters.append(parameter.key, parameter.value) + } + } + } + } + + suspend fun request( + httpMethod: HttpMethod, + path: String, + urlParameters: Map = mapOf(), + httpHeaders: Map = mapOf() + ): HttpResponse { + return prepareRequest(httpMethod, path, urlParameters, httpHeaders).execute() + } + + /* example + suspend fun login(request: LoginRequest): LoginResponse { + return + } + */ +} + +fun AtalaClient.login() { + +} + +suspend fun x() { + val client = AtalaClient("www.google.com") + val request = client.prepareRequest( + HttpMethod.Post, + "" + ) + request.execute() +} \ No newline at end of file diff --git a/wallet-core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt rename to core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt diff --git a/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt b/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt new file mode 100644 index 000000000..c10ac7d4f --- /dev/null +++ b/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt @@ -0,0 +1,13 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.* +import io.ktor.client.engine.darwin.* + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { + config(this) + engine { + configureRequest { + setAllowsCellularAccess(true) + } + } +} \ No newline at end of file diff --git a/wallet-core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt rename to core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt diff --git a/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt b/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt new file mode 100644 index 000000000..8232431a8 --- /dev/null +++ b/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt @@ -0,0 +1,8 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.* +import io.ktor.client.engine.js.* + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Js) { + config(this) +} \ No newline at end of file diff --git a/wallet-core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename to core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt diff --git a/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt b/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt new file mode 100644 index 000000000..d7d70a450 --- /dev/null +++ b/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt @@ -0,0 +1,8 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { + config(this) +} \ No newline at end of file diff --git a/wallet-core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename to core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt diff --git a/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt b/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt new file mode 100644 index 000000000..c10ac7d4f --- /dev/null +++ b/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt @@ -0,0 +1,13 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.* +import io.ktor.client.engine.darwin.* + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { + config(this) + engine { + configureRequest { + setAllowsCellularAccess(true) + } + } +} \ No newline at end of file diff --git a/wallet-core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt rename to core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt diff --git a/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt b/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt new file mode 100644 index 000000000..c10ac7d4f --- /dev/null +++ b/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt @@ -0,0 +1,13 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.* +import io.ktor.client.engine.darwin.* + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { + config(this) + engine { + configureRequest { + setAllowsCellularAccess(true) + } + } +} \ No newline at end of file diff --git a/wallet-core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt rename to core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt diff --git a/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt b/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt new file mode 100644 index 000000000..c10ac7d4f --- /dev/null +++ b/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt @@ -0,0 +1,13 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.* +import io.ktor.client.engine.darwin.* + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { + config(this) + engine { + configureRequest { + setAllowsCellularAccess(true) + } + } +} \ No newline at end of file diff --git a/wallet-core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt similarity index 100% rename from wallet-core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt rename to core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 55885de55..58a851af1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,4 +8,4 @@ pluginManagement { rootProject.name = "wallet-sdk" include(":wallet-sdk") -include(":wallet-core-sdk") \ No newline at end of file +include(":core-sdk") \ No newline at end of file diff --git a/wallet-sdk/build.gradle.kts b/wallet-sdk/build.gradle.kts index 8506abaa4..3f005f369 100644 --- a/wallet-sdk/build.gradle.kts +++ b/wallet-sdk/build.gradle.kts @@ -3,7 +3,7 @@ import org.jetbrains.dokka.gradle.DokkaTask import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target version = rootProject.version -val currentModuleName: String = "wallet-sdk" +val currentModuleName: String = "core-sdk" val os: OperatingSystem = OperatingSystem.current() plugins { @@ -92,7 +92,7 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation(project(":wallet-core-sdk")) + implementation(project(":core-sdk")) } } val commonTest by getting { diff --git a/wallet-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletsdk/WalletSDK.kt b/wallet-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletsdk/WalletSDK.kt new file mode 100644 index 000000000..33a2f33a3 --- /dev/null +++ b/wallet-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletsdk/WalletSDK.kt @@ -0,0 +1,5 @@ +package io.iohk.atala.prism.walletsdk + +final class WalletSDK { + +} \ No newline at end of file diff --git a/wallet-sdk/wallet_sdk.podspec b/wallet-sdk/wallet_sdk.podspec index ac8400b10..61422b876 100644 --- a/wallet-sdk/wallet_sdk.podspec +++ b/wallet-sdk/wallet_sdk.podspec @@ -6,7 +6,7 @@ Pod::Spec.new do |spec| spec.authors = 'IOG' spec.license = '' spec.summary = 'Wallet-SDK - DIDComm V2 operation' - spec.vendored_frameworks = 'build/cocoapods/framework/wallet-sdk.framework' + spec.vendored_frameworks = 'build/cocoapods/framework/core-sdk.framework' spec.libraries = 'c++' spec.ios.deployment_target = '13.0' spec.osx.deployment_target = '12.0' @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':wallet-sdk', - 'PRODUCT_MODULE_NAME' => 'wallet-sdk', + 'PRODUCT_MODULE_NAME' => 'core-sdk', } spec.script_phases = [ From 1b0e6b5570856af2b2ad26f57c4a0daafb581233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Sun, 13 Nov 2022 12:47:58 +0100 Subject: [PATCH 07/21] feat: integrate authenticate-sdk, buildSrc (Deps + Version globals), Protos and basic dependencies from old SDK --- authenticate-sdk/build.gradle.kts | 148 ++ .../src/androidMain/AndroidManifest.xml | 2 + .../src/androidMain/kotlin/authenticate.kt | 3 + .../src/androidMain/kotlin/createChallenge.kt | 3 + .../src/commonMain/kotlin/authenticate.kt | 1 + .../src/commonMain/kotlin/createChallenge.kt | 1 + .../src/jsMain/kotlin/authenticate.kt | 4 + .../src/jsMain/kotlin/createChallenge.kt | 5 + .../src/jvmMain/kotlin/authenticate.kt | 3 + .../src/jvmMain/kotlin/createChallenge.kt | 3 + build.gradle.kts | 39 +- buildSrc/build.gradle.kts | 9 + buildSrc/src/main/kotlin/Deps.kt | 30 + buildSrc/src/main/kotlin/PluginVersions.kt | 14 + buildSrc/src/main/kotlin/Plugins.kt | 15 + buildSrc/src/main/kotlin/Versions.kt | 30 + core-sdk/build.gradle.kts | 2 +- core-sdk/core_sdk.podspec | 4 +- protosLib/build.gradle.kts | 83 + protosLib/src/main/proto/common_models.proto | 108 ++ protosLib/src/main/proto/connector_api.proto | 443 +++++ .../src/main/proto/connector_models.proto | 90 + protosLib/src/main/proto/console_api.proto | 1481 +++++++++++++++++ protosLib/src/main/proto/console_models.proto | 244 +++ .../src/main/proto/credential_models.proto | 76 + protosLib/src/main/proto/cviews_api.proto | 21 + protosLib/src/main/proto/cviews_models.proto | 17 + protosLib/src/main/proto/health.proto | 63 + .../src/main/proto/intdemo/intdemo_api.proto | 57 + .../main/proto/intdemo/intdemo_models.proto | 17 + protosLib/src/main/proto/node_api.proto | 376 +++++ protosLib/src/main/proto/node_internal.proto | 30 + protosLib/src/main/proto/node_models.proto | 247 +++ protosLib/src/main/proto/package.json | 10 + .../src/main/proto/resources/markdown.tmpl | 95 ++ protosLib/src/main/proto/status.proto | 47 + settings.gradle.kts | 38 +- wallet-sdk/build.gradle.kts | 2 +- .../src/androidMain/AndroidManifest.xml | 2 + wallet-sdk/wallet_sdk.podspec | 4 +- 40 files changed, 3854 insertions(+), 13 deletions(-) create mode 100644 authenticate-sdk/build.gradle.kts create mode 100644 authenticate-sdk/src/androidMain/AndroidManifest.xml create mode 100644 authenticate-sdk/src/androidMain/kotlin/authenticate.kt create mode 100644 authenticate-sdk/src/androidMain/kotlin/createChallenge.kt create mode 100644 authenticate-sdk/src/commonMain/kotlin/authenticate.kt create mode 100644 authenticate-sdk/src/commonMain/kotlin/createChallenge.kt create mode 100644 authenticate-sdk/src/jsMain/kotlin/authenticate.kt create mode 100644 authenticate-sdk/src/jsMain/kotlin/createChallenge.kt create mode 100644 authenticate-sdk/src/jvmMain/kotlin/authenticate.kt create mode 100644 authenticate-sdk/src/jvmMain/kotlin/createChallenge.kt create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/Deps.kt create mode 100644 buildSrc/src/main/kotlin/PluginVersions.kt create mode 100644 buildSrc/src/main/kotlin/Plugins.kt create mode 100644 buildSrc/src/main/kotlin/Versions.kt create mode 100644 protosLib/build.gradle.kts create mode 100644 protosLib/src/main/proto/common_models.proto create mode 100644 protosLib/src/main/proto/connector_api.proto create mode 100644 protosLib/src/main/proto/connector_models.proto create mode 100644 protosLib/src/main/proto/console_api.proto create mode 100644 protosLib/src/main/proto/console_models.proto create mode 100644 protosLib/src/main/proto/credential_models.proto create mode 100644 protosLib/src/main/proto/cviews_api.proto create mode 100644 protosLib/src/main/proto/cviews_models.proto create mode 100644 protosLib/src/main/proto/health.proto create mode 100755 protosLib/src/main/proto/intdemo/intdemo_api.proto create mode 100644 protosLib/src/main/proto/intdemo/intdemo_models.proto create mode 100644 protosLib/src/main/proto/node_api.proto create mode 100644 protosLib/src/main/proto/node_internal.proto create mode 100644 protosLib/src/main/proto/node_models.proto create mode 100644 protosLib/src/main/proto/package.json create mode 100644 protosLib/src/main/proto/resources/markdown.tmpl create mode 100644 protosLib/src/main/proto/status.proto create mode 100644 wallet-sdk/src/androidMain/AndroidManifest.xml diff --git a/authenticate-sdk/build.gradle.kts b/authenticate-sdk/build.gradle.kts new file mode 100644 index 000000000..805e27478 --- /dev/null +++ b/authenticate-sdk/build.gradle.kts @@ -0,0 +1,148 @@ +import org.gradle.internal.os.OperatingSystem +import org.jetbrains.dokka.gradle.DokkaTask +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target + +version = rootProject.version +val currentModuleName: String = "authenticate_sdk" +val os: OperatingSystem = OperatingSystem.current() + +plugins { + kotlin("multiplatform") + id("com.android.library") + id("org.jetbrains.dokka") +} + +kotlin { + android { + publishAllLibraryVariants() + } + jvm { + compilations.all { + kotlinOptions { + jvmTarget = "11" + } + } + testRuns["test"].executionTask.configure { + useJUnitPlatform() + } + } + + js(IR) { + this.moduleName = currentModuleName + this.binaries.library() + this.useCommonJs() + this.compilations["main"].packageJson { + this.version = rootProject.version.toString() + } + this.compilations["test"].packageJson { + this.version = rootProject.version.toString() + } + browser { + this.webpackTask { + this.output.library = currentModuleName + this.output.libraryTarget = Target.VAR + } + this.commonWebpackConfig { + this.cssSupport { + this.enabled = true + } + } + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } + } + nodejs { + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } + } + } + + + sourceSets { + val commonMain by getting { + dependencies { + implementation("com.benasher44:uuid:0.3.0") + implementation(project(":core-sdk")) + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + } + } + val jvmMain by getting + val jvmTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val androidMain by getting + val androidTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val jsMain by getting + val jsTest by getting + + all { + languageSettings.optIn("kotlin.RequiresOptIn") + } + } +} + +android { + compileSdk = 32 + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdk = 21 + targetSdk = 32 + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + /** + * Because Software Components will not be created automatically for Maven publishing from + * Android Gradle Plugin 8.0. To opt-in to the future behavior, set the Gradle property android. + * disableAutomaticComponentCreation=true in the `gradle.properties` file or use the new + * publishing DSL. + */ + publishing { + multipleVariants { + withSourcesJar() + withJavadocJar() + allVariants() + } + } +} + +// Dokka implementation +tasks.withType { + moduleName.set(project.name) + moduleVersion.set(rootProject.version.toString()) + description = """ + This is a Kotlin Multiplatform Wallet-SDK Library + """.trimIndent() + dokkaSourceSets { + // TODO: Figure out how to include files to the documentations + named("commonMain") { + includes.from("Module.md", "docs/Module.md") + } + } +} + +// afterEvaluate { +// tasks.withType { +// testLogging { +// events("passed", "skipped", "failed", "standard_out", "standard_error") +// showExceptions = true +// showStackTraces = true +// } +// } +// } \ No newline at end of file diff --git a/authenticate-sdk/src/androidMain/AndroidManifest.xml b/authenticate-sdk/src/androidMain/AndroidManifest.xml new file mode 100644 index 000000000..7e4dcbacb --- /dev/null +++ b/authenticate-sdk/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/authenticate-sdk/src/androidMain/kotlin/authenticate.kt b/authenticate-sdk/src/androidMain/kotlin/authenticate.kt new file mode 100644 index 000000000..1960c88f9 --- /dev/null +++ b/authenticate-sdk/src/androidMain/kotlin/authenticate.kt @@ -0,0 +1,3 @@ +actual fun authenticate(did: String, signature: String, originalText: String):String { + return "hola"; +} diff --git a/authenticate-sdk/src/androidMain/kotlin/createChallenge.kt b/authenticate-sdk/src/androidMain/kotlin/createChallenge.kt new file mode 100644 index 000000000..2eab196d8 --- /dev/null +++ b/authenticate-sdk/src/androidMain/kotlin/createChallenge.kt @@ -0,0 +1,3 @@ +actual fun createChallenge(expiration: Int): String { + return "hola"; +} \ No newline at end of file diff --git a/authenticate-sdk/src/commonMain/kotlin/authenticate.kt b/authenticate-sdk/src/commonMain/kotlin/authenticate.kt new file mode 100644 index 000000000..01b6b0481 --- /dev/null +++ b/authenticate-sdk/src/commonMain/kotlin/authenticate.kt @@ -0,0 +1 @@ +expect fun authenticate(did: String, signature: String, originalText: String):String diff --git a/authenticate-sdk/src/commonMain/kotlin/createChallenge.kt b/authenticate-sdk/src/commonMain/kotlin/createChallenge.kt new file mode 100644 index 000000000..4c268ae48 --- /dev/null +++ b/authenticate-sdk/src/commonMain/kotlin/createChallenge.kt @@ -0,0 +1 @@ +expect fun createChallenge(expiration: Int): String \ No newline at end of file diff --git a/authenticate-sdk/src/jsMain/kotlin/authenticate.kt b/authenticate-sdk/src/jsMain/kotlin/authenticate.kt new file mode 100644 index 000000000..8d89e415c --- /dev/null +++ b/authenticate-sdk/src/jsMain/kotlin/authenticate.kt @@ -0,0 +1,4 @@ +@JsExport +actual fun authenticate(did: String, signature: String, originalText: String):String { + return "hola"; +} diff --git a/authenticate-sdk/src/jsMain/kotlin/createChallenge.kt b/authenticate-sdk/src/jsMain/kotlin/createChallenge.kt new file mode 100644 index 000000000..e83348369 --- /dev/null +++ b/authenticate-sdk/src/jsMain/kotlin/createChallenge.kt @@ -0,0 +1,5 @@ + +@JsExport +actual fun createChallenge(expiration: Int): String { + return "hola"; +} \ No newline at end of file diff --git a/authenticate-sdk/src/jvmMain/kotlin/authenticate.kt b/authenticate-sdk/src/jvmMain/kotlin/authenticate.kt new file mode 100644 index 000000000..1960c88f9 --- /dev/null +++ b/authenticate-sdk/src/jvmMain/kotlin/authenticate.kt @@ -0,0 +1,3 @@ +actual fun authenticate(did: String, signature: String, originalText: String):String { + return "hola"; +} diff --git a/authenticate-sdk/src/jvmMain/kotlin/createChallenge.kt b/authenticate-sdk/src/jvmMain/kotlin/createChallenge.kt new file mode 100644 index 000000000..2eab196d8 --- /dev/null +++ b/authenticate-sdk/src/jvmMain/kotlin/createChallenge.kt @@ -0,0 +1,3 @@ +actual fun createChallenge(expiration: Int): String { + return "hola"; +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 275d65b19..668844023 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,17 +1,38 @@ import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + vendor.set(JvmVendorSpec.ADOPTOPENJDK) + } +} + plugins { - id("maven-publish") - id("org.jetbrains.dokka") version "1.7.10" - id("org.jlleitschuh.gradle.ktlint") version "11.0.0" + java + kotlin(Plugins.multiplatform) version PluginVersions.multiplatform apply false + kotlin(Plugins.serialization) version PluginVersions.multiplatform apply false + id(Plugins.protobuf) version PluginVersions.protobuf apply false + id(Plugins.npmPublish) version PluginVersions.npmPublish apply false + id(Plugins.gitVersion) version PluginVersions.gitVersion + id(Plugins.klint) version PluginVersions.klint + id(Plugins.compatibilityValidator) version PluginVersions.compatibilityValidator + id(Plugins.gitOps) version PluginVersions.gitOps + id(Plugins.koverage) version PluginVersions.koverage + id(Plugins.dokka) version PluginVersions.dokka + `maven-publish` } buildscript { repositories { - gradlePluginPortal() - google() mavenCentral() + mavenLocal() + google() + maven("https://plugins.gradle.org/m2/") + // Needed for Kotlin coroutines that support new memory management mode + maven { + url = uri("https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven") + } } dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20") @@ -24,8 +45,14 @@ group = "io.iohk.atala.prism" allprojects { repositories { - google() mavenCentral() + mavenLocal() + google() + maven("https://plugins.gradle.org/m2/") + // Needed for Kotlin coroutines that support new memory management mode + maven { + url = uri("https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven") + } } // apply(plugin = "org.gradle.maven-publish") diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 000000000..181a98709 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,9 @@ +import org.gradle.kotlin.dsl.`kotlin-dsl` + +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() +} diff --git a/buildSrc/src/main/kotlin/Deps.kt b/buildSrc/src/main/kotlin/Deps.kt new file mode 100644 index 000000000..5e02fb8af --- /dev/null +++ b/buildSrc/src/main/kotlin/Deps.kt @@ -0,0 +1,30 @@ +object Deps { + const val kotlinSerializationJson = "org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.kotlinSerializationJson}" + const val kotlinBignum = "com.ionspin.kotlin:bignum:${Versions.kotlinBignum}" + const val kotlinCoroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}" + const val kotlinCoroutinesJDK8 = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:${Versions.kotlinCoroutinesJDK8}" + const val kotlinNodejs = "org.jetbrains.kotlinx:kotlinx-nodejs:${Versions.kotlinNodejs}" + const val kotlinDatetime = "org.jetbrains.kotlinx:kotlinx-datetime:${Versions.kotlinDatetime}" + const val grpcKotlinStub = "io.grpc:grpc-kotlin-stub:${Versions.grpcKotlinStub}" + const val grpcKotlinOkhttp = "io.grpc:grpc-okhttp:${Versions.grpcKotlinOkhttp}" + + const val bitcoinj = "org.bitcoinj:bitcoinj-core:${Versions.bitcoinj}" + const val bitcoinKmp = "fr.acinq.bitcoin:bitcoin-kmp:${Versions.bitcoinKmp}" + + const val pbandkRuntime = "io.iohk:pbandk-runtime:${Versions.pbandk}" + const val pbandkProtocGen = "io.iohk:protoc-gen-pbandk-lib-jvm:${Versions.pbandk}" + // NOTE: this adds Kotlin interop with some of the jvm8 features (e.g. CompletableFuture). + const val pbandkProtocGenJDK8 = "io.iohk:protoc-gen-pbandk-jvm:${Versions.pbandk}:jvm8@jar" + const val pbandkPrismClientsGenerator = "io.iohk.atala:pbandk-prism-clients-generator:${Versions.pbandk}" + + const val protobufJava = "com.google.protobuf:protobuf-java:${Versions.protobuf}" + const val protobufProtoc = "com.google.protobuf:protoc:${Versions.protobuf}" + const val protobufLite = "io.grpc:grpc-protobuf-lite:${Versions.protobufLite}" + + const val betterParse = "com.github.h0tk3y.betterParse:better-parse:${Versions.betterParse}" + const val krypto = "com.soywiz.korlibs.krypto:krypto:${Versions.krypto}" + const val guava = "com.google.guava:guava:${Versions.guava}" + const val spongyCastle = "com.madgag.spongycastle:prov:${Versions.spongyCastle}" + const val bouncyCastle = "org.bouncycastle:bcprov-jdk15on:${Versions.bouncyCastle}" + const val uuid = "com.benasher44:uuid:${Versions.uuid}" +} diff --git a/buildSrc/src/main/kotlin/PluginVersions.kt b/buildSrc/src/main/kotlin/PluginVersions.kt new file mode 100644 index 000000000..c64b89032 --- /dev/null +++ b/buildSrc/src/main/kotlin/PluginVersions.kt @@ -0,0 +1,14 @@ +object PluginVersions { + const val multiplatform = "1.6.0" + const val androidLibrary = "4.1.2" + const val protobuf = "0.8.14" + const val npmPublish = "2.0.2" + const val gitVersion = "0.12.3" + const val klint = "10.0.0" + const val multiplatformSwift = "2.0.3" + const val kfcDefinitions = "4.32.0" + const val compatibilityValidator = "0.8.0-RC" + const val gitOps = "5.0.0-rc.3" + const val koverage = "0.5.0" + const val dokka = "1.7.0" +} diff --git a/buildSrc/src/main/kotlin/Plugins.kt b/buildSrc/src/main/kotlin/Plugins.kt new file mode 100644 index 000000000..657d5ae5e --- /dev/null +++ b/buildSrc/src/main/kotlin/Plugins.kt @@ -0,0 +1,15 @@ +object Plugins { + const val multiplatform = "multiplatform" + const val serialization = "plugin.serialization" + const val androidLibrary = "com.android.library" + const val protobuf = "com.google.protobuf" + const val npmPublish = "dev.petuska.npm.publish" + const val gitVersion = "com.palantir.git-version" + const val klint = "org.jlleitschuh.gradle.ktlint" + const val multiplatformSwift = "com.chromaticnoise.multiplatform-swiftpackage" + const val kfcDefinitions = "com.github.turansky.kfc.definitions" + const val compatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator" + const val gitOps = "org.ajoberstar.grgit" + const val koverage = "org.jetbrains.kotlinx.kover" + const val dokka = "org.jetbrains.dokka" +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt new file mode 100644 index 000000000..f50b347ad --- /dev/null +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -0,0 +1,30 @@ +object Versions { + const val jvmTarget = "11" + const val iosTarget = "13" + const val androidTargetSdk = 29 + const val androidMinSdk = 26 + + const val kotlinSerializationJson = "1.3.0" + const val kotlinBignum = "0.3.1" + const val kotlinCoroutines = "1.5.1-new-mm-dev2" + const val kotlinCoroutinesJDK8 = "1.5.2" + const val kotlinNodejs = "0.0.7" + const val kotlinDatetime = "0.2.1" + const val grpcKotlinStub = "1.0.0" + const val grpcKotlinOkhttp = "1.36.0" + + const val bitcoinj = "0.15.10" + const val bitcoinKmp = "0.7.0" + + const val pbandk = "0.20.7" + const val protobuf = "3.12.0" + const val protobufLite = "1.36.0" + + const val swiftTools = "5.3" + const val betterParse = "0.4.3" + const val krypto = "2.4.12" + const val guava = "30.1-jre" + const val spongyCastle = "1.58.0.0" + const val bouncyCastle = "1.68" + const val uuid = "0.3.0" +} diff --git a/core-sdk/build.gradle.kts b/core-sdk/build.gradle.kts index 518586b6c..196146a3a 100644 --- a/core-sdk/build.gradle.kts +++ b/core-sdk/build.gradle.kts @@ -3,7 +3,7 @@ import org.jetbrains.dokka.gradle.DokkaTask import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target version = rootProject.version -val currentModuleName: String = "wallet-core-sdk" +val currentModuleName: String = "wallet_core_sdk" val os: OperatingSystem = OperatingSystem.current() plugins { diff --git a/core-sdk/core_sdk.podspec b/core-sdk/core_sdk.podspec index 3f27f1b9a..d7c7278d3 100644 --- a/core-sdk/core_sdk.podspec +++ b/core-sdk/core_sdk.podspec @@ -6,7 +6,7 @@ Pod::Spec.new do |spec| spec.authors = 'IOG' spec.license = '' spec.summary = 'Wallet-Core-SDK' - spec.vendored_frameworks = 'build/cocoapods/framework/wallet-core-sdk.framework' + spec.vendored_frameworks = 'build/cocoapods/framework/wallet_core_sdk.framework' spec.libraries = 'c++' spec.ios.deployment_target = '13.0' spec.osx.deployment_target = '12.0' @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':core-sdk', - 'PRODUCT_MODULE_NAME' => 'wallet-core-sdk', + 'PRODUCT_MODULE_NAME' => 'wallet_core_sdk', } spec.script_phases = [ diff --git a/protosLib/build.gradle.kts b/protosLib/build.gradle.kts new file mode 100644 index 000000000..b92a590b5 --- /dev/null +++ b/protosLib/build.gradle.kts @@ -0,0 +1,83 @@ +import com.google.protobuf.gradle.* +import org.apache.tools.ant.taskdefs.condition.Os + +plugins { + `java-library` + id(Plugins.protobuf) +} + +// Mock configuration which derives compile only. +// Needed to resolve jar files of the dependency +val jarPathConf by configurations.creating { + extendsFrom(configurations.compileOnly.get()) +} + +dependencies { + jarPathConf(Deps.pbandkPrismClientsGenerator) + + // This is needed for includes, ref: https://github.com/google/protobuf-gradle-plugin/issues/41#issuecomment-143884188 + compileOnly(Deps.protobufJava) +} + +sourceSets { + main { + proto { + setSrcDirs(listOf("src/main/proto")) + setIncludes( + listOf( + "common_*.proto", + "node_*.proto", + "connector_*.proto", + "console_*.proto", + "status.proto", + "credential_*.proto" + ) + ) + } + } +} + +protobuf { + protoc { + artifact = if (Os.isFamily(Os.FAMILY_MAC)) { + if (System.getProperty("os.arch") != "x86_64") { + // In case of macOS and M1 chip then we need to use a different version of protobuf that support M1 chip arch + "${Deps.protobufProtoc}:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" + } else { + Deps.protobufProtoc + } + } else { + Deps.protobufProtoc + } + } + plugins { + id("kotlin") { + artifact = Deps.pbandkProtocGenJDK8 + } + } + + val pbandkClientsGeneratorJar = configurations["jarPathConf"].files(configurations["jarPathConf"].dependencies.first()).first() + + generateProtoTasks { + ofSourceSet("main").forEach { task -> + task.builtins { + remove("java") + } + task.plugins { + id("kotlin") { + option("kotlin_package=io.iohk.atala.prism.protos") + option("kotlin_service_gen=$pbandkClientsGeneratorJar|io.iohk.atala.prism.generator.Generator") + option("visibility=public") + option("js_export=true") + option("with_annotations=@io.iohk.atala.prism.common.PrismSdkInternal") + } + } + } + } +} + +tasks { + compileJava { + enabled = false + } +} diff --git a/protosLib/src/main/proto/common_models.proto b/protosLib/src/main/proto/common_models.proto new file mode 100644 index 000000000..dcb5fe568 --- /dev/null +++ b/protosLib/src/main/proto/common_models.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "google/protobuf/timestamp.proto"; + +/** + * A request that can be used to check service health. + * All PRISM services expose an RPC that accepts this message as request. + */ +message HealthCheckRequest {} + +/** + * A response that represents service health. + * Status code 0 with empty response represents a healthy and reachable service, + * while all other status codes represent issues with the service. + */ +message HealthCheckResponse {} + +/** + * Represents a date by its parts (day, month, year). + */ +message Date { + int32 year = 1; // A positive value. + int32 month = 2; // A value in the [1, 12] range. + int32 day = 3; // A value in the [1, 31] range (depending on the month, the maximum value might be 28). +} + +/** + * Represents a time interval between two given timestamps. + * The message represents a closed interval (i.e. both ends are inclusive and mandatory). + */ +message TimeInterval { + /** + * The starting timestamp. + * start_timestamp must be before or equal to end_timestamp. + */ + google.protobuf.Timestamp start_timestamp = 1; + /** + * The ending timestamp. + * end_timestamp must be after or equal to start_timestamp. + */ + google.protobuf.Timestamp end_timestamp = 2; +} + +/** + * This enum provides a way for some RPC requests to specify the direction so that the response values are sorted + * the way you want them to. + * Note that it specifies the direction only and doesn't say anything about a comparator + * (e.g. natural order, some RPC-specific order etc). + */ +enum SortByDirection { + SORT_BY_DIRECTION_UNKNOWN = 0; // Nothing provided, each API can define whether to fail or take a default value (commonly ASCENDING). + SORT_BY_DIRECTION_ASCENDING = 1; // Sort the results in ascending order. + SORT_BY_DIRECTION_DESCENDING = 2; // Sort the results in descending order. +} + +/** + * The supported ledger types. Specifies which chain is used for storing transactions. + */ +enum Ledger { + reserved 2; // Removed BITCOIN_TESTNET + reserved "BITCOIN_TESTNET"; + reserved 3; // Removed BITCOIN_MAINNET + reserved "BITCOIN_MAINNET"; + + UNKNOWN_LEDGER = 0; // Invalid default value. + IN_MEMORY = 1; // Store transactions in memory instead of blockchain, used only for development. + CARDANO_TESTNET = 4; // Cardano testnet, used for testing. + CARDANO_MAINNET = 5; // Cardano mainnet, used in production. +} + +/** + * Information about a ledger block. + * See Ledger documentation for details on which ledgers are possible. + */ +message BlockInfo { + reserved 2; // Removed timestamp_deprecated field + reserved "timestamp_deprecated"; + + int32 number = 1; // Number of the block in the ledger. + int32 index = 3; // Index of the transaction within the block. + google.protobuf.Timestamp timestamp = 4; // Timestamp when the block was created. +} + +/** + * Information about a ledger transaction and the block that the transaction is included in. + */ +message TransactionInfo { + string transaction_id = 1; // Transaction ID. + Ledger ledger = 2; // Ledger the transaction was published to. + BlockInfo block = 3; // Block the transaction was included in. +} + +/** + * The status of an Atala operation. + */ +enum OperationStatus { + UNKNOWN_OPERATION = 0; // The operation hasn't been received by the node service yet. + PENDING_SUBMISSION = 1; // The transaction containing this operation hasn't been published to the chain yet. + AWAIT_CONFIRMATION = 2; // The transaction containing this operation has been published to the chain, but hasn't been processed by PRISM yet. + CONFIRMED_AND_APPLIED = 3; // The operation has been successfully applied to the PRISM. + CONFIRMED_AND_REJECTED = 4; // The operation has been processed by PRISM, but rejected because of some error. +} + diff --git a/protosLib/src/main/proto/connector_api.proto b/protosLib/src/main/proto/connector_api.proto new file mode 100644 index 000000000..6521eb35a --- /dev/null +++ b/protosLib/src/main/proto/connector_api.proto @@ -0,0 +1,443 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +import "common_models.proto"; +import "connector_models.proto"; +import "node_models.proto"; + +package io.iohk.atala.prism.protos; + +/** + * The Connector API. + * An intermediate service for communication of parties: + Issuer with Holder, Holder with Verifier, etc. +*/ +service ConnectorService { + /** + * PUBLIC + * + * Checks if the service is healthy. + * Status code 0 with empty response represents a healthy and reachable service, + * while all other status codes represent issues with the service. + */ + rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse) {} + + /** + * PUBLIC + * + * Registers as a participant. + * A party registered as a participant is considered authenticated and has access + * to RPC methods with corresponding AUTHENTICATED access level. + * This is commonly expected for a user willing to register their public DID. + * The method invokes the Atala node to publish the DID to the blockchain + * or binds existing already published DID to an institution if passed. + @exclude TODO: Delete method, we should not register the DID but receive the registered one. + * Errors: + * - Invalid DID (INVALID_ARGUMENT). + * - Invalid DID document (INVALID_ARGUMENT). + * - DID Document does not match DID (INVALID_ARGUMENT). + * - DID already exists (INVALID_ARGUMENT). + * - Expected published DID (INVALID_ARGUMENT). + * - The passed DID was not found on the Atala node (INVALID_ARGUMENT). + * - Expected existing DID or Atala operation (INVALID_ARGUMENT). + */ + rpc RegisterDID (RegisterDIDRequest) returns (RegisterDIDResponse) {} + + /** + * AUTHENTICATED + * + * Generates connection tokens that can be used to instantiate connections. + * One of the participants (so called creator) is expected to generate a token and + * share with the other one (so called acceptor) via trusted and secured communication channel (e.g, via a QR-code). + * After that the acceptor instantiates a connection using the token. + */ + rpc GenerateConnectionToken (GenerateConnectionTokenRequest) returns (GenerateConnectionTokenResponse) {} + + /** + * PUBLIC + * + * Returns info about a connection token (creator info, for example). + * This is commonly used to verify whether you want to accept the connection or not. + * Errors: + * - No such connection token (UNKNOWN) + */ + rpc GetConnectionTokenInfo (GetConnectionTokenInfoRequest) returns (GetConnectionTokenInfoResponse) {} + + /** + * PUBLIC + * + * Instantiates a connection from a connection token, connection status set to accepted. + * Before the connection instantiation, a caller (acceptor) is registered as a participant. + * Creator's name, logo and DID are in the response. + * Errors: + * - A caller's DID is already used for another connection (ALREADY_EXISTS), in other words already registered + * - Passed public key is already used for another connection (ALREADY_EXISTS), in other words already registered + * - No such connection token (UNKNOWN) + */ + rpc AddConnectionFromToken (AddConnectionFromTokenRequest) returns (AddConnectionFromTokenResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves a connection for a given connection token if any. + */ + rpc GetConnectionByToken (GetConnectionByTokenRequest) returns (GetConnectionByTokenResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves a connection for a given connection id if any. + */ + rpc GetConnectionById (GetConnectionByIdRequest) returns (GetConnectionByIdResponse) {} + + /** + * AUTHENTICATED + * + * Gets a chunk of active connections created after the given connection, ordered by instantiation time. + * The size of the chunk doesn't exceed the passed limit. + * Both created and accepted connections will be returned. + * Errors: + * - Negative or zero limit (INVALID_ARGUMENT) + */ + rpc GetConnectionsPaginated (GetConnectionsPaginatedRequest) returns (GetConnectionsPaginatedResponse) {} + + /** + * AUTHENTICATED + * + * Revokes an active connection (this can be done from any of the sides involved). + * Once the connection is revoked: + * - No messages will be accepted. + * - The existing messages are deleted. + * - The related contact connection status gets updated. + * Errors: + * - A caller is neither sides of connection (UNKNOWN) + */ + rpc RevokeConnection (RevokeConnectionRequest) returns (RevokeConnectionResponse) {} + + /** + * AUTHENTICATED + * + * Gets a chunk of incoming messages received after the given message id, + * sorted in ascending order by reception time. + * The size of the chunk doesn't exceed the passed limit. + * Errors: + * - Negative or zero limit (INVALID_ARGUMENT) + */ + rpc GetMessagesPaginated (GetMessagesPaginatedRequest) returns (GetMessagesPaginatedResponse) {} + + /** + * AUTHENTICATED + * + * Streams all incoming messages across all the connections, received after the given optional message. + */ + rpc GetMessageStream (GetMessageStreamRequest) returns (stream GetMessageStreamResponse) {} + + /** + * AUTHENTICATED + * + * Return messages received on the given connection. + * No pagination is required, as the number of messages is small. + */ + rpc GetMessagesForConnection (GetMessagesForConnectionRequest) returns (GetMessagesForConnectionResponse) {} + + /** + * AUTHENTICATED + * + * Returns public keys that can be used for secure communication with the other end of the connection. + */ + rpc GetConnectionCommunicationKeys (GetConnectionCommunicationKeysRequest) returns (GetConnectionCommunicationKeysResponse) {} + + /** + * AUTHENTICATED + * + * Sends message over a connection. + * Errors: + * - Provided message id already exists (ALREADY_EXISTS) + * - Appropriate connection not found (NOT_FOUND) + * - Connection revoked (FAILED_PRECONDITION). + */ + rpc SendMessage (SendMessageRequest) returns (SendMessageResponse) {} + + /** + * AUTHENTICATED + * + * Sends multiple messages over many connections atomically. + * If one message cannot be sent (because of an unknown connection, for example), + * the rest also remain unsent. This method uses connection tokens instead of connections IDs. + * Errors: + * - Provided message id already exists (ALREADY_EXISTS) + * - Provided messages ids are not unique (ALREADY_EXISTS) + * - One of the connections not found by a connection token (NOT_FOUND) + * - Connection revoked (FAILED_PRECONDITION). + */ + rpc SendMessages (SendMessagesRequest) returns (SendMessagesResponse) {} + + /** + * AUTHENTICATED + * + * Returns the details for the authenticated user. + * Errors: + * - Participant not found (UNKNOWN) + */ + rpc GetCurrentUser (GetCurrentUserRequest) returns (GetCurrentUserResponse); + + /** + * AUTHENTICATED + * + * Updates an existing participant's profile. + */ + rpc UpdateParticipantProfile (UpdateProfileRequest) returns (UpdateProfileResponse) {} + + /** + * PUBLIC + * + * Returns information about the Connector and Node builds. + */ + rpc GetBuildInfo (GetBuildInfoRequest) returns (GetBuildInfoResponse); +} + +service ContactConnectionService { + /** + * WHITELISTED_DID + * + * Gets connection statuses by connection tokens. + */ + rpc GetConnectionStatus (ConnectionsStatusRequest) returns (ConnectionsStatusResponse) {} +} + +// Finds a connection by the given token. +message GetConnectionByTokenRequest { + string token = 1; // The token related to the connection. This must not be empty. +} +// The response while finding a connection by token. +message GetConnectionByTokenResponse { + io.iohk.atala.prism.protos.Connection connection = 1; +} + +// Finds a connection by the given id. +message GetConnectionByIdRequest { + string id = 1; // The id related to the connection. This must not be empty. +} +// The response while finding a connection by id. +message GetConnectionByIdResponse { + io.iohk.atala.prism.protos.ConnectionInfo connection = 1; +} + +// Requests connections instantiated by/with us, possibly after a known connection. +// +// The results are sorted in ascending orer by the time the connection was created. +message GetConnectionsPaginatedRequest { + string last_seen_connection_id = 1; // Returned connections will have been created after the last seen connection (optional field). + int32 limit = 2; // The maximum number of connections to return; must be greater than 0. +} + +// Result with instantiated connections. +message GetConnectionsPaginatedResponse { + repeated io.iohk.atala.prism.protos.ConnectionInfo connections = 1; // Connections sorted in ascending order by instantiation time. +} + +// Request to obtain information of connection token. +message GetConnectionTokenInfoRequest { + string token = 1; // The token value to get information for. +} + +// Result with information on connection token. +message GetConnectionTokenInfoResponse { + string creator_name = 2; // Creator name. + bytes creator_logo = 3; // Creator logo. + string creator_did = 4; // Creator did. + reserved 1; // Removed creator field + reserved "creator"; +} + +// Request to instantiate a connection using a token. +message AddConnectionFromTokenRequest { + // This used to allow the holder public key as (x, y). It was replaced by the holderEncodedPublicKey field. + reserved 2; + reserved "holderPublicKey"; + + // This was used to allow taking payments while creating connections, which is no longer required. + reserved 3; + reserved "paymentNonce"; + + string token = 1; // A token to instantiate a connection. + io.iohk.atala.prism.protos.EncodedPublicKey holder_encoded_public_key = 4; // Uncompressed encoded public key. +} + +// Confirmation of connection instantiation. +message AddConnectionFromTokenResponse { + io.iohk.atala.prism.protos.ConnectionInfo connection = 1; // Instantiated connection information. +} + +// Request to revoke a connection. +message RevokeConnectionRequest { + string connection_id = 1; // The ID of connection to delete. +} + +// Confirmation of connection revocation. +message RevokeConnectionResponse { +} + +// Request to generate a connection token. +message GenerateConnectionTokenRequest { + int32 count = 1; // Amount of tokens to generate (optional, the default value is 1). +} + +// Result with generated token. +message GenerateConnectionTokenResponse { + repeated string tokens = 1; // Generated tokens. +} + +// Request to return messages for us after the given known message, if any. +// Sorted by reception time in ascending order. +message GetMessagesPaginatedRequest { + string last_seen_message_id = 1; // Returned messages will have been received after the given message, if any. + int32 limit = 2; // The maximum number of messages to return. It must be greater than 0. +} + +// Response with messages. +message GetMessagesPaginatedResponse { + repeated io.iohk.atala.prism.protos.ReceivedMessage messages = 1; // Messages sorted by reception time in ascending order. +} + +// Request to stream new messages, which starts the stream from messages received after the given lastSeenMessageId +message GetMessageStreamRequest { + // Last message seen by the client, so only newer messages are returned. + string last_seen_message_id = 1; +} + +// Response for the new messages stream. +message GetMessageStreamResponse { + io.iohk.atala.prism.protos.ReceivedMessage message = 1; // The received message. +} + +// Finds available messages from the given connection. +// @exclude TODO: Remove unnecessary method, it was used before to parse received credentials but this is not required anymore. +message GetMessagesForConnectionRequest { + string connection_id = 1; +} +message GetMessagesForConnectionResponse { + repeated io.iohk.atala.prism.protos.ReceivedMessage messages = 1; +} + +// Finds the available keys to send end-to-end encrypted messages. +message GetConnectionCommunicationKeysRequest { + string connection_id = 1; // The connection we are interested in sending a message to. +} + +message GetConnectionCommunicationKeysResponse { + // Keys that can be used for communication with the other end of connection with their IDs. + // keyId inside might be empty if there is just one key in the collection. + repeated io.iohk.atala.prism.protos.ConnectionKey keys = 1; +} + +// Request to send message. +message SendMessageRequest { + string connection_id = 1; // Connection ID. + bytes message = 2; // Raw message. + // Optional id of a message. Must be valid UUID if provided. Random id will be generated + // if not provided. Error will be returned when message with the same id already exists. + string id = 3; +} + +// Confirmation of message sending. +message SendMessageResponse { + string id = 1; // Id of a message. Either provided by the sender or generated by Connector. +} + +// Request to send multiple messages. +message SendMessagesRequest { + // Messages to send. It can be empty, in which case no messages will be sent. + repeated MessageToSendByConnectionToken messages_by_connection_token = 1; +} + +// Confirmation of messages sending. +message SendMessagesResponse { + repeated string ids = 1; // Ids of a messages. Either provided by the sender or generated by Connector. +} + +// @exclude REGISTRATION AND ACCOUNT MANAGEMENT + +// Request to register DID. +// @exclude TODO: Use the method to not register the DID on the blockchain. +message RegisterDIDRequest { + oneof register_with { + // The necessary operation to publish the DID to the blockchain. + io.iohk.atala.prism.protos.SignedAtalaOperation create_did_operation = 1; + // The already published DID. + string existing_did = 5; + } + // The user's role. + // @exclude TODO: Remove, we don't use roles anymore. + Role role = 2; + + // The way to identify the institution. + string name = 3; + + // The logo linked to the institution. + bytes logo = 4; + + enum Role { + issuer = 0; + verifier = 1; + } +} + +// Request to get the authenticated user details. +message GetCurrentUserRequest {} + +// The authenticated user details. +message GetCurrentUserResponse { + Role role = 1; + string name = 2; + bytes logo = 3; + + enum Role { + issuer = 0; + verifier = 1; + } +} + +// Confirmation of DID registration. +message RegisterDIDResponse { + reserved 2; // Removed "transaction_info" field + reserved "transaction_info"; + + string did = 1; + bytes operation_id = 3; // The internal identifier of the corresponding createDID operation. Empty if used existing DID in the corresponding request. +} + +// Request to get information about this service. +message GetBuildInfoRequest {} + +// The actual service's information. +message GetBuildInfoResponse { + reserved 4; // buildTime + + string version = 1; // The service version. + string scala_version = 2; // The Scala version used by the service. + string sbt_version = 3; // The SBT version used to compile the service. + string node_version = 5; // The node service version. +} + +message ConnectionsStatusRequest { + repeated string connection_tokens = 1; +} + +message ConnectionsStatusResponse { + repeated ContactConnection connections = 1; +} + +// Request to update the participant profile name and logo +message UpdateProfileRequest { + // The way to identify the institution. + string name = 1; + // The logo linked to the institution (optional field). + // If logo is missing, this will be set to 'Empty'. + bytes logo = 2; +} + +// Confirmation of participants profile updated. +message UpdateProfileResponse {} diff --git a/protosLib/src/main/proto/connector_models.proto b/protosLib/src/main/proto/connector_models.proto new file mode 100644 index 000000000..c14e9b849 --- /dev/null +++ b/protosLib/src/main/proto/connector_models.proto @@ -0,0 +1,90 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +import "console_models.proto"; +import "credential_models.proto"; +import "google/protobuf/timestamp.proto"; + +package io.iohk.atala.prism.protos; + +// @exclude GENERAL + +// Just an elliptic curve (EC) public key represented with big integers as strings. +// +// @exclude TODO: merge with the node PublicKey +message ConnectorPublicKey { + string x = 1; + string y = 2; +} +// Public key ECPoint (uncompressed form). +message EncodedPublicKey { + bytes public_key = 1; // The bytes representing the ECPoint encoded without compression. +} + + +// @exclude CONNECTIONS + +// A connection between two parties authorizing the use of the connector as a messaging channel. +message Connection { + // The connection token used to initialize the connection with the wallet. + string connection_token = 1; + + // The connector-generated connection ID. + string connection_id = 2; +} + +// Information about the connection; both sides see the same connectionId and creation time, but each sees different participant info. +message ConnectionInfo { + reserved 2; // Removed created_deprecated field + reserved "created_deprecated"; + reserved 3; // Removed participantInfo field + reserved "participantInfo"; + + string connection_id = 1; // The connection identifier. + string token = 4; // The token used to generate the connection. + string participant_name = 5; // Participant's name. + bytes participant_logo = 6; // Participant's logo. + string participant_did = 7; // Participant's DID. + google.protobuf.Timestamp created = 8; // Timestamp of instantiation. +} + +// Communication key for connection participant. +// +// @exclude TODO: Remove this when unpublished DIDs are integrated on the apps. +message ConnectionKey { + // Key identifier; it can be empty if the participant uses only one key. + string key_id = 1; + + // The actual public key. + EncodedPublicKey key = 2; +} + + +// @exclude MESSAGES + +// Message received via a connection. +message ReceivedMessage { + reserved 2; // Removed received_deprecated field + reserved "received_deprecated"; + + string id = 1; // The unique ID for this message. + string connection_id = 3; // Connection where the message has been received. + bytes message = 4; // Raw message, which needs to be parsed to get something meaningful. AtalaMessage is the common choice. + google.protobuf.Timestamp received = 5; // The timestamp when the connector received the message. +} + +message ContactConnection { + string connection_id = 1; + string connection_token = 2; + ContactConnectionStatus connection_status = 3; +} + +message MessageToSendByConnectionToken { + string connection_token = 1; // The connection token used to accept the connection. + AtalaMessage message = 2; // Raw message. + // Optional id of a message. Must be valid UUID if provided. Random id will be generated + // if not provided. Error will be returned when message with the same id already exists. + string id = 3; +} diff --git a/protosLib/src/main/proto/console_api.proto b/protosLib/src/main/proto/console_api.proto new file mode 100644 index 000000000..6a3285a28 --- /dev/null +++ b/protosLib/src/main/proto/console_api.proto @@ -0,0 +1,1481 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "console_models.proto"; +import "common_models.proto"; +import "node_models.proto"; +import "connector_api.proto"; +import "google/protobuf/timestamp.proto"; + +/** + * The Management Console API. + * Provides a way to create and maintain issuers. +*/ +service ConsoleService { + /** + * PUBLIC + * + * Checks if the service is healthy. + * Status code 0 with empty response represents a healthy and reachable service, + * while all other status codes represent issues with the service. + */ + rpc HealthCheck (HealthCheckRequest) returns (HealthCheckResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves numbers about the operations done in the Management Console for a specific time interval. + * See GetStatisticsResponse documentation on which metrics are supported. + */ + rpc GetStatistics (GetStatisticsRequest) returns (GetStatisticsResponse) {} + + /** + * PUBLIC + * + * Registers a new DID that represents an issuer. This is required to sign further requests by the issuer. + * + * Errors: + * - DID already exists (INVALID_ARGUMENT). + */ + rpc RegisterDID (RegisterConsoleDIDRequest) returns (RegisterConsoleDIDResponse) {} + + /** + * AUTHENTICATED + * + * Returns the name and the logo for the authenticated user. + * + * Errors: + * - Unknown identifier (UNKNOWN). + */ + rpc GetCurrentUser (GetConsoleCurrentUserRequest) returns (GetConsoleCurrentUserResponse) {} + + /** + * AUTHENTICATED + * + * Updates an existing participant's profile (profile is represented by name and logo). + * + * Errors: + * - Unknown identifier (UNKNOWN). + */ + rpc UpdateParticipantProfile (ConsoleUpdateProfileRequest) returns (ConsoleUpdateProfileResponse) {} + +} + +/** + * The Contacts API. + * Provides a way to add, update, and delete contacts for an authenticated issuer. + */ +service ContactsService { + /** + * AUTHENTICATED + * + * Creates a new contact for the authenticated issuer. + * Returns the created contact. + * + * Errors: + * - Generation of connection tokens failed (INVALID_ARGUMENT). + * - A group with a passed name does not exist (INVALID_ARGUMENT). + */ + rpc CreateContact (CreateContactRequest) returns (CreateContactResponse) {} + + /** + * AUTHENTICATED + * + * Creates multiple contacts atomically for the authenticated issuer, + * and binds every contact to the provided groups. + * Returns the amount of created contacts. + * + * Errors: + * - Generation of connection tokens failed (INVALID_ARGUMENT). + * - A group with a passed name does not exist (INVALID_ARGUMENT). + */ + rpc CreateContacts (CreateContactsRequest) returns (CreateContactsResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves available contacts for the authenticated issuer. Several + * filter and sorting options are available for finding specific contacts. + * Returns contacts and their details in a paginated way. + * + * Errors: + * - Unexpected DB error (INTERNAL). + */ + rpc GetContacts (GetContactsRequest) returns (GetContactsResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves contact's info by its identifier. + * + * Errors: + * - Unexpected DB error (INTERNAL). + */ + rpc GetContact (GetContactRequest) returns (GetContactResponse) {} + + /** + * AUTHENTICATED + * + * Updates a contact by the given identifier. + * + * Errors: + * - Unexpected DB error (INTERNAL). + */ + rpc UpdateContact (UpdateContactRequest) returns (UpdateContactResponse) {} + + /** + * AUTHENTICATED + * + * Deletes a contact from the authenticated issuer. + * + * Errors: + * - The requested contact was not deleted (INTERNAL). + * - Contact doesn not belong to issuer (INVALID_ARGUMENT). + * - Contact has some existing credentials (INVALID_ARGUMENT). + */ + rpc DeleteContact (DeleteContactRequest) returns (DeleteContactResponse) {} + + /** + * AUTHENTICATED + * DEPRECATED + * + * Generates a connection token for the given contact. + * It's an obsolete since CreateContact generates a new connection by itself. + */ + rpc GenerateConnectionTokenForContact (GenerateConnectionTokenForContactRequest) returns (GenerateConnectionTokenForContactResponse) {} +} + +/** + * The Credentials Issuance API. + * Provides a way to store credentials in the console database for further publishing. + */ +service CredentialIssuanceService { + /** + * AUTHENTICATED + * + * Creates a new credential issuance. + * Accepts a list of contacts and credential data for every contact + * (all credentials in the request are based on the same template). + * Additionally, every contact info contains a list of groups it was taken from (possibly empty). + * + * Errors: + * - Credential data validation failed (INVALID_ARGUMENT). + * - External Ids were not found (INVALID_ARGUMENT). + * - Contact Ids were not found (INVALID_ARGUMENT). + * - Missing contact id and external id (INVALID_ARGUMENT). + * - Invalid groups (INVALID_ARGUMENT). + */ + rpc CreateCredentialIssuance (CreateCredentialIssuanceRequest) returns (CreateCredentialIssuanceResponse) {} + + /** + * AUTHENTICATED + * + * The same as CreateCredentialIssuance, but takes JSON instead of data structures. + * See CreateCredentialIssuance for more details. + * + * Errors: + * - Credential data validation failed (INVALID_ARGUMENT). + * - External Ids were not found (INVALID_ARGUMENT). + * - Contact Ids were not found (INVALID_ARGUMENT). + * - Missing contact id and external id (INVALID_ARGUMENT). + * - Invalid groups (INVALID_ARGUMENT). + */ + rpc CreateGenericCredentialBulk (CreateGenericCredentialBulkRequest) returns (CreateGenericCredentialBulkResponse) {} + + /** + * AUTHENTICATED + * + * Gets a credential issuance by its identifier. + * + * Errors: + * - Unexpected DB error (INTERNAL). + */ + rpc GetCredentialIssuance (GetCredentialIssuanceRequest) returns (GetCredentialIssuanceResponse) {} +} + +/** + * The Credentials API. + * Provides a way to operate on credentials (share, delete, revoke, get detailed information from the database). + */ +service CredentialsService { + // @exclude TODO: Consider renaming this to CreateDraftCredential given that this is not published. + // @exclude TODO: Consider freezing the credential details once it gets published. + /** + * AUTHENTICATED + * + * Creates a draft credential from the authenticated issuer. + * The created credential is not published on the chain yet. + * Responses with the details of the created credential. + * See CManagerGenericCredential for more information. + * + * Errors: + * - Credential data validation failed (INVALID_ARGUMENT). + * - External Ids were not found (INVALID_ARGUMENT). + * - Contact Ids were not found (INVALID_ARGUMENT). + * - Both contact id and external id are missing, one is required (INVALID_ARGUMENT). + */ + rpc CreateGenericCredential (CreateGenericCredentialRequest) returns (CreateGenericCredentialResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves the credentials created by the authenticated issuer. Several + * filter and sorting options are available for finding specific credentials. + * See CManagerGenericCredential for more information. + * + * Errors: + * - Unexpected DB error (INTERNAL). + */ + rpc GetGenericCredentials (GetGenericCredentialsRequest) returns (GetGenericCredentialsResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves the credentials for the given contact created by the authenticated issuer. + * See CManagerGenericCredential for the details. + * + * Errors: + * - Unexpected DB error (INTERNAL). + */ + rpc GetContactCredentials (GetContactCredentialsRequest) returns (GetContactCredentialsResponse) {} + + /** + * AUTHENTICATED + * + * Marks a credential as shared. + * NOTE: This does not send the actual credential to the related contact, but it's supposed to be + * invoked every time that credential is sent. + * + * Errors: + * - Cannot mark the credential as shared (INTERNAL). + */ + rpc ShareCredential (ShareCredentialRequest) returns (ShareCredentialResponse) {} + + /** + * AUTHENTICATED + * + * Sends many credentials and marks them as shared. + * NOTE: This does not send the actual credential to the related contact, but it supposed to be + * invoked every time that credential is sent. + * + * Errors: + * - Cannot mark credentials as shared (INTERNAL). + */ + rpc ShareCredentials (ShareCredentialsRequest) returns (ShareCredentialsResponse) {} + + /** + * AUTHENTICATED + * DEPRECATED + * + * Retrieves node information associated with a credential. + * This method will be obsolete when we migrate to the Management Console. + */ + rpc GetBlockchainData (GetBlockchainDataRequest) returns (GetBlockchainDataResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves node information associated with a batch, and optionally, specific + * credentials within a batch. + * This call invokes two other calls from node service: getBatchState and getCredentialRevocationTime. + * See Ledger for more information. + */ + rpc GetLedgerData (GetLedgerDataRequest) returns (GetLedgerDataResponse) {} + + /** + * AUTHENTICATED + * + * Publishes a credential batch to the ledger. + * This method also stores the published batch on the database. + * However, it does not store the individual credentials on the + * console (see StorePublishedCredential). + * Ensures to send IssueCredentialBatch Operation wrapped in Atala Operation. + * See Ledger and IssueCredentialBatch for more information. + * + * Errors: + * - Failed to extract content hash and issuer DID (INTERNAL). + */ + rpc PublishBatch (PublishBatchRequest) returns (PublishBatchResponse) {} + + /** + * AUTHENTICATED + * + * This request stores the information associated with a credential in the console database. + * The endpoint assumes that the credential has been published in a batch through the PublishBatch endpoint. + * + * Errors: + * - Credential with ID does not exists (INTERNAL). + * - The credential was not issued by the specified issuer (INTERNAL). + */ + rpc StorePublishedCredential (StorePublishedCredentialRequest) returns (StorePublishedCredentialResponse) {} + + /** + * AUTHENTICATED + * + * Revokes a single credential by publishing the operation on the node and storing + * the involved transaction ID in the database. + * Ensures to send the CredentialRevoked wrapped in an AtalaMessage to the contact to notify that the credential + * was revoked. + * See RevokeCredentialsOperation for more information. + * + * Errors: + * - Internal server error (INTERNAL). + */ + rpc RevokePublishedCredential (RevokePublishedCredentialRequest) returns (RevokePublishedCredentialResponse) {} + + /** + * AUTHENTICATED + * + * Deletes credentials from the Management Console database. + * Returns error when trying to delete published credentials. Revoked credentials can be deleted. + * If deletion of one credential fails, the deletion of other credentials also fails. + * + * Errors: + * - Published credentials are not revoked (INVALID_ARGUMENT). + */ + rpc DeleteCredentials (DeleteCredentialsRequest) returns (DeleteCredentialsResponse) {} +} + +/** + * The Credential Types API. + * Provides a way to operate on credential types. + */ +service CredentialTypesService { + /** + * AUTHENTICATED + * + * Retrieves the available credential types on the authenticated issuer. + * See CredentialType for more information. + */ + rpc GetCredentialTypes (GetCredentialTypesRequest) returns (GetCredentialTypesResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves the credential type by its identification on the authenticated issuer. + * See CredentialTypeWithRequiredFields for more information. + */ + rpc GetCredentialType (GetCredentialTypeRequest) returns (GetCredentialTypeResponse) {} + + /** + * AUTHENTICATED + * + * Creates a new credential type on the authenticated issuer. + * Responses with the created type information. + * See CreateCredentialTypeField and CredentialTypeWithRequiredFields for more information. + * + * Errors: + * - Credential Type Incorrect Mustache Template (INVALID_ARGUMENT). + */ + rpc CreateCredentialType (CreateCredentialTypeRequest) returns (CreateCredentialTypeResponse) {} + + /** + * AUTHENTICATED + * + * Updates an existing credential type. + * + * Errors: + * - Credential Type Update Incorrect State (INVALID_ARGUMENT). + * - Credential Type Incorrect Mustache Template (INVALID_ARGUMENT). + */ + rpc UpdateCredentialType (UpdateCredentialTypeRequest) returns (UpdateCredentialTypeResponse) {} + + /** + * AUTHENTICATED + * + * Requests to change credential type state to ready on the authenticated issuer. + * + * Errors: + * - Credential Type Mark Archived As Ready (INVALID_ARGUMENT). + */ + rpc MarkAsReadyCredentialType (MarkAsReadyCredentialTypeRequest) returns (MarkAsReadyCredentialTypeResponse) {} + + /** + * AUTHENTICATED + * + * Requests to change credential type state to archived on the authenticated issuer. + */ + rpc MarkAsArchivedCredentialType (MarkAsArchivedCredentialTypeRequest) returns (MarkAsArchivedCredentialTypeResponse) {} +} + +/** + * The credential type categories API + * Provides a way to operate on credential type categories + */ +service CredentialTypeCategoriesService { + /** + * AUTHENTICATED + * + * Retrieves the available credentialTypeCategories on the authenticated issuer. + */ + rpc GetCredentialTypeCategories (GetCredentialTypeCategoriesRequest) returns (GetCredentialTypeCategoriesResponse) {} + + /** + * AUTHENTICATED + * + * Creates credential type category for authenticated issuer. + */ + rpc CreateCredentialTypeCategory (CreateCredentialTypeCategoryRequest) returns (CreateCredentialTypeCategoryResponse) {} + + /** + * AUTHENTICATED + * + * Marks credential type category for authenticated issuer. + */ + rpc ArchiveCredentialTypeCategory (ArchiveCredentialTypeCategoryRequest) returns (ArchiveCredentialTypeCategoryResponse) {} + + /** + * AUTHENTICATED + * + * Unarchives credential type category for authenticated issuer. + */ + rpc UnArchiveCredentialTypeCategory (UnArchiveCredentialTypeCategoryRequest) returns (UnArchiveCredentialTypeCategoryResponse) {} +} +/** + * The Groups API. + * Provides a way to operate on groups. + */ +service GroupsService { + /** + * AUTHENTICATED + * + * Creates a group on the authenticated issuer. + */ + rpc CreateGroup (CreateGroupRequest) returns (CreateGroupResponse) {} + + /** + * AUTHENTICATED + * + * Retrieves the available groups on the authenticated issuer. Several + * filter and sorting options are available for finding specific groups. + */ + rpc GetGroups (GetGroupsRequest) returns (GetGroupsResponse) {} + + /** + * AUTHENTICATED + * + * Updates an existing group by adding new contacts and removing some of the old ones. + * + * Errors: + * - Group does not exist (INVALID_ARGUMENT). + * - Group does not match to the issuer (INVALID_ARGUMENT). + * - Contacts do not match to the issuer (INVALID_ARGUMENT). + * - Group name is not free (INVALID_ARGUMENT). + */ + rpc UpdateGroup (UpdateGroupRequest) returns (UpdateGroupResponse) {} + + /** + * AUTHENTICATED + * + * Copies group using the existing group ID and passed name. + * Responses with a new group ID. + * + * Errors: + * - Group does not exist (INVALID_ARGUMENT). + * - Group does not match to the issuer (INVALID_ARGUMENT). + * - Group name is not free (INVALID_ARGUMENT). + */ + rpc CopyGroup (CopyGroupRequest) returns (CopyGroupResponse) {} + + /** + * AUTHENTICATED + * + * Deletes an existing group by its ID. + * + * Errors: + * - Group does not exist (INVALID_ARGUMENT). + * - Group does not match to the issuer (INVALID_ARGUMENT). + */ + rpc DeleteGroup (DeleteGroupRequest) returns (DeleteGroupResponse) {} +} + +/** + * The API for received credentials. + */ +service CredentialsStoreService { + /** + * AUTHENTICATED + * + * Stores a received credential. + * This is invoked from the wallet after receiving a credential. + */ + rpc StoreCredential (StoreCredentialRequest) returns (StoreCredentialResponse) {} + + /** + * AUTHENTICATED + * + * Finds the received credentials when filters are provided. + */ + rpc GetStoredCredentialsFor (GetStoredCredentialsForRequest) returns (GetStoredCredentialsForResponse) {} + + /** + * AUTHENTICATED + * + * Finds the latest credentialExternalId received. + * This is invoked from the wallet to know what the latest received credential is, which enables us to avoid + * processing the same received credential twice. + */ + rpc GetLatestCredentialExternalId (GetLatestCredentialExternalIdRequest) returns (GetLatestCredentialExternalIdResponse) {} +} + +/** + * Request to get usage statistics for the authenticated issuer. + * See ConsoleService.GetStatistics call for more information. + */ +message GetStatisticsRequest { + /** + * The query interval for inspection. + * Optional. If missing, the response will contain all available statistics. + */ + TimeInterval interval = 1; +} + +/** + * Response with the usage statistics for the authenticated issuer. + * See ConsoleService.GetStatistics for more information. + */ +message GetStatisticsResponse { + int32 number_of_contacts = 1; // The total number of contacts created. + int32 number_of_contacts_pending_connection = 2; // The total number of contacts that are yet to accept a connection. + int32 number_of_contacts_connected = 3; // The total number of contacts that have accepted a connection. + int32 number_of_groups = 4; // The total number of groups created. + int32 number_of_credentials_in_draft = 5; // The total number of credentials that are yet to be published on the blockchain. + int32 number_of_credentials_published = 6; // The total number of credentials published on the blockchain. + int32 number_of_credentials_received = 7; // The total number of credentials received from contacts. +} + +// @exclude TODO: Verify DID's ownership. +/** + * Request to register a DID. + * See ConsoleService.RegisterDID for more information. + */ +message RegisterConsoleDIDRequest { + string did = 1; // The DID associated with the issuer. + string name = 2; // The name of the issuer. Where applicable, it should be recognizable externally (e.g. full name of the university). + bytes logo = 3; // Optional. The logo linked to the issuer. +} + +/** + * Confirmation of DID registration. + */ +message RegisterConsoleDIDResponse {} + +/** + * Request to get the authenticated user details. + * See ConsoleService.GetCurrentUser for more information. + */ +message GetConsoleCurrentUserRequest {} + +/** + * The authenticated user details. + * See ConsoleService.GetCurrentUser for more information. + */ +message GetConsoleCurrentUserResponse { + string name = 1; // The name of the authenticated issuer. + bytes logo = 2; // Optional. The associated logo. +} + +/** + * Request to create a contact on the authenticated issuer. + */ +message CreateContactRequest { + // @exclude TODO: We likely need a list of groups instead, also, use group id instead of the name. + /** + * Optional. When present, the given contact gets assigned to a group with the given name. + */ + string group_name = 1; + + /** + * Arbitrary data for the contact. This data should be a valid JSON. If missing, "{}" will be used. + */ + string json_data = 2; + + /** + * The ID provided by the issuer when the contact was created. + * An issuer cannot have two contacts with the same external ID. + * The same ID can be used by different issuers. + */ + string external_id = 3; + + /** + * The contact's name. + */ + string name = 4; + + /** + * Metadata used to authenticate GenerateConnectionTokenRequest to connector. + * Frontend must sign GenerateConnectionTokenRequest with count value equal to number of contacts and + * pass signed request metadata through this message. + * All fields of this message are required. + */ + ConnectorRequestMetadata generate_connection_tokens_request_metadata = 5; +} + +/** + * Response after creating a contact. + */ +message CreateContactResponse { + Contact contact = 1; // The created contact. +} + +/** + * Request to create contacts on the authenticated issuer. + * The request is rejected when one or more of these conditions are met: + * - No contacts provided. + * - Any contact is invalid. + * - Contacts with duplicate external IDs. + * - Duplicate groups. + * - A group does not exist in the authenticated issuer. + */ +message CreateContactsRequest { + /** + * Optional, when present, the contacts get assigned to these groups (identified by id). + */ + repeated string groups = 1; + /** + * The contacts to create. + */ + repeated Contact contacts = 2; + message Contact { + /** + * The ID provided by the issuer when the contact was created. + * An issuer cannot have two contacts with the same external ID. + * The ID could be repeated in different issuer. + */ + string external_id = 3; + /** + * The contact's name. + */ + string name = 4; + /** + * Arbitrary data for the contact, should be a valid json, when missing, "{}" will be used, + */ + string json_data = 5; + } + /** + * Metadata used to authenticate GenerateConnectionTokenRequest to connector. + * Frontend must sign GenerateConnectionTokenRequest with count value equal to 1 and + * pass signed request metadata through this message. + * All fields of this message are required. + */ + ConnectorRequestMetadata generate_connection_tokens_request_metadata = 6; +} + +/** + * Response after creating contacts. + */ +message CreateContactsResponse { + int32 contacts_created = 1; // the number of contacts created. +} + +/** + * Request to retrieve the contacts from the authenticated issuer. + * By default, the result is sorted by the contact's creation date in ascending order. + * Contacts with the same creation date are sorted by contact ID. + */ +message GetContactsRequest { + /** + * The maximum amount of contacts to return. The amount must be greater than zero. + */ + int32 limit = 1; + /** + * Retrieves the next items based on the given scroll ID, when provided. + */ + string scroll_id = 4; + /** + * When provided, it filters the results based on the given criteria, just for the Management Console. + */ + FilterBy filter_by = 5; + /** + * When provided, it sorts the results by the given criteria. + */ + SortBy sort_by = 6; + /** + * Possible ways to filter the results from GetContactsRequest. + */ + message FilterBy { + string group_name = 1; // If provided, it only gets the contacts that belong to this group. + Date created_at = 2; // If provided, the contacts should have been created in the given date. + string name_or_external_id = 3; // If provided, the contacts should partially match the given name or externalId. The resulting SQL query will have the following clause "contacts.name ILIKE %name_or_external_id% OR contacts.external_id ILIKE %name_or_external_id%". + ContactConnectionStatus connection_status = 5; // If provided, it only gets the contacts that have this connection status. + } + /** + * The possible ways to sort the results. + */ + message SortBy { + /** + * The field used to sort the results by. + */ + Field field = 1; + /** + * Specifies the order (ascending/descending) of the results (ascending by default). + */ + SortByDirection direction = 2; + /** + * The possible fields to sort the results by. + */ + enum Field { + UNKNOWN = 0; // If the value is missing, we take the default one, CREATED_AT + CREATED_AT = 1; // The createdAt field. + NAME = 2; // The name field. + EXTERNAL_ID = 3; // The externalId field. + } + } +} + +/** + * Response with the retrieved contacts. + */ +message GetContactsResponse { + /** + * The scroll ID to retrieve the next items. + */ + string scroll_id = 2; + /** + * The contacts found filled with the credential counters. + */ + repeated ContactDetails data = 3; + /** + * Represents a contact in the response. + */ + message ContactDetails { + Contact contact = 1; // The contact. + int32 number_of_credentials_received = 2; // The number of credentials received from this contact. + int32 number_of_credentials_created = 3; // The number of credentials created for this contact (includes draft and published credentials). + } +} + +/** + * Request to retrieve a contact from the authenticated issuer. + */ +message GetContactRequest { + string contact_id = 1; // The ID used to find the contact. +} + +/** + * Response for the retrieved contact. + */ +message GetContactResponse { + Contact contact = 1; // The retrieved contact. + repeated Group groups = 2; // Available groups. + repeated StoredSignedCredential received_credentials = 3; // Credentials received. + repeated CManagerGenericCredential issued_credentials = 4; // Credentials found. +} + +/** + * Request to update a contact from the authenticated issuer. + * All fields are required. This is what the contact will be updated to. + */ +message UpdateContactRequest { + string contact_id = 1; // The ID for the contact to update. + string new_external_id = 2; // The new externalId. + string new_name = 3; // The new name. + string new_json_data = 4; // The new arbitrary JSON data. If missing, "{}" will be used +} + +/** + * Response after updating the contact. + */ +message UpdateContactResponse {} + +/** + * Request to delete a contact from the authenticated issuer. + */ +message DeleteContactRequest { + /** + * The ID used to delete the contact. + */ + string contact_id = 1; + /** + * If true, related credentials will be deleted along with the contact. + * If false and has any related credentials, the request will fail to delete the contact. + * If false and has no related credentials, only the contact will be deleted. + */ + bool delete_credentials = 2; +} + +/** + * Response for the deleted contact. + */ +message DeleteContactResponse {} + +/** + * Request to generate a connection token for the given contact on the authenticated issuer. + */ +message GenerateConnectionTokenForContactRequest { + string contact_id = 1; // The contact that will be linked to the token. +} + +/** + * Response after generating a connection token. + */ +message GenerateConnectionTokenForContactResponse { + string token = 1; // The token that needs to be shared with the user to accept the connection. +} + +/** + * Request to create a new credential issuance. + * It creates all needed contacts, groups, and credentials. After that it binds credentials to the contacts. + */ +message CreateCredentialIssuanceRequest { + string name = 1; // Name of the credential issuance. + string credential_type_id = 2; // The ID (UUID) of the credential type used as template for this credential. + repeated CredentialIssuanceContact credential_issuance_contacts = 3; // The contacts and their credential data. +} + +/** + * Response to creating a credential issuance. + */ +message CreateCredentialIssuanceResponse { + string credential_issuance_id = 1; // ID of the credential issuance just created. +} + +/** + * Request to create a credential issuance for the authenticated issuer. + * The difference with CreateCredentialIssuanceRequest is that this request takes a JSON parameter. + */ +message CreateGenericCredentialBulkRequest { + /** + * The JSON that contains the credentials data in this issuance. + * The expected structure is: + *
{
+   *    "issuance_name": String,
+   *    "credential_type_id": String,
+   *    "drafts" : [
+   *      {
+   *        "external_id": String,
+   *        "credential_data": JSON,
+   *        "group_ids": [String],
+   *      }
+   *    ]
+   * }
+ */ + string credentials_json = 1; +} + +/** + * Response when a bulk of credentials is created. + */ +message CreateGenericCredentialBulkResponse { + string credential_issuance_id = 1; // The ID of the credential issuance. +} + +/** + * Request to get a credential issuance. + */ +message GetCredentialIssuanceRequest { + string credential_issuance_id = 1; // ID of the credential issuance. +} + +/** + * Response to getting a credential issuance. + */ +message GetCredentialIssuanceResponse { + string name = 1; // Name of the credential issuance. + string credential_type_id = 2; // // The ID (UUID) of the credential type used as template for this credential. + google.protobuf.Timestamp created_at = 3; // Timestamp when the credential issuance was created. + repeated CredentialIssuanceContact credential_issuance_contacts = 4; // The contacts and their credential data. +} + +/** + * Request to get a list of all credential types on the authenticated issuer. + */ +message GetCredentialTypesRequest {} + +/** + * Response with the retrieved credential types. + */ +message GetCredentialTypesResponse { + repeated CredentialType credential_types = 1; // List of the credential types. +} + +/** + * Request to get a credential type on the authenticated issuer. + */ +message GetCredentialTypeRequest { + string credential_type_id = 1; // Id of the credential type. +} + +/** + * Response with the retrieved credential type. + */ +message GetCredentialTypeResponse { + CredentialTypeWithRequiredFields credential_type = 1; // The retrieved credential type. +} + +/** + * Request to create a credential type on the authenticated issuer. + */ +message CreateCredentialTypeRequest { + CreateCredentialType credential_type = 2; // New credential type. +} + +/** + * Response with the created credential type. + */ +message CreateCredentialTypeResponse { + CredentialTypeWithRequiredFields credential_type = 1; // The created credential type. +} + +/** + * Request to update a credential type on the authenticated issuer. + */ +message UpdateCredentialTypeRequest { + UpdateCredentialType credential_type = 2; // Credential type to update. +} + +/** + * Empty response after credential type update. + */ +message UpdateCredentialTypeResponse {} + +/** + * Request to change credential type state to ready on the authenticated issuer. + */ +message MarkAsReadyCredentialTypeRequest { + string credential_type_id = 1; // Credential type to update. +} + +/** + * Empty response after state update. + */ +message MarkAsReadyCredentialTypeResponse {} + +/** + * Request to change state to archived in credential type on the authenticated issuer. + */ +message MarkAsArchivedCredentialTypeRequest { + string credential_type_id = 1; // Credential type to update. +} + +/** + * Empty response after state update. + */ +message MarkAsArchivedCredentialTypeResponse {} + + +/** + * Request to get a list of all credential type categories on the authenticated issuer. + */ +message GetCredentialTypeCategoriesRequest {} + +/** + * Response with the retrieved credential type categories. + */ +message GetCredentialTypeCategoriesResponse { + repeated CredentialTypeCategory credential_type_categories = 1; +} + +/** + * Request to create a credential type category + */ +message CreateCredentialTypeCategoryRequest { + CreateCredentialTypeCategory credential_type_category = 1; +} + +/** + * Response with the created credential type + */ +message CreateCredentialTypeCategoryResponse { + CredentialTypeCategory credential_type_category = 1; +} + +/** + * Request to archive a credential type category by id + */ +message ArchiveCredentialTypeCategoryRequest { + string credential_type_category_id = 1; +} + +/** + * Response with archived credential type category + */ +message ArchiveCredentialTypeCategoryResponse { + CredentialTypeCategory credential_type_category = 1; +} + +/** + * Request to unarchive a credential type category by id + */ +message UnArchiveCredentialTypeCategoryRequest { + string credential_type_category_id = 1; +} + +/** + * Response with unCredentialTypeCategoryarchived credential type category + */ +message UnArchiveCredentialTypeCategoryResponse { + CredentialTypeCategory credential_type_category = 1; +} + + +/** + * Request to create a group on the authenticated issuer. + * See GroupsService.CreateGroup for more information. + */ +message CreateGroupRequest { + string name = 1; // The group name, which must not exist. + repeated string contact_ids = 2; // Contacts to put in the new group. New contacts cannot be duplicate. +} + +/** + * Response after creating a group. + */ +message CreateGroupResponse { + Group group = 1; // The group created and its associated details. +} + +/** + * Request to retrieve the available groups on the authenticated issuer. + * See GroupsService.GetGroups for more information. + */ +message GetGroupsRequest { + /** + * Optional, default value is 10. The maximum amount of groups to return. + */ + int32 limit = 2; + /** + * Optional, default is 0. The offset for pagination. + */ + int32 offset = 3; + /** + * When provided, filter the results based on the given criteria, just for the Management Console. + */ + FilterBy filter_by = 4; + /** + * Optional. When provided, it sorts the results by the given criteria (sorted by name in ascending order by default). + */ + SortBy sort_by = 5; + /** + * The possible ways to filter the results from GetGroupsRequest. + */ + message FilterBy { + string name = 1; // If provided, it returns the groups containing the given name (case insensitive). + Date created_after = 2; // If provided, it returns groups created at the given date or after. + Date created_before = 3; // If provided, it returns groups created before or at the given date. + string contact_id = 4; // If provided, it returns groups related to the given contact only. + } + /** + * The possible ways to sort the results. + */ + message SortBy { + Field field = 1; // The field used to sort the results by. + SortByDirection direction = 2; // Sorts results in ascending/descending order (ascending by default). + + /** + * The possible fields to sort the results by. + */ + enum Field { + UNKNOWN = 0; // If the value is missing, we take the default one: NAME. + NAME = 1; // The name field. + CREATED_AT = 2; // The createdAt field. + NUMBER_OF_CONTACTS = 3; // Number of contacts. + } + } +} + +/** + * Response with the available groups. + */ +message GetGroupsResponse { + /** + * The available groups. + */ + repeated Group groups = 1; + /** + * The total number of groups that matches the filterBy criteria supplied in request, + * used to offset based pagination to compute the number of available pages. + */ + int32 total_number_of_groups = 2; +} + +/** + * Request to update a group. + * See GroupsService.UpdateGroupRequest for more information. + */ +message UpdateGroupRequest { + string group_id = 1; // The ID of the existing group. + repeated string contact_ids_to_add = 2; // The list of contact IDs to be added to the specified group. + repeated string contact_ids_to_remove = 3; // The list of contact IDs to be removed from the specified group. + string name = 4; // The new name for the group. +} + +/** + * Response after updating a group. + * See GroupsService.UpdateGroup to see possible errors. + */ +message UpdateGroupResponse {} + +/** + * Request to copy a group. + */ +message CopyGroupRequest { + string group_id = 1; // The ID of the existing group. + string name = 2; // The new name of the copied group. +} + +/** + * Response after copying a group. + * See GroupsService.CopyGroup to see possible errors. + */ +message CopyGroupResponse { + string group_id = 1; // The new group's ID. +} + +/** + * Request to delete a group. + */ +message DeleteGroupRequest { + string group_id = 1; // The ID of the existing group to delete. +} + +/** + * Response after deleting a group. + * See GroupsService.DeleteGroup to see possible errors. + */ +message DeleteGroupResponse {} + +/** + * Request to create a credential on the authenticated issuer. + * See CredentialsService.CreateGenericCredential for more information. + */ +message CreateGenericCredentialRequest { + /** + * The contact ID to link the credential to. + * Required if the external ID is not provided, it is ignored otherwise. + */ + string contact_id = 1; + /** + * The credential payload as a JSON string. + * A valid non-empty JSON is required. + */ + string credential_data = 2; + /** + * The ID provided by the issuer when the contact was created. If this timestamp is not provided, + * the contact ID is expected. + */ + string external_id = 4; + /** + * The ID (UUID) of the credential type used as a template for this credential. + */ + string credential_type_id = 5; +} + +/** + * Response when a credential is created. + * See CManagerGenericCredential, CredentialsService.CreateGenericCredential for more information. + */ +message CreateGenericCredentialResponse { + CManagerGenericCredential generic_credential = 1; // The credential details. +} + +/** + * The authenticated issuer is retrieving its issued credentials. + * The results are sorted in ascending order by creation date. Results with same creation date are sorted by their ID. + * See CredentialsService.GetGenericCredentials for more information. + */ +message GetGenericCredentialsRequest { + /** + * Optional, default value is 10. The maximum amount of credentials to return. + */ + int32 limit = 1; + + /** + * Removed lastSeenCredentialId field + */ + reserved 2; + reserved "lastSeenCredentialId"; + + /** + * Optional, default is 0. The offset for pagination. + */ + int32 offset = 3; + + /** + * When provided, filter the results based on the given criteria, just for the Management Console. + */ + FilterBy filter_by = 4; + /** + * Optional. When provided, it sorts the results by the given criteria (sorted by name in ascending order by default). + */ + SortBy sort_by = 5; + + /** + * The possible ways to filter the results from GetGenericCredentialsRequest. + */ + message FilterBy { + string credential_type = 1; // If provided, it returns the credentials containing the given type. + Date created_after = 2; // If provided, it returns credentials created at the given date or after. + Date created_before = 3; // If provided, it returns credentials created before or at the given date. + CredentialStatus credentialStatus = 4; // If provided credentials being in the status are returned + ContactConnectionStatus contactConnectionStatus = 5; // If provided credentials belonging to a contact with the status are returned + string contactExternalId = 6; // If provided credentials belonging to a contact with the external id are returned + string contactName = 7; // If provided credentials belonging to contact with a name containing the specified substring + } + + /** + * The possible ways to sort the results. + */ + message SortBy { + Field field = 1; // The field used to sort the results by. + SortByDirection direction = 2; // Sorts results in ascending/descending order (ascending by default). + + /** + * The possible fields to sort the results by. + */ + enum Field { + UNKNOWN = 0; // If the value is missing, we take the default one: NAME. + CREDENTIAL_TYPE = 1; // The credential type field. + CREATED_ON = 2; // The createdOn field. + EXTERNAL_ID = 3; // The external_id field. + CREDENTIAL_STATUS = 4; // The credential status. https://github.com/input-output-hk/atala-prism-management-console-web/blob/e23cfa606036ac718660730ac5dd38cd0028bf02/src/APIs/helpers/credentialHelpers.js#L22 + } + } +} + +/** + * Response with the credentials found. + */ +message GetGenericCredentialsResponse { + repeated CManagerGenericCredential credentials = 1; // The retrieved credentials. + int32 totalCount = 2; // Total number of credentials retrievable ignoring pagination. +} + +// @exclude TODO: Consider renaming this to MarkCredentialAsSent. +/** + * Request to share a credential, which just marks the credential as sent. + * This is intended to be invoked after sending the credential through the connector. + */ +message ShareCredentialRequest { + string cmanager_credential_id = 2; // cmanager internal credential ID. +} + +/** + * Response after sharing a credential. + */ +message ShareCredentialResponse {} + +/** + * Request to share many credentials, which sends credentials through the connector and marks them as sent. + * See CredentialsService.ShareCredentials for more information. + */ +message ShareCredentialsRequest { + /** + * Non-empty list of IDs of credentials that will be sent to the connector, and later marked as shared. + */ + repeated string credentials_ids = 1; + /** + * Request to connector containing messages with signed credentials. + */ + SendMessagesRequest send_messages_request = 2; + /** + * Metadata used to authenticate SendMessagesRequest to connector. + * Frontend must sign SendMessagesRequest that can be fetched. + * From GetShareCredentialsRequestToSign gRPC Management Console method and + * pass signed request through this message. + * All fields of this message are required. + */ + ConnectorRequestMetadata send_messages_request_metadata = 3; +} + +/** + * Response after sharing a credential. + */ +message ShareCredentialsResponse {} + +/** + * Request to get the credentials for the given contact. + * As the expected amount of credentials per contact is small, no pagination is required. + */ +message GetContactCredentialsRequest { + string contact_id = 1; // The contact identifier. +} + +/** + * Response with the contact credentials. + * See CManagerGenericCredential for more information. + */ +message GetContactCredentialsResponse { + repeated CManagerGenericCredential generic_credentials = 1; // The credentials found. + int32 totalCount = 2; // Total number of credentials found. +} + +/** + * Request to get blockchain-related information for a credential. + */ +message GetBlockchainDataRequest { + string encoded_signed_credential = 1; // Encoded credential we want to retrieve information for. +} + +/** + * Response with the information found in the blockchain. + * See TransactionInfo for more information. + */ +message GetBlockchainDataResponse { + TransactionInfo issuance_proof = 1; // Transaction information associated with the credential issuance event. +} + +/** + * Request to store a received credential. + * See CredentialsStoreService.StoreCredential for more information. + */ +message StoreCredentialRequest { + string connection_token = 1; // The connection token related to the connector message that carried the credential. + string encoded_signed_credential = 2; // The encoded signed data. + string credential_external_id = 3; // A credential's external id (currently, the ID of the connector message that carried it). + string batch_inclusion_proof = 4; // Inclusion proof associated to the encodedSignedCredential. +} + +/** + * Response after storing a received credential. + */ +message StoreCredentialResponse {} + +/** + * Request to find the received credentials. + */ +message GetStoredCredentialsForRequest { + // @exclude TODO: Rename to `contactId` after removing legacy methods. + string individual_id = 1; // Optional, allows to retrieve received credentials from a single contact. +} + +/** + * Response with the received credentials. + * See StoredSignedCredential for more information. + */ +message GetStoredCredentialsForResponse { + repeated StoredSignedCredential credentials = 1; // The received credentials. + int32 totalCount = 2; // Total number of received credentials. +} + +/** + * Request to find the latest credentialExternalId. + */ +message GetLatestCredentialExternalIdRequest {} + +/** + * Response with the latest credentialExternalId. + */ +message GetLatestCredentialExternalIdResponse { + string latest_credential_external_id = 1; // The identifier of the latest received credential. +} + +/** + * Request to publish a credential batch to the blockchain. + * See CredentialsService.PublishBatch, IssueCredentialBatch, SignedAtalaOperation for more information. + */ +message PublishBatchRequest { + SignedAtalaOperation issue_credential_batch_operation = 1; // A signed instance of IssueCredentialBatch operation. +} + +/** + * Response after publishing a batch. + * See CredentialsService.PublishBatch, PublishBatchRequest, TransactionInfo for more information. + */ +message PublishBatchResponse { + reserved 2; // Removed "transaction_info" field. + reserved "transaction_info"; + + string batch_id = 1; // The protocol assigned ID for the batch. + bytes operation_id = 3; // The internal identifier of the corresponding operation. +} + +/** + * Request to store a credential for which its batch has been published. + * See CredentialsService.StorePublishedCredential for more information. + */ +message StorePublishedCredentialRequest { + string encoded_signed_credential = 1; // The encoded credential to store. + string console_credential_id = 2; // Management Console internal credential ID. + string batch_id = 3; // The protocol ID associated with the batch that contains this credential. + string encoded_inclusion_proof = 4; // The Merkle proof of inclusion for the batch associated with the credential. +} + +/** + * Response after publishing a credential. + */ +message StorePublishedCredentialResponse {} + +/** + * Request to revoke a published credential. + * See CredentialsService.RevokePublishedCredential, RevokeCredentials, SignedAtalaOperation for more information. + */ +message RevokePublishedCredentialRequest { + /** + * The internal credential ID, used to link the revocation transaction ID. It must be an UUID. + */ + string credential_id = 1; + /** + * A signed instance of the RevokeCredentials operation. + * Note that even though the operation allows many credentials to be revoked, the request + * is only accepted when only a single credential involved. + */ + SignedAtalaOperation revoke_credentials_operation = 2; +} + +/** + * Response after revoking a credential. + * See CredentialsService.RevokePublishedCredential, TransactionInfo for more information. + */ +message RevokePublishedCredentialResponse { + reserved 1; // Removed "transaction_info" field. + reserved "transaction_info"; + + bytes operation_id = 2; // The internal identifier of the corresponding operation. +} + +/** + * Request to delete many credentials. + */ +message DeleteCredentialsRequest { + repeated string credentials_ids = 1; // IDs of credentials to delete (non-empty). +} + +/** + * Confirmation of credential deletion. + */ +message DeleteCredentialsResponse {} + +/** + * Requests ledger data for a specific batch and credential recorded by the node. + */ +message GetLedgerDataRequest { + /** + * The batchId (assigned by the protocol) that we want information to be returned for. + */ + string batch_id = 1; + /** + * Optional. The credential hash that we want information to be returned for. We assume that the credential + * was issued in the batch associated with `batchId`. + */ + bytes credential_hash = 2; +} + +/** + * Returns the ledger data from the node associated to a batch and credential. + * See CredentialsService.GetLedgerData and LedgerData for more information. + */ +message GetLedgerDataResponse { + LedgerData batch_issuance = 1; // If present, the ledger data associated with the issuance of the batch requested. + LedgerData batch_revocation = 2; // If present, the ledger data associated with the revocation of the batch requested. + LedgerData credential_revocation = 3; // If present, the ledger data associated with the revocation of the credential requested. +} + +/** + * Request to update participant's profile name and logo. + * See ConsoleService.UpdateParticipantProfile for more information. + */ +message ConsoleUpdateProfileRequest { + string name = 1; // The name of the issuer. Where applicable, it should be recognizable externally (e.g. full name of the university). + bytes logo = 2; // Optional. The logo linked to the issuer. If logo is missing, the field will be set to empty. +} + +/** + * Confirmation of participant's profile updated. + * See ConsoleService.UpdateParticipantProfile for more information. + */ +message ConsoleUpdateProfileResponse {} diff --git a/protosLib/src/main/proto/console_models.proto b/protosLib/src/main/proto/console_models.proto new file mode 100644 index 000000000..78923e2ad --- /dev/null +++ b/protosLib/src/main/proto/console_models.proto @@ -0,0 +1,244 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "common_models.proto"; +import "google/protobuf/timestamp.proto"; + +/** + * Indicates the status of the contact's connection. + */ +enum ContactConnectionStatus { + STATUS_MISSING = 0; // Default value, represents the lack of status. + // @exclude TODO remove after removing console functionality from connector + STATUS_INVITATION_MISSING = 1; // No connection token is generated yet, kept for compatibility with connector as the console backend generates the tokens while creating contacts. + STATUS_CONNECTION_MISSING = 2; // The contact has been invited and the connection token has been generated. + STATUS_CONNECTION_ACCEPTED = 3; // The contact accepted the connection. + STATUS_CONNECTION_REVOKED = 4; // The contact rejected the connection. +} + +/** + * Indicates the state of credential. + */ +enum CredentialStatus { + CREDENTIAL_STATUS_MISSING = 0; // Default value, represents the lack of status. + CREDENTIAL_DRAFT = 1; + CREDENTIAL_SIGNED = 2; + CREDENTIAL_SENT = 3; + CREDENTIAL_REVOKED = 4; +} + +/** + * Represents a contact. + */ +message Contact { + reserved 7; // Reserved createdAt_deprecated field + reserved "createdAt_deprecated"; + + string contact_id = 1; // The internal ID to identify the contact. + string external_id = 2; // The ID provided by the issuer when the contact was created. It is commonly used to match the issuer's record keeping system, for example, it could be the student ID for a university. + string json_data = 3; // Arbitrary data for the contact. Should be a valid JSON. If missing, "{}" will be used. + ContactConnectionStatus connection_status = 4; // The connection status for this contact. + string connection_token = 5; // The connection token used to get this contact connected, present when the status is ConnectionMissing. + string connection_id = 6; // The necessary connection ID to send messages to this contact, present when the status is ConnectionAccepted. + string name = 8; // The contact's name, only used by the Management Console. + google.protobuf.Timestamp created_at = 9; // The timestamp when the contact was created. +} + +/** + * Contains credential data and a list of groups for a contact. + */ +message CredentialIssuanceContact { + string contact_id = 1; // ID of the contact the credential data is about. + string credential_data = 2; // Actual credential data of the contact, in JSON format. + repeated string group_ids = 3; // IDs of the groups the contact was taken from, empty if added directly. +} + +/** + * Indicates the state of the credential type. + */ +enum CredentialTypeState { + CREDENTIAL_TYPE_UNKNOWN = 0; // Invalid value, should not happen. + CREDENTIAL_TYPE_DRAFT = 1; // The credential type is still being defined and is not final, it cannot be used to create a new credential. + CREDENTIAL_TYPE_READY = 2; // The credential type is ready to use, it can be used to create a new credential. + CREDENTIAL_TYPE_ARCHIVED = 3; // The credential type is archived, it cannot be used to create a new credential. +} + +/** + * Indicates the state of the credential type category. + */ +enum CredentialTypeCategoryState { + CREDENTIAL_TYPE_CATEGORY_DRAFT = 0; // The credential type category is still being defined and is not final, it cannot be used to create a new credential. + CREDENTIAL_TYPE_CATEGORY_READY = 1; // The credential type category is ready to use, it can be used to create a new credential. + CREDENTIAL_TYPE_CATEGORY_ARCHIVED = 2; // The credential type category is archived, it cannot be used to create a new credential. +} + +/** + * Indicates the data type of a field in the credential. + */ +enum CredentialTypeFieldType { + CREDENTIAL_TYPE_FIELD_UNKNOWN = 0; // Invalid value, should not happen. + CREDENTIAL_TYPE_FIELD_STRING = 1; // Any string. + CREDENTIAL_TYPE_FIELD_INT = 2; // Positive and negative integer numbers. + CREDENTIAL_TYPE_FIELD_BOOLEAN = 3; // True/False only. + CREDENTIAL_TYPE_FIELD_DATE = 4; // The date as string in DD/MM/YY or DD/MM/YYYY format. +} + +/** + * Describes the field in the credential type. + */ +message CredentialTypeField { + string id = 1; // UUID + string credential_type_id = 2; // Identifier of the credential template which uses this field. + string name = 3; // Field name. + string description = 4; // Field description. + CredentialTypeFieldType type = 5; // Type of the data for this field. +} + +/** + * Create new field for credential templates. + */ +message CreateCredentialTypeField { + string name = 1; // Field name. + string description = 2; // Field description. + CredentialTypeFieldType type = 3; // Type of the data for this field. +} + +/** + * Credential type entity. It represents the template for issuing new credentials. + */ +message CredentialType { + string id = 1; // UUID + string name = 2; // The credential type name. + CredentialTypeState state = 3; // The credential type state, can be: draft, ready, or archived. + string template = 4; // The credential type template, HTML with optional mustache syntax variables. + google.protobuf.Timestamp created_at = 5; // The timestamp when the credential type was created. + bytes icon = 6; // Optional. Icon of the credential type. +} + +/** + * Credential type entity needed to create a new record, all fields are required. + */ +message CreateCredentialType { + string name = 1; // The credential type name -required field. + string template = 2; // The credential type template, HTML with optional mustache syntax variables. + bytes icon = 3; // Optional. Icon of the credential type. + repeated CreateCredentialTypeField fields = 4; // List of the credential type fields. +} + +/** + * Credential type category entity needed to create a new record, all fields are required. + */ +message CreateCredentialTypeCategory { + string name = 1; + CredentialTypeCategoryState state = 2; +} + +/** + * Credential type category as represented in Database with all fields. + */ +message CredentialTypeCategory { + string id = 1; + string name = 2; + CredentialTypeCategoryState state = 3; + string institution_id = 4; +} + +/** + * Credential type entity needed for the update. + */ +message UpdateCredentialType { + string id = 1; // UUID (required). + string name = 2; // Optional. The credential type name. + string template = 3; // Optional. The credential type template. + bytes icon = 4; // Optional. The icon of the credential type. + repeated CreateCredentialTypeField fields = 5; // Optional. List of the credential type fields. If present, the fields will be overwritten. +} + +/** + * Credential type with required fields. + */ +message CredentialTypeWithRequiredFields { + CredentialType credential_type = 1; // Credential type. + repeated CredentialTypeField required_fields = 2; // List of the credential type fields. +} + +/** + * Represents a group that contacts can be assigned to. + * A group is generally used to collect the contacts related to the same issuance event, + * for a university, it can be a graduation group, for example. + */ +message Group { + reserved 3; // Removed createdAt_deprecated field + reserved "createdAt_deprecated"; + + string name = 1; // The group name. + string id = 2; // The unique ID for the group, generated by the server. + int32 number_of_contacts = 4; // The number of contacts associated with the group. + google.protobuf.Timestamp created_at = 5; // The time when the group was created. +} + +/** + * Represents all the details of the credential. + */ +message CManagerGenericCredential { + reserved 8; // Removed nodeCredentialId field + reserved "nodeCredentialId"; + reserved 11; // Removed publicationStoredAt_deprecated field + reserved "publicationStoredAt_deprecated"; + reserved 14; // Removed sharedAt_deprecated field + reserved "sharedAt_deprecated"; + reserved 15; // Removed issuance_proof field. + reserved "issuance_proof"; + reserved 18; // Removed revocation_proof field. + reserved "revocation_proof"; + + string credential_id = 1; // Credential identifier internal to the cmanager. + string issuer_id = 2; // Issuer identifier internal to the cmanager. + string contact_id = 3; // Contact identifier internal to cmanager. + string credential_data = 4; // The arbitrary JSON data involved in the credential (claims). + string issuer_name = 5; // The name of the issuer according to the cmanager internal data. + string contact_data = 7; // The arbitrary JSON data related to the contact. + + // @exclude The fields below will only be populated after the credential is published to the blockchain. + + bytes issuance_operation_hash = 9; // The hash of the associated issuance operation. + string encoded_signed_credential = 10; // The actual published credential. + string external_id = 12; // The ID provided by the issuer when the contact was created. + ContactConnectionStatus connection_status = 13; // Checks if a contact has accepted the connection request. + string batch_inclusion_proof = 16; // Inclusion proof that shows that encodedSignedCredential is a member of a batch. + string batch_id = 17; // The batch ID defined by protocol, representing the batch that contains the encodedSignedCredential. + google.protobuf.Timestamp publication_stored_at = 19; // The timestamp when the publication data was stored in the database. + google.protobuf.Timestamp shared_at = 20; // The last time the credential was sent to the related contact. + bytes revoked_on_operation_id = 21; // The operation where the credential was requested to be revoked (if any). + OperationStatus revoked_on_operation_status = 22; // The operation status when the credential was requested to be revoked (if any). +} + +/** + * Represents a received credential. + */ +message StoredSignedCredential { + reserved 3; // Removed storedAt_deprecated field + reserved "storedAt_deprecated"; + + // @exclude TODO: Rename to contactId. + string individual_id = 1; // The contact that sent the credential. + string encoded_signed_credential = 2; // The signed credential encoded as a string. + string external_id = 4; // The external ID associated with the contact that sent the credential. + string batch_inclusion_proof = 5; // The inclusion proof associated with the encodedSignedCredential. + google.protobuf.Timestamp stored_at = 6; // The timestamp when the credential was stored in the database. +} + +/** + * Metadata used to authenticate some request to the connector. + * All fields of this message are required. + */ +message ConnectorRequestMetadata { + string did = 1; // value of did + string did_key_id = 2; // id of did key + string did_signature = 3; // Base64-encoded signature of request and request nonce signed with the issuer's private key. + string request_nonce = 4; // Base64-encoded request nonce. +} diff --git a/protosLib/src/main/proto/credential_models.proto b/protosLib/src/main/proto/credential_models.proto new file mode 100644 index 000000000..4dda1f760 --- /dev/null +++ b/protosLib/src/main/proto/credential_models.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +import "common_models.proto"; +import "status.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/any.proto"; + +package io.iohk.atala.prism.protos; + + +message ProofRequest { + repeated string type_ids = 1; + string connection_token = 2; +} + +message EncryptedMessage { + // The identifier of the key used to encrypt the message. This might be empty if the receiver uses only one key. + string key_id = 1; + // Encrypted content of the message. After decryption, it should be deserialized as an AtalaMessage instance. + bytes encrypted_content = 2; +} + +// ATA-3250: Until we implement e2e encryption, we will share +// credentials using this message. +message PlainTextCredential { + string encoded_credential = 1; // The encoded and signed credential. + string encoded_merkle_proof = 2; // The encoded Merkle proof of inclusion associated with the encodedCredential. +} + +// Used to notify the apps that a credential was revoked. +message CredentialRevoked { + string encoded_credential = 1; // The encoded and signed credential. + string reason = 2; // An optional revocation reason, as provided by the issuer. +} + +message AtalaErrorMessage { + google.rpc.Status status = 1; +} + +message CredentialOwnershipVerificationRequest { + CredentialAndVerificationNonce credential_and_verification_nonce = 1; +} + +message CredentialOwnershipVerificationResponse { + bytes signature = 1; + bytes nonce = 2; +} + +message CredentialAndVerificationNonce { + string encoded_credential = 1; + bytes nonce = 2; +} + +message AtalaMessage { + oneof message { + CredentialOwnershipVerificationRequest credential_ownership_verification_request = 1; + CredentialOwnershipVerificationResponse credential_ownership_verification_response = 2; + ProofRequest proof_request = 3; + EncryptedMessage encrypted_message = 4; + PlainTextCredential plain_credential = 6; + CredentialRevoked credential_revoked = 8; + AtalaErrorMessage atala_error_message = 9; + google.protobuf.Any custom_message = 10; // variant to use for messages from external components, e.g. Mirror + } + reserved 5; //removed variant MirrorMessage mirror_message = 5; + reserved "mirror_message"; + reserved 7; // removed variant KycBridgeMessage kyc_bridge_message = 7; + reserved "kyc_bridge_message"; + + // Optional, if set, it's the id of an existing message from the same connection. + // It means that sent message is a reply to one of messages received by the sender. + string reply_to = 101; +} diff --git a/protosLib/src/main/proto/cviews_api.proto b/protosLib/src/main/proto/cviews_api.proto new file mode 100644 index 000000000..fcc221061 --- /dev/null +++ b/protosLib/src/main/proto/cviews_api.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "cviews_models.proto"; + +// The API for the credential views. +service CredentialViewsService { + // Gets the available view templates. + rpc GetCredentialViewTemplates (GetCredentialViewTemplatesRequest) returns (GetCredentialViewTemplatesResponse) {} +} + +// Request to get the available view templates. +message GetCredentialViewTemplatesRequest {} +// Response with the available view templates. +message GetCredentialViewTemplatesResponse { + repeated CredentialViewTemplate templates = 1; // the available templates +} diff --git a/protosLib/src/main/proto/cviews_models.proto b/protosLib/src/main/proto/cviews_models.proto new file mode 100644 index 000000000..7af8503e1 --- /dev/null +++ b/protosLib/src/main/proto/cviews_models.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +// Represents a credential template. +message CredentialViewTemplate { + int64 id = 1; // The unique ID for this template. + string name = 2; // The template's name. + string encoded_logo_image = 3; // Logo image encoded in base64 as a UTF-8 string. + string logo_image_mime_type = 4; // The MIME Type for the logo. + + // HTML view with replaceable variables enclosed by double brackets, e.g., "{{foo.bar}}" + string html_template = 5; +} diff --git a/protosLib/src/main/proto/health.proto b/protosLib/src/main/proto/health.proto new file mode 100644 index 000000000..53e6e0325 --- /dev/null +++ b/protosLib/src/main/proto/health.proto @@ -0,0 +1,63 @@ +// Copyright 2015 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// 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. + +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto + +syntax = "proto3"; + +package grpc.health.v1; + +option csharp_namespace = "Grpc.Health.V1"; +option go_package = "google.golang.org/grpc/health/grpc_health_v1"; +//option java_multiple_files = true; +//option java_outer_classname = "HealthProto"; +//option java_package = "io.grpc.health.v1"; + +message HealthCheckRequest { + string service = 1; +} + +message HealthCheckResponse { + enum ServingStatus { + UNKNOWN = 0; + SERVING = 1; + NOT_SERVING = 2; + SERVICE_UNKNOWN = 3; // Used only by the Watch method. + } + ServingStatus status = 1; +} + +service Health { + // If the requested service is unknown, the call will fail with status + // NOT_FOUND. + rpc Check(HealthCheckRequest) returns (HealthCheckResponse); + + // Performs a watch for the serving status of the requested service. + // The server will immediately send back a message indicating the current + // serving status. It will then subsequently send a new message whenever + // the service's serving status changes. + // + // If the requested service is unknown when the call is received, the + // server will send a message setting the serving status to + // SERVICE_UNKNOWN but will *not* terminate the call. If at some + // future point, the serving status of the service becomes known, the + // server will send a new message with the service's serving status. + // + // If the call terminates with status UNIMPLEMENTED, then clients + // should assume this method is not supported and should not retry the + // call. If the call terminates with any other status (including OK), + // clients should retry the call with appropriate exponential backoff. + rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); +} diff --git a/protosLib/src/main/proto/intdemo/intdemo_api.proto b/protosLib/src/main/proto/intdemo/intdemo_api.proto new file mode 100755 index 000000000..d47c248d9 --- /dev/null +++ b/protosLib/src/main/proto/intdemo/intdemo_api.proto @@ -0,0 +1,57 @@ +syntax = "proto3"; + +import "intdemo/intdemo_models.proto"; + +package io.iohk.atala.prism.intdemo.protos; + +// This service simulates an application run by a government body who use io.iohk.atala's connector. +service IDService { + rpc GetConnectionToken (GetConnectionTokenRequest) returns (GetConnectionTokenResponse) {} + rpc GetSubjectStatus (GetSubjectStatusRequest) returns (GetSubjectStatusResponse) {} + rpc GetSubjectStatusStream (GetSubjectStatusRequest) returns (stream GetSubjectStatusResponse) {} + rpc SetPersonalData (SetPersonalDataRequest) returns (SetPersonalDataResponse) {} +} + +// This service simulates an application run by a university who use io.iohk.atala's connector. +service DegreeService { + rpc GetConnectionToken (GetConnectionTokenRequest) returns (GetConnectionTokenResponse) {} + rpc GetSubjectStatus (GetSubjectStatusRequest) returns (GetSubjectStatusResponse) {} + rpc GetSubjectStatusStream (GetSubjectStatusRequest) returns (stream GetSubjectStatusResponse) {} +} + +// ... a company's application +service EmploymentService { + rpc GetConnectionToken (GetConnectionTokenRequest) returns (GetConnectionTokenResponse) {} + rpc GetSubjectStatus (GetSubjectStatusRequest) returns (GetSubjectStatusResponse) {} + rpc GetSubjectStatusStream (GetSubjectStatusRequest) returns (stream GetSubjectStatusResponse) {} +} + +// ... another company's application +service InsuranceService { + rpc GetConnectionToken (GetConnectionTokenRequest) returns (GetConnectionTokenResponse); + rpc GetSubjectStatus (GetSubjectStatusRequest) returns (GetSubjectStatusResponse) {} + rpc GetSubjectStatusStream (GetSubjectStatusRequest) returns (stream GetSubjectStatusResponse) {} +} + +message GetSubjectStatusRequest { + string connection_token = 1; +} + +message GetSubjectStatusResponse { + SubjectStatus subject_status = 1; +} + +message GetConnectionTokenRequest { +} + +message GetConnectionTokenResponse { + string connection_token = 1; +} + +message SetPersonalDataRequest { + string connection_token = 1; + string first_name = 2; + Date date_of_birth = 3; +} + +message SetPersonalDataResponse {} diff --git a/protosLib/src/main/proto/intdemo/intdemo_models.proto b/protosLib/src/main/proto/intdemo/intdemo_models.proto new file mode 100644 index 000000000..5901372fa --- /dev/null +++ b/protosLib/src/main/proto/intdemo/intdemo_models.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package io.iohk.atala.prism.intdemo.protos; + +message Date { + int32 year = 1; // positive value + int32 month = 2; // value in the [1, 12] interval + int32 day = 3; // value in the [1, 31] interval (depending on the month, the max value might be 28 +} + +enum SubjectStatus { + UNCONNECTED = 0; + CONNECTED = 1; + CREDENTIAL_AVAILABLE = 2; + CREDENTIAL_SENT = 3; + CREDENTIAL_RECEIVED = 4; +} diff --git a/protosLib/src/main/proto/node_api.proto b/protosLib/src/main/proto/node_api.proto new file mode 100644 index 000000000..69a1d9c69 --- /dev/null +++ b/protosLib/src/main/proto/node_api.proto @@ -0,0 +1,376 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "common_models.proto"; +import "node_models.proto"; + +import "google/protobuf/timestamp.proto"; + +/** + * Service for PRISM Node API. Provides a way to store, retrieve and update + * Decentralized identifiers (DIDs), and Credentials' commitments into/from the underlying blockchain. + */ +service NodeService { + /** + * PUBLIC + * + * Sends a request that can be used to check service health. + * All PRISM services expose an RPC that accepts this message as request. + */ + rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse) {} + + /** + * PUBLIC + * + * Retrieves a DID Document associated to a DID. + * + * Errors: + * - Invalid long form DID (INVALID_ARGUMENT) + * - DID format not supported (INVALID_ARGUMENT) + * - Invalid DID (INVALID_ARGUMENT) + * - Unknown DID (INVALID_ARGUMENT) + */ + rpc GetDidDocument(GetDidDocumentRequest) returns (GetDidDocumentResponse) {} + + /** + * PUBLIC + * + * Retrieves the Node version info. + */ + rpc GetNodeBuildInfo(GetNodeBuildInfoRequest) returns (GetNodeBuildInfoResponse) {} + + /** + * PUBLIC + * + * Retrieves the Node version info. + */ + rpc GetNodeNetworkProtocolInfo(GetNodeNetworkProtocolInfoRequest) returns (GetNodeNetworkProtocolInfoResponse) {} + + /** + * PUBLIC + * + * Finds the state for a given credential's batch. + * + * Errors: + * - Invalid batch id (INVALID_ARGUMENT) + * - Unknown batch id (INVALID_ARGUMENT) + */ + rpc GetBatchState(GetBatchStateRequest) returns (GetBatchStateResponse) {} + + /** + * PUBLIC + * + * Finds the time when a credential was revoked. + * + * Errors: + * - Invalid batch id (INVALID_ARGUMENT) + * - Unknown batch id (INVALID_ARGUMENT) + */ + rpc GetCredentialRevocationTime(GetCredentialRevocationTimeRequest) returns (GetCredentialRevocationTimeResponse) {} + + /** + * PUBLIC + * + * Retrieves the status of an operation. + */ + rpc GetOperationInfo(GetOperationInfoRequest) returns (GetOperationInfoResponse) {} + + /** + * PUBLIC + * + * Timestamp of the latest block processed by PRISM Node. + */ + rpc GetLastSyncedBlockTimestamp(GetLastSyncedBlockTimestampRequest) returns (GetLastSyncedBlockTimestampResponse) {} + + /** + * PUBLIC + * + * Schedules a list of operations for further publication. + */ + rpc ScheduleOperations(ScheduleOperationsRequest) returns (ScheduleOperationsResponse) {} +} + +service NodeExplorerService { + /** + * WHITELISTED_DID + * + * Return a list of scheduled but unconfirmed operations. + */ + rpc GetScheduledOperations(GetScheduledOperationsRequest) returns (GetScheduledOperationsResponse) {} + + /** + * WHITELISTED_DID + * + * Return a list of wallet transactions. + */ + rpc GetWalletTransactionsPaginated(GetWalletTransactionsRequest) returns (GetWalletTransactionsResponse) {} + + /** + * WHITELISTED_DID + * + * Return the Node Wallet Balance + */ + rpc GetWalletBalance(GetWalletBalanceRequest) returns (GetWalletBalanceResponse) {} + + /** + * WHITELISTED_DID + * + * Retrieves list of available metrics. + */ + rpc GetAvailableMetrics(GetAvailableMetricsRequest) returns (GetAvailableMetricsResponse) {} + + /** + * WHITELISTED_DID + * + * Get statistics + */ + rpc GetNodeStatistics(GetNodeStatisticsRequest) returns (GetNodeStatisticsResponse) {} +} + +/** + * Retrieve statistics from the Node. + */ +message GetNodeStatisticsRequest { + repeated string metrics = 1; +} + +/** + * Statistics from the Node. + */ +message GetNodeStatisticsResponse { + repeated double metrics = 1; +} + +/** + * Request to find metrics exposed by Node. + * See NodeService.GetAvailableMetrics for more information. + */ +message GetAvailableMetricsRequest {} + +/** + * Response with a list of metrics exposed by Node. + * See NodeService.GetAvailableMetrics for more information. + */ +message GetAvailableMetricsResponse { + repeated string metrics = 1; +} + +/** + * Request to find a DID Document. + * See NodeService.GetDidDocument for more information. + */ +message GetDidDocumentRequest { + string did = 1; // The DID. +} +/** + * Response to a DID Document query. + * See NodeService.GetDidDocument for more information. + */ +message GetDidDocumentResponse { + DIDData document = 1; // The DID Document. + google.protobuf.Timestamp last_synced_block_timestamp = 5; // Timestamp of the latest synchronized block. + bytes last_update_operation = 6; // The hash of the last did update operation. +} + +/** + * Request to get the Node version info. + * See NodeService.GetNodeBuildInfo for more information. + */ +message GetNodeBuildInfoRequest { +} +/** + * Response with the Node version info. + * See NodeService.GetNodeBuildInfo for more information. + */ +message GetNodeBuildInfoResponse { + reserved 4; + + string version = 1; // The actual version. + string scala_version = 2; // The Scala version used to compile the app. + string sbt_version = 3; // The SBT version used to compile the app. +} + +/** + * Request to get the Node version info. + * See NodeService.GetNodeBuildInfo for more information. + */ +message GetNodeNetworkProtocolInfoRequest { +} +/** + * Response with the Node Protocol version info. + * See NodeService.GetNodeProtocolVersionInfo for more information. + */ +message GetNodeNetworkProtocolInfoResponse { + ProtocolVersion supported_network_protocol_version = 5; // Network protocol version number supported by Node. + ProtocolVersion current_network_protocol_version = 6; // Current network protocol version number. +} + +/** + * Request to get the credential's batch state. + * See NodeService.GetBatchState for more information. + */ +message GetBatchStateRequest { + string batch_id = 1; // The batch ID. +} +/** + * Response with the credential's batch state. + * See NodeService.GetBatchState for more information. + */ +message GetBatchStateResponse { + /** + * DID suffix used to sign the IssueCredentialBatch operation. + */ + string issuer_did = 1; + + /** + * The Merkle root used for the IssueCredential operation. + */ + bytes merkle_root = 2; + + /** + * Underlying blockchain data that refers to the transaction that + * contains the IssueCredential operation associated with the credential. + */ + LedgerData publication_ledger_data = 3; + + /** + * Underlying blockchain data that refers to the transaction that + * contains the RevokeCredential operation associated with the credential. + * This is optional. + */ + LedgerData revocation_ledger_data = 4; + + /** + * Timestamp of the latest synchronized block. + */ + google.protobuf.Timestamp last_synced_block_timestamp = 5; + + /** + * The hash of the credential to query about. + */ + bytes issuance_hash = 6; +} + +/** + * Request to get the credential's revocation time. + * See NodeService.GetCredentialRevocationTime for more information. + */ +message GetCredentialRevocationTimeRequest { + string batch_id = 1; // The ID corresponding to the credential to query about. + bytes credential_hash = 2; // The hash of the credential to query about. +} +/** + * Response with the credential's revocation time. + * See NodeService.GetCredentialRevocationTime for more information. + */ +message GetCredentialRevocationTimeResponse { + LedgerData revocation_ledger_data = 1; // The ledger data when the credential was revoked. This is optional. + google.protobuf.Timestamp last_synced_block_timestamp = 2; // Timestamp of the latest synchronized block. +} + +/** + * Request to get the operation status. + * See NodeService.GetOperationInfo for more information. + */ +message GetOperationInfoRequest { + bytes operation_id = 1; // Operation identifier. The identifier is returned to the corresponding operation request. +} +/** + * Response with the current operation status. + * See NodeService.GetOperationInfo for more information. + */ +message GetOperationInfoResponse { + OperationStatus operation_status = 1; // Contains the status of this operation. + string transaction_id = 3; // Transaction identifier containing the operation. Presented only when operation was approved by the ledger. + google.protobuf.Timestamp last_synced_block_timestamp = 2; // Timestamp of the latest synchronized block. + string details = 4; // Contains additional information about the operation state. For example, error descriptions. Can be empty. +} + +/** + * Request to retrieve the timestamp of the latest synchronized (processed by PRISM Node) block. + * See NodeService.GetLastSyncedBlockTimestampRequest for more information. + */ +message GetLastSyncedBlockTimestampRequest { +} +/** + * Response with the timestamp of the latest synchronized (processed by PRISM Node) block. + * See NodeService.GetLastSyncedBlockTimestampResponse for more information. + */ +message GetLastSyncedBlockTimestampResponse { + /** + * Timestamp of the latest synchronized (processed by PRISM Node) block. + */ + google.protobuf.Timestamp last_synced_block_timestamp = 1; +} + +/** + * Request to retrieve transaction info and operations outputs. + */ +message ScheduleOperationsRequest { + /** + * List of signed operations to apply. The operations will be applied in the order specified here. + */ + repeated SignedAtalaOperation signed_operations = 1; // a list of signed operations +} + +/** + * Response with the transaction info and operations outputs. + */ +message ScheduleOperationsResponse { + /** + * The responses for scheduled operations, ordered the same as the operations sent in ScheduleOperationsRequest. + */ + repeated OperationOutput outputs = 1; +} + +/** + * Request to retrieve all scheduled but not confirmed Atala operations. + */ +message GetScheduledOperationsRequest { + /** + * Operations of which type should be returned. + */ + OperationType operationsType = 1; + + enum OperationType { + AnyOperationType = 0; // Any operation + CreateDidOperationOperationType = 1; + UpdateDidOperationOperationType = 2; + IssueCredentialBatchOperationType = 3; + RevokeCredentialsOperationType = 4; + ProtocolVersionUpdateOperationType = 5; + } +} + +message GetScheduledOperationsResponse { + repeated SignedAtalaOperation scheduled_operations = 1; // a list of scheduled operations +} + +/** + * Request to retrieve wallet transactions, either ongoing or confirmed. + * Pagination included. + */ +message GetWalletTransactionsRequest { + TransactionState state = 1; // Transaction state: either ongoing or confirmed + string last_seen_transaction_id = 2; // Last seen transaction id + int32 limit = 3; // The maximum number of transactions to return; must be greater than 0. + + enum TransactionState { + Ongoing = 0; // Transactions which hasn't been confirmed by Prism Node + Confirmed = 1; // Transactions which ahs been confirmed by Prism Node + } +} + +message GetWalletTransactionsResponse { + repeated TransactionInfo transactions = 1; +} + +message GetWalletBalanceRequest { +} +message GetWalletBalanceResponse { + bytes balance = 1; +} diff --git a/protosLib/src/main/proto/node_internal.proto b/protosLib/src/main/proto/node_internal.proto new file mode 100644 index 000000000..167a08fe7 --- /dev/null +++ b/protosLib/src/main/proto/node_internal.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +import "node_models.proto"; + +package io.iohk.atala.prism.protos; + +/** + * Represent a block that holds operations. + * @exclude Intended for internal usage inside. Not publicly accessible from gRPC. + */ +message AtalaBlock { + reserved 1; // Represents the version of the block. Deprecated + repeated SignedAtalaOperation operations = 2; // A signed operation, necessary to post anything on the blockchain. +} + +/** + * Wraps an AtalaBlock and its metadata. + * @exclude Intended for internal usage inside. Not publicly accessible from gRPC. + */ +message AtalaObject { + reserved 1; // Removed block_hash field. + reserved "block_hash"; + + int32 block_operation_count = 2; // Number of operations in the block. + int32 block_byte_length = 3; // Byte length of the block. + AtalaBlock block_content = 4; // The block content. +} diff --git a/protosLib/src/main/proto/node_models.proto b/protosLib/src/main/proto/node_models.proto new file mode 100644 index 000000000..816b6d527 --- /dev/null +++ b/protosLib/src/main/proto/node_models.proto @@ -0,0 +1,247 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.iohk.atala.prism.protos"; + +package io.iohk.atala.prism.protos; + +import "common_models.proto"; +import "google/protobuf/timestamp.proto"; + +// Includes timestamping details about a blockchain's block. +message TimestampInfo { + reserved 1; // Removed blockTimestamp_deprecated field + reserved "blockTimestamp_deprecated"; + + uint32 block_sequence_number = 2; // The transaction index inside the underlying block. + uint32 operation_sequence_number = 3; // The operation index inside the AtalaBlock. + google.protobuf.Timestamp block_timestamp = 4; // The timestamp provided from the underlying blockchain. +} + +// Every key has a single purpose: +enum KeyUsage { + // UNKNOWN_KEY is an invalid value - Protobuf uses 0 if no value is provided and we want the user to explicitly choose the usage. + UNKNOWN_KEY = 0; + + // This is the most privileged key-type, when any other key is lost, you could use this to recover the others. + MASTER_KEY = 1; + + // This key-type is used for issuing credentials only, it should be kept in a safe place + // to avoid malicious credentials being issued. + ISSUING_KEY = 2; + + // This key-type is used for end-to-end encrypted communication, whoever wants to send a message should + // use this key-type to encrypt the content. + COMMUNICATION_KEY = 3; + + // This key-type is used to authenticate requests or logging into services. + AUTHENTICATION_KEY = 4; + + // This key-type is used for revoking credentials only, it should be kept in a safe place + // to avoid malicious credentials being issued. + REVOCATION_KEY = 5; +} + +/** + * Holds the necessary data to recover an Elliptic Curve (EC)'s public key. + * @exclude TODO: Consider renaming this to ECPublicKeyData. + */ +message ECKeyData { + string curve = 1; // The curve name, like secp256k1. + bytes x = 2; // The x coordinate, represented as bytes. + bytes y = 3; // The y coordinate, represented as bytes. +} + +/** + * Holds the compressed representation of data needed to recover Elliptic Curve (EC)'s public key. + * @exclude TODO: Consider renaming this to CompressedECPublicKeyData. + */ +message CompressedECKeyData { + string curve = 1; // The curve name, like secp256k1. + bytes data = 2; // compressed Elliptic Curve (EC) public key data. +} + +/** + * Represents a public key with metadata, necessary for a DID document. + * @exclude TODO: Consider renaming this to something more specific, like DIDPublicKey. + */ +message PublicKey { + reserved 3, 4; + string id = 1; // The key identifier within the DID Document. + KeyUsage usage = 2; // The key's purpose. + LedgerData added_on = 5; // The ledger details related to the event that added the key to the DID Document. + LedgerData revoked_on = 6; // The ledger details related to the event that revoked the key to the DID Document. + + // The key's representation. + oneof key_data { + ECKeyData ec_key_data = 8; // The Elliptic Curve (EC) key. + CompressedECKeyData compressed_ec_key_data = 9; // Compressed Elliptic Curve (EC) key. + }; +} + +// The DID Document's data. +message DIDData { + string id = 1; // The DID suffix, where DID is in form did:prism:[DID suffix] + repeated PublicKey public_keys = 2; // The keys that belong to this DID Document. +} + +// The operation to create a public DID. +message CreateDIDOperation { + DIDCreationData did_data = 1; // DIDCreationData with public keys + + // The data necessary to create a DID. + message DIDCreationData { + reserved 1; // Removed DID id field which is empty on creation + repeated PublicKey public_keys = 2; // The keys that belong to this DID Document. + } +} + +// The necessary data to add a key to a DID. +message AddKeyAction { + PublicKey key = 1; // The key to include. +} + +// The necessary data to remove a key from a DID. +message RemoveKeyAction { + string keyId = 1; // the key id to remove +} + +// The potential details that can be updated in a DID. +message UpdateDIDAction { + + // The action to perform. + oneof action { + AddKeyAction add_key = 1; // Used to add a new key to the DID. + RemoveKeyAction remove_key = 2; // Used to remove a key from the DID. + } +} + +// Specifies the necessary data to update a public DID. +message UpdateDIDOperation { + bytes previous_operation_hash = 1; // The hash of the operation that issued the DID. + string id = 2; // @exclude TODO: To be redefined after we start using this operation. + repeated UpdateDIDAction actions = 3; // The actual updates to perform on the DID. +} + +// Represents a credential's batch. +// +// Check the protocol docs to understand it. +message CredentialBatchData { + string issuer_did = 1; // The DID suffix that issues the credential's batch. + bytes merkle_root = 2; // The Merkle root for the credential's batch. +} + +// Specifies the data to issue a credential batch. +message IssueCredentialBatchOperation { + CredentialBatchData credential_batch_data = 1; // The actual credential batch data. +} + +// Specifies the credentials to revoke (the whole batch, or just a subset of it). +message RevokeCredentialsOperation { + bytes previous_operation_hash = 1; // The hash of the operation that issued the batch. + string credential_batch_id = 2; // The corresponding batch ID, as returned in IssueCredentialBatchResponse. + repeated bytes credentials_to_revoke = 3; // The hashes of the credentials to revoke. If empty, the full batch is revoked. +} + +// Specifies the protocol version update +message ProtocolVersionUpdateOperation { + string proposer_did = 1; // The DID suffix that proposes the protocol update. + ProtocolVersionInfo version = 2; // Information of the new version +} + + +message ProtocolVersion { + // Represent the major version + int32 major_version = 1; + // Represent the minor version + int32 minor_version = 2; +} + +message ProtocolVersionInfo { + reserved 2, 3; + string version_name = 1; // (optional) name of the version + int32 effective_since = 4; // Cardano block number that tells since which block the update is enforced + + // New major and minor version to be announced, + // If major value changes, the node MUST stop issuing and reading operations, and upgrade before `effective_since` because the new protocol version. + // If minor value changes, the node can opt to not update. All events _published_ by this node would be also + // understood by other nodes with the same major version. However, there may be new events that this node won't _read_ + ProtocolVersion protocol_version = 5; +} + +message DeactivateDIDOperation { + bytes previous_operation_hash = 1; // The hash of the operation that issued the DID. + string id = 2; // DID Suffix of the DID to be deactivated +} + +// The possible operations affecting the blockchain. +message AtalaOperation { + // The actual operation. + oneof operation { + // Used to create a public DID. + CreateDIDOperation create_did = 1; + + // Used to update an existing public DID. + UpdateDIDOperation update_did = 2; + + // Used to issue a batch of credentials. + IssueCredentialBatchOperation issue_credential_batch = 3; + + // Used to revoke a credential batch. + RevokeCredentialsOperation revoke_credentials = 4; + + // Used to announce new protocol update + ProtocolVersionUpdateOperation protocol_version_update = 5; + + // Used to deactivate DID + DeactivateDIDOperation deactivate_did = 6; + }; +} + +// A signed operation, necessary to post anything on the blockchain. +message SignedAtalaOperation { + string signed_with = 1; // The key ID used to sign the operation, it must belong to the DID that signs the operation. + bytes signature = 2; // The actual signature. + AtalaOperation operation = 3; // The operation that was signed. +} + +// Ledger data associated to a protocol event. +// Note that the difference with TransactionInfo is that this message contains a full +// timestamp, and there is no expectation for it to be optional. +message LedgerData { + string transaction_id = 1; // ID of the transaction. + Ledger ledger = 2; // Ledger the transaction was published to. + TimestampInfo timestamp_info = 3; // The timestamp of the protocol event. +} + +// Used to encode the responses of the operations issued in an AtalaBlock. +message OperationOutput { + oneof result { + // Represents the response provided by IssueCredentialBatchOperation. + IssueCredentialBatchOutput batch_output = 1; + // Represents the response provided by CreateDIDOperation. + CreateDIDOutput create_did_output = 2; + // Represents the response provided by UpdateDIDOperation. + UpdateDIDOutput update_did_output = 3; + // Represents the response provided by RevokeCredentialOperation. + RevokeCredentialsOutput revoke_credentials_output = 4; + // Represents the response provided by ProtocolVersionUpdateOperation. + ProtocolVersionUpdateOutput protocol_version_update_output = 7; + DeactivateDIDOutput deactivate_did_output = 8; + } + oneof operation_maybe { + bytes operation_id = 5; // Operation identifier. + string error = 6; // Error description if PRISM Node service haven't scheduled the operation. + } +} + +message IssueCredentialBatchOutput { + string batch_id = 1; +} +message CreateDIDOutput { + string did_suffix = 1; +} +message UpdateDIDOutput {} +message RevokeCredentialsOutput {} +message ProtocolVersionUpdateOutput {} +message DeactivateDIDOutput {} diff --git a/protosLib/src/main/proto/package.json b/protosLib/src/main/proto/package.json new file mode 100644 index 000000000..36afdf83f --- /dev/null +++ b/protosLib/src/main/proto/package.json @@ -0,0 +1,10 @@ +{ + "name": "@input-output-hk/atala-prism-protos", + "version": "VERSION", + "description": "raw proto files for Atala PRISM project", + "repository": { + "type": "git", + "url": "git+https://github.com/input-output-hk/atala-prism-sdk.git" + }, + "author": "input-output-hk" +} diff --git a/protosLib/src/main/proto/resources/markdown.tmpl b/protosLib/src/main/proto/resources/markdown.tmpl new file mode 100644 index 000000000..056eb47f7 --- /dev/null +++ b/protosLib/src/main/proto/resources/markdown.tmpl @@ -0,0 +1,95 @@ +# gRPC API Reference + + +## Table of Contents +{{range .Files}} +{{$file_name := .Name}}- [{{.Name}}](#{{.Name}}) + {{- if .Messages }} + {{range .Messages}} - [{{.LongName}}](#{{.FullName}}) + {{end}} + {{- end -}} + {{- if .Enums }} + {{range .Enums}} - [{{.LongName}}](#{{.FullName}}) + {{end}} + {{- end -}} + {{- if .Extensions }} + {{range .Extensions}} - [File-level Extensions](#{{$file_name}}-extensions) + {{end}} + {{- end -}} + {{- if .Services }} + {{range .Services}} - [{{.Name}}](#{{.FullName}}) + {{end}} + {{- end -}} +{{end}} + +{{range .Files}} +{{$file_name := .Name}} + +

Top

+ +## {{.Name}} +{{.Description}} + +{{range .Messages}} + + +### {{.LongName}} +{{.Description}} + +{{if .HasFields}} +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +{{range .Fields -}} + | {{.Name}} | [{{.LongType}}](#{{.FullType}}) | {{.Label}} | {{if (index .Options "deprecated"|default false)}}**Deprecated.** {{end}}{{.Description | replace "\n" "
"}}{{if .DefaultValue}} Default: {{.DefaultValue}}{{end}} | +{{end}} +{{end}} + +{{if .HasExtensions}} +| Extension | Type | Base | Number | Description | +| --------- | ---- | ---- | ------ | ----------- | +{{range .Extensions -}} + | {{.Name}} | {{.LongType}} | {{.ContainingLongType}} | {{.Number}} | {{.Description | replace "\n" "
"}}{{if .DefaultValue}} Default: {{.DefaultValue}}{{end}} | +{{end}} +{{end}} + +{{end}} + +{{range .Enums}} + + +### {{.LongName}} +{{.Description}} + +| Name | Number | Description | +| ---- | ------ | ----------- | +{{range .Values -}} + | {{.Name}} | {{.Number}} | {{.Description | replace "\n" "
"}} | +{{end}} + +{{end}} + +{{if .HasExtensions}} + + +### File-level Extensions +| Extension | Type | Base | Number | Description | +| --------- | ---- | ---- | ------ | ----------- | +{{range .Extensions -}} + | {{.Name}} | {{.LongType}} | {{.ContainingLongType}} | {{.Number}} | {{.Description | replace "\n" "
"}}{{if .DefaultValue}} Default: `{{.DefaultValue}}`{{end}} | +{{end}} +{{end}} + +{{range .Services}} + + +### {{.Name}} +{{.Description}} + +| Method Name | Request Type | Response Type | Description | +| ----------- | ------------ | ------------- | ------------| +{{range .Methods -}} + | {{.Name}} | [{{.RequestLongType}}](#{{.RequestFullType}}){{if .RequestStreaming}} stream{{end}} | [{{.ResponseLongType}}](#{{.ResponseFullType}}){{if .ResponseStreaming}} stream{{end}} | {{.Description | replace "\n" "
"}} | +{{end}} +{{end}} + +{{end}} diff --git a/protosLib/src/main/proto/status.proto b/protosLib/src/main/proto/status.proto new file mode 100644 index 000000000..5bd51aa2f --- /dev/null +++ b/protosLib/src/main/proto/status.proto @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// 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. + +syntax = "proto3"; + +package google.rpc; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; +option java_multiple_files = true; +option java_outer_classname = "StatusProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The `Status` type defines a logical error model that is suitable for +// different programming environments, including REST APIs and RPC APIs. It is +// used by [gRPC](https://github.com/grpc). Each `Status` message contains +// three pieces of data: error code, error message, and error details. +// +// You can find out more about this error model and how to work with it in the +// [API Design Guide](https://cloud.google.com/apis/design/errors). +message Status { + // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + int32 code = 1; + + // A developer-facing error message, which should be in English. Any + // user-facing error message should be localized and sent in the + // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + string message = 2; + + // A list of messages that carry the error details. There is a common set of + // message types for APIs to use. + repeated google.protobuf.Any details = 3; +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 58a851af1..5a34bfbef 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,11 +1,47 @@ pluginManagement { repositories { + gradlePluginPortal() + mavenCentral() google() + } + resolutionStrategy { + eachPlugin { + when (requested.id.id) { + "binary-compatibility-validator" -> { + useModule("org.jetbrains.kotlinx:binary-compatibility-validator:${requested.version}") + } + "com.android.application", "com.android.library" -> { + useModule("com.android.tools.build:gradle:${requested.version}") + } + } + } + } +} + +buildscript { + repositories { gradlePluginPortal() mavenCentral() + mavenLocal() + google() + maven("https://plugins.gradle.org/m2/") + // Needed for Kotlin coroutines that support new memory management mode + maven { + url = uri("https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven") + } + } + + dependencies { + classpath("io.arrow-kt:arrow-ank-gradle:0.11.0") } } + rootProject.name = "wallet-sdk" +include(":protosLib") + include(":wallet-sdk") -include(":core-sdk") \ No newline at end of file +include(":core-sdk") +include(":authenticate-sdk") +include(":prism-crypto") + diff --git a/wallet-sdk/build.gradle.kts b/wallet-sdk/build.gradle.kts index 3f005f369..2ab1cacf4 100644 --- a/wallet-sdk/build.gradle.kts +++ b/wallet-sdk/build.gradle.kts @@ -3,7 +3,7 @@ import org.jetbrains.dokka.gradle.DokkaTask import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target version = rootProject.version -val currentModuleName: String = "core-sdk" +val currentModuleName: String = "core_sdk" val os: OperatingSystem = OperatingSystem.current() plugins { diff --git a/wallet-sdk/src/androidMain/AndroidManifest.xml b/wallet-sdk/src/androidMain/AndroidManifest.xml new file mode 100644 index 000000000..1bef8c601 --- /dev/null +++ b/wallet-sdk/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/wallet-sdk/wallet_sdk.podspec b/wallet-sdk/wallet_sdk.podspec index 61422b876..43d0bbab5 100644 --- a/wallet-sdk/wallet_sdk.podspec +++ b/wallet-sdk/wallet_sdk.podspec @@ -6,7 +6,7 @@ Pod::Spec.new do |spec| spec.authors = 'IOG' spec.license = '' spec.summary = 'Wallet-SDK - DIDComm V2 operation' - spec.vendored_frameworks = 'build/cocoapods/framework/core-sdk.framework' + spec.vendored_frameworks = 'build/cocoapods/framework/core_sdk.framework' spec.libraries = 'c++' spec.ios.deployment_target = '13.0' spec.osx.deployment_target = '12.0' @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':wallet-sdk', - 'PRODUCT_MODULE_NAME' => 'core-sdk', + 'PRODUCT_MODULE_NAME' => 'core_sdk', } spec.script_phases = [ From 68243de91abb72cb6e90c3dfb6eed6fe06608a95 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Mon, 14 Nov 2022 12:49:09 +0400 Subject: [PATCH 08/21] enhancement: code & structure WIP: - Remove buildSrc module - Fix protosbuf and provide an implementation ready --- authenticate-sdk/build.gradle.kts | 3 +- .../src/androidMain/AndroidManifest.xml | 2 +- .../prism/authenticatesdk}/authenticate.kt | 2 ++ .../prism/authenticatesdk}/createChallenge.kt | 2 +- .../authenticate.kt | 2 ++ .../createChallenge.kt | 2 ++ .../src/jsMain/kotlin/JSExport.kt | 14 +++++++++ .../authenticate.kt | 3 +- .../createChallenge.kt | 2 ++ .../prism/authenticatesdk}/authenticate.kt | 2 ++ .../prism/authenticatesdk}/createChallenge.kt | 2 ++ build.gradle.kts | 30 +++++++------------ gradle.properties | 2 +- settings.gradle.kts | 14 --------- 14 files changed, 43 insertions(+), 39 deletions(-) rename authenticate-sdk/src/androidMain/kotlin/{ => io/iohk/atala/prism/authenticatesdk}/authenticate.kt (70%) rename authenticate-sdk/src/{jsMain/kotlin => androidMain/kotlin/io/iohk/atala/prism/authenticatesdk}/createChallenge.kt (63%) rename authenticate-sdk/src/commonMain/kotlin/{ => io.iohk.atala.prism.authenticatesdk}/authenticate.kt (65%) rename authenticate-sdk/src/commonMain/kotlin/{ => io.iohk.atala.prism.authenticatesdk}/createChallenge.kt (53%) create mode 100644 authenticate-sdk/src/jsMain/kotlin/JSExport.kt rename authenticate-sdk/src/jsMain/kotlin/{ => io.iohk.atala.prism.authenticatesdk}/authenticate.kt (70%) rename authenticate-sdk/src/{jvmMain/kotlin => jsMain/kotlin/io.iohk.atala.prism.authenticatesdk}/createChallenge.kt (62%) rename authenticate-sdk/src/jvmMain/kotlin/{ => io/iohk/atala/prism/authenticatesdk}/authenticate.kt (70%) rename authenticate-sdk/src/{androidMain/kotlin => jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk}/createChallenge.kt (62%) diff --git a/authenticate-sdk/build.gradle.kts b/authenticate-sdk/build.gradle.kts index 805e27478..28be753ff 100644 --- a/authenticate-sdk/build.gradle.kts +++ b/authenticate-sdk/build.gradle.kts @@ -62,7 +62,6 @@ kotlin { } } - sourceSets { val commonMain by getting { dependencies { @@ -127,7 +126,7 @@ tasks.withType { moduleName.set(project.name) moduleVersion.set(rootProject.version.toString()) description = """ - This is a Kotlin Multiplatform Wallet-SDK Library + This is a Kotlin Multiplatform Authenticate-SDK Library """.trimIndent() dokkaSourceSets { // TODO: Figure out how to include files to the documentations diff --git a/authenticate-sdk/src/androidMain/AndroidManifest.xml b/authenticate-sdk/src/androidMain/AndroidManifest.xml index 7e4dcbacb..ad65b7668 100644 --- a/authenticate-sdk/src/androidMain/AndroidManifest.xml +++ b/authenticate-sdk/src/androidMain/AndroidManifest.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/authenticate-sdk/src/androidMain/kotlin/authenticate.kt b/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt similarity index 70% rename from authenticate-sdk/src/androidMain/kotlin/authenticate.kt rename to authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt index 1960c88f9..e91976812 100644 --- a/authenticate-sdk/src/androidMain/kotlin/authenticate.kt +++ b/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt @@ -1,3 +1,5 @@ +package io.iohk.atala.prism.authenticatesdk + actual fun authenticate(did: String, signature: String, originalText: String):String { return "hola"; } diff --git a/authenticate-sdk/src/jsMain/kotlin/createChallenge.kt b/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt similarity index 63% rename from authenticate-sdk/src/jsMain/kotlin/createChallenge.kt rename to authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt index e83348369..7802f7cf6 100644 --- a/authenticate-sdk/src/jsMain/kotlin/createChallenge.kt +++ b/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt @@ -1,5 +1,5 @@ +package io.iohk.atala.prism.authenticatesdk -@JsExport actual fun createChallenge(expiration: Int): String { return "hola"; } \ No newline at end of file diff --git a/authenticate-sdk/src/commonMain/kotlin/authenticate.kt b/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt similarity index 65% rename from authenticate-sdk/src/commonMain/kotlin/authenticate.kt rename to authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt index 01b6b0481..3231656cb 100644 --- a/authenticate-sdk/src/commonMain/kotlin/authenticate.kt +++ b/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt @@ -1 +1,3 @@ +package io.iohk.atala.prism.authenticatesdk + expect fun authenticate(did: String, signature: String, originalText: String):String diff --git a/authenticate-sdk/src/commonMain/kotlin/createChallenge.kt b/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt similarity index 53% rename from authenticate-sdk/src/commonMain/kotlin/createChallenge.kt rename to authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt index 4c268ae48..987bd3a03 100644 --- a/authenticate-sdk/src/commonMain/kotlin/createChallenge.kt +++ b/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt @@ -1 +1,3 @@ +package io.iohk.atala.prism.authenticatesdk + expect fun createChallenge(expiration: Int): String \ No newline at end of file diff --git a/authenticate-sdk/src/jsMain/kotlin/JSExport.kt b/authenticate-sdk/src/jsMain/kotlin/JSExport.kt new file mode 100644 index 000000000..837497342 --- /dev/null +++ b/authenticate-sdk/src/jsMain/kotlin/JSExport.kt @@ -0,0 +1,14 @@ +import io.iohk.atala.prism.authenticatesdk.authenticate +import io.iohk.atala.prism.authenticatesdk.createChallenge + +@JsExport +@JsName("authenticate") +fun jsAuthenticate(did: String, signature: String, originalText: String): String { + return authenticate(did, signature, originalText) +} + +@JsExport +@JsName("createChallenge") +fun jsCreateChallenge(expiration: Int): String { + return createChallenge(expiration) +} \ No newline at end of file diff --git a/authenticate-sdk/src/jsMain/kotlin/authenticate.kt b/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt similarity index 70% rename from authenticate-sdk/src/jsMain/kotlin/authenticate.kt rename to authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt index 8d89e415c..e91976812 100644 --- a/authenticate-sdk/src/jsMain/kotlin/authenticate.kt +++ b/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt @@ -1,4 +1,5 @@ -@JsExport +package io.iohk.atala.prism.authenticatesdk + actual fun authenticate(did: String, signature: String, originalText: String):String { return "hola"; } diff --git a/authenticate-sdk/src/jvmMain/kotlin/createChallenge.kt b/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt similarity index 62% rename from authenticate-sdk/src/jvmMain/kotlin/createChallenge.kt rename to authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt index 2eab196d8..7802f7cf6 100644 --- a/authenticate-sdk/src/jvmMain/kotlin/createChallenge.kt +++ b/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt @@ -1,3 +1,5 @@ +package io.iohk.atala.prism.authenticatesdk + actual fun createChallenge(expiration: Int): String { return "hola"; } \ No newline at end of file diff --git a/authenticate-sdk/src/jvmMain/kotlin/authenticate.kt b/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt similarity index 70% rename from authenticate-sdk/src/jvmMain/kotlin/authenticate.kt rename to authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt index 1960c88f9..e91976812 100644 --- a/authenticate-sdk/src/jvmMain/kotlin/authenticate.kt +++ b/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt @@ -1,3 +1,5 @@ +package io.iohk.atala.prism.authenticatesdk + actual fun authenticate(did: String, signature: String, originalText: String):String { return "hola"; } diff --git a/authenticate-sdk/src/androidMain/kotlin/createChallenge.kt b/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt similarity index 62% rename from authenticate-sdk/src/androidMain/kotlin/createChallenge.kt rename to authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt index 2eab196d8..7802f7cf6 100644 --- a/authenticate-sdk/src/androidMain/kotlin/createChallenge.kt +++ b/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt @@ -1,3 +1,5 @@ +package io.iohk.atala.prism.authenticatesdk + actual fun createChallenge(expiration: Int): String { return "hola"; } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 668844023..d201c2d62 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,26 +1,18 @@ import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) - vendor.set(JvmVendorSpec.ADOPTOPENJDK) - } -} - plugins { - java - kotlin(Plugins.multiplatform) version PluginVersions.multiplatform apply false - kotlin(Plugins.serialization) version PluginVersions.multiplatform apply false - id(Plugins.protobuf) version PluginVersions.protobuf apply false - id(Plugins.npmPublish) version PluginVersions.npmPublish apply false - id(Plugins.gitVersion) version PluginVersions.gitVersion - id(Plugins.klint) version PluginVersions.klint - id(Plugins.compatibilityValidator) version PluginVersions.compatibilityValidator - id(Plugins.gitOps) version PluginVersions.gitOps - id(Plugins.koverage) version PluginVersions.koverage - id(Plugins.dokka) version PluginVersions.dokka - `maven-publish` + kotlin("jvm") version "1.7.20" + kotlin("plugin.serialization") version "1.7.20" + id("maven-publish") + id("org.jlleitschuh.gradle.ktlint") version "11.0.0" + id("org.jetbrains.dokka") version "1.7.10" + id("com.google.protobuf") version "0.9.1" + // id(Plugins.npmPublish) version PluginVersions.npmPublish apply false + // id(Plugins.gitVersion) version PluginVersions.gitVersion + // id(Plugins.compatibilityValidator) version PluginVersions.compatibilityValidator + // id(Plugins.gitOps) version PluginVersions.gitOps + // id(Plugins.koverage) version PluginVersions.koverage } buildscript { diff --git a/gradle.properties b/gradle.properties index d859a10f8..e8a33f968 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,4 +11,4 @@ android.useAndroidX=true # kotlin.mpp.enableGranularSourceSetsMetadata=true # kotlin.native.enableDependencyPropagation=false kotlin.mpp.enableCInteropCommonization=true -kotlin.native.cacheKind.iosSimulatorArm64=none \ No newline at end of file +kotlin.native.cacheKind.iosSimulatorArm64=none diff --git a/settings.gradle.kts b/settings.gradle.kts index 5a34bfbef..db8bbd605 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,18 +4,6 @@ pluginManagement { mavenCentral() google() } - resolutionStrategy { - eachPlugin { - when (requested.id.id) { - "binary-compatibility-validator" -> { - useModule("org.jetbrains.kotlinx:binary-compatibility-validator:${requested.version}") - } - "com.android.application", "com.android.library" -> { - useModule("com.android.tools.build:gradle:${requested.version}") - } - } - } - } } buildscript { @@ -39,9 +27,7 @@ buildscript { rootProject.name = "wallet-sdk" include(":protosLib") - include(":wallet-sdk") include(":core-sdk") include(":authenticate-sdk") include(":prism-crypto") - From a30a391e20b8da668842f0e07fc99d5a194abb3f Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Mon, 14 Nov 2022 19:24:57 +0400 Subject: [PATCH 09/21] enchantments: sdk enchantment --- authenticate-sdk/build.gradle.kts | 2 +- protosLib/build.gradle.kts | 21 +++++++++++---------- settings.gradle.kts | 1 - 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/authenticate-sdk/build.gradle.kts b/authenticate-sdk/build.gradle.kts index 28be753ff..cacb66bf5 100644 --- a/authenticate-sdk/build.gradle.kts +++ b/authenticate-sdk/build.gradle.kts @@ -65,7 +65,7 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation("com.benasher44:uuid:0.3.0") + implementation("com.benasher44:uuid:0.3.0") // Apollo UUID implementation(project(":core-sdk")) } } diff --git a/protosLib/build.gradle.kts b/protosLib/build.gradle.kts index b92a590b5..68c2dcfe8 100644 --- a/protosLib/build.gradle.kts +++ b/protosLib/build.gradle.kts @@ -1,9 +1,11 @@ +import org.gradle.internal.os.OperatingSystem import com.google.protobuf.gradle.* -import org.apache.tools.ant.taskdefs.condition.Os + +val os: OperatingSystem = OperatingSystem.current() plugins { `java-library` - id(Plugins.protobuf) + id("com.google.protobuf") } // Mock configuration which derives compile only. @@ -13,10 +15,10 @@ val jarPathConf by configurations.creating { } dependencies { - jarPathConf(Deps.pbandkPrismClientsGenerator) + jarPathConf("io.iohk.atala:pbandk-prism-clients-generator:0.20.7") // This is needed for includes, ref: https://github.com/google/protobuf-gradle-plugin/issues/41#issuecomment-143884188 - compileOnly(Deps.protobufJava) + // compileOnly("com.google.protobuf:protobuf-java:3.21.9") } sourceSets { @@ -39,20 +41,20 @@ sourceSets { protobuf { protoc { - artifact = if (Os.isFamily(Os.FAMILY_MAC)) { + artifact = if (os.isMacOsX) { if (System.getProperty("os.arch") != "x86_64") { // In case of macOS and M1 chip then we need to use a different version of protobuf that support M1 chip arch - "${Deps.protobufProtoc}:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" + "com.google.protobuf:protoc:3.21.9:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" } else { - Deps.protobufProtoc + "com.google.protobuf:protoc:3.21.9" } } else { - Deps.protobufProtoc + "com.google.protobuf:protoc:3.21.9" } } plugins { id("kotlin") { - artifact = Deps.pbandkProtocGenJDK8 + artifact = "io.iohk:protoc-gen-pbandk-jvm:0.20.7:jvm8@jar" } } @@ -69,7 +71,6 @@ protobuf { option("kotlin_service_gen=$pbandkClientsGeneratorJar|io.iohk.atala.prism.generator.Generator") option("visibility=public") option("js_export=true") - option("with_annotations=@io.iohk.atala.prism.common.PrismSdkInternal") } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index db8bbd605..dfc7b87a7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,4 +30,3 @@ include(":protosLib") include(":wallet-sdk") include(":core-sdk") include(":authenticate-sdk") -include(":prism-crypto") From 6c217772c5adb93a8936de2555ec10547ff5f44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Mon, 14 Nov 2022 18:06:17 +0100 Subject: [PATCH 10/21] enchantments: SDK porting prism-protos + protosLib. --- build.gradle.kts | 8 + prism-protos/api/android/prism-protos.api | 134 ++++++++++++++ prism-protos/api/jvm/prism-protos.api | 127 +++++++++++++ prism-protos/build.gradle.kts | 152 +++++++++++++++ prism-protos/karma.config.d/timeout.js | 9 + .../src/androidMain/AndroidManifest.xml | 2 + .../io/iohk/atala/prism/protos/GrpcClient.kt | 174 ++++++++++++++++++ .../atala/prism/protos/util/Base64Utils.kt | 11 ++ .../io/iohk/atala/prism/protos/GrpcClient.kt | 62 +++++++ .../iohk/atala/prism/protos/models/Ledger.kt | 41 +++++ .../atala/prism/protos/models/LedgerData.kt | 26 +++ .../prism/protos/models/TimestampInfo.kt | 43 +++++ .../atala/prism/protos/util/Base64Utils.kt | 13 ++ .../io/iohk/atala/prism/protos/ProtoTest.kt | 15 ++ .../prism/protos/util/Base64UtilsTest.kt | 19 ++ .../io/iohk/atala/prism/protos/GrpcClient.kt | 44 +++++ .../atala/prism/protos/util/Base64Utils.kt | 33 ++++ .../io/iohk/atala/prism/protos/GrpcClient.kt | 167 +++++++++++++++++ .../iohk/atala/prism/protos/ProtoGlobals.kt | 4 + ...dex.grpc_web.StatusCode.module_grpc-web.kt | 51 +++++ .../index.grpc_web.module_grpc-web.kt | 98 ++++++++++ .../atala/prism/protos/util/Base64Utils.kt | 29 +++ prism-protos/webpack.config.d/polyfill.js | 10 + protosLib/build.gradle.kts | 6 +- 24 files changed, 1275 insertions(+), 3 deletions(-) create mode 100644 prism-protos/api/android/prism-protos.api create mode 100644 prism-protos/api/jvm/prism-protos.api create mode 100644 prism-protos/build.gradle.kts create mode 100644 prism-protos/karma.config.d/timeout.js create mode 100644 prism-protos/src/androidMain/AndroidManifest.xml create mode 100644 prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt create mode 100644 prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt create mode 100644 prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt create mode 100644 prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/Ledger.kt create mode 100644 prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/LedgerData.kt create mode 100644 prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/TimestampInfo.kt create mode 100644 prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt create mode 100644 prism-protos/src/commonTest/kotlin/io/iohk/atala/prism/protos/ProtoTest.kt create mode 100644 prism-protos/src/commonTest/kotlin/io/iohk/atala/prism/protos/util/Base64UtilsTest.kt create mode 100644 prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt create mode 100644 prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt create mode 100644 prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt create mode 100644 prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/ProtoGlobals.kt create mode 100644 prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.StatusCode.module_grpc-web.kt create mode 100644 prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.module_grpc-web.kt create mode 100644 prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt create mode 100644 prism-protos/webpack.config.d/polyfill.js diff --git a/build.gradle.kts b/build.gradle.kts index d201c2d62..96c55af3b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,15 @@ import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + vendor.set(JvmVendorSpec.ADOPTOPENJDK) + } +} + plugins { + java kotlin("jvm") version "1.7.20" kotlin("plugin.serialization") version "1.7.20" id("maven-publish") diff --git a/prism-protos/api/android/prism-protos.api b/prism-protos/api/android/prism-protos.api new file mode 100644 index 000000000..ec6e058ce --- /dev/null +++ b/prism-protos/api/android/prism-protos.api @@ -0,0 +1,134 @@ +public final class io/iohk/atala/prism/protos/BuildConfig { + public static final field BUILD_TYPE Ljava/lang/String; + public static final field DEBUG Z + public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String; + public fun ()V +} + +public final class io/iohk/atala/prism/protos/Common_modelsKt { +} + +public final class io/iohk/atala/prism/protos/Connector_apiKt { +} + +public final class io/iohk/atala/prism/protos/Connector_modelsKt { +} + +public final class io/iohk/atala/prism/protos/Console_apiKt { +} + +public final class io/iohk/atala/prism/protos/Console_modelsKt { +} + +public final class io/iohk/atala/prism/protos/Credential_modelsKt { +} + +public final class io/iohk/atala/prism/protos/GrpcClientKt { + public static final field DID Ljava/lang/String; + public static final field DID_KEY_ID Ljava/lang/String; + public static final field DID_SIGNATURE Ljava/lang/String; + public static final field PRISM_AUTH_TOKEN Ljava/lang/String; + public static final field REQUEST_NONCE Ljava/lang/String; +} + +public final class io/iohk/atala/prism/protos/GrpcOptions { + public fun (Ljava/lang/String;Ljava/lang/String;I)V + public fun (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()I + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)Lio/iohk/atala/prism/protos/GrpcOptions; + public static synthetic fun copy$default (Lio/iohk/atala/prism/protos/GrpcOptions;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;ILjava/lang/Object;)Lio/iohk/atala/prism/protos/GrpcOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getHost ()Ljava/lang/String; + public final fun getPort ()I + public final fun getProtocol ()Ljava/lang/String; + public final fun getToken ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/iohk/atala/prism/protos/Node_apiKt { +} + +public final class io/iohk/atala/prism/protos/Node_internalKt { +} + +public final class io/iohk/atala/prism/protos/Node_modelsKt { +} + +public final class io/iohk/atala/prism/protos/PrismMetadata { + public fun (Ljava/lang/String;Ljava/lang/String;[B[B)V + public final fun getDid ()Ljava/lang/String; + public final fun getDidKeyId ()Ljava/lang/String; + public final fun getDidSignature ()[B + public final fun getRequestNonce ()[B +} + +public final class io/iohk/atala/prism/protos/StatusKt { +} + +public final class io/iohk/atala/prism/protos/models/Ledger { + public static final field INSTANCE Lio/iohk/atala/prism/protos/models/Ledger; + public final fun asString (I)Ljava/lang/String; + public final fun fromString (Ljava/lang/String;)I + public final fun getCARDANO_MAINNET ()I + public final fun getCARDANO_TESTNET ()I + public final fun getIN_MEMORY ()I + public final fun getUNKNOWN_LEDGER ()I +} + +public final class io/iohk/atala/prism/protos/models/LedgerData { + public fun (Ljava/lang/String;ILio/iohk/atala/prism/protos/models/TimestampInfo;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()I + public final fun component3 ()Lio/iohk/atala/prism/protos/models/TimestampInfo; + public final fun copy (Ljava/lang/String;ILio/iohk/atala/prism/protos/models/TimestampInfo;)Lio/iohk/atala/prism/protos/models/LedgerData; + public static synthetic fun copy$default (Lio/iohk/atala/prism/protos/models/LedgerData;Ljava/lang/String;ILio/iohk/atala/prism/protos/models/TimestampInfo;ILjava/lang/Object;)Lio/iohk/atala/prism/protos/models/LedgerData; + public fun equals (Ljava/lang/Object;)Z + public final fun getLedger ()I + public final fun getTimestampInfo ()Lio/iohk/atala/prism/protos/models/TimestampInfo; + public final fun getTransactionId ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/iohk/atala/prism/protos/models/LedgerDataKt { + public static final fun toModel (Lio/iohk/atala/prism/protos/LedgerData;)Lio/iohk/atala/prism/protos/models/LedgerData; + public static final fun toProto (Lio/iohk/atala/prism/protos/models/LedgerData;)Lio/iohk/atala/prism/protos/LedgerData; +} + +public final class io/iohk/atala/prism/protos/models/LedgerKt { + public static final fun toModel (Lio/iohk/atala/prism/protos/Ledger;)I + public static final fun toProto (I)Lio/iohk/atala/prism/protos/Ledger; +} + +public final class io/iohk/atala/prism/protos/models/TimestampInfo { + public fun (JII)V + public final fun component1 ()J + public final fun component2 ()I + public final fun component3 ()I + public final fun copy (JII)Lio/iohk/atala/prism/protos/models/TimestampInfo; + public static synthetic fun copy$default (Lio/iohk/atala/prism/protos/models/TimestampInfo;JIIILjava/lang/Object;)Lio/iohk/atala/prism/protos/models/TimestampInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getAtalaBlockSequenceNumber ()I + public final fun getAtalaBlockTimestamp ()J + public final fun getOperationSequenceNumber ()I + public fun hashCode ()I + public final fun occurredBefore (Lio/iohk/atala/prism/protos/models/TimestampInfo;)Z + public fun toString ()Ljava/lang/String; +} + +public final class io/iohk/atala/prism/protos/models/TimestampInfoKt { + public static final fun toModel (Lio/iohk/atala/prism/protos/TimestampInfo;)Lio/iohk/atala/prism/protos/models/TimestampInfo; + public static final fun toProto (Lio/iohk/atala/prism/protos/models/TimestampInfo;)Lio/iohk/atala/prism/protos/TimestampInfo; +} + +public final class io/iohk/atala/prism/protos/util/Base64Utils { + public static final field INSTANCE Lio/iohk/atala/prism/protos/util/Base64Utils; + public final fun decode (Ljava/lang/String;)[B + public final fun encode ([B)Ljava/lang/String; +} + diff --git a/prism-protos/api/jvm/prism-protos.api b/prism-protos/api/jvm/prism-protos.api new file mode 100644 index 000000000..32290f363 --- /dev/null +++ b/prism-protos/api/jvm/prism-protos.api @@ -0,0 +1,127 @@ +public final class io/iohk/atala/prism/protos/Common_modelsKt { +} + +public final class io/iohk/atala/prism/protos/Connector_apiKt { +} + +public final class io/iohk/atala/prism/protos/Connector_modelsKt { +} + +public final class io/iohk/atala/prism/protos/Console_apiKt { +} + +public final class io/iohk/atala/prism/protos/Console_modelsKt { +} + +public final class io/iohk/atala/prism/protos/Credential_modelsKt { +} + +public final class io/iohk/atala/prism/protos/GrpcClientKt { + public static final field DID Ljava/lang/String; + public static final field DID_KEY_ID Ljava/lang/String; + public static final field DID_SIGNATURE Ljava/lang/String; + public static final field PRISM_AUTH_TOKEN Ljava/lang/String; + public static final field REQUEST_NONCE Ljava/lang/String; +} + +public final class io/iohk/atala/prism/protos/GrpcOptions { + public fun (Ljava/lang/String;Ljava/lang/String;I)V + public fun (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()I + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)Lio/iohk/atala/prism/protos/GrpcOptions; + public static synthetic fun copy$default (Lio/iohk/atala/prism/protos/GrpcOptions;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;ILjava/lang/Object;)Lio/iohk/atala/prism/protos/GrpcOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getHost ()Ljava/lang/String; + public final fun getPort ()I + public final fun getProtocol ()Ljava/lang/String; + public final fun getToken ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/iohk/atala/prism/protos/Node_apiKt { +} + +public final class io/iohk/atala/prism/protos/Node_internalKt { +} + +public final class io/iohk/atala/prism/protos/Node_modelsKt { +} + +public final class io/iohk/atala/prism/protos/PrismMetadata { + public fun (Ljava/lang/String;Ljava/lang/String;[B[B)V + public final fun getDid ()Ljava/lang/String; + public final fun getDidKeyId ()Ljava/lang/String; + public final fun getDidSignature ()[B + public final fun getRequestNonce ()[B +} + +public final class io/iohk/atala/prism/protos/StatusKt { +} + +public final class io/iohk/atala/prism/protos/models/Ledger { + public static final field INSTANCE Lio/iohk/atala/prism/protos/models/Ledger; + public final fun asString (I)Ljava/lang/String; + public final fun fromString (Ljava/lang/String;)I + public final fun getCARDANO_MAINNET ()I + public final fun getCARDANO_TESTNET ()I + public final fun getIN_MEMORY ()I + public final fun getUNKNOWN_LEDGER ()I +} + +public final class io/iohk/atala/prism/protos/models/LedgerData { + public fun (Ljava/lang/String;ILio/iohk/atala/prism/protos/models/TimestampInfo;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()I + public final fun component3 ()Lio/iohk/atala/prism/protos/models/TimestampInfo; + public final fun copy (Ljava/lang/String;ILio/iohk/atala/prism/protos/models/TimestampInfo;)Lio/iohk/atala/prism/protos/models/LedgerData; + public static synthetic fun copy$default (Lio/iohk/atala/prism/protos/models/LedgerData;Ljava/lang/String;ILio/iohk/atala/prism/protos/models/TimestampInfo;ILjava/lang/Object;)Lio/iohk/atala/prism/protos/models/LedgerData; + public fun equals (Ljava/lang/Object;)Z + public final fun getLedger ()I + public final fun getTimestampInfo ()Lio/iohk/atala/prism/protos/models/TimestampInfo; + public final fun getTransactionId ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/iohk/atala/prism/protos/models/LedgerDataKt { + public static final fun toModel (Lio/iohk/atala/prism/protos/LedgerData;)Lio/iohk/atala/prism/protos/models/LedgerData; + public static final fun toProto (Lio/iohk/atala/prism/protos/models/LedgerData;)Lio/iohk/atala/prism/protos/LedgerData; +} + +public final class io/iohk/atala/prism/protos/models/LedgerKt { + public static final fun toModel (Lio/iohk/atala/prism/protos/Ledger;)I + public static final fun toProto (I)Lio/iohk/atala/prism/protos/Ledger; +} + +public final class io/iohk/atala/prism/protos/models/TimestampInfo { + public fun (JII)V + public final fun component1 ()J + public final fun component2 ()I + public final fun component3 ()I + public final fun copy (JII)Lio/iohk/atala/prism/protos/models/TimestampInfo; + public static synthetic fun copy$default (Lio/iohk/atala/prism/protos/models/TimestampInfo;JIIILjava/lang/Object;)Lio/iohk/atala/prism/protos/models/TimestampInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getAtalaBlockSequenceNumber ()I + public final fun getAtalaBlockTimestamp ()J + public final fun getOperationSequenceNumber ()I + public fun hashCode ()I + public final fun occurredBefore (Lio/iohk/atala/prism/protos/models/TimestampInfo;)Z + public fun toString ()Ljava/lang/String; +} + +public final class io/iohk/atala/prism/protos/models/TimestampInfoKt { + public static final fun toModel (Lio/iohk/atala/prism/protos/TimestampInfo;)Lio/iohk/atala/prism/protos/models/TimestampInfo; + public static final fun toProto (Lio/iohk/atala/prism/protos/models/TimestampInfo;)Lio/iohk/atala/prism/protos/TimestampInfo; +} + +public final class io/iohk/atala/prism/protos/util/Base64Utils { + public static final field INSTANCE Lio/iohk/atala/prism/protos/util/Base64Utils; + public final fun decode (Ljava/lang/String;)[B + public final fun encode ([B)Ljava/lang/String; +} + diff --git a/prism-protos/build.gradle.kts b/prism-protos/build.gradle.kts new file mode 100644 index 000000000..c5d24285b --- /dev/null +++ b/prism-protos/build.gradle.kts @@ -0,0 +1,152 @@ +import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode +import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon +import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile + +plugins { + kotlin("multiplatform") + id("com.android.library") +} + +repositories { + mavenCentral() + mavenLocal() +} + +kotlin { + explicitApi() + explicitApi = ExplicitApiMode.Strict + + android { + publishAllLibraryVariants() + } + jvm { + compilations.all { + kotlinOptions { + jvmTarget = "11" + } + } + } + js(IR) { + moduleName = "protos" + browser { + testTask { + useKarma { + useChromeHeadless() + } + } + } + binaries.library() + useCommonJs() + + val prismVersion: String by rootProject.extra + compilations["main"].packageJson { + version = prismVersion + } + + compilations["test"].packageJson { + version = prismVersion + } + } + ios("ios") { + binaries.all {} + } + + sourceSets { + val commonMain by getting { + kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/main/kotlin") + resources.srcDir("${project(":protosLib").projectDir}/src/main") + dependencies { + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1-new-mm-dev2") + api("io.iohk:pbandk-runtime:0.20.7") { + exclude("com.google.protobuf") + } + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1") + implementation("io.ktor:ktor-io:1.6.5") + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + } + } + val androidMain by getting { + kotlin.srcDir("src/commonJvmAndroidMain/kotlin") + kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/commonJvmAndroidMain/kotlin") + dependencies { + implementation("io.grpc:grpc-kotlin-stub:1.0.0") { + exclude("io.grpc", "grpc-protobuf") + exclude("com.google.protobuf") + } + implementation("io.grpc:grpc-okhttp:1.36.0") + implementation("io.grpc:grpc-protobuf-lite:1.36.0") + implementation("io.iohk:protoc-gen-pbandk-jvm:0.20.7:jvm8@jar") + } + } + val jvmMain by getting { + kotlin.srcDir("src/commonJvmAndroidMain/kotlin") + kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/commonJvmAndroidMain/kotlin") + dependencies { + implementation("io.grpc:grpc-kotlin-stub:1.0.0") + implementation("io.grpc:grpc-okhttp:1.36.0") + implementation("io.grpc:grpc-protobuf-lite:1.36.0") + implementationimplementation("io.iohk:protoc-gen-pbandk-jvm:0.20.7:jvm8@jar") + } + } + val jsMain by getting { + kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/jsMain/kotlin") + dependencies { + implementation(npm("grpc-web", "1.2.1")) + // Polyfill dependencies + implementation(npm("stream-browserify", "3.0.0")) + implementation(npm("buffer", "6.0.3")) + } + } + val jsTest by getting + val iosMain by getting + val iosTest by getting + + all { + languageSettings.optIn("kotlin.js.ExperimentalJsExport") + languageSettings.optIn("io.iohk.atala.prism.common.PrismSdkInternal") + } + } +} + +android { + compileSdkVersion(Versions.androidTargetSdk) + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdkVersion(26) + targetSdkVersion(29) + } +} + +tasks { + "jvmTest"(Test::class) { + useJUnitPlatform() + } + + project(":protosLib").tasks + .matching { it.name == "generateProto" } + .all { + val compileTasks = listOf>( + named("compileReleaseKotlinAndroid").get(), + named("compileDebugKotlinAndroid").get(), + named("compileKotlinJvm").get(), + named("compileKotlinJs").get(), + named("compileKotlinIosX64").get(), + named("compileKotlinIosArm64").get(), + named("compileKotlinMetadata").get() + ) + + compileTasks.forEach { + it.dependsOn(this) + it.kotlinOptions { + freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlinx.coroutines.DelicateCoroutinesApi,kotlin.RequiresOptIn" + suppressWarnings = true + } + } + } +} diff --git a/prism-protos/karma.config.d/timeout.js b/prism-protos/karma.config.d/timeout.js new file mode 100644 index 000000000..2c29ef748 --- /dev/null +++ b/prism-protos/karma.config.d/timeout.js @@ -0,0 +1,9 @@ +config.set({ + browserDisconnectTimeout: 5000, + processKillTimeout: 5000, + client: { + mocha: { + timeout: 5000 + } + } +}); diff --git a/prism-protos/src/androidMain/AndroidManifest.xml b/prism-protos/src/androidMain/AndroidManifest.xml new file mode 100644 index 000000000..3922aea99 --- /dev/null +++ b/prism-protos/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt b/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt new file mode 100644 index 000000000..d73341337 --- /dev/null +++ b/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt @@ -0,0 +1,174 @@ +package io.iohk.atala.prism.protos + +import io.grpc.* +import io.grpc.kotlin.ClientCalls +import io.grpc.stub.MetadataUtils +import io.iohk.atala.prism.common.PrismSdkInternal +import io.ktor.utils.io.core.* +import kotlinx.coroutines.flow.Flow +import pbandk.Message +import pbandk.decodeFromStream +import pbandk.encodeToByteArray +import java.io.InputStream +import java.util.* +import java.util.concurrent.TimeUnit + +@PrismSdkInternal +public actual class GrpcClient actual constructor(options: GrpcOptions) : Closeable { + private val channel: ManagedChannel = + if (options.protocol == "http") { + ManagedChannelBuilder.forAddress(options.host, options.port).usePlaintext().build() + } else { + ManagedChannelBuilder.forAddress(options.host, options.port).useTransportSecurity().build() + } + private val token: String? = options.token + + @PrismSdkInternal + public class MessageMarshaller(private val companion: Message.Companion) : + MethodDescriptor.Marshaller { + override fun stream(value: T): InputStream = + value.encodeToByteArray().inputStream() + + override fun parse(stream: InputStream?): T = + companion.decodeFromStream(stream!!) + } + + private fun methodDescriptorUnary( + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): MethodDescriptor { + return MethodDescriptor + .newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName(MethodDescriptor.generateFullMethodName(serviceName, methodName)) + .setRequestMarshaller(MessageMarshaller(reqCompanion)) + .setResponseMarshaller(MessageMarshaller(respCompanion)) + .build() + } + + private fun methodDescriptorServerStreaming( + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): MethodDescriptor { + return MethodDescriptor + .newBuilder() + .setType(MethodDescriptor.MethodType.SERVER_STREAMING) + .setFullMethodName(MethodDescriptor.generateFullMethodName(serviceName, methodName)) + .setRequestMarshaller(MessageMarshaller(reqCompanion)) + .setResponseMarshaller(MessageMarshaller(respCompanion)) + .build() + } + + private fun toMetadata(prismMetadata: PrismMetadata): Metadata { + val metadata = Metadata() + if (token != null) + metadata.put(PRISM_AUTH_TOKEN_HEADER, token) + + metadata.put(DID_HEADER, prismMetadata.did) + metadata.put(DID_KEY_ID_HEADER, prismMetadata.didKeyId) + metadata.put( + DID_SIGNATURE_HEADER, + Base64.getUrlEncoder().encode(prismMetadata.didSignature).decodeToString() + ) + metadata.put( + REQUEST_NONCE_HEADER, + Base64.getUrlEncoder().encode(prismMetadata.requestNonce).decodeToString() + ) + return metadata + } + + private fun authChannel(prismMetadata: PrismMetadata): Channel { + val metadata = toMetadata(prismMetadata) + val interceptor = MetadataUtils.newAttachHeadersInterceptor(metadata) + return ClientInterceptors.intercept(channel, interceptor) + } + + private fun channelWithAuthTokenHeader(): Channel { + val metadata = Metadata() + if (token != null) { + metadata.put(PRISM_AUTH_TOKEN_HEADER, token) + } + val interceptor = MetadataUtils.newAttachHeadersInterceptor(metadata) + return ClientInterceptors.intercept(channel, interceptor) + } + + public actual suspend fun call( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): Resp { + val methodDescriptor = + methodDescriptorUnary(reqCompanion, respCompanion, serviceName, methodName) + val tokenizedChannel = channelWithAuthTokenHeader() + return ClientCalls.unaryRpc(tokenizedChannel, methodDescriptor, request) + } + + public actual suspend fun callAuth( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + prismMetadata: PrismMetadata + ): Resp { + val authChannel = authChannel(prismMetadata) + val methodDescriptor = + methodDescriptorUnary(reqCompanion, respCompanion, serviceName, methodName) + return ClientCalls.unaryRpc(authChannel, methodDescriptor, request) + } + + public actual fun stream( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): Flow { + val methodDescriptor = + methodDescriptorServerStreaming(reqCompanion, respCompanion, serviceName, methodName) + val tokenizedChannel = channelWithAuthTokenHeader() + return ClientCalls.serverStreamingRpc(tokenizedChannel, methodDescriptor, request) + } + + public actual fun streamAuth( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + prismMetadata: PrismMetadata + ): Flow { + val authChannel = authChannel(prismMetadata) + val methodDescriptor = + methodDescriptorServerStreaming(reqCompanion, respCompanion, serviceName, methodName) + return ClientCalls.serverStreamingRpc(authChannel, methodDescriptor, request) + } + + public override fun close() { + try { + channel.shutdown().awaitTermination(10, TimeUnit.SECONDS) + } catch (err: Exception) { + throw RuntimeException("Wasn't able to close the channel", err.cause) + } + } + + @PrismSdkInternal + public companion object { + public val DID_HEADER: Metadata.Key = + Metadata.Key.of(DID, Metadata.ASCII_STRING_MARSHALLER) + public val DID_KEY_ID_HEADER: Metadata.Key = + Metadata.Key.of(DID_KEY_ID, Metadata.ASCII_STRING_MARSHALLER) + public val DID_SIGNATURE_HEADER: Metadata.Key = + Metadata.Key.of(DID_SIGNATURE, Metadata.ASCII_STRING_MARSHALLER) + public val REQUEST_NONCE_HEADER: Metadata.Key = + Metadata.Key.of(REQUEST_NONCE, Metadata.ASCII_STRING_MARSHALLER) + public val PRISM_AUTH_TOKEN_HEADER: Metadata.Key = + Metadata.Key.of(PRISM_AUTH_TOKEN, Metadata.ASCII_STRING_MARSHALLER) + } +} diff --git a/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt b/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt new file mode 100644 index 000000000..aab2fa335 --- /dev/null +++ b/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt @@ -0,0 +1,11 @@ +package io.iohk.atala.prism.protos.util + +import java.util.* + +public actual object Base64Utils { + public actual fun encode(bytes: ByteArray): String = + Base64.getUrlEncoder().withoutPadding().encodeToString(bytes) + + public actual fun decode(src: String): ByteArray = + Base64.getUrlDecoder().decode(src) +} diff --git a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt new file mode 100644 index 000000000..20eed30bf --- /dev/null +++ b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt @@ -0,0 +1,62 @@ +package io.iohk.atala.prism.protos + +import io.iohk.atala.prism.common.PrismSdkInternal +import io.ktor.utils.io.core.Closeable +import kotlinx.coroutines.flow.Flow +import pbandk.Message +import kotlin.js.JsExport +import kotlin.jvm.JvmOverloads + +@JsExport +public data class GrpcOptions @JvmOverloads constructor(val protocol: String, val host: String, val port: Int, val token: String? = null) + +@JsExport +public class PrismMetadata( + public val did: String, + public val didKeyId: String, + public val didSignature: ByteArray, + public val requestNonce: ByteArray +) + +public const val DID: String = "did" +public const val DID_KEY_ID: String = "did-key-id" +public const val DID_SIGNATURE: String = "did-signature" +public const val REQUEST_NONCE: String = "request-nonce" +public const val PRISM_AUTH_TOKEN: String = "prism-auth-token" + +@PrismSdkInternal +public expect class GrpcClient(options: GrpcOptions) : Closeable { + public suspend fun call( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): Resp + + public suspend fun callAuth( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + prismMetadata: PrismMetadata + ): Resp + + public fun stream( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): Flow + + public fun streamAuth( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + prismMetadata: PrismMetadata + ): Flow +} diff --git a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/Ledger.kt b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/Ledger.kt new file mode 100644 index 000000000..247cddeea --- /dev/null +++ b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/Ledger.kt @@ -0,0 +1,41 @@ +package io.iohk.atala.prism.protos.models + +import kotlin.js.JsExport + +public typealias LedgerEnum = Int + +// TODO: This smell-code is because Kotlin/JS doesn't support interfaces and enum classes now. +// We should switch to a enum class once Kotlin/JS fixes the issue: https://youtrack.jetbrains.com/issue/KT-37916. +@JsExport +public object Ledger { + public val UNKNOWN_LEDGER: Int = 0 + public val IN_MEMORY: Int = 1 + public val CARDANO_TESTNET: Int = 4 + public val CARDANO_MAINNET: Int = 5 + + public fun asString(ledger: LedgerEnum): String = + when (ledger) { + 0 -> "UNKNOWN_LEDGER" + 1 -> "IN_MEMORY" + 4 -> "CARDANO_TESTNET" + 5 -> "CARDANO_MAINNET" + else -> throw IllegalArgumentException("Unrecognized ledger type") + } + + public fun fromString(string: String): LedgerEnum = + when (string) { + "UNKNOWN_LEDGER" -> UNKNOWN_LEDGER + "IN_MEMORY" -> IN_MEMORY + "CARDANO_TESTNET" -> CARDANO_TESTNET + "CARDANO_MAINNET" -> CARDANO_MAINNET + else -> throw IllegalArgumentException("Unrecognized ledger type") + } +} + +public fun io.iohk.atala.prism.protos.Ledger.toModel(): LedgerEnum { + return Ledger.fromString(name!!) +} + +public fun LedgerEnum.toProto(): io.iohk.atala.prism.protos.Ledger { + return io.iohk.atala.prism.protos.Ledger.fromName(Ledger.asString(this)) +} diff --git a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/LedgerData.kt b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/LedgerData.kt new file mode 100644 index 000000000..14f511f7d --- /dev/null +++ b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/LedgerData.kt @@ -0,0 +1,26 @@ +package io.iohk.atala.prism.protos.models + +import kotlin.js.JsExport + +@JsExport +public data class LedgerData( + val transactionId: String, + val ledger: LedgerEnum, + val timestampInfo: TimestampInfo +) + +public fun io.iohk.atala.prism.protos.LedgerData.toModel(): LedgerData { + return LedgerData( + transactionId, + ledger.toModel(), + timestampInfo!!.toModel() + ) +} + +public fun LedgerData.toProto(): io.iohk.atala.prism.protos.LedgerData { + return io.iohk.atala.prism.protos.LedgerData( + transactionId, + ledger.toProto(), + timestampInfo.toProto() + ) +} diff --git a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/TimestampInfo.kt b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/TimestampInfo.kt new file mode 100644 index 000000000..a4978c5f6 --- /dev/null +++ b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/models/TimestampInfo.kt @@ -0,0 +1,43 @@ +package io.iohk.atala.prism.protos.models + +import kotlinx.datetime.Instant +import pbandk.wkt.Timestamp +import kotlin.js.JsExport + +@JsExport +public data class TimestampInfo( + val atalaBlockTimestamp: Long, // timestamp provided from the underlying blockchain + val atalaBlockSequenceNumber: Int, // transaction index inside the underlying blockchain block + val operationSequenceNumber: Int // operation index inside the AtalaBlock +) { + public fun occurredBefore(later: TimestampInfo): Boolean { + return (atalaBlockTimestamp < later.atalaBlockTimestamp) || + ( + atalaBlockTimestamp == later.atalaBlockTimestamp && + atalaBlockSequenceNumber < later.atalaBlockSequenceNumber + ) || + ( + atalaBlockTimestamp == later.atalaBlockTimestamp && + atalaBlockSequenceNumber == later.atalaBlockSequenceNumber && + operationSequenceNumber < later.operationSequenceNumber + ) + } +} + +public fun io.iohk.atala.prism.protos.TimestampInfo.toModel(): TimestampInfo { + val instant = Instant.fromEpochSeconds(blockTimestamp?.seconds!!, blockTimestamp.nanos) + return TimestampInfo( + atalaBlockTimestamp = instant.toEpochMilliseconds(), + atalaBlockSequenceNumber = blockSequenceNumber, + operationSequenceNumber = operationSequenceNumber + ) +} + +public fun TimestampInfo.toProto(): io.iohk.atala.prism.protos.TimestampInfo { + val instant = Instant.fromEpochMilliseconds(atalaBlockTimestamp) + return io.iohk.atala.prism.protos.TimestampInfo( + blockTimestamp = Timestamp(seconds = instant.epochSeconds, nanos = instant.nanosecondsOfSecond), + blockSequenceNumber = atalaBlockSequenceNumber, + operationSequenceNumber = operationSequenceNumber + ) +} diff --git a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt new file mode 100644 index 000000000..2c3f0bb3d --- /dev/null +++ b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt @@ -0,0 +1,13 @@ +package io.iohk.atala.prism.protos.util + +public expect object Base64Utils { + /** + * Returns a URL-safe Base64 encoding without padding (i.e. no trailing '='s). + */ + public fun encode(bytes: ByteArray): String + + /** + * Decodes a URL-safe Base64 encoding without padding into a list of bytes. + */ + public fun decode(src: String): ByteArray +} diff --git a/prism-protos/src/commonTest/kotlin/io/iohk/atala/prism/protos/ProtoTest.kt b/prism-protos/src/commonTest/kotlin/io/iohk/atala/prism/protos/ProtoTest.kt new file mode 100644 index 000000000..f4dcd556f --- /dev/null +++ b/prism-protos/src/commonTest/kotlin/io/iohk/atala/prism/protos/ProtoTest.kt @@ -0,0 +1,15 @@ +package io.iohk.atala.prism.protos + +import pbandk.decodeFromByteArray +import pbandk.encodeToByteArray +import kotlin.test.Test +import kotlin.test.assertEquals + +class ProtoTest { + @Test + fun testProtobufModelEncoding() { + val request = GetBatchStateRequest(batchId = "123") + val decodedRequest = GetBatchStateRequest.decodeFromByteArray(request.encodeToByteArray()) + assertEquals(request, decodedRequest) + } +} diff --git a/prism-protos/src/commonTest/kotlin/io/iohk/atala/prism/protos/util/Base64UtilsTest.kt b/prism-protos/src/commonTest/kotlin/io/iohk/atala/prism/protos/util/Base64UtilsTest.kt new file mode 100644 index 000000000..952581955 --- /dev/null +++ b/prism-protos/src/commonTest/kotlin/io/iohk/atala/prism/protos/util/Base64UtilsTest.kt @@ -0,0 +1,19 @@ +package io.iohk.atala.prism.protos.util + +import kotlin.test.Test +import kotlin.test.assertEquals + +class Base64UtilsTest { + @Test + fun testEncoding() { + val actual = Base64Utils.encode("subjects?_d=1~~~".encodeToByteArray()) + // Actual Base64 is c3ViamVjdHM/X2Q9MX5+fg==, but we need the URL-encoded version of it + assertEquals("c3ViamVjdHM_X2Q9MX5-fg", actual) + } + + @Test + fun testDecoding() { + val actual = Base64Utils.decode("c3ViamVjdHM_X2Q9MX5-fg") + assertEquals("subjects?_d=1~~~", actual.decodeToString()) + } +} diff --git a/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt b/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt new file mode 100644 index 000000000..981e4014e --- /dev/null +++ b/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt @@ -0,0 +1,44 @@ +package io.iohk.atala.prism.protos + +import io.ktor.utils.io.core.Closeable +import kotlinx.coroutines.flow.Flow +import pbandk.Message + +public actual class GrpcClient actual constructor(options: GrpcOptions) : Closeable { + public actual suspend fun call( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): Resp = TODO("iOS GRPC client is not supported yet") + + public actual suspend fun callAuth( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + prismMetadata: PrismMetadata + ): Resp = TODO("iOS GRPC client is not supported yet") + + public actual fun stream( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): Flow = TODO("iOS GRPC client is not supported yet") + + public actual fun streamAuth( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + prismMetadata: PrismMetadata + ): Flow = TODO("iOS GRPC client is not supported yet") + + public override fun close() { + } +} diff --git a/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt b/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt new file mode 100644 index 000000000..a8c800587 --- /dev/null +++ b/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt @@ -0,0 +1,33 @@ +package io.iohk.atala.prism.protos.util + +import kotlinx.cinterop.* +import platform.Foundation.NSData +import platform.Foundation.base64EncodedStringWithOptions +import platform.Foundation.create +import platform.posix.memcpy + +public actual object Base64Utils { + public actual fun encode(bytes: ByteArray): String { + val nsData = memScoped { + NSData.create( + bytes = allocArrayOf(bytes), + length = bytes.size.convert() + ) + } + val base64Encoded = nsData.base64EncodedStringWithOptions(0) + // Make Base64 representation URL-safe + return base64Encoded.replace('/', '_').replace('+', '-').dropLastWhile { it == '=' } + } + + public actual fun decode(src: String): ByteArray { + val expectedLength = (src.length + 3) / 4 * 4 + val base64encoded = + src.replace('_', '/').replace('-', '+').padEnd(expectedLength, '=') + val data = NSData.create(base64encoded, 0)!! + return ByteArray(data.length.toInt()).apply { + usePinned { + memcpy(it.addressOf(0), data.bytes, data.length) + } + } + } +} diff --git a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt new file mode 100644 index 000000000..397e52f1c --- /dev/null +++ b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt @@ -0,0 +1,167 @@ +package io.iohk.atala.prism.protos + +import io.iohk.atala.prism.protos.externals.* +import io.iohk.atala.prism.protos.util.Base64Utils +import io.ktor.utils.io.core.Closeable +import kotlinx.coroutines.await +import kotlinx.coroutines.cancel +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import pbandk.Message +import pbandk.decodeFromByteArray +import pbandk.encodeToByteArray +import kotlin.js.json + +public actual class GrpcClient actual constructor( + private val options: GrpcOptions +) : Closeable { + private fun channel(serviceName: String, methodName: String) = + "${options.protocol}://${options.host}:${options.port}/$serviceName/$methodName" + + private fun methodDescriptor( + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): MethodDescriptor { + return MethodDescriptor( + "/$serviceName/$methodName", + "unary", + { reqCompanion.asDynamic().defaultInstance }, + { respCompanion.asDynamic().defaultInstance }, + { req: Req -> req.encodeToByteArray() }, + { b: ByteArray -> respCompanion.decodeFromByteArray(b) } + ) + } + + public actual suspend fun call( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): Resp = + call( + request, + reqCompanion, + respCompanion, + serviceName, + methodName, + metadataFromOptions() + ) + + public actual suspend fun callAuth( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + prismMetadata: PrismMetadata + ): Resp = + call( + request, + reqCompanion, + respCompanion, + serviceName, + methodName, + metadata(prismMetadata) + ) + + public actual fun stream( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String + ): Flow = callbackFlow { + stream( + request, + reqCompanion, + respCompanion, + serviceName, + methodName, + metadataFromOptions() + ) + } + + public actual fun streamAuth( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + prismMetadata: PrismMetadata + ): Flow = + callbackFlow { + stream( + request, + reqCompanion, + respCompanion, + serviceName, + methodName, + metadata(prismMetadata) + ) + } + + private suspend fun stream( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + metadata: Metadata + ): Flow = callbackFlow { + val client = GrpcWebClientBase(object : GrpcWebClientBaseOptions {}) + val methodDescriptor = + methodDescriptor(reqCompanion, respCompanion, serviceName, methodName) + + val stream: ClientReadableStream = client.serverStreaming( + channel(serviceName, methodName), + request, + metadata, + methodDescriptor + ) + + stream.on("data") { response: Resp -> trySend(response) } + stream.on("error") { error: Error -> close(RuntimeException(error.message)) } + stream.on("end") { -> close() } + + awaitClose { cancel() } + } + + private suspend fun call( + request: Req, + reqCompanion: Message.Companion, + respCompanion: Message.Companion, + serviceName: String, + methodName: String, + metadata: Metadata + ): Resp { + val client = GrpcWebClientBase(object : GrpcWebClientBaseOptions {}) + val methodDescriptor = + methodDescriptor(reqCompanion, respCompanion, serviceName, methodName) + + return client.thenableCall( + channel(serviceName, methodName), + request, + metadata, + methodDescriptor + ).await() + } + + private fun metadataFromOptions() = json( + PRISM_AUTH_TOKEN to options.token + ).unsafeCast() + + private fun metadata(prismMetadata: PrismMetadata) = json( + DID to prismMetadata.did, + DID_KEY_ID to prismMetadata.didKeyId, + DID_SIGNATURE to Base64Utils.encode(prismMetadata.didSignature), + REQUEST_NONCE to Base64Utils.encode(prismMetadata.requestNonce), + PRISM_AUTH_TOKEN to options.token // See also metadataFromOptions + ).unsafeCast() + + public override fun close() { + } +} diff --git a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/ProtoGlobals.kt b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/ProtoGlobals.kt new file mode 100644 index 000000000..64b01898c --- /dev/null +++ b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/ProtoGlobals.kt @@ -0,0 +1,4 @@ +package io.iohk.atala.prism.protos + +@JsExport +public val noUnknownFields: Map = emptyMap() diff --git a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.StatusCode.module_grpc-web.kt b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.StatusCode.module_grpc-web.kt new file mode 100644 index 000000000..c00d8cdd1 --- /dev/null +++ b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.StatusCode.module_grpc-web.kt @@ -0,0 +1,51 @@ +@file:JsQualifier("grpc_web.StatusCode") +@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS") +package io.iohk.atala.prism.protos.externals + +import kotlin.js.* +import org.khronos.webgl.* +import org.w3c.dom.* +import org.w3c.dom.events.* +import org.w3c.dom.parsing.* +import org.w3c.dom.svg.* +import org.w3c.dom.url.* +import org.w3c.fetch.* +import org.w3c.files.* +import org.w3c.notifications.* +import org.w3c.performance.* +import org.w3c.workers.* +import org.w3c.xhr.* + +internal external var ABORTED: Number + +internal external var ALREADY_EXISTS: Number + +internal external var CANCELLED: Number + +internal external var DATA_LOSS: Number + +internal external var DEADLINE_EXCEEDED: Number + +internal external var FAILED_PRECONDITION: Number + +internal external var INTERNAL: Number + +internal external var INVALID_ARGUMENT: Number + +internal external var NOT_FOUND: Number + +internal external var OK: Number + +internal external var OUT_OF_RANGE: Number + +internal external var PERMISSION_DENIED: Number + +internal external var RESOURCE_EXHAUSTED: Number + +internal external var UNAUTHENTICATED: Number + +internal external var UNAVAILABLE: Number + +internal external var UNIMPLEMENTED: Number + +internal external var UNKNOWN: Number diff --git a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.module_grpc-web.kt b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.module_grpc-web.kt new file mode 100644 index 000000000..ad7d7597b --- /dev/null +++ b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.module_grpc-web.kt @@ -0,0 +1,98 @@ +@file:JsModule("grpc-web") +@file:JsNonModule +@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS") +package io.iohk.atala.prism.protos.externals + +import kotlin.js.* +import org.khronos.webgl.* +import org.w3c.dom.* +import org.w3c.dom.events.* +import org.w3c.dom.parsing.* +import org.w3c.dom.svg.* +import org.w3c.dom.url.* +import org.w3c.fetch.* +import org.w3c.files.* +import org.w3c.notifications.* +import org.w3c.performance.* +import org.w3c.workers.* +import org.w3c.xhr.* + +internal external interface Metadata { + @nativeGetter + operator fun get(s: String): String? + @nativeSetter + operator fun set(s: String, value: String) +} + +internal external open class AbstractClientBase { + open fun thenableCall(method: String, request: REQ, metadata: Metadata, methodDescriptor: MethodDescriptor): Promise + open fun rpcCall(method: String, request: REQ, metadata: Metadata, methodDescriptor: MethodDescriptor, callback: (err: Error, response: RESP) -> Unit): ClientReadableStream + open fun serverStreaming(method: String, request: REQ, metadata: Metadata, methodDescriptor: MethodDescriptor): ClientReadableStream + open class MethodInfo(responseType: Any, requestSerializeFn: (request: REQ) -> Any, responseDeserializeFn: (bytes: Uint8Array) -> RESP) +} + +internal external open class ClientReadableStream { + open fun on(eventType: String /* "error" */, callback: (err: Error) -> Unit): ClientReadableStream + open fun on(eventType: String /* "status" */, callback: (status: Status) -> Unit): ClientReadableStream + open fun on(eventType: String /* "metadata" */, callback: (status: Metadata) -> Unit): ClientReadableStream + open fun on(eventType: String /* "data" */, callback: (response: RESP) -> Unit): ClientReadableStream + open fun on(eventType: String /* "end" */, callback: () -> Unit): ClientReadableStream + open fun removeListener(eventType: String /* "error" */, callback: (err: Error) -> Unit) + open fun removeListener(eventType: String /* "status" */, callback: (status: Status) -> Unit) + open fun removeListener(eventType: String /* "metadata" */, callback: (status: Metadata) -> Unit) + open fun removeListener(eventType: String /* "data" */, callback: (response: RESP) -> Unit) + open fun removeListener(eventType: String /* "end" */, callback: () -> Unit) + open fun cancel() +} + +internal external interface StreamInterceptor { + fun intercept(request: Request, invoker: (request: Request) -> ClientReadableStream): ClientReadableStream +} + +internal external interface UnaryInterceptor { + fun intercept(request: Request, invoker: (request: Request) -> Promise>): Promise> +} + +internal external open class CallOptions(options: Json) + +internal external open class MethodDescriptor(name: String, methodType: Any, requestType: Any, responseType: Any, requestSerializeFn: Any, responseDeserializeFn: Any) { + open fun createRequest(requestMessage: REQ, metadata: Metadata, callOptions: CallOptions): UnaryResponse +} + +internal external open class Request { + open fun getRequestMessage(): REQ + open fun getMethodDescriptor(): MethodDescriptor + open fun getMetadata(): Metadata + open fun getCallOptions(): CallOptions +} + +internal external open class UnaryResponse { + open fun getResponseMessage(): RESP + open fun getMetadata(): Metadata + open fun getMethodDescriptor(): MethodDescriptor + open fun getStatus(): Status +} + +internal external interface GrpcWebClientBaseOptions { + var format: String? + get() = definedExternally + set(value) = definedExternally + var suppressCorsPreflight: Boolean? + get() = definedExternally + set(value) = definedExternally +} + +internal external open class GrpcWebClientBase(options: GrpcWebClientBaseOptions) : AbstractClientBase + +internal external interface Error { + var code: Number + var message: String +} + +internal external interface Status { + var code: Number + var details: String + var metadata: Metadata? + get() = definedExternally + set(value) = definedExternally +} \ No newline at end of file diff --git a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt new file mode 100644 index 000000000..2f5e12670 --- /dev/null +++ b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt @@ -0,0 +1,29 @@ +package io.iohk.atala.prism.protos.util + +public actual object Base64Utils { + // https://regexland.com/base64/ + private val base64Regex = """^(?:[A-Za-z\d+/]{4})*(?:[A-Za-z\d+/]{3}=|[A-Za-z\d+/]{2}==)?$""".toRegex() + + private val bufferImport = js("require('buffer')") + + public actual fun encode(bytes: ByteArray): String { + val buffer = bufferImport.Buffer.from(bytes) + val result = buffer.toString("base64") as String + return result.replace('/', '_').replace('+', '-').dropLastWhile { it == '=' } + } + + public actual fun decode(src: String): ByteArray { + val expectedLength = (src.length + 3) / 4 * 4 + val base64encoded = + src.replace('_', '/').replace('-', '+').padEnd(expectedLength, '=') + if (!base64Regex.matches(base64encoded)) { + throw Exception("\"$base64encoded\" is not a valid base64 string") + } + val decoded = bufferImport.Buffer.from(base64encoded, "base64") + val result = ByteArray(decoded.length as Int) + for (i in result.indices) { + result[i] = (decoded[i] as Int).toByte() + } + return result + } +} diff --git a/prism-protos/webpack.config.d/polyfill.js b/prism-protos/webpack.config.d/polyfill.js new file mode 100644 index 000000000..f5b3bf1c8 --- /dev/null +++ b/prism-protos/webpack.config.d/polyfill.js @@ -0,0 +1,10 @@ +config.resolve = { + fallback: { + stream: require.resolve("stream-browserify") + } +}; +var webpack = require('webpack'); + +config.plugins.push(new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], +})); diff --git a/protosLib/build.gradle.kts b/protosLib/build.gradle.kts index 68c2dcfe8..6749beb41 100644 --- a/protosLib/build.gradle.kts +++ b/protosLib/build.gradle.kts @@ -44,12 +44,12 @@ protobuf { artifact = if (os.isMacOsX) { if (System.getProperty("os.arch") != "x86_64") { // In case of macOS and M1 chip then we need to use a different version of protobuf that support M1 chip arch - "com.google.protobuf:protoc:3.21.9:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" + "com.google.protobuf:protoc:3.12.0:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" } else { - "com.google.protobuf:protoc:3.21.9" + "com.google.protobuf:protoc:3.12.0" } } else { - "com.google.protobuf:protoc:3.21.9" + "com.google.protobuf:protoc:3.12.0" } } plugins { From 23bf2982c3037bab279ded8619fd4f1d5022d830 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Mon, 14 Nov 2022 23:18:19 +0400 Subject: [PATCH 11/21] fix - Handled all kotlin linting issues - Fixed file/class naming as we now have Java in our gradle - Fixe protosLib gradle file --- authenticate-sdk/build.gradle.kts | 2 +- .../prism/authenticatesdk/authenticate.kt | 4 ++-- .../prism/authenticatesdk/createChallenge.kt | 4 ++-- .../authenticate.kt | 2 +- .../createChallenge.kt | 2 +- .../src/jsMain/kotlin/JSExport.kt | 2 +- .../authenticate.kt | 4 ++-- .../createChallenge.kt | 4 ++-- .../prism/authenticatesdk/authenticate.kt | 4 ++-- .../prism/authenticatesdk/createChallenge.kt | 4 ++-- core-sdk/build.gradle.kts | 2 +- .../iohk/atala/prism/walletcore/Platform.kt | 2 +- .../{AtalaClient.kt => httpClient.kt} | 7 ++++--- .../AtalaClient.kt | 21 ++++++++++++------- .../Platform.kt | 2 +- .../httpClient.kt | 7 +++++++ .../Platform.kt | 2 +- .../httpClient.kt} | 7 ++++--- .../iohk/atala/prism/walletcore/Platform.kt | 2 +- .../{AtalaClient.kt => httpClient.kt} | 7 ++++--- .../iohk/atala/prism/walletcore/Platform.kt | 2 +- .../{AtalaClient.kt => httpClient.kt} | 7 ++++--- .../iohk/atala/prism/walletcore/Platform.kt | 2 +- .../atala/prism/walletcore/httpClient.kt} | 7 ++++--- .../Platform.kt | 2 +- .../{AtalaClient.kt => httpClient.kt} | 7 ++++--- .../Platform.kt | 2 +- .../{AtalaClient.kt => httpClient.kt} | 7 ++++--- protosLib/build.gradle.kts | 4 +++- settings.gradle.kts | 1 - wallet-sdk/build.gradle.kts | 2 +- .../WalletSDK.kt | 4 +--- 32 files changed, 78 insertions(+), 60 deletions(-) rename core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/{AtalaClient.kt => httpClient.kt} (56%) create mode 100644 core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt rename core-sdk/src/{macosX64Main/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt => iosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt} (68%) rename core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/{AtalaClient.kt => httpClient.kt} (57%) rename core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/{AtalaClient.kt => httpClient.kt} (56%) rename core-sdk/src/{iosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt => macosX64Main/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt} (68%) rename core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/{AtalaClient.kt => httpClient.kt} (68%) rename core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/{AtalaClient.kt => httpClient.kt} (68%) diff --git a/authenticate-sdk/build.gradle.kts b/authenticate-sdk/build.gradle.kts index cacb66bf5..ac5e23683 100644 --- a/authenticate-sdk/build.gradle.kts +++ b/authenticate-sdk/build.gradle.kts @@ -144,4 +144,4 @@ tasks.withType { // showStackTraces = true // } // } -// } \ No newline at end of file +// } diff --git a/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt b/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt index e91976812..cfd36e701 100644 --- a/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt +++ b/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt @@ -1,5 +1,5 @@ package io.iohk.atala.prism.authenticatesdk -actual fun authenticate(did: String, signature: String, originalText: String):String { - return "hola"; +actual fun authenticate(did: String, signature: String, originalText: String): String { + return "hola" } diff --git a/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt b/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt index 7802f7cf6..ec62ac7e7 100644 --- a/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt +++ b/authenticate-sdk/src/androidMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt @@ -1,5 +1,5 @@ package io.iohk.atala.prism.authenticatesdk actual fun createChallenge(expiration: Int): String { - return "hola"; -} \ No newline at end of file + return "hola" +} diff --git a/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt b/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt index 3231656cb..4d6335d25 100644 --- a/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt +++ b/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt @@ -1,3 +1,3 @@ package io.iohk.atala.prism.authenticatesdk -expect fun authenticate(did: String, signature: String, originalText: String):String +expect fun authenticate(did: String, signature: String, originalText: String): String diff --git a/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt b/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt index 987bd3a03..6fff1bd26 100644 --- a/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt +++ b/authenticate-sdk/src/commonMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt @@ -1,3 +1,3 @@ package io.iohk.atala.prism.authenticatesdk -expect fun createChallenge(expiration: Int): String \ No newline at end of file +expect fun createChallenge(expiration: Int): String diff --git a/authenticate-sdk/src/jsMain/kotlin/JSExport.kt b/authenticate-sdk/src/jsMain/kotlin/JSExport.kt index 837497342..e8f669456 100644 --- a/authenticate-sdk/src/jsMain/kotlin/JSExport.kt +++ b/authenticate-sdk/src/jsMain/kotlin/JSExport.kt @@ -11,4 +11,4 @@ fun jsAuthenticate(did: String, signature: String, originalText: String): String @JsName("createChallenge") fun jsCreateChallenge(expiration: Int): String { return createChallenge(expiration) -} \ No newline at end of file +} diff --git a/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt b/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt index e91976812..cfd36e701 100644 --- a/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt +++ b/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/authenticate.kt @@ -1,5 +1,5 @@ package io.iohk.atala.prism.authenticatesdk -actual fun authenticate(did: String, signature: String, originalText: String):String { - return "hola"; +actual fun authenticate(did: String, signature: String, originalText: String): String { + return "hola" } diff --git a/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt b/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt index 7802f7cf6..ec62ac7e7 100644 --- a/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt +++ b/authenticate-sdk/src/jsMain/kotlin/io.iohk.atala.prism.authenticatesdk/createChallenge.kt @@ -1,5 +1,5 @@ package io.iohk.atala.prism.authenticatesdk actual fun createChallenge(expiration: Int): String { - return "hola"; -} \ No newline at end of file + return "hola" +} diff --git a/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt b/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt index e91976812..cfd36e701 100644 --- a/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt +++ b/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/authenticate.kt @@ -1,5 +1,5 @@ package io.iohk.atala.prism.authenticatesdk -actual fun authenticate(did: String, signature: String, originalText: String):String { - return "hola"; +actual fun authenticate(did: String, signature: String, originalText: String): String { + return "hola" } diff --git a/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt b/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt index 7802f7cf6..ec62ac7e7 100644 --- a/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt +++ b/authenticate-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/authenticatesdk/createChallenge.kt @@ -1,5 +1,5 @@ package io.iohk.atala.prism.authenticatesdk actual fun createChallenge(expiration: Int): String { - return "hola"; -} \ No newline at end of file + return "hola" +} diff --git a/core-sdk/build.gradle.kts b/core-sdk/build.gradle.kts index 196146a3a..cde4014de 100644 --- a/core-sdk/build.gradle.kts +++ b/core-sdk/build.gradle.kts @@ -235,4 +235,4 @@ tasks.withType { // showStackTraces = true // } // } -// } \ No newline at end of file +// } diff --git a/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt index c46a58a8e..fc7f34202 100644 --- a/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt +++ b/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -3,4 +3,4 @@ package io.iohk.atala.prism.walletcore internal actual object Platform { actual val OS: String get() = "Android ${android.os.Build.VERSION.SDK_INT}" -} \ No newline at end of file +} diff --git a/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt b/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt similarity index 56% rename from core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt rename to core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt index d7d70a450..4d3777a99 100644 --- a/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt +++ b/core-sdk/src/androidMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt @@ -1,8 +1,9 @@ package io.iohk.atala.prism.walletcore -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.okhttp.OkHttp internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { config(this) -} \ No newline at end of file +} diff --git a/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt index 290fa0187..e9d9c3a12 100644 --- a/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt +++ b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt @@ -1,11 +1,14 @@ package io.iohk.atala.prism.walletcore -import io.ktor.client.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* - -internal expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClient +import io.ktor.client.HttpClient +import io.ktor.client.request.prepareRequest +import io.ktor.client.statement.HttpResponse +import io.ktor.client.statement.HttpStatement +import io.ktor.http.ContentType +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpMethod +import io.ktor.http.URLProtocol +import io.ktor.http.path class AtalaClient( private val baseURL: String, @@ -20,7 +23,7 @@ class AtalaClient( httpHeaders: Map = mapOf() ): HttpStatement { return client.prepareRequest { - for(header in httpHeaders) { + for (header in httpHeaders) { if ( httpMethod == HttpMethod.Get && header.key == HttpHeaders.ContentType && @@ -58,6 +61,7 @@ class AtalaClient( */ } +/* fun AtalaClient.login() { } @@ -69,4 +73,5 @@ suspend fun x() { "" ) request.execute() -} \ No newline at end of file +} +*/ diff --git a/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt index 36165f8e0..deb17f0f1 100644 --- a/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt +++ b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt @@ -2,4 +2,4 @@ package io.iohk.atala.prism.walletcore internal expect object Platform { val OS: String -} \ No newline at end of file +} diff --git a/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt new file mode 100644 index 000000000..20fbb7ee2 --- /dev/null +++ b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt @@ -0,0 +1,7 @@ +package io.iohk.atala.prism.walletcore + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig + + +internal expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClient diff --git a/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt index 90dc2403d..b2a4c2985 100644 --- a/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt +++ b/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt @@ -5,4 +5,4 @@ import platform.UIKit.UIDevice internal actual object Platform { actual val OS: String get() = "${UIDevice.currentDevice.systemName()}-${UIDevice.currentDevice.systemVersion}" -} \ No newline at end of file +} diff --git a/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt b/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt similarity index 68% rename from core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt rename to core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt index c10ac7d4f..2055ba90f 100644 --- a/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt +++ b/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt @@ -1,7 +1,8 @@ package io.iohk.atala.prism.walletcore -import io.ktor.client.* -import io.ktor.client.engine.darwin.* +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.darwin.Darwin internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { config(this) @@ -10,4 +11,4 @@ internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpCli setAllowsCellularAccess(true) } } -} \ No newline at end of file +} diff --git a/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt index aeacb5434..ae167c4a3 100644 --- a/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt +++ b/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -8,4 +8,4 @@ internal actual object Platform { } else { "JS" } -} \ No newline at end of file +} diff --git a/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt b/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt similarity index 57% rename from core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt rename to core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt index 8232431a8..c4ca03d5b 100644 --- a/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt +++ b/core-sdk/src/jsMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt @@ -1,8 +1,9 @@ package io.iohk.atala.prism.walletcore -import io.ktor.client.* -import io.ktor.client.engine.js.* +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.js.Js internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Js) { config(this) -} \ No newline at end of file +} diff --git a/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt index 21a5caa50..d5e1cafc9 100644 --- a/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt +++ b/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -3,4 +3,4 @@ package io.iohk.atala.prism.walletcore internal actual object Platform { actual val OS: String get() = "JVM - ${System.getProperty("java.version")}" -} \ No newline at end of file +} diff --git a/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt b/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt similarity index 56% rename from core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt rename to core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt index d7d70a450..4d3777a99 100644 --- a/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/AtalaClient.kt +++ b/core-sdk/src/jvmMain/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt @@ -1,8 +1,9 @@ package io.iohk.atala.prism.walletcore -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.okhttp.OkHttp internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { config(this) -} \ No newline at end of file +} diff --git a/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt b/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt index b605c884c..34dfe2bca 100644 --- a/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt +++ b/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/Platform.kt @@ -8,4 +8,4 @@ internal actual object Platform { val processInfo = NSProcessInfo.processInfo() return "${processInfo.operatingSystemName()}-${processInfo.operatingSystemVersionString()}" } -} \ No newline at end of file +} diff --git a/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt b/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt similarity index 68% rename from core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt rename to core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt index c10ac7d4f..2055ba90f 100644 --- a/core-sdk/src/iosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt +++ b/core-sdk/src/macosX64Main/kotlin/io/iohk/atala/prism/walletcore/httpClient.kt @@ -1,7 +1,8 @@ package io.iohk.atala.prism.walletcore -import io.ktor.client.* -import io.ktor.client.engine.darwin.* +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.darwin.Darwin internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { config(this) @@ -10,4 +11,4 @@ internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpCli setAllowsCellularAccess(true) } } -} \ No newline at end of file +} diff --git a/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt index 90dc2403d..b2a4c2985 100644 --- a/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt +++ b/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt @@ -5,4 +5,4 @@ import platform.UIKit.UIDevice internal actual object Platform { actual val OS: String get() = "${UIDevice.currentDevice.systemName()}-${UIDevice.currentDevice.systemVersion}" -} \ No newline at end of file +} diff --git a/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt b/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt similarity index 68% rename from core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt rename to core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt index c10ac7d4f..2055ba90f 100644 --- a/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt +++ b/core-sdk/src/tvosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt @@ -1,7 +1,8 @@ package io.iohk.atala.prism.walletcore -import io.ktor.client.* -import io.ktor.client.engine.darwin.* +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.darwin.Darwin internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { config(this) @@ -10,4 +11,4 @@ internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpCli setAllowsCellularAccess(true) } } -} \ No newline at end of file +} diff --git a/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt b/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt index 2212c6bd7..6619ba4ae 100644 --- a/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt +++ b/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/Platform.kt @@ -8,4 +8,4 @@ internal actual object Platform { val wkInterfaceDevice = WKInterfaceDevice.currentDevice() return "${wkInterfaceDevice.systemName}-${wkInterfaceDevice.systemVersion}" } -} \ No newline at end of file +} diff --git a/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt b/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt similarity index 68% rename from core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt rename to core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt index c10ac7d4f..2055ba90f 100644 --- a/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/AtalaClient.kt +++ b/core-sdk/src/watchosMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt @@ -1,7 +1,8 @@ package io.iohk.atala.prism.walletcore -import io.ktor.client.* -import io.ktor.client.engine.darwin.* +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.darwin.Darwin internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { config(this) @@ -10,4 +11,4 @@ internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpCli setAllowsCellularAccess(true) } } -} \ No newline at end of file +} diff --git a/protosLib/build.gradle.kts b/protosLib/build.gradle.kts index 6749beb41..49be53483 100644 --- a/protosLib/build.gradle.kts +++ b/protosLib/build.gradle.kts @@ -1,5 +1,7 @@ +import com.google.protobuf.gradle.id +import com.google.protobuf.gradle.proto +import com.google.protobuf.gradle.remove import org.gradle.internal.os.OperatingSystem -import com.google.protobuf.gradle.* val os: OperatingSystem = OperatingSystem.current() diff --git a/settings.gradle.kts b/settings.gradle.kts index dfc7b87a7..eeecf8889 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,7 +24,6 @@ buildscript { } } - rootProject.name = "wallet-sdk" include(":protosLib") include(":wallet-sdk") diff --git a/wallet-sdk/build.gradle.kts b/wallet-sdk/build.gradle.kts index 2ab1cacf4..848931317 100644 --- a/wallet-sdk/build.gradle.kts +++ b/wallet-sdk/build.gradle.kts @@ -205,4 +205,4 @@ tasks.withType { // showStackTraces = true // } // } -// } \ No newline at end of file +// } diff --git a/wallet-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletsdk/WalletSDK.kt b/wallet-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletsdk/WalletSDK.kt index 33a2f33a3..65fda0945 100644 --- a/wallet-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletsdk/WalletSDK.kt +++ b/wallet-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletsdk/WalletSDK.kt @@ -1,5 +1,3 @@ package io.iohk.atala.prism.walletsdk -final class WalletSDK { - -} \ No newline at end of file +final class WalletSDK From b86a4ab3d9dcb0d4c14037363b7c73bd66c93ed7 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Mon, 14 Nov 2022 23:23:32 +0400 Subject: [PATCH 12/21] test --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index 96c55af3b..3ca0c51c4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,6 +16,7 @@ plugins { id("org.jlleitschuh.gradle.ktlint") version "11.0.0" id("org.jetbrains.dokka") version "1.7.10" id("com.google.protobuf") version "0.9.1" + // This should be changed // id(Plugins.npmPublish) version PluginVersions.npmPublish apply false // id(Plugins.gitVersion) version PluginVersions.gitVersion // id(Plugins.compatibilityValidator) version PluginVersions.compatibilityValidator From 1ed30cffe5020ac0581013dfce9f3e2be0aa6139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Mon, 14 Nov 2022 21:44:43 +0100 Subject: [PATCH 13/21] fix: Fix dependencies to fully integrate with latest version of packages in prism-protos + protosLib. --- build.gradle.kts | 19 +++++++++++++++++-- prism-protos/build.gradle.kts | 2 +- protosLib/build.gradle.kts | 6 +++--- settings.gradle.kts | 1 + 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3ca0c51c4..ec2c6a52e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,9 +18,9 @@ plugins { id("com.google.protobuf") version "0.9.1" // This should be changed // id(Plugins.npmPublish) version PluginVersions.npmPublish apply false - // id(Plugins.gitVersion) version PluginVersions.gitVersion + id(Plugins.gitVersion) version PluginVersions.gitVersion // id(Plugins.compatibilityValidator) version PluginVersions.compatibilityValidator - // id(Plugins.gitOps) version PluginVersions.gitOps + id(Plugins.gitOps) version PluginVersions.gitOps // id(Plugins.koverage) version PluginVersions.koverage } @@ -44,6 +44,21 @@ buildscript { version = "1.0.0-alpha" group = "io.iohk.atala.prism" +val prismVersion: String by extra { + if (System.getenv("PRISM_SDK_VERSION") != null && System.getenv("PRISM_SDK_VERSION") != "") + System.getenv("PRISM_SDK_VERSION") + else { + val latestReleaseTag: String = grgit.tag.list().filter { tag -> + Regex("""[v]?\d+\.\d+\.\d+$""").matchEntire(tag.name) != null + }.map { + it.name + }.last() + val commitShortSha: String = grgit.head().abbreviatedId + val commitTimestamp = grgit.head().dateTime.toEpochSecond().toString() + "$latestReleaseTag-snapshot-$commitTimestamp-$commitShortSha" + } +} + allprojects { repositories { mavenCentral() diff --git a/prism-protos/build.gradle.kts b/prism-protos/build.gradle.kts index c5d24285b..93b9721a5 100644 --- a/prism-protos/build.gradle.kts +++ b/prism-protos/build.gradle.kts @@ -91,7 +91,7 @@ kotlin { implementation("io.grpc:grpc-kotlin-stub:1.0.0") implementation("io.grpc:grpc-okhttp:1.36.0") implementation("io.grpc:grpc-protobuf-lite:1.36.0") - implementationimplementation("io.iohk:protoc-gen-pbandk-jvm:0.20.7:jvm8@jar") + implementation("io.iohk:protoc-gen-pbandk-jvm:0.20.7:jvm8@jar") } } val jsMain by getting { diff --git a/protosLib/build.gradle.kts b/protosLib/build.gradle.kts index 49be53483..4ef5b27fc 100644 --- a/protosLib/build.gradle.kts +++ b/protosLib/build.gradle.kts @@ -46,12 +46,12 @@ protobuf { artifact = if (os.isMacOsX) { if (System.getProperty("os.arch") != "x86_64") { // In case of macOS and M1 chip then we need to use a different version of protobuf that support M1 chip arch - "com.google.protobuf:protoc:3.12.0:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" + "com.google.protobuf:protoc:3.21.9:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" } else { - "com.google.protobuf:protoc:3.12.0" + "com.google.protobuf:protoc:3.21.9" } } else { - "com.google.protobuf:protoc:3.12.0" + "com.google.protobuf:protoc:3.21.9" } } plugins { diff --git a/settings.gradle.kts b/settings.gradle.kts index eeecf8889..27ff27bcd 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,6 +26,7 @@ buildscript { rootProject.name = "wallet-sdk" include(":protosLib") +include(":prism-protos") include(":wallet-sdk") include(":core-sdk") include(":authenticate-sdk") From 682b1848dfc40c3e4e3e1bc67a73580a6acf2079 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Tue, 15 Nov 2022 07:59:35 +0400 Subject: [PATCH 14/21] enchantments: prism-protos gradle update step 1 --- build.gradle.kts | 33 +++----- prism-protos/build.gradle.kts | 122 ++++++++++++++++++++++-------- prism-protos/prism_protos.podspec | 42 ++++++++++ 3 files changed, 141 insertions(+), 56 deletions(-) create mode 100644 prism-protos/prism_protos.podspec diff --git a/build.gradle.kts b/build.gradle.kts index ec2c6a52e..649447130 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,12 +1,8 @@ import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) - vendor.set(JvmVendorSpec.ADOPTOPENJDK) - } -} +version = "1.0.0-alpha" +group = "io.iohk.atala.prism" plugins { java @@ -16,11 +12,11 @@ plugins { id("org.jlleitschuh.gradle.ktlint") version "11.0.0" id("org.jetbrains.dokka") version "1.7.10" id("com.google.protobuf") version "0.9.1" - // This should be changed + // The following should be removed // id(Plugins.npmPublish) version PluginVersions.npmPublish apply false - id(Plugins.gitVersion) version PluginVersions.gitVersion + // id(Plugins.gitVersion) version PluginVersions.gitVersion // id(Plugins.compatibilityValidator) version PluginVersions.compatibilityValidator - id(Plugins.gitOps) version PluginVersions.gitOps + // id(Plugins.gitOps) version PluginVersions.gitOps // id(Plugins.koverage) version PluginVersions.koverage } @@ -41,21 +37,10 @@ buildscript { } } -version = "1.0.0-alpha" -group = "io.iohk.atala.prism" - -val prismVersion: String by extra { - if (System.getenv("PRISM_SDK_VERSION") != null && System.getenv("PRISM_SDK_VERSION") != "") - System.getenv("PRISM_SDK_VERSION") - else { - val latestReleaseTag: String = grgit.tag.list().filter { tag -> - Regex("""[v]?\d+\.\d+\.\d+$""").matchEntire(tag.name) != null - }.map { - it.name - }.last() - val commitShortSha: String = grgit.head().abbreviatedId - val commitTimestamp = grgit.head().dateTime.toEpochSecond().toString() - "$latestReleaseTag-snapshot-$commitTimestamp-$commitShortSha" +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + vendor.set(JvmVendorSpec.ADOPTOPENJDK) } } diff --git a/prism-protos/build.gradle.kts b/prism-protos/build.gradle.kts index 93b9721a5..61ca5d278 100644 --- a/prism-protos/build.gradle.kts +++ b/prism-protos/build.gradle.kts @@ -1,12 +1,18 @@ -import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile +version = rootProject.version +val currentModuleName: String = "protos" +val os: org.gradle.internal.os.OperatingSystem = org.gradle.internal.os.OperatingSystem.current() + plugins { kotlin("multiplatform") + kotlin("native.cocoapods") id("com.android.library") + id("org.jetbrains.dokka") } repositories { @@ -15,9 +21,6 @@ repositories { } kotlin { - explicitApi() - explicitApi = ExplicitApiMode.Strict - android { publishAllLibraryVariants() } @@ -27,43 +30,74 @@ kotlin { jvmTarget = "11" } } + testRuns["test"].executionTask.configure { + useJUnitPlatform() + } + } + if (os.isMacOsX) { + ios() } js(IR) { - moduleName = "protos" + this.moduleName = currentModuleName + this.binaries.executable() + this.useCommonJs() + this.compilations["main"].packageJson { + this.version = rootProject.version.toString() + } + this.compilations["test"].packageJson { + this.version = rootProject.version.toString() + } browser { - testTask { - useKarma { - useChromeHeadless() + this.webpackTask { + this.output.library = currentModuleName + this.output.libraryTarget = Target.VAR + } + this.commonWebpackConfig { + this.cssSupport { + this.enabled = true + } + } + this.testTask { + this.useKarma { + this.useChromeHeadless() } } } - binaries.library() - useCommonJs() - - val prismVersion: String by rootProject.extra - compilations["main"].packageJson { - version = prismVersion + nodejs { + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } } + } - compilations["test"].packageJson { - version = prismVersion + if (os.isMacOsX) { + cocoapods { + this.summary = "Wallet-Core-SDK" + this.version = rootProject.version.toString() + this.authors = "IOG" + this.ios.deploymentTarget = "13.0" + this.osx.deploymentTarget = "12.0" + this.tvos.deploymentTarget = "13.0" + this.watchos.deploymentTarget = "8.0" + framework { + this.baseName = currentModuleName + } } } - ios("ios") { - binaries.all {} - } sourceSets { val commonMain by getting { kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/main/kotlin") resources.srcDir("${project(":protosLib").projectDir}/src/main") dependencies { - api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1-new-mm-dev2") + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") api("io.iohk:pbandk-runtime:0.20.7") { exclude("com.google.protobuf") } - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1") - implementation("io.ktor:ktor-io:1.6.5") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") + implementation("io.ktor:ktor-io:2.1.3") } } val commonTest by getting { @@ -71,8 +105,14 @@ kotlin { implementation(kotlin("test")) } } + val commonJvmAndroidMain by creating { + dependsOn(commonMain) + } + val commonJvmAndroidTest by creating { + dependsOn(commonTest) + } val androidMain by getting { - kotlin.srcDir("src/commonJvmAndroidMain/kotlin") + dependsOn(commonJvmAndroidMain) // kotlin.srcDir("src/commonJvmAndroidMain/kotlin") kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/commonJvmAndroidMain/kotlin") dependencies { implementation("io.grpc:grpc-kotlin-stub:1.0.0") { @@ -84,8 +124,11 @@ kotlin { implementation("io.iohk:protoc-gen-pbandk-jvm:0.20.7:jvm8@jar") } } + val androidTest by getting { + dependsOn(commonJvmAndroidTest) + } val jvmMain by getting { - kotlin.srcDir("src/commonJvmAndroidMain/kotlin") + dependsOn(commonJvmAndroidMain) // kotlin.srcDir("src/commonJvmAndroidMain/kotlin") kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/commonJvmAndroidMain/kotlin") dependencies { implementation("io.grpc:grpc-kotlin-stub:1.0.0") @@ -94,6 +137,9 @@ kotlin { implementation("io.iohk:protoc-gen-pbandk-jvm:0.20.7:jvm8@jar") } } + val jvmTest by getting { + dependsOn(commonJvmAndroidTest) + } val jsMain by getting { kotlin.srcDir("${project(":protosLib").buildDir}/generated/source/proto/jsMain/kotlin") dependencies { @@ -109,25 +155,37 @@ kotlin { all { languageSettings.optIn("kotlin.js.ExperimentalJsExport") - languageSettings.optIn("io.iohk.atala.prism.common.PrismSdkInternal") } } } android { - compileSdkVersion(Versions.androidTargetSdk) + compileSdk = 32 sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") defaultConfig { - minSdkVersion(26) - targetSdkVersion(29) + minSdk = 21 + targetSdk = 32 + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + /** + * Because Software Components will not be created automatically for Maven publishing from + * Android Gradle Plugin 8.0. To opt-in to the future behavior, set the Gradle property android. + * disableAutomaticComponentCreation=true in the `gradle.properties` file or use the new + * publishing DSL. + */ + publishing { + multipleVariants { + withSourcesJar() + withJavadocJar() + allVariants() + } } } tasks { - "jvmTest"(Test::class) { - useJUnitPlatform() - } - project(":protosLib").tasks .matching { it.name == "generateProto" } .all { diff --git a/prism-protos/prism_protos.podspec b/prism-protos/prism_protos.podspec new file mode 100644 index 000000000..c648fe3a3 --- /dev/null +++ b/prism-protos/prism_protos.podspec @@ -0,0 +1,42 @@ +Pod::Spec.new do |spec| + spec.name = 'prism_protos' + spec.version = '1.0.0-alpha' + spec.homepage = '' + spec.source = { :http=> ''} + spec.authors = 'IOG' + spec.license = '' + spec.summary = 'Wallet-Core-SDK' + spec.vendored_frameworks = 'build/cocoapods/framework/protos.framework' + spec.libraries = 'c++' + spec.ios.deployment_target = '13.0' + spec.osx.deployment_target = '12.0' + spec.tvos.deployment_target = '13.0' + spec.watchos.deployment_target = '8.0' + + + spec.pod_target_xcconfig = { + 'KOTLIN_PROJECT_PATH' => ':prism-protos', + 'PRODUCT_MODULE_NAME' => 'protos', + } + + spec.script_phases = [ + { + :name => 'Build prism_protos', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then + echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"" + exit 0 + fi + set -ev + REPO_ROOT="$PODS_TARGET_SRCROOT" + "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \ + -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \ + -Pkotlin.native.cocoapods.archs="$ARCHS" \ + -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" + SCRIPT + } + ] + +end \ No newline at end of file From 8eaf85217314769d78145adb190c91d3ea84a9ef Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Tue, 15 Nov 2022 08:55:14 +0400 Subject: [PATCH 15/21] feat: add protobuf-gradle-plugin --- build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 649447130..ee5bdffe2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,6 +25,7 @@ buildscript { mavenCentral() mavenLocal() google() + gradlePluginPortal() maven("https://plugins.gradle.org/m2/") // Needed for Kotlin coroutines that support new memory management mode maven { @@ -34,6 +35,7 @@ buildscript { dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20") classpath("com.android.tools.build:gradle:7.2.2") + classpath("com.google.protobuf:protobuf-gradle-plugin:0.9.1") } } From 14aaa887d76b174365adea38b4068979d91fbced Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Tue, 15 Nov 2022 09:03:11 +0400 Subject: [PATCH 16/21] enhancements: - disable all Apple platforms except for iOS - fix gradle build files - add todo comments - remove extra lines in some files - remove annotation @PrismSdkInternal as it is no longer will be used in V2.0 - fix JS external functions --- authenticate-sdk/build.gradle.kts | 2 +- core-sdk/build.gradle.kts | 90 +++++++++---------- core-sdk/core_sdk.podspec | 3 - .../httpClient.kt | 1 - prism-protos/build.gradle.kts | 16 ++-- .../io/iohk/atala/prism/protos/GrpcClient.kt | 4 - .../atala/prism/protos/util/Base64Utils.kt | 1 + .../io/iohk/atala/prism/protos/GrpcClient.kt | 2 - .../atala/prism/protos/util/Base64Utils.kt | 1 + .../atala/prism/protos/util/Base64Utils.kt | 1 + .../index.grpc_web.module_grpc-web.kt | 16 ++-- .../atala/prism/protos/util/Base64Utils.kt | 1 + protosLib/build.gradle.kts | 7 +- wallet-sdk/build.gradle.kts | 66 +++++++------- wallet-sdk/wallet_sdk.podspec | 3 - 15 files changed, 105 insertions(+), 109 deletions(-) diff --git a/authenticate-sdk/build.gradle.kts b/authenticate-sdk/build.gradle.kts index ac5e23683..cfd7c1183 100644 --- a/authenticate-sdk/build.gradle.kts +++ b/authenticate-sdk/build.gradle.kts @@ -65,7 +65,7 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation("com.benasher44:uuid:0.3.0") // Apollo UUID + implementation("com.benasher44:uuid:0.3.0") // TODO("use Apollo UUID") implementation(project(":core-sdk")) } } diff --git a/core-sdk/build.gradle.kts b/core-sdk/build.gradle.kts index cde4014de..592f4dc39 100644 --- a/core-sdk/build.gradle.kts +++ b/core-sdk/build.gradle.kts @@ -29,14 +29,14 @@ kotlin { } if (os.isMacOsX) { ios() - tvos() - watchos() - macosX64() +// tvos() +// watchos() +// macosX64() if (System.getProperty("os.arch") != "x86_64") { // M1Chip iosSimulatorArm64() - tvosSimulatorArm64() - watchosSimulatorArm64() - macosArm64() +// tvosSimulatorArm64() +// watchosSimulatorArm64() +// macosArm64() } } js(IR) { @@ -80,9 +80,9 @@ kotlin { this.version = rootProject.version.toString() this.authors = "IOG" this.ios.deploymentTarget = "13.0" - this.osx.deploymentTarget = "12.0" - this.tvos.deploymentTarget = "13.0" - this.watchos.deploymentTarget = "8.0" +// this.osx.deploymentTarget = "12.0" +// this.tvos.deploymentTarget = "13.0" +// this.watchos.deploymentTarget = "8.0" framework { this.baseName = currentModuleName } @@ -135,24 +135,24 @@ kotlin { } } val iosTest by getting - val tvosMain by getting { - dependencies { - implementation("io.ktor:ktor-client-darwin:2.1.3") - } - } - val tvosTest by getting - val watchosMain by getting { - dependencies { - implementation("io.ktor:ktor-client-darwin:2.1.3") - } - } - val watchosTest by getting - val macosX64Main by getting { - dependencies { - implementation("io.ktor:ktor-client-darwin:2.1.3") - } - } - val macosX64Test by getting +// val tvosMain by getting { +// dependencies { +// implementation("io.ktor:ktor-client-darwin:2.1.3") +// } +// } +// val tvosTest by getting +// val watchosMain by getting { +// dependencies { +// implementation("io.ktor:ktor-client-darwin:2.1.3") +// } +// } +// val watchosTest by getting +// val macosX64Main by getting { +// dependencies { +// implementation("io.ktor:ktor-client-darwin:2.1.3") +// } +// } +// val macosX64Test by getting if (System.getProperty("os.arch") != "x86_64") { // M1Chip val iosSimulatorArm64Main by getting { this.dependsOn(iosMain) @@ -160,24 +160,24 @@ kotlin { val iosSimulatorArm64Test by getting { this.dependsOn(iosTest) } - val tvosSimulatorArm64Main by getting { - this.dependsOn(tvosMain) - } - val tvosSimulatorArm64Test by getting { - this.dependsOn(tvosTest) - } - val watchosSimulatorArm64Main by getting { - this.dependsOn(watchosMain) - } - val watchosSimulatorArm64Test by getting { - this.dependsOn(watchosTest) - } - val macosArm64Main by getting { - this.dependsOn(macosX64Main) - } - val macosArm64Test by getting { - this.dependsOn(macosX64Test) - } +// val tvosSimulatorArm64Main by getting { +// this.dependsOn(tvosMain) +// } +// val tvosSimulatorArm64Test by getting { +// this.dependsOn(tvosTest) +// } +// val watchosSimulatorArm64Main by getting { +// this.dependsOn(watchosMain) +// } +// val watchosSimulatorArm64Test by getting { +// this.dependsOn(watchosTest) +// } +// val macosArm64Main by getting { +// this.dependsOn(macosX64Main) +// } +// val macosArm64Test by getting { +// this.dependsOn(macosX64Test) +// } } } all { diff --git a/core-sdk/core_sdk.podspec b/core-sdk/core_sdk.podspec index d7c7278d3..741eeae49 100644 --- a/core-sdk/core_sdk.podspec +++ b/core-sdk/core_sdk.podspec @@ -9,9 +9,6 @@ Pod::Spec.new do |spec| spec.vendored_frameworks = 'build/cocoapods/framework/wallet_core_sdk.framework' spec.libraries = 'c++' spec.ios.deployment_target = '13.0' - spec.osx.deployment_target = '12.0' - spec.tvos.deployment_target = '13.0' - spec.watchos.deployment_target = '8.0' spec.pod_target_xcconfig = { diff --git a/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt index 20fbb7ee2..4cbaec333 100644 --- a/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt +++ b/core-sdk/src/commonMain/kotlin/io.iohk.atala.prism.walletcore/httpClient.kt @@ -3,5 +3,4 @@ package io.iohk.atala.prism.walletcore import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig - internal expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClient diff --git a/prism-protos/build.gradle.kts b/prism-protos/build.gradle.kts index 61ca5d278..f0ff399ab 100644 --- a/prism-protos/build.gradle.kts +++ b/prism-protos/build.gradle.kts @@ -15,11 +15,6 @@ plugins { id("org.jetbrains.dokka") } -repositories { - mavenCentral() - mavenLocal() -} - kotlin { android { publishAllLibraryVariants() @@ -36,6 +31,9 @@ kotlin { } if (os.isMacOsX) { ios() + if (System.getProperty("os.arch") != "x86_64") { // M1Chip + iosSimulatorArm64() + } } js(IR) { this.moduleName = currentModuleName @@ -152,6 +150,14 @@ kotlin { val jsTest by getting val iosMain by getting val iosTest by getting + if (System.getProperty("os.arch") != "x86_64") { // M1Chip + val iosSimulatorArm64Main by getting { + this.dependsOn(iosMain) + } + val iosSimulatorArm64Test by getting { + this.dependsOn(iosTest) + } + } all { languageSettings.optIn("kotlin.js.ExperimentalJsExport") diff --git a/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt b/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt index d73341337..a9fc58a22 100644 --- a/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt +++ b/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt @@ -3,7 +3,6 @@ package io.iohk.atala.prism.protos import io.grpc.* import io.grpc.kotlin.ClientCalls import io.grpc.stub.MetadataUtils -import io.iohk.atala.prism.common.PrismSdkInternal import io.ktor.utils.io.core.* import kotlinx.coroutines.flow.Flow import pbandk.Message @@ -13,7 +12,6 @@ import java.io.InputStream import java.util.* import java.util.concurrent.TimeUnit -@PrismSdkInternal public actual class GrpcClient actual constructor(options: GrpcOptions) : Closeable { private val channel: ManagedChannel = if (options.protocol == "http") { @@ -23,7 +21,6 @@ public actual class GrpcClient actual constructor(options: GrpcOptions) : Closea } private val token: String? = options.token - @PrismSdkInternal public class MessageMarshaller(private val companion: Message.Companion) : MethodDescriptor.Marshaller { override fun stream(value: T): InputStream = @@ -158,7 +155,6 @@ public actual class GrpcClient actual constructor(options: GrpcOptions) : Closea } } - @PrismSdkInternal public companion object { public val DID_HEADER: Metadata.Key = Metadata.Key.of(DID, Metadata.ASCII_STRING_MARSHALLER) diff --git a/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt b/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt index aab2fa335..5fd9fde2e 100644 --- a/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt +++ b/prism-protos/src/commonJvmAndroidMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt @@ -2,6 +2,7 @@ package io.iohk.atala.prism.protos.util import java.util.* +// TODO("Use Apollo Base64") public actual object Base64Utils { public actual fun encode(bytes: ByteArray): String = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes) diff --git a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt index 20eed30bf..1998776fb 100644 --- a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt +++ b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/GrpcClient.kt @@ -1,6 +1,5 @@ package io.iohk.atala.prism.protos -import io.iohk.atala.prism.common.PrismSdkInternal import io.ktor.utils.io.core.Closeable import kotlinx.coroutines.flow.Flow import pbandk.Message @@ -24,7 +23,6 @@ public const val DID_SIGNATURE: String = "did-signature" public const val REQUEST_NONCE: String = "request-nonce" public const val PRISM_AUTH_TOKEN: String = "prism-auth-token" -@PrismSdkInternal public expect class GrpcClient(options: GrpcOptions) : Closeable { public suspend fun call( request: Req, diff --git a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt index 2c3f0bb3d..d9bc310da 100644 --- a/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt +++ b/prism-protos/src/commonMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt @@ -1,5 +1,6 @@ package io.iohk.atala.prism.protos.util +// TODO("Use Apollo Base64") public expect object Base64Utils { /** * Returns a URL-safe Base64 encoding without padding (i.e. no trailing '='s). diff --git a/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt b/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt index a8c800587..1e211c13c 100644 --- a/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt +++ b/prism-protos/src/iosMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt @@ -6,6 +6,7 @@ import platform.Foundation.base64EncodedStringWithOptions import platform.Foundation.create import platform.posix.memcpy +// TODO("Use Apollo Base64") public actual object Base64Utils { public actual fun encode(bytes: ByteArray): String { val nsData = memScoped { diff --git a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.module_grpc-web.kt b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.module_grpc-web.kt index ad7d7597b..7c624c666 100644 --- a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.module_grpc-web.kt +++ b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/externals/index.grpc_web.module_grpc-web.kt @@ -24,14 +24,14 @@ internal external interface Metadata { operator fun set(s: String, value: String) } -internal external open class AbstractClientBase { +internal open external class AbstractClientBase { open fun thenableCall(method: String, request: REQ, metadata: Metadata, methodDescriptor: MethodDescriptor): Promise open fun rpcCall(method: String, request: REQ, metadata: Metadata, methodDescriptor: MethodDescriptor, callback: (err: Error, response: RESP) -> Unit): ClientReadableStream open fun serverStreaming(method: String, request: REQ, metadata: Metadata, methodDescriptor: MethodDescriptor): ClientReadableStream open class MethodInfo(responseType: Any, requestSerializeFn: (request: REQ) -> Any, responseDeserializeFn: (bytes: Uint8Array) -> RESP) } -internal external open class ClientReadableStream { +internal open external class ClientReadableStream { open fun on(eventType: String /* "error" */, callback: (err: Error) -> Unit): ClientReadableStream open fun on(eventType: String /* "status" */, callback: (status: Status) -> Unit): ClientReadableStream open fun on(eventType: String /* "metadata" */, callback: (status: Metadata) -> Unit): ClientReadableStream @@ -53,20 +53,20 @@ internal external interface UnaryInterceptor { fun intercept(request: Request, invoker: (request: Request) -> Promise>): Promise> } -internal external open class CallOptions(options: Json) +internal open external class CallOptions(options: Json) -internal external open class MethodDescriptor(name: String, methodType: Any, requestType: Any, responseType: Any, requestSerializeFn: Any, responseDeserializeFn: Any) { +internal open external class MethodDescriptor(name: String, methodType: Any, requestType: Any, responseType: Any, requestSerializeFn: Any, responseDeserializeFn: Any) { open fun createRequest(requestMessage: REQ, metadata: Metadata, callOptions: CallOptions): UnaryResponse } -internal external open class Request { +internal open external class Request { open fun getRequestMessage(): REQ open fun getMethodDescriptor(): MethodDescriptor open fun getMetadata(): Metadata open fun getCallOptions(): CallOptions } -internal external open class UnaryResponse { +internal open external class UnaryResponse { open fun getResponseMessage(): RESP open fun getMetadata(): Metadata open fun getMethodDescriptor(): MethodDescriptor @@ -82,7 +82,7 @@ internal external interface GrpcWebClientBaseOptions { set(value) = definedExternally } -internal external open class GrpcWebClientBase(options: GrpcWebClientBaseOptions) : AbstractClientBase +internal open external class GrpcWebClientBase(options: GrpcWebClientBaseOptions) : AbstractClientBase internal external interface Error { var code: Number @@ -95,4 +95,4 @@ internal external interface Status { var metadata: Metadata? get() = definedExternally set(value) = definedExternally -} \ No newline at end of file +} diff --git a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt index 2f5e12670..a8d2da8dd 100644 --- a/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt +++ b/prism-protos/src/jsMain/kotlin/io/iohk/atala/prism/protos/util/Base64Utils.kt @@ -1,5 +1,6 @@ package io.iohk.atala.prism.protos.util +// TODO("Use Apollo Base64") public actual object Base64Utils { // https://regexland.com/base64/ private val base64Regex = """^(?:[A-Za-z\d+/]{4})*(?:[A-Za-z\d+/]{3}=|[A-Za-z\d+/]{2}==)?$""".toRegex() diff --git a/protosLib/build.gradle.kts b/protosLib/build.gradle.kts index 4ef5b27fc..89cef1c17 100644 --- a/protosLib/build.gradle.kts +++ b/protosLib/build.gradle.kts @@ -1,6 +1,5 @@ -import com.google.protobuf.gradle.id -import com.google.protobuf.gradle.proto -import com.google.protobuf.gradle.remove +@file:Suppress("ktlint:no-wildcard-imports") +import com.google.protobuf.gradle.* import org.gradle.internal.os.OperatingSystem val os: OperatingSystem = OperatingSystem.current() @@ -20,7 +19,7 @@ dependencies { jarPathConf("io.iohk.atala:pbandk-prism-clients-generator:0.20.7") // This is needed for includes, ref: https://github.com/google/protobuf-gradle-plugin/issues/41#issuecomment-143884188 - // compileOnly("com.google.protobuf:protobuf-java:3.21.9") + compileOnly("com.google.protobuf:protobuf-java:3.21.9") } sourceSets { diff --git a/wallet-sdk/build.gradle.kts b/wallet-sdk/build.gradle.kts index 848931317..755e93819 100644 --- a/wallet-sdk/build.gradle.kts +++ b/wallet-sdk/build.gradle.kts @@ -29,14 +29,14 @@ kotlin { } if (os.isMacOsX) { ios() - tvos() - watchos() - macosX64() +// tvos() +// watchos() +// macosX64() if (System.getProperty("os.arch") != "x86_64") { // M1Chip iosSimulatorArm64() - tvosSimulatorArm64() - watchosSimulatorArm64() - macosArm64() +// tvosSimulatorArm64() +// watchosSimulatorArm64() +// macosArm64() } } js(IR) { @@ -80,9 +80,9 @@ kotlin { this.version = rootProject.version.toString() this.authors = "IOG" this.ios.deploymentTarget = "13.0" - this.osx.deploymentTarget = "12.0" - this.tvos.deploymentTarget = "13.0" - this.watchos.deploymentTarget = "8.0" +// this.osx.deploymentTarget = "12.0" +// this.tvos.deploymentTarget = "13.0" +// this.watchos.deploymentTarget = "8.0" framework { this.baseName = currentModuleName } @@ -117,12 +117,12 @@ kotlin { if (os.isMacOsX) { val iosMain by getting val iosTest by getting - val tvosMain by getting - val tvosTest by getting - val watchosMain by getting - val watchosTest by getting - val macosX64Main by getting - val macosX64Test by getting +// val tvosMain by getting +// val tvosTest by getting +// val watchosMain by getting +// val watchosTest by getting +// val macosX64Main by getting +// val macosX64Test by getting if (System.getProperty("os.arch") != "x86_64") { // M1Chip val iosSimulatorArm64Main by getting { this.dependsOn(iosMain) @@ -130,24 +130,24 @@ kotlin { val iosSimulatorArm64Test by getting { this.dependsOn(iosTest) } - val tvosSimulatorArm64Main by getting { - this.dependsOn(tvosMain) - } - val tvosSimulatorArm64Test by getting { - this.dependsOn(tvosTest) - } - val watchosSimulatorArm64Main by getting { - this.dependsOn(watchosMain) - } - val watchosSimulatorArm64Test by getting { - this.dependsOn(watchosTest) - } - val macosArm64Main by getting { - this.dependsOn(macosX64Main) - } - val macosArm64Test by getting { - this.dependsOn(macosX64Test) - } +// val tvosSimulatorArm64Main by getting { +// this.dependsOn(tvosMain) +// } +// val tvosSimulatorArm64Test by getting { +// this.dependsOn(tvosTest) +// } +// val watchosSimulatorArm64Main by getting { +// this.dependsOn(watchosMain) +// } +// val watchosSimulatorArm64Test by getting { +// this.dependsOn(watchosTest) +// } +// val macosArm64Main by getting { +// this.dependsOn(macosX64Main) +// } +// val macosArm64Test by getting { +// this.dependsOn(macosX64Test) +// } } } all { diff --git a/wallet-sdk/wallet_sdk.podspec b/wallet-sdk/wallet_sdk.podspec index 43d0bbab5..c7ad23cd0 100644 --- a/wallet-sdk/wallet_sdk.podspec +++ b/wallet-sdk/wallet_sdk.podspec @@ -9,9 +9,6 @@ Pod::Spec.new do |spec| spec.vendored_frameworks = 'build/cocoapods/framework/core_sdk.framework' spec.libraries = 'c++' spec.ios.deployment_target = '13.0' - spec.osx.deployment_target = '12.0' - spec.tvos.deployment_target = '13.0' - spec.watchos.deployment_target = '8.0' spec.pod_target_xcconfig = { From a0f08b4d8e6c2c05aa8143261a7ff336caa99f0b Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Tue, 15 Nov 2022 10:31:23 +0400 Subject: [PATCH 17/21] downgrading com.google.protobuf to 3.12.0 --- protosLib/build.gradle.kts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/protosLib/build.gradle.kts b/protosLib/build.gradle.kts index 89cef1c17..ae0764e56 100644 --- a/protosLib/build.gradle.kts +++ b/protosLib/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { jarPathConf("io.iohk.atala:pbandk-prism-clients-generator:0.20.7") // This is needed for includes, ref: https://github.com/google/protobuf-gradle-plugin/issues/41#issuecomment-143884188 - compileOnly("com.google.protobuf:protobuf-java:3.21.9") + compileOnly("com.google.protobuf:protobuf-java:3.12.0") } sourceSets { @@ -45,12 +45,12 @@ protobuf { artifact = if (os.isMacOsX) { if (System.getProperty("os.arch") != "x86_64") { // In case of macOS and M1 chip then we need to use a different version of protobuf that support M1 chip arch - "com.google.protobuf:protoc:3.21.9:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" + "com.google.protobuf:protoc:3.12.0:osx-x86_64" // "com.google.protobuf:protoc:3.12.0:osx-x86_64" } else { - "com.google.protobuf:protoc:3.21.9" + "com.google.protobuf:protoc:3.12.0" } } else { - "com.google.protobuf:protoc:3.21.9" + "com.google.protobuf:protoc:3.12.0" } } plugins { From ae296193370fd66cb28c7b5938eb7b14a7ea1c69 Mon Sep 17 00:00:00 2001 From: Ahmed Moussa Date: Tue, 15 Nov 2022 15:45:07 +0400 Subject: [PATCH 18/21] workaround: PrismSdkInternal - workaround for PrismSdkInternal which is needed for protoBuf in for Iris replacement --- .../io.iohk.atala.prism.common/PrismSdkInternal.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 prism-protos/src/commonMain/kotlin/io.iohk.atala.prism.common/PrismSdkInternal.kt diff --git a/prism-protos/src/commonMain/kotlin/io.iohk.atala.prism.common/PrismSdkInternal.kt b/prism-protos/src/commonMain/kotlin/io.iohk.atala.prism.common/PrismSdkInternal.kt new file mode 100644 index 000000000..d6a80c055 --- /dev/null +++ b/prism-protos/src/commonMain/kotlin/io.iohk.atala.prism.common/PrismSdkInternal.kt @@ -0,0 +1,12 @@ +package io.iohk.atala.prism.common + +@Retention(AnnotationRetention.BINARY) +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.CONSTRUCTOR, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.VALUE_PARAMETER, +) +public annotation class PrismSdkInternal \ No newline at end of file From 16665d500671bd018ca4c3856b02a2a4d492b54d Mon Sep 17 00:00:00 2001 From: Cristian G Date: Thu, 29 Dec 2022 15:04:08 -0500 Subject: [PATCH 19/21] [Pluto] Define interfaces for the providers to be implemented later on --- pluto/build.gradle.kts | 147 ++++++++++++++++++ pluto/src/androidMain/AndroidManifest.xml | 2 + .../models/CredentialType.kt | 3 + .../io.iohk.atala.prism.pluto/models/DID.kt | 4 + .../models/DIDKeyPairIndex.kt | 5 + .../models/DIDMediator.kt | 4 + .../models/DIDPair.kt | 4 + .../models/DIDPrivateKey.kt | 25 +++ .../models/Message.kt | 3 + .../models/PrivateKey.kt | 4 + .../models/VerifiableCredential.kt | 3 + .../VerifiableCredentialTypeContainer.kt | 3 + .../providers/DIDPairProvider.kt | 15 ++ .../providers/DIDPrivateKeyProvider.kt | 13 ++ .../providers/DIDProvider.kt | 16 ++ .../providers/MediatorProvider.kt | 4 + .../providers/MessageProvider.kt | 4 + .../providers/VerifiableCredentialProvider.kt | 4 + 18 files changed, 263 insertions(+) create mode 100644 pluto/build.gradle.kts create mode 100644 pluto/src/androidMain/AndroidManifest.xml create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/CredentialType.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DID.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDKeyPairIndex.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDMediator.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPair.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPrivateKey.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/Message.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/PrivateKey.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredential.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredentialTypeContainer.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt diff --git a/pluto/build.gradle.kts b/pluto/build.gradle.kts new file mode 100644 index 000000000..cfd7c1183 --- /dev/null +++ b/pluto/build.gradle.kts @@ -0,0 +1,147 @@ +import org.gradle.internal.os.OperatingSystem +import org.jetbrains.dokka.gradle.DokkaTask +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target + +version = rootProject.version +val currentModuleName: String = "authenticate_sdk" +val os: OperatingSystem = OperatingSystem.current() + +plugins { + kotlin("multiplatform") + id("com.android.library") + id("org.jetbrains.dokka") +} + +kotlin { + android { + publishAllLibraryVariants() + } + jvm { + compilations.all { + kotlinOptions { + jvmTarget = "11" + } + } + testRuns["test"].executionTask.configure { + useJUnitPlatform() + } + } + + js(IR) { + this.moduleName = currentModuleName + this.binaries.library() + this.useCommonJs() + this.compilations["main"].packageJson { + this.version = rootProject.version.toString() + } + this.compilations["test"].packageJson { + this.version = rootProject.version.toString() + } + browser { + this.webpackTask { + this.output.library = currentModuleName + this.output.libraryTarget = Target.VAR + } + this.commonWebpackConfig { + this.cssSupport { + this.enabled = true + } + } + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } + } + nodejs { + this.testTask { + this.useKarma { + this.useChromeHeadless() + } + } + } + } + + sourceSets { + val commonMain by getting { + dependencies { + implementation("com.benasher44:uuid:0.3.0") // TODO("use Apollo UUID") + implementation(project(":core-sdk")) + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + } + } + val jvmMain by getting + val jvmTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val androidMain by getting + val androidTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val jsMain by getting + val jsTest by getting + + all { + languageSettings.optIn("kotlin.RequiresOptIn") + } + } +} + +android { + compileSdk = 32 + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdk = 21 + targetSdk = 32 + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + /** + * Because Software Components will not be created automatically for Maven publishing from + * Android Gradle Plugin 8.0. To opt-in to the future behavior, set the Gradle property android. + * disableAutomaticComponentCreation=true in the `gradle.properties` file or use the new + * publishing DSL. + */ + publishing { + multipleVariants { + withSourcesJar() + withJavadocJar() + allVariants() + } + } +} + +// Dokka implementation +tasks.withType { + moduleName.set(project.name) + moduleVersion.set(rootProject.version.toString()) + description = """ + This is a Kotlin Multiplatform Authenticate-SDK Library + """.trimIndent() + dokkaSourceSets { + // TODO: Figure out how to include files to the documentations + named("commonMain") { + includes.from("Module.md", "docs/Module.md") + } + } +} + +// afterEvaluate { +// tasks.withType { +// testLogging { +// events("passed", "skipped", "failed", "standard_out", "standard_error") +// showExceptions = true +// showStackTraces = true +// } +// } +// } diff --git a/pluto/src/androidMain/AndroidManifest.xml b/pluto/src/androidMain/AndroidManifest.xml new file mode 100644 index 000000000..ad65b7668 --- /dev/null +++ b/pluto/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/CredentialType.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/CredentialType.kt new file mode 100644 index 000000000..865171237 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/CredentialType.kt @@ -0,0 +1,3 @@ +package io.iohk.atala.prism.pluto.models + +data class CredentialType() diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DID.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DID.kt new file mode 100644 index 000000000..68ec33275 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DID.kt @@ -0,0 +1,4 @@ +package io.iohk.atala.prism.pluto.models + +class DID { +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDKeyPairIndex.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDKeyPairIndex.kt new file mode 100644 index 000000000..9bfb86e4f --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDKeyPairIndex.kt @@ -0,0 +1,5 @@ +package io.iohk.atala.prism.pluto.models + +data class DIDKeyPair( + val +) diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDMediator.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDMediator.kt new file mode 100644 index 000000000..672715d61 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDMediator.kt @@ -0,0 +1,4 @@ +package io.iohk.atala.prism.pluto.models + +class DIDMediator { +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPair.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPair.kt new file mode 100644 index 000000000..272f2a5c1 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPair.kt @@ -0,0 +1,4 @@ +package io.iohk.atala.prism.pluto.models + +class DIDPair { +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPrivateKey.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPrivateKey.kt new file mode 100644 index 000000000..3671bcd48 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPrivateKey.kt @@ -0,0 +1,25 @@ +package io.iohk.atala.prism.pluto.models + +data class DIDInfo( + val did: DID, + val privateKeys: Array +) { + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as DIDInfo + + if (did != other.did) return false + if (!privateKeys.contentEquals(other.privateKeys)) return false + + return true + } + + override fun hashCode(): Int { + var result = did.hashCode() + result = 31 * result + privateKeys.contentHashCode() + return result + } +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/Message.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/Message.kt new file mode 100644 index 000000000..0e3760128 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/Message.kt @@ -0,0 +1,3 @@ +package io.iohk.atala.prism.pluto.models + +data class Message() diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/PrivateKey.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/PrivateKey.kt new file mode 100644 index 000000000..97c1feeff --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/PrivateKey.kt @@ -0,0 +1,4 @@ +package io.iohk.atala.prism.pluto.models + +class PrivateKey { +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredential.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredential.kt new file mode 100644 index 000000000..47164bdd6 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredential.kt @@ -0,0 +1,3 @@ +package io.iohk.atala.prism.pluto.models + +data class VerifiableCredential() diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredentialTypeContainer.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredentialTypeContainer.kt new file mode 100644 index 000000000..edae95604 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredentialTypeContainer.kt @@ -0,0 +1,3 @@ +package io.iohk.atala.prism.pluto.models + +data class VerifiableCredentialTypeContainer() diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt new file mode 100644 index 000000000..d6fbb40d5 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt @@ -0,0 +1,15 @@ +package io.iohk.atala.prism.pluto + +import io.iohk.atala.prism.pluto.models.DID +import io.iohk.atala.prism.pluto.models.DIDPair +import kotlinx.coroutines.flow.Flow + +interface DIDPairProvider { + + fun getAll(): Flow + + fun getPair(did: DID): Flow + + fun getPair(name: String): Flow + +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt new file mode 100644 index 000000000..83754c903 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt @@ -0,0 +1,13 @@ +package io.iohk.atala.prism.pluto + +import io.iohk.atala.prism.pluto.models.DID +import kotlinx.coroutines.flow.Flow + +interface DIDPrivateKeyProvider { + + fun getAll(): Flow<> + + fun getDIDInfo(did: DID) + + fun getPrivateKeys(did: DID) +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt new file mode 100644 index 000000000..45375d8d5 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt @@ -0,0 +1,16 @@ +package io.iohk.atala.prism.pluto + +import io.iohk.atala.prism.pluto.models.DID + +interface DIDProvider { + + fun getAll() + + fun getDIDInfo(alias: String) + + fun getDIDInfo(did: DID) + + fun getDIDInfo(keyPairIndex: Int) + + fun getLastKeyPairIndex() +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt new file mode 100644 index 000000000..0846c573f --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt @@ -0,0 +1,4 @@ +package io.iohk.atala.prism.pluto.providers + +class MediatorProvider { +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt new file mode 100644 index 000000000..c7399d069 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt @@ -0,0 +1,4 @@ +package io.iohk.atala.prism.pluto.providers + +interface MessageProvider { +} \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt new file mode 100644 index 000000000..73c9e2b4b --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt @@ -0,0 +1,4 @@ +package io.iohk.atala.prism.pluto.providers + +interface VerifiableCredentialProvider { +} \ No newline at end of file From fbb40834f78edef333b470c5d03f95f3860f53f4 Mon Sep 17 00:00:00 2001 From: Cristian G Date: Tue, 3 Jan 2023 09:58:47 -0500 Subject: [PATCH 20/21] Pluto interfaces for the providers --- pluto/build.gradle.kts | 14 ++++- pluto/src/androidMain/AndroidManifest.xml | 2 +- .../models/CredentialType.kt | 6 +- .../io.iohk.atala.prism.pluto/models/DID.kt | 29 +++++++++- .../models/DIDKeyPairIndex.kt | 6 +- .../models/DIDMediator.kt | 7 ++- .../models/DIDPair.kt | 7 ++- .../models/DIDPrivateKey.kt | 4 +- .../models/Message.kt | 56 ++++++++++++++++++- .../models/PrivateKey.kt | 6 +- .../models/VerifiableCredential.kt | 18 +++++- .../VerifiableCredentialTypeContainer.kt | 5 +- .../providers/DIDPairProvider.kt | 4 +- .../providers/DIDPrivateKeyProvider.kt | 13 +++-- .../providers/DIDProvider.kt | 16 +++--- .../providers/MediatorProvider.kt | 10 +++- .../providers/MessageProvider.kt | 21 ++++++- .../providers/VerifiableCredentialProvider.kt | 10 +++- prism-protos/build.gradle.kts | 3 - settings.gradle.kts | 2 + 20 files changed, 198 insertions(+), 41 deletions(-) diff --git a/pluto/build.gradle.kts b/pluto/build.gradle.kts index cfd7c1183..d8a1d2ab4 100644 --- a/pluto/build.gradle.kts +++ b/pluto/build.gradle.kts @@ -3,7 +3,7 @@ import org.jetbrains.dokka.gradle.DokkaTask import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target version = rootProject.version -val currentModuleName: String = "authenticate_sdk" +val currentModuleName: String = "pluto" val os: OperatingSystem = OperatingSystem.current() plugins { @@ -67,6 +67,7 @@ kotlin { dependencies { implementation("com.benasher44:uuid:0.3.0") // TODO("use Apollo UUID") implementation(project(":core-sdk")) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") } } val commonTest by getting { @@ -80,7 +81,11 @@ kotlin { implementation("junit:junit:4.13.2") } } - val androidMain by getting + val androidMain by getting { + dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") + } + } val androidTest by getting { dependencies { implementation("junit:junit:4.13.2") @@ -120,13 +125,16 @@ android { } } } +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:5.8.1") +} // Dokka implementation tasks.withType { moduleName.set(project.name) moduleVersion.set(rootProject.version.toString()) description = """ - This is a Kotlin Multiplatform Authenticate-SDK Library + This is a Kotlin Multiplatform Pluto Library """.trimIndent() dokkaSourceSets { // TODO: Figure out how to include files to the documentations diff --git a/pluto/src/androidMain/AndroidManifest.xml b/pluto/src/androidMain/AndroidManifest.xml index ad65b7668..f056377b5 100644 --- a/pluto/src/androidMain/AndroidManifest.xml +++ b/pluto/src/androidMain/AndroidManifest.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/CredentialType.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/CredentialType.kt index 865171237..e1327349a 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/CredentialType.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/CredentialType.kt @@ -1,3 +1,7 @@ package io.iohk.atala.prism.pluto.models -data class CredentialType() +enum class CredentialType(val type: String) { + JWT("jwt"), + W3C("w3c"), + Unknown("Unknown") +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DID.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DID.kt index 68ec33275..8fb9c9c3a 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DID.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DID.kt @@ -1,4 +1,29 @@ package io.iohk.atala.prism.pluto.models -class DID { -} \ No newline at end of file +data class DID( + val schema: String, + val method: String, + val methodId: String +) { + + constructor( + string: String + ) : this(getSchemaFromString(string), getMethodFromString(string), getMethodIdFromString(string)) + + companion object { + fun getSchemaFromString(string: String): String { + val split = string.split(":") + return split[0] + } + + fun getMethodFromString(string: String): String { + val split = string.split(":") + return split[1] + } + + fun getMethodIdFromString(string: String): String { + val split = string.split(":") + return split[2] + } + } +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDKeyPairIndex.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDKeyPairIndex.kt index 9bfb86e4f..858228a9d 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDKeyPairIndex.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDKeyPairIndex.kt @@ -1,5 +1,7 @@ package io.iohk.atala.prism.pluto.models -data class DIDKeyPair( - val +data class DIDKeyPairIndex( + val did: DID, + val keyPairIndex: Int, + val alias: String? = null ) diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDMediator.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDMediator.kt index 672715d61..da59836ca 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDMediator.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDMediator.kt @@ -1,4 +1,7 @@ package io.iohk.atala.prism.pluto.models -class DIDMediator { -} \ No newline at end of file +data class DIDMediator( + val did: DID, + val routingDID: DID, + val mediatorDID: DID +) diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPair.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPair.kt index 272f2a5c1..b46738a5d 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPair.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPair.kt @@ -1,4 +1,7 @@ package io.iohk.atala.prism.pluto.models -class DIDPair { -} \ No newline at end of file +data class DIDPair( + val holder: DID, + val other: DID, + val name: String? = null +) diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPrivateKey.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPrivateKey.kt index 3671bcd48..cd57eefb6 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPrivateKey.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/DIDPrivateKey.kt @@ -1,6 +1,6 @@ package io.iohk.atala.prism.pluto.models -data class DIDInfo( +data class DIDPrivateKey( val did: DID, val privateKeys: Array ) { @@ -9,7 +9,7 @@ data class DIDInfo( if (this === other) return true if (other == null || this::class != other::class) return false - other as DIDInfo + other as DIDPrivateKey if (did != other.did) return false if (!privateKeys.contentEquals(other.privateKeys)) return false diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/Message.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/Message.kt index 0e3760128..6ad8aea59 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/Message.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/Message.kt @@ -1,3 +1,57 @@ package io.iohk.atala.prism.pluto.models -data class Message() +data class Message( + val id: String, + val piuri: String, + val from: DID?, + val to: DID?, + val fromPrior: String?, + val body: String, // TODO: Change to Data + val extraHeaders: Array, + val createdTime: String, // TODO: Change to Date + val expiresTimePlus: String, // TODO: Change to Date + val attachments: Array, // TODO: Change to AttachmentDescriptor + val thid: String? = null, + val pthid: String? = null, + val ack: Array +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as Message + + if (id != other.id) return false + if (piuri != other.piuri) return false + if (from != other.from) return false + if (to != other.to) return false + if (fromPrior != other.fromPrior) return false + if (body != other.body) return false + if (!extraHeaders.contentEquals(other.extraHeaders)) return false + if (createdTime != other.createdTime) return false + if (expiresTimePlus != other.expiresTimePlus) return false + if (!attachments.contentEquals(other.attachments)) return false + if (thid != other.thid) return false + if (pthid != other.pthid) return false + if (!ack.contentEquals(other.ack)) return false + + return true + } + + override fun hashCode(): Int { + var result = id.hashCode() + result = 31 * result + piuri.hashCode() + result = 31 * result + (from?.hashCode() ?: 0) + result = 31 * result + (to?.hashCode() ?: 0) + result = 31 * result + (fromPrior?.hashCode() ?: 0) + result = 31 * result + body.hashCode() + result = 31 * result + extraHeaders.contentHashCode() + result = 31 * result + createdTime.hashCode() + result = 31 * result + expiresTimePlus.hashCode() + result = 31 * result + attachments.contentHashCode() + result = 31 * result + (thid?.hashCode() ?: 0) + result = 31 * result + (pthid?.hashCode() ?: 0) + result = 31 * result + ack.contentHashCode() + return result + } +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/PrivateKey.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/PrivateKey.kt index 97c1feeff..7871140fe 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/PrivateKey.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/PrivateKey.kt @@ -1,4 +1,6 @@ package io.iohk.atala.prism.pluto.models -class PrivateKey { -} \ No newline at end of file +data class PrivateKey( + val curve: String, // TODO: Change to KeyCurve + val value: String, // TODO: Change to Data +) diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredential.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredential.kt index 47164bdd6..4ca9f6bd2 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredential.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredential.kt @@ -1,3 +1,19 @@ package io.iohk.atala.prism.pluto.models -data class VerifiableCredential() +data class VerifiableCredential( +val credentialType: CredentialType, +val id: String, +val context: Set, +val type: Set, +val issuer: DID, +val issuanceDate: String, // Date +val expirationDate: String?, // Date +val credentialSchema: VerifiableCredentialTypeContainer?, +val credentialSubject: String, +val credentialStatus: VerifiableCredentialTypeContainer?, +val refreshService: VerifiableCredentialTypeContainer?, +val evidence: VerifiableCredentialTypeContainer?, +val termsOfUse: VerifiableCredentialTypeContainer?, +val validFrom: VerifiableCredentialTypeContainer?, +val validUntil: VerifiableCredentialTypeContainer?, +) diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredentialTypeContainer.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredentialTypeContainer.kt index edae95604..647006436 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredentialTypeContainer.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/models/VerifiableCredentialTypeContainer.kt @@ -1,3 +1,6 @@ package io.iohk.atala.prism.pluto.models -data class VerifiableCredentialTypeContainer() +data class VerifiableCredentialTypeContainer( + val id: String, + val type: String +) diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt index d6fbb40d5..64a080a88 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt @@ -1,4 +1,4 @@ -package io.iohk.atala.prism.pluto +package io.iohk.atala.prism.pluto.providers import io.iohk.atala.prism.pluto.models.DID import io.iohk.atala.prism.pluto.models.DIDPair @@ -12,4 +12,4 @@ interface DIDPairProvider { fun getPair(name: String): Flow -} \ No newline at end of file +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt index 83754c903..9f5049842 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt @@ -1,13 +1,16 @@ -package io.iohk.atala.prism.pluto +package io.iohk.atala.prism.pluto.providers import io.iohk.atala.prism.pluto.models.DID +import io.iohk.atala.prism.pluto.models.DIDPrivateKey +import io.iohk.atala.prism.pluto.models.PrivateKey import kotlinx.coroutines.flow.Flow interface DIDPrivateKeyProvider { - fun getAll(): Flow<> + fun getAll(): Flow - fun getDIDInfo(did: DID) + fun getDIDInfo(did: DID): Flow - fun getPrivateKeys(did: DID) -} \ No newline at end of file + fun getPrivateKeys(did: DID): Flow?> + +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt index 45375d8d5..f8e215ae7 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt @@ -1,16 +1,18 @@ -package io.iohk.atala.prism.pluto +package io.iohk.atala.prism.pluto.providers import io.iohk.atala.prism.pluto.models.DID +import io.iohk.atala.prism.pluto.models.DIDKeyPairIndex +import kotlinx.coroutines.flow.Flow interface DIDProvider { - fun getAll() + fun getAll(): Flow - fun getDIDInfo(alias: String) + fun getDIDInfo(alias: String): Flow - fun getDIDInfo(did: DID) + fun getDIDInfo(did: DID): Flow - fun getDIDInfo(keyPairIndex: Int) + fun getDIDInfo(keyPairIndex: Int): Flow - fun getLastKeyPairIndex() -} \ No newline at end of file + fun getLastKeyPairIndex(): Flow +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt index 0846c573f..f90fb2dc3 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt @@ -1,4 +1,10 @@ package io.iohk.atala.prism.pluto.providers -class MediatorProvider { -} \ No newline at end of file +import io.iohk.atala.prism.pluto.models.DIDMediator +import kotlinx.coroutines.flow.Flow + +interface MediatorProvider { + + fun getAll(): Flow + +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt index c7399d069..c19324605 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt @@ -1,4 +1,23 @@ package io.iohk.atala.prism.pluto.providers +import io.iohk.atala.prism.pluto.models.DID +import io.iohk.atala.prism.pluto.models.Message +import kotlinx.coroutines.flow.Flow + interface MessageProvider { -} \ No newline at end of file + + fun getAll(): Flow + + fun getAllFor(did: DID): Flow + + fun getAllSentTo(did: DID): Flow + + fun getAllReceivedFrom(did: DID): Flow + + fun getAllOfType(type: String, relatedWithDID: DID?): Flow + + fun getAll(from: DID, to: DID): Flow + + fun getMessage(id: String): Flow + +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt index 73c9e2b4b..aa52c15c6 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt @@ -1,4 +1,12 @@ package io.iohk.atala.prism.pluto.providers +import io.iohk.atala.prism.pluto.models.VerifiableCredential +import kotlinx.coroutines.flow.Flow + interface VerifiableCredentialProvider { -} \ No newline at end of file + + fun getAll(): Flow> // TODO: Change to VerifiableCredential + + fun getCredential(id: String): Flow // TODO: Change to VerifiableCredential + +} diff --git a/prism-protos/build.gradle.kts b/prism-protos/build.gradle.kts index f0ff399ab..27d90cabc 100644 --- a/prism-protos/build.gradle.kts +++ b/prism-protos/build.gradle.kts @@ -91,9 +91,6 @@ kotlin { resources.srcDir("${project(":protosLib").projectDir}/src/main") dependencies { api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") - api("io.iohk:pbandk-runtime:0.20.7") { - exclude("com.google.protobuf") - } implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") implementation("io.ktor:ktor-io:2.1.3") } diff --git a/settings.gradle.kts b/settings.gradle.kts index 27ff27bcd..96f64967c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,3 +30,5 @@ include(":prism-protos") include(":wallet-sdk") include(":core-sdk") include(":authenticate-sdk") +include(":pluto") +include("domain") From cc325b8e69e245d5b350d41625d514f31182ae43 Mon Sep 17 00:00:00 2001 From: Cristian G Date: Thu, 5 Jan 2023 14:22:49 -0500 Subject: [PATCH 21/21] [ATL-2857] Define secure storage interfaces --- .../DIDProvider.kt => data/interfaces/DID.kt} | 10 ++++++++-- .../interfaces/DIDPair.kt} | 9 +++++++-- .../interfaces/DIDPrivateKey.kt} | 9 +++++++-- .../data/interfaces/Mediator.kt | 14 ++++++++++++++ .../interfaces/Message.kt} | 12 ++++++++++-- .../data/interfaces/VerifiableCredential.kt | 19 +++++++++++++++++++ .../providers/MediatorProvider.kt | 10 ---------- .../providers/VerifiableCredentialProvider.kt | 12 ------------ 8 files changed, 65 insertions(+), 30 deletions(-) rename pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/{providers/DIDProvider.kt => data/interfaces/DID.kt} (68%) rename pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/{providers/DIDPairProvider.kt => data/interfaces/DIDPair.kt} (56%) rename pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/{providers/DIDPrivateKeyProvider.kt => data/interfaces/DIDPrivateKey.kt} (65%) create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/Mediator.kt rename pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/{providers/MessageProvider.kt => data/interfaces/Message.kt} (69%) create mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/VerifiableCredential.kt delete mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt delete mode 100644 pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DID.kt similarity index 68% rename from pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt rename to pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DID.kt index f8e215ae7..5d6831f88 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DID.kt @@ -1,10 +1,10 @@ -package io.iohk.atala.prism.pluto.providers +package io.iohk.atala.prism.pluto.data.interfaces import io.iohk.atala.prism.pluto.models.DID import io.iohk.atala.prism.pluto.models.DIDKeyPairIndex import kotlinx.coroutines.flow.Flow -interface DIDProvider { +interface DID { fun getAll(): Flow @@ -15,4 +15,10 @@ interface DIDProvider { fun getDIDInfo(keyPairIndex: Int): Flow fun getLastKeyPairIndex(): Flow + + fun addDID(did: DID, keyPairIndex: Int, alias: String? = null) + + fun removeDID(did: DID) + + fun removeAll() } diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DIDPair.kt similarity index 56% rename from pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt rename to pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DIDPair.kt index 64a080a88..2c3477a43 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPairProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DIDPair.kt @@ -1,10 +1,10 @@ -package io.iohk.atala.prism.pluto.providers +package io.iohk.atala.prism.pluto.data.interfaces import io.iohk.atala.prism.pluto.models.DID import io.iohk.atala.prism.pluto.models.DIDPair import kotlinx.coroutines.flow.Flow -interface DIDPairProvider { +interface DIDPair { fun getAll(): Flow @@ -12,4 +12,9 @@ interface DIDPairProvider { fun getPair(name: String): Flow + fun addDIDPair(holder: DID, other: DID, name: String) + + fun removeDIDPair(holder: DID, other: DID) + + fun removeAll() } diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DIDPrivateKey.kt similarity index 65% rename from pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt rename to pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DIDPrivateKey.kt index 9f5049842..a3474b77e 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/DIDPrivateKeyProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/DIDPrivateKey.kt @@ -1,11 +1,11 @@ -package io.iohk.atala.prism.pluto.providers +package io.iohk.atala.prism.pluto.data.interfaces import io.iohk.atala.prism.pluto.models.DID import io.iohk.atala.prism.pluto.models.DIDPrivateKey import io.iohk.atala.prism.pluto.models.PrivateKey import kotlinx.coroutines.flow.Flow -interface DIDPrivateKeyProvider { +interface DIDPrivateKey { fun getAll(): Flow @@ -13,4 +13,9 @@ interface DIDPrivateKeyProvider { fun getPrivateKeys(did: DID): Flow?> + fun addDID(did: DID, privateKeys: Array) + + fun removeDID(did: DID) + + fun removeAll() } diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/Mediator.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/Mediator.kt new file mode 100644 index 000000000..12718bd4d --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/Mediator.kt @@ -0,0 +1,14 @@ +package io.iohk.atala.prism.pluto.data.interfaces + +import io.iohk.atala.prism.pluto.models.DID +import io.iohk.atala.prism.pluto.models.DIDMediator +import kotlinx.coroutines.flow.Flow + +interface Mediator { + + fun getAll(): Flow + + fun addMediator(peer: DID, routingDID: DID, mediatorDID: DID) + + fun removeMediator(peer: DID) +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/Message.kt similarity index 69% rename from pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt rename to pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/Message.kt index c19324605..55d7e1367 100644 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MessageProvider.kt +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/Message.kt @@ -1,10 +1,10 @@ -package io.iohk.atala.prism.pluto.providers +package io.iohk.atala.prism.pluto.data.interfaces import io.iohk.atala.prism.pluto.models.DID import io.iohk.atala.prism.pluto.models.Message import kotlinx.coroutines.flow.Flow -interface MessageProvider { +interface Message { fun getAll(): Flow @@ -20,4 +20,12 @@ interface MessageProvider { fun getMessage(id: String): Flow + fun addMessages(messages: Array) + + fun addMessage(message: Message) + + fun removeMessage(id: String) + + fun removeAll() + } diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/VerifiableCredential.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/VerifiableCredential.kt new file mode 100644 index 000000000..03ea551a5 --- /dev/null +++ b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/data/interfaces/VerifiableCredential.kt @@ -0,0 +1,19 @@ +package io.iohk.atala.prism.pluto.data.interfaces + +import io.iohk.atala.prism.pluto.models.VerifiableCredential +import kotlinx.coroutines.flow.Flow + +interface VerifiableCredential { + + fun getAll(): Flow> + + fun getCredential(id: String): Flow + + fun addCredentials(credentials: Array) + + fun addCredential(credential: VerifiableCredential) + + fun removeCredential(id: String) + + fun removeAll() +} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt deleted file mode 100644 index f90fb2dc3..000000000 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/MediatorProvider.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.iohk.atala.prism.pluto.providers - -import io.iohk.atala.prism.pluto.models.DIDMediator -import kotlinx.coroutines.flow.Flow - -interface MediatorProvider { - - fun getAll(): Flow - -} diff --git a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt b/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt deleted file mode 100644 index aa52c15c6..000000000 --- a/pluto/src/commonMain/kotlin/io.iohk.atala.prism.pluto/providers/VerifiableCredentialProvider.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.iohk.atala.prism.pluto.providers - -import io.iohk.atala.prism.pluto.models.VerifiableCredential -import kotlinx.coroutines.flow.Flow - -interface VerifiableCredentialProvider { - - fun getAll(): Flow> // TODO: Change to VerifiableCredential - - fun getCredential(id: String): Flow // TODO: Change to VerifiableCredential - -}